码迷,mamicode.com
首页 > 系统相关 > 详细

Linux内核--网络栈实现分析(三)--驱动程序层+链路层(上)

时间:2014-11-02 18:02:12      阅读:483      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   io   ar   os   for   sp   strong   

本文分析基于Linux Kernel 1.2.13

原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7497260

更多请看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html

作者:闫明

注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析、”(下)“表示分析是从上向下分析。

 

经过前面两篇博文的分析,已经对Linux的内核网络栈的结构有了一个模糊的认识,这里我们开始从底层开始详细分析Linux内核网络栈的实现。由于这是早期版本,代码的层次隔离做的还不是很好,这里说是从底层分析,但是不免会牵扯上层或下层的函数,许多关键代码都在驱动的文件夹下。

我们首先有第一篇博文中知道在网络栈初始化的时候在net/socket.c中的函数sock_init()函数中当proto_init()完成后会执行dev_init()来进行网络设备模块的初始化。

首先说明一下,在drivers/net/space.c中定义了设备首节点地址dev_base,其实际上是回环设备的地址。

 

  1. struct device loopback_dev = {  
  2.     "lo",           /* Software Loopback interface      */  
  3.     0x0,            /* recv memory end          */  
  4.     0x0,            /* recv memory start            */  
  5.     0x0,            /* memory end               */  
  6.     0x0,            /* memory start             */  
  7.     0,          /* base I/O address         */  
  8.     0,          /* IRQ                  */  
  9.     0, 0, 0,        /* flags                */  
  10.     NEXT_DEV,       /* next device              */  
  11.     loopback_init       /* loopback_init should set up the rest */  
  12. };  
  13.   
  14. struct device *dev_base = &loopback_dev;  
而NEXT_DEV宏定义即定义了下一个网络设备的地址,这样可以把设备串成链。

 

附网络设备的定义(include/linux/netdevice.h)如下:

 

  1. /* 
  2.  * The DEVICE structure. 
  3.  * Actually, this whole structure is a big mistake.  It mixes I/O 
  4.  * data with strictly "high-level" data, and it has to know about 
  5.  * almost every data structure used in the INET module.   
  6.  */  
  7. struct device   
  8. {  
  9.   
  10.   /* 
  11.    * This is the first field of the "visible" part of this structure 
  12.    * (i.e. as seen by users in the "Space.c" file).  It is the name 
  13.    * the interface. 
  14.    */  
  15.   char            *name;  
  16.   
  17.   /* I/O specific fields - FIXME: Merge these and struct ifmap into one */  
  18.   unsigned long       rmem_end;     /* shmem "recv" end */  
  19.   unsigned long       rmem_start;       /* shmem "recv" start   */  
  20.   unsigned long       mem_end;      /* sahared mem end  */  
  21.   unsigned long       mem_start;        /* shared mem start */  
  22.   unsigned long       base_addr;        /* device I/O address   */  
  23.   unsigned char       irq;          /* device IRQ number    */  
  24.   
  25.   /* Low-level status flags. */  
  26.   volatile unsigned char  start,        /* start an operation   */  
  27.                           tbusy,        /* transmitter busy */  
  28.                           interrupt;        /* interrupt arrived    */  
  29.   
  30.   struct device       *next;  
  31.   
  32.   /* The device initialization function. Called only once. */  
  33.   int             (*init)(struct device *dev);  
  34.   
  35.   /* Some hardware also needs these fields, but they are not part of the 
  36.      usual set specified in Space.c. */  
  37.   unsigned char       if_port;      /* Selectable AUI, TP,..*/  
  38.   unsigned char       dma;          /* DMA channel      */  
  39.   
  40.   struct enet_statistics* (*get_stats)(struct device *dev);  
  41.   
  42.   /* 
  43.    * This marks the end of the "visible" part of the structure. All 
  44.    * fields hereafter are internal to the system, and may change at 
  45.    * will (read: may be cleaned up at will). 
  46.    */  
  47.   
  48.   /* These may be needed for future network-power-down code. */  
  49.   unsigned long       trans_start;  /* Time (in jiffies) of last Tx */  
  50.   unsigned long       last_rx;  /* Time of last Rx      */  
  51.   
  52.   unsigned short      flags;    /* interface flags (a la BSD)   */  
  53.   unsigned short      family;   /* address family ID (AF_INET)  */  
  54.   unsigned short      metric;   /* routing metric (not used)    */  
  55.   unsigned short      mtu;      /* interface MTU value      */  
  56.   unsigned short      type;     /* interface hardware type  */  
  57.   unsigned short      hard_header_len;  /* hardware hdr length  */  
  58.   void            *priv;    /* pointer to private data  */  
  59.   
  60.   /* Interface address info. */  
  61.   unsigned char       broadcast[MAX_ADDR_LEN];  /* hw bcast add */  
  62.   unsigned char       dev_addr[MAX_ADDR_LEN];   /* hw address   */  
  63.   unsigned char       addr_len; /* hardware address length  */  
  64.   unsigned long       pa_addr;  /* protocol address     */  
  65.   unsigned long       pa_brdaddr;   /* protocol broadcast addr  */  
  66.   unsigned long       pa_dstaddr;   /* protocol P-P other side addr */  
  67.   unsigned long       pa_mask;  /* protocol netmask     */  
  68.   unsigned short      pa_alen;  /* protocol address length  */  
  69.   
  70.   struct dev_mc_list     *mc_list;  /* Multicast mac addresses  */  
  71.   int            mc_count;  /* Number of installed mcasts   */  
  72.     
  73.   struct ip_mc_list  *ip_mc_list;   /* IP multicast filter chain    */  
  74.       
  75.   /* For load balancing driver pair support */  
  76.     
  77.   unsigned long        pkt_queue;   /* Packets queued */  
  78.   struct device       *slave;   /* Slave device */  
  79.     
  80.   
  81.   /* Pointer to the interface buffers. */  
  82.   struct sk_buff_head     buffs[DEV_NUMBUFFS];  
  83.   
  84.   /* Pointers to interface service routines. */  
  85.   int             (*open)(struct device *dev);  
  86.   int             (*stop)(struct device *dev);  
  87.   int             (*hard_start_xmit) (struct sk_buff *skb,  
  88.                           struct device *dev);  
  89.   int             (*hard_header) (unsigned char *buff,  
  90.                       struct device *dev,  
  91.                       unsigned short type,  
  92.                       void *daddr,  
  93.                       void *saddr,  
  94.                       unsigned len,  
  95.                       struct sk_buff *skb);  
  96.   int             (*rebuild_header)(void *eth, struct device *dev,  
  97.                 unsigned long raddr, struct sk_buff *skb);  
  98.   unsigned short      (*type_trans) (struct sk_buff *skb,  
  99.                      struct device *dev);  
  100. #define HAVE_MULTICAST             
  101.   void            (*set_multicast_list)(struct device *dev,  
  102.                      int num_addrs, void *addrs);  
  103. #define HAVE_SET_MAC_ADDR          
  104.   int             (*set_mac_address)(struct device *dev, void *addr);  
  105. #define HAVE_PRIVATE_IOCTL  
  106.   int             (*do_ioctl)(struct device *dev, struct ifreq *ifr, int cmd);  
  107. #define HAVE_SET_CONFIG  
  108.   int             (*set_config)(struct device *dev, struct ifmap *map);  
  109.     
  110. };  

dev_init()网络设备的初始化函数如下:

 

 

  1. /* 
  2.  *  Initialize the DEV module. At boot time this walks the device list and 
  3.  *  unhooks any devices that fail to initialise (normally hardware not  
  4.  *  present) and leaves us with a valid list of present and active devices. 
  5.  * 
  6.  *  The PCMCIA code may need to change this a little, and add a pair 
  7.  *  of register_inet_device() unregister_inet_device() calls. This will be 
  8.  *  needed for ethernet as modules support. 
  9.  */  
  10.    
  11. void dev_init(void)  
  12. {  
  13.     struct device *dev, *dev2;  
  14.   
  15.     /* 
  16.      *  Add the devices. 
  17.      *  If the call to dev->init fails, the dev is removed 
  18.      *  from the chain disconnecting the device until the 
  19.      *  next reboot. 
  20.      */  
  21.        
  22.     dev2 = NULL;  
  23.     for (dev = dev_base; dev != NULL; dev=dev->next) //循环移除设备由璞傅絛ev_base指向的网络设备链表  
  24.     {  
  25.         if (dev->init && dev->init(dev)) //如果设备有初始化函数并且初始化失败,则从链表摘除设备(init()函数成功返回0)  
  26.         {  
  27.             /* 
  28.              *  It failed to come up. Unhook it.这个函数还挺有技巧性的,从默认配置的设备中扫描不存在的设备,将其移除 
  29.              */  
  30.                
  31.             if (dev2 == NULL)   
  32.                 dev_base = dev->next;  
  33.             else   
  34.                 dev2->next = dev->next;  
  35.         }   
  36.         else  
  37.         {  
  38.             dev2 = dev;  
  39.         }  
  40.     }  
  41. }  
这里我们看一下dev_base这个队列是如何定义的,这里我们仅仅看eth网卡的定义方式即可

 

 

  1. /* "eth0" defaults to autoprobe (== 0), other use a base of 0xffe0 (== -0x20), 
  2.    which means "don‘t probe".  These entries exist to only to provide empty 
  3.    slots which may be enabled at boot-time. */  
  4.   
  5. static struct device eth3_dev = {  
  6.     "eth3", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe };  
  7. static struct device eth2_dev = {  
  8.     "eth2", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, eth3_dev, ethif_probe };  
  9. static struct device eth1_dev = {  
  10.     "eth1", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, eth2_dev, ethif_probe };  
  11.   
  12. static struct device eth0_dev = {  
  13.     "eth0", 0, 0, 0, 0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, eth1_dev, ethif_probe };  
  14.   
  15. #   undef NEXT_DEV  
  16. #   define NEXT_DEV (eth0_dev)  

可以看出eth系列网卡设备的init函数定义为ethif_probe(),该函数会调用具体网卡的探测函数,我们还是以 NS8390 ethernet网卡为例来分析,该网卡的驱动实现文件为drivers/net/ne.c

ethif_probe()函数会调用函数ne_probe()探测函数,而该函数对设备地址进行检查后调用ne_probe1()函数,具体工作有ne_probe1()函数完成。

bubuko.com,布布扣

 

函数如下:

 

  1. static int ne_probe1(struct device *dev, int ioaddr)  
  2. {  
  3. .....................//合法性检查  
  4. /* Fixup for users that don‘t know that IRQ 2 is really IRQ 9, 
  5.        or don‘t know which one to set. */  
  6.     dev->irq = 9;//设置中断类型号  
  7.       
  8.     /* Snarf the interrupt now.  There‘s no point in waiting since we cannot 
  9.        share and the board will usually be enabled. */  
  10.     {  
  11.     int irqval = request_irq (dev->irq, ei_interrupt, 0, wordlength==2 ? "ne2000":"ne1000");//注册申请中断,中断处理函数为ei_interrupt  
  12.     if (irqval) {  
  13.         printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);  
  14.         return EAGAIN;  
  15.     }  
  16.     }  
  17.   
  18.     dev->base_addr = ioaddr;  
  19.   
  20.     request_region(ioaddr, NE_IO_EXTENT, wordlength==2 ? "ne2000":"ne1000");//申请内存空间  
  21.   
  22.     for(i = 0; i < ETHER_ADDR_LEN; i++)  
  23.     dev->dev_addr[i] = SA_prom[i];  
  24.   
  25.     ethdev_init(dev);//调用函数对dev设备结构体进行初始化  
  26.     printk("\n%s: %s found at %#x, using IRQ %d.\n",  
  27.        dev->name, name, ioaddr, dev->irq);  
  28.   
  29.     if (ei_debug > 0)  
  30.     printk(version);  
  31.   
  32.     ei_status.name = name;  
  33.     ei_status.tx_start_page = start_page;  
  34.     ei_status.stop_page = stop_page;  
  35.     ei_status.word16 = (wordlength == 2);  
  36.   
  37.     ei_status.rx_start_page = start_page + TX_PAGES;  
  38. #ifdef PACKETBUF_MEMSIZE  
  39.     /* Allow the packet buffer size to be overridden by know-it-alls. */  
  40.     ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;  
  41. #endif  
  42.   
  43.     ei_status.reset_8390 = &ne_reset_8390;  
  44.     ei_status.block_input = &ne_block_input;  
  45.     ei_status.block_output = &ne_block_output;  
  46.     NS8390_init(dev, 0);//配置网卡中的寄存器等到默认状态  
  47.     return 0;  
  48. }  
初始化函数ethdev_init()在文件drivers/net/8390.c中。如下:

 

 

  1. /* Initialize the rest of the 8390 device structure. */  
  2. int ethdev_init(struct device *dev)  
  3. {  
  4.     if (ei_debug > 1)  
  5.         printk(version);  
  6.       
  7.     if (dev->priv == NULL) {//申请私有空间存储具体网卡的结构体信息  
  8.         struct ei_device *ei_local;//8390网卡设备的结构体  
  9.           
  10.         dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL);//申请内核内存空间  
  11.         memset(dev->priv, 0, sizeof(struct ei_device));  
  12.         ei_local = (struct ei_device *)dev->priv;  
  13. #ifndef NO_PINGPONG  
  14.         ei_local->pingpong = 1;  
  15. #endif  
  16.     }  
  17.       
  18.     /* The open call may be overridden by the card-specific code. */  
  19.     if (dev->open == NULL)  
  20.         dev->open = &ei_open;//设备的打开函数  
  21.     /* We should have a dev->stop entry also. */  
  22.     dev->hard_start_xmit = &ei_start_xmit;//设备的发送函数,定义在8390.c中  
  23.     dev->get_stats   = get_stats;  
  24. #ifdef HAVE_MULTICAST  
  25.     dev->set_multicast_list = &set_multicast_list;  
  26. #endif  
  27.   
  28.     ether_setup(dev);//进一步调用函数设置dev设备结构体  
  29.           
  30.     return 0;  
  31. }  
ether_setup()函数的实现如下:

 

 

  1. void ether_setup(struct device *dev)  
  2. {  
  3.     int i;  
  4.     /* Fill in the fields of the device structure with ethernet-generic values. 
  5.        This should be in a common file instead of per-driver.  */  
  6.     for (i = 0; i < DEV_NUMBUFFS; i++)  
  7.         skb_queue_head_init(&dev->buffs[i]);//缓冲队列初始化  
  8.   
  9.     /* register boot-defined "eth" devices */  
  10.     if (dev->name && (strncmp(dev->name, "eth", 3) == 0)) {//定义eth网卡的名称  
  11.         i = simple_strtoul(dev->name + 3, NULL, 0);  
  12.         if (ethdev_index[i] == NULL) {  
  13.             ethdev_index[i] = dev;  
  14.         }  
  15.         else if (dev != ethdev_index[i]) {  
  16.             /* Really shouldn‘t happen! */  
  17.             printk("ether_setup: Ouch! Someone else took %s\n",  
  18.                 dev->name);  
  19.         }  
  20.     }  
  21.   
  22.     dev->hard_header = eth_header;//该函数的作用是创建链路层首部,定义在eth.c中  
  23.     dev->rebuild_header = eth_rebuild_header;//该函数的作用是重建链路层首部,用于ARP协议  
  24.     dev->type_trans = eth_type_trans;  
  25.   
  26.     dev->type        = ARPHRD_ETHER;  
  27.     dev->hard_header_len = ETH_HLEN;  
  28.     dev->mtu     = 1500; /* eth_mtu */  
  29.     dev->addr_len    = ETH_ALEN;  
  30.     for (i = 0; i < ETH_ALEN; i++) {  
  31.         dev->broadcast[i]=0xff;  
  32.     }  
  33.   
  34.     /* New-style flags. */  
  35.     dev->flags       = IFF_BROADCAST|IFF_MULTICAST;  
  36.     dev->family      = AF_INET;  
  37.     dev->pa_addr = 0;  
  38.     dev->pa_brdaddr = 0;  
  39.     dev->pa_mask = 0;  
  40.     dev->pa_alen = sizeof(unsigned long);  
  41. }  

这样,网络设备的初始化工作就完成了。

 

在drivers/net/8390.c中实现了该网卡的设备的基本操作函数,

bubuko.com,布布扣

设备的打开函数ei_open()比较简单,下面列出该设备的发送和接收函数,在这里不做具体的分析,如果想更多了解请点击前面分析过的DM9000网卡驱动,下面给出链接:

 

  1. ARM-Linux驱动--DM9000网卡驱动分析(一)
  2. ARM-Linux驱动--DM9000网卡驱动分析(二)
  3. ARM-Linux驱动--DM9000网卡驱动分析(三)
  4. ARM-Linux驱动--DM9000网卡驱动分析(四)
其基本结构是一致的。

 

ei_start_xmit()

 

  1. static int ei_start_xmit(struct sk_buff *skb, struct device *dev)  
  2. {  
  3.     int e8390_base = dev->base_addr;  
  4.     struct ei_device *ei_local = (struct ei_device *) dev->priv;  
  5.     int length, send_length;  
  6.     unsigned long flags;  
  7.       
  8. /* 
  9.  *  We normally shouldn‘t be called if dev->tbusy is set, but the 
  10.  *  existing code does anyway. If it has been too long since the 
  11.  *  last Tx, we assume the board has died and kick it. 
  12.  */  
  13.    
  14.     if (dev->tbusy) {    /* Do timeouts, just like the 8003 driver. */  
  15.         int txsr = inb(e8390_base+EN0_TSR), isr;  
  16.         int tickssofar = jiffies - dev->trans_start;  
  17.         if (tickssofar < TX_TIMEOUT ||   (tickssofar < (TX_TIMEOUT+5) && ! (txsr & ENTSR_PTX))) {  
  18.             return 1;  
  19.         }  
  20.         isr = inb(e8390_base+EN0_ISR);  
  21.         if (dev->start == 0) {  
  22.             printk("%s: xmit on stopped card\n", dev->name);  
  23.             return 1;  
  24.         }  
  25.         printk(KERN_DEBUG "%s: transmit timed out, TX status %#2x, ISR %#2x.\n",  
  26.                dev->name, txsr, isr);  
  27.         /* Does the 8390 thinks it has posted an interrupt? */  
  28.         if (isr)  
  29.             printk(KERN_DEBUG "%s: Possible IRQ conflict on IRQ%d?\n", dev->name, dev->irq);  
  30.         else {  
  31.             /* The 8390 probably hasn‘t gotten on the cable yet. */  
  32.             printk(KERN_DEBUG "%s: Possible network cable problem?\n", dev->name);  
  33.             if(ei_local->stat.tx_packets==0)  
  34.                 ei_local->interface_num ^= 1;    /* Try a different xcvr.  */  
  35.         }  
  36.         /* Try to restart the card.  Perhaps the user has fixed something. */  
  37.         ei_reset_8390(dev);  
  38.         NS8390_init(dev, 1);  
  39.         dev->trans_start = jiffies;  
  40.     }  
  41.       
  42.     /* Sending a NULL skb means some higher layer thinks we‘ve missed an 
  43.        tx-done interrupt. Caution: dev_tint() handles the cli()/sti() 
  44.        itself. */  
  45.     if (skb == NULL) {  
  46.         dev_tint(dev);  
  47.         return 0;  
  48.     }  
  49.       
  50.     length = skb->len;  
  51.     if (skb->len <= 0)  
  52.         return 0;  
  53.   
  54.     save_flags(flags);  
  55.     cli();  
  56.   
  57.     /* Block a timer-based transmit from overlapping. */  
  58.     if ((set_bit(0, (void*)&dev->tbusy) != 0) || ei_local->irqlock) {  
  59.     printk("%s: Tx access conflict. irq=%d lock=%d tx1=%d tx2=%d last=%d\n",  
  60.         dev->name, dev->interrupt, ei_local->irqlock, ei_local->tx1,  
  61.         ei_local->tx2, ei_local->lasttx);  
  62.     restore_flags(flags);  
  63.     return 1;  
  64.     }  
  65.   
  66.     /* Mask interrupts from the ethercard. */  
  67.     outb(0x00, e8390_base + EN0_IMR);  
  68.     ei_local->irqlock = 1;  
  69.     restore_flags(flags);  
  70.   
  71.     send_length = ETH_ZLEN < length ? length : ETH_ZLEN;  
  72.   
  73.     if (ei_local->pingpong) {  
  74.         int output_page;  
  75.         if (ei_local->tx1 == 0) {  
  76.             output_page = ei_local->tx_start_page;  
  77.             ei_local->tx1 = send_length;  
  78.             if (ei_debug  &&  ei_local->tx2 > 0)  
  79.                 printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",  
  80.                        dev->name, ei_local->tx2, ei_local->lasttx,  
  81.                        ei_local->txing);  
  82.         } else if (ei_local->tx2 == 0) {  
  83.             output_page = ei_local->tx_start_page + 6;  
  84.             ei_local->tx2 = send_length;  
  85.             if (ei_debug  &&  ei_local->tx1 > 0)  
  86.                 printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",  
  87.                        dev->name, ei_local->tx1, ei_local->lasttx,  
  88.                        ei_local->txing);  
  89.         } else {    /* We should never get here. */  
  90.             if (ei_debug)  
  91.                 printk("%s: No Tx buffers free. irq=%d tx1=%d tx2=%d last=%d\n",  
  92.                     dev->name, dev->interrupt, ei_local->tx1,   
  93.                     ei_local->tx2, ei_local->lasttx);  
  94.             ei_local->irqlock = 0;  
  95.             dev->tbusy = 1;  
  96.             outb_p(ENISR_ALL, e8390_base + EN0_IMR);  
  97.             return 1;  
  98.         }  
  99.         ei_block_output(dev, length, skb->data, output_page);  
  100.         if (! ei_local->txing) {  
  101.             ei_local->txing = 1;  
  102.             NS8390_trigger_send(dev, send_length, output_page);  
  103.             dev->trans_start = jiffies;  
  104.             if (output_page == ei_local->tx_start_page)  
  105.                 ei_local->tx1 = -1, ei_local->lasttx = -1;  
  106.             else  
  107.                 ei_local->tx2 = -1, ei_local->lasttx = -2;  
  108.         } else  
  109.             ei_local->txqueue++;  
  110.   
  111.         dev->tbusy = (ei_local->tx1  &&  ei_local->tx2);  
  112.     } else {  /* No pingpong, just a single Tx buffer. */  
  113.         ei_block_output(dev, length, skb->data, ei_local->tx_start_page);  
  114.         ei_local->txing = 1;  
  115.         NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);  
  116.         dev->trans_start = jiffies;  
  117.         dev->tbusy = 1;  
  118.     }  
  119.       
  120.     /* Turn 8390 interrupts back on. */  
  121.     ei_local->irqlock = 0;  
  122.     outb_p(ENISR_ALL, e8390_base + EN0_IMR);  
  123.   
  124.     dev_kfree_skb (skb, FREE_WRITE);  
  125.       
  126.     return 0;  
  127. }  

ei_receive()函数

 

 

  1. static void ei_receive(struct device *dev)  
  2. {  
  3.     int e8390_base = dev->base_addr;  
  4.     struct ei_device *ei_local = (struct ei_device *) dev->priv;  
  5.     int rxing_page, this_frame, next_frame, current_offset;  
  6.     int rx_pkt_count = 0;  
  7.     struct e8390_pkt_hdr rx_frame;  
  8.     int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;  
  9.       
  10.     while (++rx_pkt_count < 10) {  
  11.         int pkt_len;  
  12.           
  13.         /* Get the rx page (incoming packet pointer). */  
  14.         outb_p(E8390_NODMA+E8390_PAGE1, e8390_base + E8390_CMD);  
  15.         rxing_page = inb_p(e8390_base + EN1_CURPAG);  
  16.         outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);  
  17.           
  18.         /* Remove one frame from the ring.  Boundary is always a page behind. */  
  19.         this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;  
  20.         if (this_frame >= ei_local->stop_page)  
  21.             this_frame = ei_local->rx_start_page;  
  22.           
  23.         /* Someday we‘ll omit the previous, iff we never get this message. 
  24.            (There is at least one clone claimed to have a problem.)  */  
  25.         if (ei_debug > 0  &&  this_frame != ei_local->current_page)  
  26.             printk("%s: mismatched read page pointers %2x vs %2x.\n",  
  27.                    dev->name, this_frame, ei_local->current_page);  
  28.           
  29.         if (this_frame == rxing_page)   /* Read all the frames? */  
  30.             break;              /* Done for now */  
  31.           
  32.         current_offset = this_frame << 8;  
  33.         ei_block_input(dev, sizeof(rx_frame), (char *)&rx_frame,  
  34.                        current_offset);  
  35.           
  36.         pkt_len = rx_frame.count - sizeof(rx_frame);  
  37.           
  38.         next_frame = this_frame + 1 + ((pkt_len+4)>>8);  
  39.           
  40.         /* Check for bogosity warned by 3c503 book: the status byte is never 
  41.            written.  This happened a lot during testing! This code should be 
  42.            cleaned up someday. */  
  43.         if (rx_frame.next != next_frame  
  44.             && rx_frame.next != next_frame + 1  
  45.             && rx_frame.next != next_frame - num_rx_pages  
  46.             && rx_frame.next != next_frame + 1 - num_rx_pages) {  
  47.             ei_local->current_page = rxing_page;  
  48.             outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);  
  49.             ei_local->stat.rx_errors++;  
  50.             continue;  
  51.         }  
  52.   
  53.         if (pkt_len < 60  ||  pkt_len > 1518) {  
  54.             if (ei_debug)  
  55.                 printk("%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",  
  56.                        dev->name, rx_frame.count, rx_frame.status,  
  57.                        rx_frame.next);  
  58.             ei_local->stat.rx_errors++;  
  59.         } else if ((rx_frame.status & 0x0F) == ENRSR_RXOK) {  
  60.             struct sk_buff *skb;  
  61.               
  62.             skb = alloc_skb(pkt_len, GFP_ATOMIC);  
  63.             if (skb == NULL) {  
  64.                 if (ei_debug > 1)  
  65.                     printk("%s: Couldn‘t allocate a sk_buff of size %d.\n",  
  66.                            dev->name, pkt_len);  
  67.                 ei_local->stat.rx_dropped++;  
  68.                 break;  
  69.             } else {  
  70.                 skb->len = pkt_len;  
  71.                 skb->dev = dev;  
  72.                   
  73.                 ei_block_input(dev, pkt_len, (char *) skb->data,  
  74.                                current_offset + sizeof(rx_frame));  
  75.                 netif_rx(skb);  
  76.                 ei_local->stat.rx_packets++;  
  77.             }  
  78.         } else {  
  79.             int errs = rx_frame.status;  
  80.             if (ei_debug)  
  81.                 printk("%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",  
  82.                        dev->name, rx_frame.status, rx_frame.next,  
  83.                        rx_frame.count);  
  84.             if (errs & ENRSR_FO)  
  85.                 ei_local->stat.rx_fifo_errors++;  
  86.         }  
  87.         next_frame = rx_frame.next;  
  88.           
  89.         /* This _should_ never happen: it‘s here for avoiding bad clones. */  
  90.         if (next_frame >= ei_local->stop_page) {  
  91.             printk("%s: next frame inconsistency, %#2x\n", dev->name,  
  92.                    next_frame);  
  93.             next_frame = ei_local->rx_start_page;  
  94.         }  
  95.         ei_local->current_page = next_frame;  
  96.         outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);  
  97.     }  
  98.     /* If any worth-while packets have been received, dev_rint() 
  99.        has done a mark_bh(NET_BH) for us and will work on them 
  100.        when we get to the bottom-half routine. */  
  101.   
  102.     /* Record the maximum Rx packet queue. */  
  103.     if (rx_pkt_count > high_water_mark)  
  104.         high_water_mark = rx_pkt_count;  
  105.   
  106.     /* Bug alert!  Reset ENISR_OVER to avoid spurious overruns! */  
  107.     outb_p(ENISR_RX+ENISR_RX_ERR+ENISR_OVER, e8390_base+EN0_ISR);  
  108.     return;  
  109. }  

Linux内核--网络栈实现分析(三)--驱动程序层+链路层(上)

标签:style   blog   http   io   ar   os   for   sp   strong   

原文地址:http://www.cnblogs.com/farman/p/4069572.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!