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

📄 dev.c

📁 LINUX 1.0 内核c源代码.ZIP
💻 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_IPX

static 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_AX25

static struct packet_type ax25_packet_type = {
  NET16(ETH_P_AX25),
  0,
  ax25_rcv,
  NULL,
#ifdef CONFIG_IPX
  &ipx_packet_type
#else
  NULL
#endif
};
#endif


static 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 long
min(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 long
get_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);
}


int
ip_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 long
my_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. */
void
dev_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. */
void
dev_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. */
int
dev_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. */
int
dev_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. */
void
dev_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.
 */
void
netif_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"). 
 */
int
dev_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 + -