LwIP:處理鏈路狀態改變


[文/告別年代   Email:byeyear@hotmail.com]

 

重大修訂記錄

-----------------------------------------

2016.11.03

感謝@ wayne88 指出(見文后討論帖),對本文所述的NETIF_FLAG_UP標記和有效IP地址之間的關系,lwip代碼作者其實是存有疑慮的。見以下鏈接:

http://savannah.nongnu.org/bugs/?func=detailitem&item_id=37068

所幸該鏈接不會影響本文內容。對1.4.1版代碼,代碼作者仍然采用了如本文所述的、他認為可能是“unclear”的做法。

 

注意 

-----------------------------------------

本文基於lwip-1.4.1,若文章與代碼對不上,請確認代碼版本。

 

基本流程

-----------------------------------------

A. link up -> link down:

   關閉MAC和DMA;

   調用netif_set_link_down

B. link down -> link up:

   打開MAC和DMA;

   調用netif_set_link_up

C. 注意:當使用RAW API時,所有使用RAW API的代碼(包括處理鏈路狀態的代碼)必須運行於同一線程環境。

-----------------------------------------

 

代碼分析

-----------------------------------------

有四個函數和兩個標志位和鏈路狀態改變有關:

A. netif_set_up

   該函數設置NETIF_FLAG_UP標記,並在鏈路已up(NETIF_FLAG_LINK_UP有效)的情況下發送arp探測。

/* 刪除了部分預編譯條件和無關代碼 */
void netif_set_up(struct netif *netif)
{
  if (!(netif->flags & NETIF_FLAG_UP)) {
    netif->flags |= NETIF_FLAG_UP;
    /* 鏈路有效情況下發送ARP探測 */
    if (netif->flags & NETIF_FLAG_LINK_UP) {
      if (netif->flags & (NETIF_FLAG_ETHARP)) {
        etharp_gratuitous(netif);
      }
    }
  }
}

   如果你的網絡使用靜態IP,那么在lwip初始化時調用該函數;

   如果你的網絡使用DHCP,那么DHCP成功后lwip會幫你調用netif_set_up。

B. netif_set_down

   除非你需要關閉網絡,否則一般不需要主動調用該函數。

C. netif_set_link_up

   該函數設置NETIF_FLAG_LINK_UP標記,啟動DHCP和AutoIP,並在NETIF_FLAG_UP標記有效的情況下發送arp探測。

void netif_set_link_up(struct netif *netif )
{
  if (!(netif->flags & NETIF_FLAG_LINK_UP)) {
    netif->flags |= NETIF_FLAG_LINK_UP;
    if (netif->dhcp) {
      dhcp_network_changed(netif);
    }
    /* ...其它代碼(autoip相關)... */
    if (netif->flags & NETIF_FLAG_UP) {
      if (netif->flags & NETIF_FLAG_ETHARP) {
        etharp_gratuitous(netif);
      }
    }
    NETIF_LINK_CALLBACK(netif);
  }
}

   當驅動程序檢測到鏈路從down變化為up時,重新初始化MAC和DMA,然后調用該函數。

   注意:初始化時如果鏈路有效,low_level_init直接設置NETIF_FLAG_LINK_UP,而不調用netif_set_link_up函數,避免在lwip沒有完全初始化好時啟動DHCP。

D. netif_set_link_down

   當驅動程序檢測到鏈路從up變為down時調用該函數,並關閉MAC和DMA。

E. NETIF_FLAG_UP和NETIF_FLAG_LINK_UP

   前者表示lwip協議棧已經就緒(已得到合法IP地址,且協議棧已准備好收發數據包);后者表示鏈路層有效。

   或者說,一個是軟件(協議棧)就緒標志,一個是硬件(鏈路層)就緒標志。

F. 參考lwip代碼中的netif.h文件對這兩個標記的詳細說明。

   網上很多port代碼不管是否使用DHCP都在lwip初始化時設置NETIF_FLAG_UP,這是*不*正確的。

   NETIF_FLAG_UP必須在獲得有效IP地址后才能置位,以保證順利發送ARP探測。

   所以,如果使用了DHCP,那么初始化時就不能設置NETIF_FLAG_UP。

   LwIP會在鏈路有效情況下發送DHCP請求,並在拿到有效IP地址后為你設置NETIF_FLAG_UP。

 

情景分析

--------------------------------------------------------------

A. 靜態IP,初始化時鏈路有效

    這是最簡情況。驅動層會看到Link有效,並直接設置NETIF_FLAG_LINK_UP。

    隨后lwip初始化過程中調用netif_set_up,該函數設置NETIF_FLAG_UP,並發送arp探測。

B. 靜態IP,初始化時鏈路無效

    驅動層不會設置NETIF_FLAG_LINK_UP。

    lwip初始化過程會調用netif_set_up,該函數看到沒有link,除了設置NETIF_FLAG_UP標記外不會做任何事。

    當鏈路變為有效后,驅動層調用netif_set_link_up,發送arp探測。

C. 動態IP,初始化時鏈路有效

    驅動層直接設置NETIF_FLAG_LINK_UP。

    lwip初始化過程中調用dhcp_start,啟動DHCP過程。

    但lwip初始化過程不會調用netif_set_up,因為還沒有獲得有效IP地址。

    獲得有效IP后,lwip會幫我們調用netif_set_up,發送arp探測。

D. 動態IP,初始化時鏈路無效

    驅動層不會設置NETIF_FLAG_LINK_UP。

    lwip初始化過程中仍然會調用dhcp_start。對dhcp_start的調用是必須的,因為dhcp過程需要的資源將在該函數中分配。

    等到鏈路有效后驅動層調用netif_set_link_up,該函數會啟動DHCP過程。

    獲得有效IP后,lwip會幫我們調用netif_set_up,發送arp探測。

E. 靜態IP,鏈路斷開后重建

    鏈路斷開時netif_set_link_down,重建后netif_set_link_up發送arp探測。

    NETIF_FLAG_UP在設置后就一直有效。

F. 動態IP,鏈路斷開后重建

    鏈路重建后netif_set_link_up重新啟動DHCP過程,該過程會清除NETIF_FLAG_UP標記。

    DHCP完成后lwip自動調用netif_set_up重新置位該標記並發起arp探測。

 

總結

-------------------------------------------------------------------------------------

1. 使用靜態IP

    low_level_init根據當前鏈路狀態設置或不設置NETIF_FLAG_LINK_UP;

    lwip初始化時調用netif_set_up;

    鏈路狀態改變時調用netif_set_link_up/netif_set_link_down。

2. 使用動態IP

    low_level_init根據當前鏈路狀態設置或不設置NETIF_FLAG_LINK_UP;

    lwip初始化時調用dhcp_start;

    鏈路狀態改變時調用netif_set_link_up/netif_set_link_down;

    不要在使用動態IP時直接調用netif_set_up,而是由lwip協議棧代碼在成功獲得IP后為你調用這個函數。

 

[文/告別年代   Email:byeyear@hotmail.com]


免責聲明!

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



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