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

📄 dev.c

📁 LINUX 1.0 内核c源代码,是一份精简的linux内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	  if (backlog != NULL)
	      return(1);
	  printk("INET: dev_rint: no longer dropping packets.\n");
	  dropping = 0;
	}

	skb = alloc_skb(sizeof(*skb) + len, GFP_ATOMIC);
	if (skb == NULL) {
		printk("dev_rint: packet dropped on %s (no memory) !\n",
		       dev->name);
		dropping = 1;
		return(1);
	}
	skb->mem_len = sizeof(*skb) + len;
	skb->mem_addr = (struct sk_buff *) skb;

	/* First we copy the packet into a buffer, and save it for later. */
	to = skb->data;
	left = len;
	len2 = len;
	while (len2 > 0) {
		amount = min(len2, (unsigned long) dev->rmem_end -
						(unsigned long) buff);
		memcpy(to, buff, amount);
		len2 -= amount;
		left -= amount;
		buff += amount;
		to += amount;
		if ((unsigned long) buff == dev->rmem_end)
			buff = (unsigned char *) dev->rmem_start;
	}
  }
  skb->len = len;
  skb->dev = dev;
  skb->free = 1;

  netif_rx(skb);
  /* OK, all done. */
  return(0);
}


/* This routine causes all interfaces to try to send some data. */
void
dev_transmit(void)
{
  struct device *dev;

  for (dev = dev_base; dev != NULL; dev = dev->next) {
	if (!dev->tbusy) {
		dev_tint(dev);
	}
  }
}

static volatile char in_bh = 0;

int in_inet_bh()	/* Used by timer.c */
{
	return(in_bh==0?0:1);
}

/*
 * This function gets called periodically, to see if we can
 * process any data that came in from some interface.
 *
 */
void
inet_bh(void *tmp)
{
  struct sk_buff *skb;
  struct packet_type *ptype;
  unsigned short type;
  unsigned char flag = 0;
  int nitcount;

  /* Atomically check and mark our BUSY state. */
  if (set_bit(1, (void*)&in_bh))
      return;

  /* Can we send anything now? */
  dev_transmit();
  
  /* Any data left to process? */
  while((skb=skb_dequeue(&backlog))!=NULL)
  {
  	nitcount=dev_nit;
	flag=0;
	sti();
       /*
	* Bump the pointer to the next structure.
	* This assumes that the basic 'skb' pointer points to
	* the MAC header, if any (as indicated by its "length"
	* field).  Take care now!
	*/
       skb->h.raw = skb->data + skb->dev->hard_header_len;
       skb->len -= skb->dev->hard_header_len;

       /*
	* Fetch the packet protocol ID.  This is also quite ugly, as
	* it depends on the protocol driver (the interface itself) to
	* know what the type is, or where to get it from.  The Ethernet
	* interfaces fetch the ID from the two bytes in the Ethernet MAC
	* header (the h_proto field in struct ethhdr), but drivers like
	* SLIP and PLIP have no alternative but to force the type to be
	* IP or something like that.  Sigh- FvK
	*/
       type = skb->dev->type_trans(skb, skb->dev);

	/*
	 * We got a packet ID.  Now loop over the "known protocols"
	 * table (which is actually a linked list, but this will
	 * change soon if I get my way- FvK), and forward the packet
	 * to anyone who wants it.
	 */
	for (ptype = ptype_base; ptype != NULL; ptype = ptype->next) {
		if (ptype->type == type || ptype->type == NET16(ETH_P_ALL)) {
			struct sk_buff *skb2;

			if (ptype->type==NET16(ETH_P_ALL))
				nitcount--;
			if (ptype->copy || nitcount) {	/* copy if we need to	*/
				skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC);
				if (skb2 == NULL) 
					continue;
				memcpy(skb2, (const void *) skb, skb->mem_len);
				skb2->mem_addr = skb2;
				skb2->h.raw = (unsigned char *)(
				    (unsigned long) skb2 +
				    (unsigned long) skb->h.raw -
				    (unsigned long) skb
				);
				skb2->free = 1;
			} else {
				skb2 = skb;
			}

			/* This used to be in the 'else' part, but then
			 * we don't have this flag set when we get a
			 * protocol that *does* require copying... -FvK
			 */
			flag = 1;

			/* Kick the protocol handler. */
			ptype->func(skb2, skb->dev, ptype);
		}
	}

	/*
	 * That's odd.  We got an unknown packet.  Who's using
	 * stuff like Novell or Amoeba on this network??
	 */
	if (!flag) {
		DPRINTF((DBG_DEV,
			"INET: unknown packet type 0x%04X (ignored)\n", type));
		skb->sk = NULL;
		kfree_skb(skb, FREE_WRITE);
	}

	/* Again, see if we can transmit anything now. */
	dev_transmit();
	cli();
  }
  in_bh = 0;
  sti();
  dev_transmit();
}


/*
 * 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;
	struct sk_buff *skb;
	
	for(i = 0;i < DEV_NUMBUFFS; i++) {
		while((skb=skb_dequeue(&dev->buffs[i]))!=NULL)
		{
			skb->magic = 0;
			skb->next = NULL;
			skb->prev = NULL;
			dev->queue_xmit(skb,dev,-i - 1);
			if (dev->tbusy)
				return;
		}
	}
}


/* Perform a SIOCGIFCONF call. */
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;

  /* 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))
        	continue;
	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);
	if (len < sizeof(struct ifreq)) break;
  }

  /* 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));
  return(pos - arg);
}

/* Print device statistics. */
char *sprintf_stats(char *buffer, struct device *dev)
{
  char *pos = buffer;
  struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL);

  if (stats)
    pos += sprintf(pos, "%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
      pos += sprintf(pos, "%6s: No statistics available.\n", dev->name);

  return pos;
}

/* Called from the PROCfs module. */
int
dev_get_info(char *buffer)
{
  char *pos = buffer;
  struct device *dev;

  pos +=
      sprintf(pos,
	      "Inter-|   Receive                  |  Transmit\n"
	      " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n");
  for (dev = dev_base; dev != NULL; dev = dev->next) {
      pos = sprintf_stats(pos, dev);
  }
  return pos - buffer;
}

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. */
static int
dev_ifsioc(void *arg, unsigned int getset)
{
  struct ifreq ifr;
  struct device *dev;
  int ret;

  /* Fetch the caller's info block. */
  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. */
  if ((dev = dev_get(ifr.ifr_name)) == NULL) return(-EINVAL);

  switch(getset) {
	case SIOCGIFFLAGS:
		ifr.ifr_flags = dev->flags;
		memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
		ret = 0;
		break;
	case SIOCSIFFLAGS:
		{
		  int old_flags = dev->flags;
		  dev->flags = ifr.ifr_flags & (
			IFF_UP | IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK |
			IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING |
			IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI);
			
		  if ( (old_flags & IFF_PROMISC) && ((dev->flags & IFF_PROMISC) == 0))
		  	dev->set_multicast_list(dev,0,NULL);
		  if ( (dev->flags & IFF_PROMISC) && ((old_flags & IFF_PROMISC) == 0))
		  	dev->set_multicast_list(dev,-1,NULL);
		  if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0)) {
			ret = dev_close(dev);
		  } else
		  {
		      ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP))
			? dev_open(dev) : 0;
		      if(ret<0)
		      	dev->flags&=~IFF_UP;	/* Didnt open so down the if */
		  }
	        }
		break;
	case SIOCGIFADDR:
		(*(struct sockaddr_in *)
		  &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr;
		(*(struct sockaddr_in *)
		  &ifr.ifr_addr).sin_family = dev->family;
		(*(struct sockaddr_in *)
		  &ifr.ifr_addr).sin_port = 0;
		memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
		ret = 0;
		break;
	case SIOCSIFADDR:
		dev->pa_addr = (*(struct sockaddr_in *)
				 &ifr.ifr_addr).sin_addr.s_addr;
		dev->family = ifr.ifr_addr.sa_family;
		dev->pa_mask = get_mask(dev->pa_addr);
		dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
		ret = 0;
		break;
	case SIOCGIFBRDADDR:
		(*(struct sockaddr_in *)
		  &ifr.ifr_broadaddr).sin_addr.s_addr = dev->pa_brdaddr;
		(*(struct sockaddr_in *)
		  &ifr.ifr_broadaddr).sin_family = dev->family;
		(*(struct sockaddr_in *)
		  &ifr.ifr_broadaddr).sin_port = 0;
		memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
		ret = 0;
		break;
	case SIOCSIFBRDADDR:
		dev->pa_brdaddr = (*(struct sockaddr_in *)
				    &ifr.ifr_broadaddr).sin_addr.s_addr;
		ret = 0;
		break;
	case SIOCGIFDSTADDR:
		(*(struct sockaddr_in *)
		  &ifr.ifr_dstaddr).sin_addr.s_addr = dev->pa_dstaddr;
		(*(struct sockaddr_in *)
		  &ifr.ifr_broadaddr).sin_family = dev->family;
		(*(struct sockaddr_in *)
		  &ifr.ifr_broadaddr).sin_port = 0;
		memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
		ret = 0;
		break;
	case SIOCSIFDSTADDR:
		dev->pa_dstaddr = (*(struct sockaddr_in *)
				    &ifr.ifr_dstaddr).sin_addr.s_addr;
		ret = 0;
		break;
	case SIOCGIFNETMASK:
		(*(struct sockaddr_in *)
		  &ifr.ifr_netmask).sin_addr.s_addr = dev->pa_mask;
		(*(struct sockaddr_in *)
		  &ifr.ifr_netmask).sin_family = dev->family;
		(*(struct sockaddr_in *)
		  &ifr.ifr_netmask).sin_port = 0;
		memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
		ret = 0;
		break;
	case SIOCSIFNETMASK: {
		unsigned long mask = (*(struct sockaddr_in *)
			&ifr.ifr_netmask).sin_addr.s_addr;
		ret = -EINVAL;
		if (bad_mask(mask,0))
			break;
		dev->pa_mask = mask;
		ret = 0;
		break;
	}
	case SIOCGIFMETRIC:
		ifr.ifr_metric = dev->metric;
		memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
		ret = 0;
		break;
	case SIOCSIFMETRIC:
		dev->metric = ifr.ifr_metric;
		ret = 0;
		break;
	case SIOCGIFMTU:
		ifr.ifr_mtu = dev->mtu;
		memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
		ret = 0;
		break;
	case SIOCSIFMTU:
		dev->mtu = ifr.ifr_mtu;
		ret = 0;
		break;
	case SIOCGIFMEM:
		printk("NET: ioctl(SIOCGIFMEM, 0x%08X)\n", (int)arg);
		ret = -EINVAL;
		break;
	case SIOCSIFMEM:
		printk("NET: ioctl(SIOCSIFMEM, 0x%08X)\n", (int)arg);
		ret = -EINVAL;
		break;
	case SIOCGIFHWADDR:
		memcpy(ifr.ifr_hwaddr,dev->dev_addr, MAX_ADDR_LEN);
		memcpy_tofs(arg,&ifr,sizeof(struct ifreq));
		ret=0;
		break;
	default:
		ret = -EINVAL;
  }
  return(ret);
}


/* This function handles all "interface"-type I/O control requests. */
int
dev_ioctl(unsigned int cmd, void *arg)
{
  struct iflink iflink;
  struct ddi_device *dev;

  switch(cmd) {
	case IP_SET_DEV:
		printk("Your network configuration program needs upgrading.\n");
		return -EINVAL;

	case SIOCGIFCONF:
		(void) dev_ifconf((char *) arg);
		return 0;

	case SIOCGIFFLAGS:
	case SIOCGIFADDR:
	case SIOCGIFDSTADDR:
	case SIOCGIFBRDADDR:
	case SIOCGIFNETMASK:
	case SIOCGIFMETRIC:
	case SIOCGIFMTU:
	case SIOCGIFMEM:
	case SIOCGIFHWADDR:
		return dev_ifsioc(arg, cmd);

	case SIOCSIFFLAGS:
	case SIOCSIFADDR:
	case SIOCSIFDSTADDR:
	case SIOCSIFBRDADDR:
	case SIOCSIFNETMASK:
	case SIOCSIFMETRIC:
	case SIOCSIFMTU:
	case SIOCSIFMEM:
		if (!suser())
			return -EPERM;
		return dev_ifsioc(arg, cmd);

	case SIOCSIFLINK:
		if (!suser())
			return -EPERM;
		memcpy_fromfs(&iflink, arg, sizeof(iflink));
		dev = ddi_map(iflink.id);
		if (dev == NULL)
			return -EINVAL;

		/* Now allocate an interface and connect it. */
		printk("AF_INET: DDI \"%s\" linked to stream \"%s\"\n",
						dev->name, iflink.stream);
		return 0;

	default:
		return -EINVAL;
  }
}


/* Initialize the DEV module. */
void
dev_init(void)
{
  struct device *dev, *dev2;

  /* Add the devices.
   * If the call to dev->init fails, the dev is removed
   * from the chain disconnecting the device until the
   * next reboot.
   */
  dev2 = NULL;
  for (dev = dev_base; dev != NULL; dev=dev->next) {
	if (dev->init && dev->init(dev)) {
		if (dev2 == NULL) dev_base = dev->next;
		  else dev2->next = dev->next;
	} else {
		dev2 = dev;
	}
  }

  /* Set up some IP addresses. */
  ip_bcast = in_aton("255.255.255.255");
}

⌨️ 快捷键说明

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