zoukankan      html  css  js  c++  java
  • Linux内核网络栈实现分析(三)驱动程序层+链路层(上)

    本文分析基于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()函数完成。


    函数如下:

    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中实现了该网卡的设备的基本操作函数,



    设备的打开函数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. }  
  • 相关阅读:
    Shiro 登录、退出、校验是否登录涉及到的Session和Cookie
    Apache Tomcat 8.0 官方文档
    FastDFS分布式文件系统(主备Tracker、主备Storage)
    PHP文件系统
    PHP 文件包含
    PHP函数
    PHP 全局变量
    PHP7新增知识点
    PHP数据
    PHP常量
  • 原文地址:https://www.cnblogs.com/hehehaha/p/6332917.html
Copyright © 2011-2022 走看看