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

📄 dev.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
 *	This routine causes all interfaces to try to send some data.  */ static void dev_transmit(void){	struct device *dev;	for (dev = dev_base; dev != NULL; dev = dev->next)	{		if (dev->flags != 0 && !dev->tbusy) {			/*			 *	Kick the device			 */			dev_tint(dev);		}	}}/**********************************************************************************			Receive Queue Processor			***********************************************************************************//* *	When we are called the queue is ready to grab, the interrupts are *	on and hardware can interrupt and queue to the receive queue as we *	run with no problems. *	This is run as a bottom half after an interrupt handler that does *	mark_bh(NET_BH); */ void net_bh(void){	struct packet_type *ptype;	struct packet_type *pt_prev;	unsigned short type;	/*	 *	Can we send anything now? We want to clear the	 *	decks for any more sends that get done as we	 *	process the input. This also minimises the	 *	latency on a transmit interrupt bh.	 */	dev_transmit();  	/*	 *	Any data left to process. This may occur because a	 *	mark_bh() is done after we empty the queue including	 *	that from the device which does a mark_bh() just after	 */	/*	 *	While the queue is not empty..	 *	 *	Note that the queue never shrinks due to	 *	an interrupt, so we can do this test without	 *	disabling interrupts.	 */	while (!skb_queue_empty(&backlog)) {		struct sk_buff * skb = backlog.next;		/*		 *	We have a packet. Therefore the queue has shrunk		 */		cli();		__skb_unlink(skb, &backlog);  		backlog_size--;		sti();		#ifdef CONFIG_BRIDGE		/*		 *	If we are bridging then pass the frame up to the		 *	bridging code. If it is bridged then move on		 */		 		if (br_stats.flags & BR_UP)		{			/*			 *	We pass the bridge a complete frame. This means			 *	recovering the MAC header first.			 */			 			int offset=skb->data-skb->mac.raw;			cli();			skb_push(skb,offset);	/* Put header back on for bridge */			if(br_receive_frame(skb))			{				sti();				continue;			}			/*			 *	Pull the MAC header off for the copy going to			 *	the upper layers.			 */			skb_pull(skb,offset);			sti();		}#endif				/*	 	 *	Bump the pointer to the next structure.		 * 		 *	On entry to the protocol layer. skb->data and		 *	skb->h.raw point to the MAC and encapsulated data		 */		skb->h.raw = skb->data;		/*		 * 	Fetch the packet protocol ID. 		 */				type = skb->protocol;		/*		 *	We got a packet ID.  Now loop over the "known protocols"		 * 	list. There are two lists. The ptype_all list of taps (normally empty)		 *	and the main protocol list which is hashed perfectly for normal protocols.		 */				pt_prev = NULL;		for (ptype = ptype_all; ptype!=NULL; ptype=ptype->next)		{			if(!ptype->dev || ptype->dev == skb->dev) {				if(pt_prev) {					struct sk_buff *skb2=skb_clone(skb, GFP_ATOMIC);					if(skb2)						pt_prev->func(skb2,skb->dev, pt_prev);				}				pt_prev=ptype;			}		}				for (ptype = ptype_base[ntohs(type)&15]; ptype != NULL; ptype = ptype->next) 		{			if (ptype->type == type && (!ptype->dev || ptype->dev==skb->dev))			{				/*				 *	We already have a match queued. Deliver				 *	to it and then remember the new match				 */				if(pt_prev)				{					struct sk_buff *skb2;					skb2=skb_clone(skb, GFP_ATOMIC);					/*					 *	Kick the protocol handler. This should be fast					 *	and efficient code.					 */					if(skb2)						pt_prev->func(skb2, skb->dev, pt_prev);				}				/* Remember the current last to do */				pt_prev=ptype;			}		} /* End of protocol list loop */				/*		 *	Is there a last item to send to ?		 */		if(pt_prev)			pt_prev->func(skb, skb->dev, pt_prev);		/*		 * 	Has an unknown packet has been received ?		 */	 		else			kfree_skb(skb, FREE_WRITE);		/*		 *	Again, see if we can transmit anything now. 		 *	[Ought to take this out judging by tests it slows		 *	 us down not speeds us up]		 */#ifdef XMIT_EVERY		dev_transmit();#endif		  	}	/* End of queue loop */  	  	/*  	 *	We have emptied the queue  	 */		/*	 *	One last output flush.	 */#ifdef XMIT_AFTER	 	dev_transmit();#endif}/* *	This routine is called when an device driver (i.e. an *	interface) is ready to transmit a packet. */ void dev_tint(struct device *dev){	int i;	unsigned long flags;	struct sk_buff_head * head;		/*	 * aliases do not transmit (for now :) )	 */#ifdef CONFIG_NET_ALIAS	if (net_alias_is(dev)) return;#endif	head = dev->buffs;	save_flags(flags);	cli();	/*	 *	Work the queues in priority order	 */	 	for(i = 0;i < DEV_NUMBUFFS; i++,head++)	{		while (!skb_queue_empty(head)) {			struct sk_buff *skb;			skb = head->next;			__skb_unlink(skb, head);			/*			 *	Stop anyone freeing the buffer while we retransmit it			 */			skb_device_lock(skb);			restore_flags(flags);			/*			 *	Feed them to the output stage and if it fails			 *	indicate they re-queue at the front.			 */			do_dev_queue_xmit(skb,dev,-i - 1);			/*			 *	If we can take no more then stop here.			 */			if (dev->tbusy)				return;			cli();		}	}	restore_flags(flags);}/* *	Perform a SIOCGIFCONF call. This structure will change *	size shortly, and there is nothing I can do about it. *	Thus we will need a 'compatibility mode'. */static int dev_ifconf(char *arg){	struct ifconf ifc;	struct ifreq ifr;	struct device *dev;	char *pos;	int len;	int err;	/*	 *	Fetch the caller's info block. 	 */	 	err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf));	if(err)	  	return err;	memcpy_fromfs(&ifc, arg, sizeof(struct ifconf));	len = ifc.ifc_len;	pos = ifc.ifc_buf;	/*	 *	We now walk the device list filling each active device	 *	into the array.	 */	 	err=verify_area(VERIFY_WRITE,pos,len);	if(err)	  	return err;  		/*	 *	Loop over the interfaces, and write an info block for each. 	 */	for (dev = dev_base; dev != NULL; dev = dev->next) 	{		if(!(dev->flags & IFF_UP))	/* Downed devices don't count */			continue;		/*		 *	Have we run out of space here ?		 */			if (len < sizeof(struct ifreq)) 			break;		memset(&ifr, 0, sizeof(struct ifreq));		strcpy(ifr.ifr_name, dev->name);		(*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = dev->family;		(*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr;		/*		 *	Write this block to the caller's space. 		 */		 		memcpy_tofs(pos, &ifr, sizeof(struct ifreq));		pos += sizeof(struct ifreq);		len -= sizeof(struct ifreq);		  	}	/*	 *	All done.  Write the updated control block back to the caller. 	 */	 	ifc.ifc_len = (pos - ifc.ifc_buf);	ifc.ifc_req = (struct ifreq *) ifc.ifc_buf;	memcpy_tofs(arg, &ifc, sizeof(struct ifconf));		/*	 *	Report how much was filled in	 */	 	return(pos - arg);}/* *	This is invoked by the /proc filesystem handler to display a device *	in detail. */#ifdef CONFIG_PROC_FSstatic int sprintf_stats(char *buffer, struct device *dev){	struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL);	int size;		if (stats)		size = sprintf(buffer, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n",		   dev->name,		   stats->rx_packets, stats->rx_errors,		   stats->rx_dropped + stats->rx_missed_errors,		   stats->rx_fifo_errors,		   stats->rx_length_errors + stats->rx_over_errors		   + stats->rx_crc_errors + stats->rx_frame_errors,		   stats->tx_packets, stats->tx_errors, stats->tx_dropped,		   stats->tx_fifo_errors, stats->collisions,		   stats->tx_carrier_errors + stats->tx_aborted_errors		   + stats->tx_window_errors + stats->tx_heartbeat_errors);	else		size = sprintf(buffer, "%6s: No statistics available.\n", dev->name);	return size;}/* *	Called from the PROCfs module. This now uses the new arbitrary sized /proc/net interface *	to create /proc/net/dev */ int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy){	int len=0;	off_t begin=0;	off_t pos=0;	int size;		struct device *dev;	size = sprintf(buffer, "Inter-|   Receive                  |  Transmit\n"			    " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n");		pos+=size;	len+=size;		for (dev = dev_base; dev != NULL; dev = dev->next) 	{		size = sprintf_stats(buffer+len, dev);		len+=size;		pos=begin+len;						if(pos<offset)		{			len=0;			begin=pos;		}		if(pos>offset+length)			break;	}		*start=buffer+(offset-begin);	/* Start of wanted data */	len-=(offset-begin);		/* Start slop */	if(len>length)		len=length;		/* Ending slop */	return len;}#endif	/* CONFIG_PROC_FS */#ifdef CONFIG_NET_RADIO#ifdef CONFIG_PROC_FS/* * Print one entry of /proc/net/wireless * This is a clone of /proc/net/dev (just above) */static intsprintf_wireless_stats(char *		buffer,		       struct device *	dev){	/* Get stats from the driver */	struct iw_statistics *stats = (dev->get_wireless_stats ?				       dev->get_wireless_stats(dev) :				       (struct iw_statistics *) NULL);	int size;		if(stats != (struct iw_statistics *) NULL)		size = sprintf(buffer,			       "%6s: %02x  %3d%c %3d%c  %3d%c %5d %5d %5d\n",			       dev->name,			       stats->status,			       stats->qual.qual,			       stats->qual.updated & 1 ? '.' : ' ',			       stats->qual.level,			       stats->qual.updated & 2 ? '.' : ' ',			       stats->qual.noise,			       stats->qual.updated & 3 ? '.' : ' ',			       stats->discard.nwid,			       stats->discard.code,			       stats->discard.misc);	else		size = 0;	return size;}/* * Print info for /proc/net/wireless (print all entries) * This is a clone of /proc/net/dev (just above) */intdev_get_wireless_info(char *	buffer,		      char **	start,		      off_t	offset,		      int	length,		      int	dummy){	int		len = 0;	off_t		begin = 0;	off_t		pos = 0;	int		size;	struct device *	dev;	size = sprintf(buffer,		       "Inter-|sta|  Quality       |  Discarded packets\n"		       " face |tus|link level noise| nwid crypt  misc\n");		pos+=size;	len+=size;	for(dev = dev_base; dev != NULL; dev = dev->next) 	{		size = sprintf_wireless_stats(buffer+len, dev);		len+=size;		pos=begin+len;		if(pos < offset)		{			len=0;			begin=pos;		}		if(pos > offset + length)			break;	}	*start = buffer + (offset - begin);	/* Start of wanted data */	len -= (offset - begin);		/* Start slop */	if(len > length)		len = length;		/* Ending slop */	return len;}#endif	/* CONFIG_PROC_FS */#endif	/* CONFIG_NET_RADIO *//* *	This checks bitmasks for the ioctl calls for devices. */ static inline int bad_mask(unsigned long mask, unsigned long addr){	if (addr & (mask = ~mask))		return 1;	mask = ntohl(mask);	if (mask & (mask+1))		return 1;	return 0;}/* *	Perform the SIOCxIFxxx calls.  * *	The socket layer has seen an ioctl the address family thinks is *	for the device. At this point we get invoked to make a decision */ static int dev_ifsioc(void *arg, unsigned int getset){	struct ifreq ifr;	struct device *dev;	int ret;	/*	 *	Fetch the caller's info block into kernel space	 */	int err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq));	if(err)		return err;		memcpy_fromfs(&ifr, arg, sizeof(struct ifreq));	/*	 *	See which interface the caller is talking about. 	 */	 	/*

⌨️ 快捷键说明

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