• Linux内核网络栈实现分析(十一)驱动程序层(下)


    本文分析基于Linux Kernel 1.2.13

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

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

    作者:闫明

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


    在博文Linux内核--网络栈实现分析(三)--驱动程序层(链路层)(上)中对网络设备结构,网络设备初始化等函数有了初步认识,并列出了设备的发送和接收函数。


    设备接口层会调用函数设备驱动层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;//取出网卡设备的私有数据,和具体的网卡型号有关,在ethdev_init()函数中已经分配空间  
    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.         ........................................  
    16.         ........................................  
    17.     }  
    18.       
    19.     /* Sending a NULL skb means some higher layer thinks we've missed an 
    20.        tx-done interrupt. Caution: dev_tint() handles the cli()/sti() 
    21.        itself. */  
    22.     if (skb == NULL) {//该条件似乎不会发生,这用于处理内核中的BUG  
    23.         dev_tint(dev);//发送设备中的所有缓存的数据包  
    24.         return 0;  
    25.     }  
    26.       
    27.     length = skb->len;  
    28.     if (skb->len <= 0)  
    29.         return 0;  
    30.   
    31.     save_flags(flags);  
    32.     cli();  
    33.   
    34.     /* Block a timer-based transmit from overlapping. */  
    35.     if ((set_bit(0, (void*)&dev->tbusy) != 0) || ei_local->irqlock) {  
    36.     printk("%s: Tx access conflict. irq=%d lock=%d tx1=%d tx2=%d last=%d\n",  
    37.         dev->name, dev->interrupt, ei_local->irqlock, ei_local->tx1,  
    38.         ei_local->tx2, ei_local->lasttx);  
    39.     restore_flags(flags);  
    40.     return 1;  
    41.     }  
    42.   
    43.     /* Mask interrupts from the ethercard. */  
    44.     outb(0x00, e8390_base + EN0_IMR);  
    45.     ei_local->irqlock = 1;  
    46.     restore_flags(flags);  
    47.   
    48.     send_length = ETH_ZLEN < length ? length : ETH_ZLEN;  
    49.   
    50.     if (ei_local->pingpong) {  
    51.         int output_page;  
    52.         if (ei_local->tx1 == 0) {  
    53.             output_page = ei_local->tx_start_page;  
    54.             ei_local->tx1 = send_length;  
    55.             if (ei_debug  &&  ei_local->tx2 > 0)  
    56.                 printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",  
    57.                        dev->name, ei_local->tx2, ei_local->lasttx,  
    58.                        ei_local->txing);  
    59.         } else if (ei_local->tx2 == 0) {  
    60.             output_page = ei_local->tx_start_page + 6;  
    61.             ei_local->tx2 = send_length;  
    62.             if (ei_debug  &&  ei_local->tx1 > 0)  
    63.                 printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",  
    64.                        dev->name, ei_local->tx1, ei_local->lasttx,  
    65.                        ei_local->txing);  
    66.         } else {    /* We should never get here. */  
    67.             if (ei_debug)  
    68.                 printk("%s: No Tx buffers free. irq=%d tx1=%d tx2=%d last=%d\n",  
    69.                     dev->name, dev->interrupt, ei_local->tx1,   
    70.                     ei_local->tx2, ei_local->lasttx);  
    71.             ei_local->irqlock = 0;  
    72.             dev->tbusy = 1;  
    73.             outb_p(ENISR_ALL, e8390_base + EN0_IMR);  
    74.             return 1;  
    75.         }  
    76.         ei_block_output(dev, length, skb->data, output_page);  
    77.         if (! ei_local->txing) {  
    78.             ei_local->txing = 1;  
    79.             NS8390_trigger_send(dev, send_length, output_page);  
    80.             dev->trans_start = jiffies;  
    81.             if (output_page == ei_local->tx_start_page)  
    82.                 ei_local->tx1 = -1, ei_local->lasttx = -1;  
    83.             else  
    84.                 ei_local->tx2 = -1, ei_local->lasttx = -2;  
    85.         } else  
    86.             ei_local->txqueue++;  
    87.   
    88.         dev->tbusy = (ei_local->tx1  &&  ei_local->tx2);  
    89.     } else {  /* No pingpong, just a single Tx buffer. */  
    90.         ei_block_output(dev, length, skb->data, ei_local->tx_start_page);  
    91.         ei_local->txing = 1;  
    92.         NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);  
    93.         dev->trans_start = jiffies;  
    94.         dev->tbusy = 1;  
    95.     }  
    96.       
    97.     /* Turn 8390 interrupts back on. */  
    98.     ei_local->irqlock = 0;  
    99.     outb_p(ENISR_ALL, e8390_base + EN0_IMR);  
    100.   
    101.     dev_kfree_skb (skb, FREE_WRITE);  
    102.       
    103.     return 0;  

    其中的dev_tint()函数是将设备的所有缓存队列中的数据全部调用dev_queue_xmit()发送全部数据包。

    1. /* 
    2.  *  This routine is called when an device driver (i.e. an 
    3.  *  interface) is ready to transmit a packet. 
    4.  */  
    5. //该函数功能:遍历设备的缓冲队列,对所有的数据包调用dev_queue_xmit()函数发送数据  
    6. void dev_tint(struct device *dev)  
    7. {  
    8.     int i;  
    9.     struct sk_buff *skb;  
    10.     unsigned long flags;  
    11.       
    12.     save_flags(flags);    
    13.     /* 
    14.      *  Work the queues in priority order 
    15.      */  
    16.        
    17.     for(i = 0;i < DEV_NUMBUFFS; i++)   
    18.     {  
    19.         /* 
    20.          *  Pull packets from the queue 
    21.          */  
    22.            
    23.   
    24.         cli();  
    25.         while((skb=skb_dequeue(&dev->buffs[i]))!=NULL)  
    26.         {  
    27.             /* 
    28.              *  Stop anyone freeing the buffer while we retransmit it 
    29.              */  
    30.             skb_device_lock(skb);  
    31.             restore_flags(flags);  
    32.             /* 
    33.              *  Feed them to the output stage and if it fails 
    34.              *  indicate they re-queue at the front. 
    35.              */  
    36.             dev_queue_xmit(skb,dev,-i - 1);//注意优先级的计算方式,在函数dev_queue_xmit()中优先级若<0则计算pri=-pri-1=-(-i-1)-1=i,  
    37.                                //这样做的目的就是为了得到正确的where值,函数(dev_queue_xmit())中  
    38.             /* 
    39.              *  If we can take no more then stop here. 
    40.              */  
    41.             if (dev->tbusy)  
    42.                 return;  
    43.             cli();  
    44.         }  
    45.     }  
    46.     restore_flags(flags);  
    47. }  


    驱动层严格的说不属于内核网络栈的内容,和硬件关系密切,何况这种网卡硬件设备可能已经不用了,这里就没有详细分析,如果对网卡驱动有兴趣可以看一下之前的分析的ARM-Linux下的DM9000网卡驱动的分析,链接如下:

    1. ARM-Linux驱动--DM9000网卡驱动分析(一)
    2. ARM-Linux驱动--DM9000网卡驱动分析(二)
    3. ARM-Linux驱动--DM9000网卡驱动分析(三)
    4. ARM-Linux驱动--DM9000网卡驱动分析(四)
  • 相关阅读:
    Less35、Less36【无闭合注入,mysql_real_escape_string()】
    Less34【POST方式宽字符注入】
    Less29,30,31【jsp环境搭建、WAF】
    Less28、28a【select、union、空格过滤】
    Less27、27a【select、union、空格过滤】
    Less26,26a【空格符号过滤】
    Less25,25a【and/or过滤】
    Less24【二次注入】
    Less23【报错注入】
    NFC
  • 原文地址:https://www.cnblogs.com/wangfengju/p/6173196.html
Copyright © 2020-2023  润新知