Linux網絡設備驅動之網絡連接狀態(七)


  網絡適配器硬件電路可以檢測出鏈路上是否有載波,載波反映了網絡的連接是否正常。網絡設備驅動可以通過 netif_carrier_on() 和 netif_carrier_off() 函數改變設備的連接狀態,如果驅動檢測到連接狀態發生變化,也應該以 netif_carrier_on() 和 netif_carrier_off() 函數顯式地通知內核。

  除了 netif_carrier_on() 和 netif_carrier_off() 函數以外,另一個函數 netif_carrier_ok() 可用於向調用者返回鏈路上的載波信號是否存在。

  這幾個函數都接收一個 net_device 設備結構體指針作為參數,原型分別為:

 1 /**
 2  *    netif_carrier_on - set carrier
 3  *    @dev: network device
 4  *
 5  * Device has detected that carrier.
 6  */
 7 void netif_carrier_on(struct net_device *dev)
 8 {
 9     if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state)) {
10         if (dev->reg_state == NETREG_UNINITIALIZED)
11             return;
12         atomic_inc(&dev->carrier_changes);
13         linkwatch_fire_event(dev);
14         if (netif_running(dev))
15             __netdev_watchdog_up(dev);
16     }
17 }
18 
19 
20 /**
21  *    netif_carrier_off - clear carrier
22  *    @dev: network device
23  *
24  * Device has detected loss of carrier.
25  */
26 void netif_carrier_off(struct net_device *dev)
27 {
28     if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state)) {
29         if (dev->reg_state == NETREG_UNINITIALIZED)
30             return;
31         atomic_inc(&dev->carrier_changes);
32         linkwatch_fire_event(dev);
33     }
34 }
35 
36 
37 /**
38  *    netif_carrier_ok - test if carrier present
39  *    @dev: network device
40  *
41  * Check if carrier is present on device
42  */
43 static inline bool netif_carrier_ok(const struct net_device *dev)
44 {
45     return !test_bit(__LINK_STATE_NOCARRIER, &dev->state);
46 }

  在網絡設備驅動程序中可采取一定的手段來檢測和報告鏈路狀態,最常見的方法是采用中斷,其次可以設置一個定時器來對鏈路狀態進行周期性的檢查。當定時器到期之后,在定時器處理函數中讀取物理設備的相關寄存器以獲得載波狀態,從而更新設備的連接狀態,如下代碼所示:

 1 /*
 2  *  網絡設備驅動用定時器周期性檢查鏈路狀態
 3  */
 4 
 5 static void xxx_timer(unsigned long data)
 6 {
 7     struct net_device *dev = (struct net_device *)data;
 8     u16 link;
 9     ···
10     if (!(dev->flags & IFF_UP))
11         goto set_timer;
12 
13     /* 獲得物理上的連接狀態 */
14     if(link = xxx_chk_link(dev)) {
15         if (!(dev->flags & IFF_RUNNING)) {
16             netif_carrier_on(dev);
17             dev->flags |= IFF_RUNNING;
18             printk(KERN_DEBUG "%s: link up\n", dev->name);   
19         }
20     } else {
21         if (dev->flags & IFF_RUNNING) {
22             netif_carrier_off(dev);
23             dev->flags &= ~IFF_RUNNING;
24             printk(KERN_DEBUG "%s: link down\n", dev->name);
25         }
26     }
27 
28 set_timer:
29     priv->timer.expires = jiffies + 1 * Hz;
30     priv->timer.data = (unsigned long)dev;
31     priv->timer.function = &xxx_timer;  /* timer handler */
32     add_timer(&priv->timer); 
33 }     

  上述代碼第 14 行調用 xxx_chk_link() 函數來讀取網絡適配器硬件的相關寄存器,以獲得鏈路連接狀態,具體實現由硬件決定。當鏈路連接上時,第 16 行的 netif_carrier_on() 函數顯式地通知內核鏈路正常;反之,第 22 行的 nerif_carrier_off() 同樣顯式地通知內核鏈路失去連接。

  此外,從上述源代碼還可以看出,定時器處理函數會不停地利用第 28 ~ 32行代碼啟動新的定時器以實現周期性檢測的目的。最初啟動定時器的地方在哪呢??很顯然,它最適合在設備的打開函數中完成,如下代碼所示:

 1 /*
 2  *  在網絡設備驅動的打開函數中初始化定時器
 3  */
 4 
 5 static int xxx_open(struct net_device *dev)
 6 {
 7     struct xxx_priv *priv = netdev_priv(dev);
 8 
 9     
10     ···
11     priv->timer.expires = jiffies + 3 * Hz;
12     priv->timer.data = (unsigned long)dev;
13     priv->timer.function = &xxx_timer; /* 定時器處理函數 */
14     ···
15 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM