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

📄 dev.c

📁 完整的1.0代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * INET		An implementation of the TCP/IP protocol suite for the LINUX *		operating system.  INET is implemented using the  BSD Socket *		interface as the means of communication with the user level. * *		Interface (streams) handling functions. * * Version:	@(#)dev.c	1.0.19	05/31/93 * * Authors:	Ross Biro, <bir7@leland.Stanford.Edu> *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> *		Mark Evans, <evansmp@uhura.aston.ac.uk> *  * Fixes:	 *		Alan Cox:	check_addr returns a value for a wrong subnet *				ie not us but don't forward this! *		Alan Cox:	block timer if the inet_bh handler is running *		Alan Cox:	generic queue code added. A lot neater now *		C.E.Hawkins:	SIOCGIFCONF only reports 'upped' interfaces *		C.E.Hawkins:	IFF_PROMISC support *		Alan Cox:	Supports Donald Beckers new hardware  *				multicast layer, but not yet multicast lists. *		Alan Cox:	ip_addr_match problems with class A/B nets. *		C.E.Hawkins	IP 0.0.0.0 and also same net route fix. [FIXME: Ought to cause ICMP_REDIRECT] *		Alan Cox:	Removed bogus subnet check now the subnet code *				a) actually works for all A/B nets *				b) doesn't forward off the same interface. *		Alan Cox:	Multiple extra protocols *		Alan Cox:	Fixed ifconfig up of dud device setting the up flag *		Alan Cox:	Fixed verify_area errors *		Alan Cox:	Removed IP_SET_DEV as per Fred's comment. I hope this doesn't give *				anything away 8) * *		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. */#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 "inet.h"#include "dev.h"#include "eth.h"#include "ip.h"#include "route.h"#include "protocol.h"#include "tcp.h"#include "skbuff.h"#include "sock.h"#include "arp.h"#ifdef CONFIG_AX25#include "ax25.h"#endif#ifdef CONFIG_IPXstatic struct packet_type ipx_8023_type = {  NET16(ETH_P_802_3),  0,  ipx_rcv,  NULL,  NULL};static struct packet_type ipx_packet_type = {  NET16(ETH_P_IPX),  0,  ipx_rcv,  NULL,  &ipx_8023_type};#endif#ifdef CONFIG_AX25static struct packet_type ax25_packet_type = {  NET16(ETH_P_AX25),  0,  ax25_rcv,  NULL,#ifdef CONFIG_IPX  &ipx_packet_type#else  NULL#endif};#endifstatic struct packet_type arp_packet_type = {  NET16(ETH_P_ARP),  0,		/* copy */  arp_rcv,  NULL,#ifdef CONFIG_IPX#ifndef CONFIG_AX25  &ipx_packet_type#else  &ax25_packet_type#endif#else#ifdef CONFIG_AX25  &ax25_packet_type#else  NULL		/* next */#endif#endif};static struct packet_type ip_packet_type = {  NET16(ETH_P_IP),  0,		/* copy */  ip_rcv,  NULL,  &arp_packet_type};   struct packet_type *ptype_base = &ip_packet_type;static struct sk_buff *volatile backlog = NULL;static unsigned long ip_bcast = 0;/* Return the lesser of the two values. */static unsigned longmin(unsigned long a, unsigned long b){  if (a < b) return(a);  return(b);}/* Determine a default network mask, based on the IP address. */static unsigned longget_mask(unsigned long addr){  unsigned long dst;  if (addr == 0L)   	return(0L);	/* special case */  dst = ntohl(addr);  if (IN_CLASSA(dst))   	return(htonl(IN_CLASSA_NET));  if (IN_CLASSB(dst))   	return(htonl(IN_CLASSB_NET));  if (IN_CLASSC(dst))   	return(htonl(IN_CLASSC_NET));    /* Something else, probably a subnet. */  return(0);}intip_addr_match(unsigned long me, unsigned long him){  int i;  unsigned long mask=0xFFFFFFFF;  DPRINTF((DBG_DEV, "ip_addr_match(%s, ", in_ntoa(me)));  DPRINTF((DBG_DEV, "%s)\n", in_ntoa(him)));  if (me == him)   	return(1);  for (i = 0; i < 4; i++, me >>= 8, him >>= 8, mask >>= 8) {	if ((me & 0xFF) != (him & 0xFF)) {		/*		 * The only way this could be a match is for		 * the rest of addr1 to be 0 or 255.		 */		if (me != 0 && me != mask) return(0);		return(1);	}  }  return(1);}/* Check the address for our address, broadcasts, etc. */int chk_addr(unsigned long addr){	struct device *dev;	unsigned long mask;	/* Accept both `all ones' and `all zeros' as BROADCAST. */	if (addr == INADDR_ANY || addr == INADDR_BROADCAST)		return IS_BROADCAST;	mask = get_mask(addr);	/* Accept all of the `loopback' class A net. */	if ((addr & mask) == htonl(0x7F000000L))		return IS_MYADDR;	/* OK, now check the interface addresses. */	for (dev = dev_base; dev != NULL; dev = dev->next) {		if (!(dev->flags & IFF_UP))			continue;		if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/)			return IS_MYADDR;		/* Is it the exact IP address? */		if (addr == dev->pa_addr)			return IS_MYADDR;		/* Is it our broadcast address? */		if ((dev->flags & IFF_BROADCAST) && addr == dev->pa_brdaddr)			return IS_BROADCAST;		/* Nope. Check for a subnetwork broadcast. */		if (((addr ^ dev->pa_addr) & dev->pa_mask) == 0) {			if ((addr & ~dev->pa_mask) == 0)				return IS_BROADCAST;			if ((addr & ~dev->pa_mask) == ~dev->pa_mask)				return IS_BROADCAST;		}		/* Nope. Check for Network broadcast. */		if (((addr ^ dev->pa_addr) & mask) == 0) {			if ((addr & ~mask) == 0)				return IS_BROADCAST;			if ((addr & ~mask) == ~mask)				return IS_BROADCAST;		}	}	return 0;		/* no match at all */}/* * Retrieve our own address. * Because the loopback address (127.0.0.1) is already recognized * automatically, we can use the loopback interface's address as * our "primary" interface.  This is the addressed used by IP et * al when it doesn't know which address to use (i.e. it does not * yet know from or to which interface to go...). */unsigned longmy_addr(void){  struct device *dev;  for (dev = dev_base; dev != NULL; dev = dev->next) {	if (dev->flags & IFF_LOOPBACK) return(dev->pa_addr);  }  return(0);}static int dev_nit=0; /* Number of network taps running *//* Add a protocol ID to the list.  This will change soon. */voiddev_add_pack(struct packet_type *pt){  struct packet_type *p1;  pt->next = ptype_base;  /* Don't use copy counts on ETH_P_ALL. Instead keep a global     count of number of these and use it and pt->copy to decide     copies */  pt->copy=0;  if(pt->type==NET16(ETH_P_ALL))  	dev_nit++;	/* I'd like a /dev/nit too one day 8) */  else  {  	/* See if we need to copy it. */  	for (p1 = ptype_base; p1 != NULL; p1 = p1->next) {		if (p1->type == pt->type) {			pt->copy = 1;			break;		}	  }  }    /*   *	NIT taps must go at the end or inet_bh will leak!   */     if(pt->type==NET16(ETH_P_ALL))  {  	pt->next=NULL;  	if(ptype_base==NULL)	  	ptype_base=pt;	else	{		for(p1=ptype_base;p1->next!=NULL;p1=p1->next);		p1->next=pt;	}  }  else  	ptype_base = pt;}/* Remove a protocol ID from the list.  This will change soon. */voiddev_remove_pack(struct packet_type *pt){  struct packet_type *lpt, *pt1;  if (pt->type == NET16(ETH_P_ALL))  	dev_nit--;  if (pt == ptype_base) {	ptype_base = pt->next;	return;  }  lpt = NULL;  for (pt1 = ptype_base; pt1->next != NULL; pt1 = pt1->next) {	if (pt1->next == pt ) {		cli();		if (!pt->copy && lpt) 			lpt->copy = 0;		pt1->next = pt->next;		sti();		return;	}	if (pt1->next -> type == pt ->type && pt->type != NET16(ETH_P_ALL)) {		lpt = pt1->next;	}  }}/* Find an interface in the list. This will change soon. */struct device *dev_get(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 an interface that can handle addresses for a certain address. */struct device * dev_check(unsigned long addr){	struct device *dev;	for (dev = dev_base; dev; dev = dev->next) {		if (!(dev->flags & IFF_UP))			continue;		if (!(dev->flags & IFF_POINTOPOINT))			continue;		if (addr != dev->pa_dstaddr)			continue;		return dev;	}	for (dev = dev_base; dev; dev = dev->next) {		if (!(dev->flags & IFF_UP))			continue;		if (dev->flags & IFF_POINTOPOINT)			continue;		if (dev->pa_mask & (addr ^ dev->pa_addr))			continue;		return dev;	}	return NULL;}/* Prepare an interface for use. */intdev_open(struct device *dev){  int ret = 0;  if (dev->open)   	ret = dev->open(dev);  if (ret == 0)   	dev->flags |= (IFF_UP | IFF_RUNNING);  return(ret);}/* Completely shutdown an interface. */intdev_close(struct device *dev){  if (dev->flags != 0) {  	int ct=0;	dev->flags = 0;	if (dev->stop) 		dev->stop(dev);	rt_flush(dev);	dev->pa_addr = 0;	dev->pa_dstaddr = 0;	dev->pa_brdaddr = 0;	dev->pa_mask = 0;	/* 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);}/* Send (or queue for sending) a packet. */voiddev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri){  int where = 0;		/* used to say if the packet should go	*/				/* at the front or the back of the	*/				/* queue.				*/  DPRINTF((DBG_DEV, "dev_queue_xmit(skb=%X, dev=%X, pri = %d)\n",							skb, dev, pri));  if (dev == NULL) {	printk("dev.c: dev_queue_xmit: dev = NULL\n");	return;  }   IS_SKB(skb);      skb->dev = dev;  if (skb->next != NULL) {	/* Make sure we haven't missed an interrupt. */	dev->hard_start_xmit(NULL, dev);	return;  }  if (pri < 0) {	pri = -pri-1;	where = 1;  }  if (pri >= DEV_NUMBUFFS) {	printk("bad priority in dev_queue_xmit.\n");	pri = 1;  }  if (dev->hard_start_xmit(skb, dev) == 0) {	return;  }  /* Put skb into a bidirectional circular linked list. */  DPRINTF((DBG_DEV, "dev_queue_xmit dev->buffs[%d]=%X\n",					pri, dev->buffs[pri]));  /* Interrupts should already be cleared by hard_start_xmit. */  cli();  skb->magic = DEV_QUEUE_MAGIC;  if(where)  	skb_queue_head(&dev->buffs[pri],skb);  else  	skb_queue_tail(&dev->buffs[pri],skb);  skb->magic = DEV_QUEUE_MAGIC;  sti();}/* * Receive a packet from a device driver and queue it for the upper * (protocol) levels.  It always succeeds. */voidnetif_rx(struct sk_buff *skb){  /* Set any necessary flags. */  skb->sk = NULL;  skb->free = 1;    /* and add it to the "backlog" queue. */  IS_SKB(skb);  skb_queue_tail(&backlog,skb);     /* If any packet arrived, mark it for processing. */  if (backlog != NULL) mark_bh(INET_BH);  return;}/* * The old interface to fetch a packet from a device driver. * This function is the base level entry point for all drivers that * want to send a packet to the upper (protocol) levels.  It takes * care of de-multiplexing the packet to the various modules based * on their protocol ID. * * Return values:	1 <- exit I can't do any more *			0 <- feed me more (i.e. "done", "OK").  */intdev_rint(unsigned char *buff, long len, int flags, struct device *dev){  static int dropping = 0;  struct sk_buff *skb = NULL;  unsigned char *to;  int amount, left;  int len2;  if (dev == NULL || buff == NULL || len <= 0) return(1);  if (flags & IN_SKBUFF) {	skb = (struct sk_buff *) buff;  } else {	if (dropping) {

⌨️ 快捷键说明

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