lwip (八)ARP層流程

2021-10-14 14:33:00 字數 4136 閱讀 2616

前面一節重點說了arp快取表以及如何對其進行相關操作,關於arp,一共想說三個函式,前面已經講過了兩個。

最後要講的乙個函式是update_arp_entry,該函式用於更新arp快取表中的表項或者在快取表中插入乙個新的表項。該函式會在收到乙個ip資料報或arp資料報後被呼叫。該函式原型如下,

static err_t

update_arp_entry

(struct netif *netif,

struct ip_addr *ipaddr,

struct eth_addr *ethaddr, u8_t flags)

其中重要的兩個引數ipaddrethaddr分別對應的ip位址和mac位址,函式利用這兩個位址去更新或插入arp表項。由於這個函式**量較小,這裡就列出原始碼來講解,注意這個原始碼是經過處理的,已經去掉了編譯選項、原始碼注釋、除錯輸出資訊等非重點部分。

static err_t

update_arp_entry

(struct netif *netif,

struct ip_addr *ipaddr,

struct eth_addr *ethaddr, u8_t flags)

arp_table[i]

.ctime =0;

// 生存時間值置0

#if arp_queueing

//該arp表項上有未傳送的佇列,則把這些佇列傳送出去

while

(arp_table[i]

.q !=

null

)#endif

return err_ok;

}

從源程式中可以看出,update_arp_entry的流程如下:先通過呼叫find_entry找到對應ipaddr對應的表項,並設定相應的arp表項的成員(主要是state, netif, ethaddr, cttime),最後如果定義了arp_queueing,並且這個arp表項上有未傳送的資料報的話,則把這些資料全部傳送出去。雖然比較囉嗦,但是還是我們還是根據不同的ipaddr經過find_entry執行後,來看看update_arp_entry執行的幾種不同情況。

首先可以肯定的是,update_arp_entry的兩個引數ipaddrethaddr必是互相匹配的,因為它們是從源主機發來的ip包或arp包中解析出來的,代表了源主機的mac位址和ip位址。find_entry利用ipaddr作為引數執行後,返回乙個arp表項索引。如果該表項處於empty狀態,那麼該表項現在一定是新建立的,此時設定該表項為stable狀態並設定該表項其他字段值後即結束。如果該表項是處於pending狀態,由於此時已經有了和ipaddr匹配的mac位址返回,所以該表項也被設定為stable狀態並同時設定該表項其他字段值。如果該表項是處於stable狀態,其實此時只需要將ctime的值復位即可,但是lwip為了節省**量,它還是選擇像上面的情況一樣做相同的處理,這樣雖然有些步驟是多餘的,但並不影響函式功能。最後都會檢查該表項是否還有資料需要傳送,如果有,則將所有資料報傳送出去。

現在是時候從巨集觀上來看看到底arp是怎麼乙個工作流程,以及它在整個lwip協議棧當中發揮的重要作用。。

該圖簡潔明瞭的解釋了基本所有lwip的資料報接收與傳送的全過程。我們可以看到幾個熟悉的身影:etharp_query、etharp_request、update_arp_entry。在前面已經講過了的!

arp從功能上來說可以簡單的分成兩個部分:當有資料報輸入時,更新arp表,如果是ip包則遞交給ip層,如果是arp包,則針對不同的arp包型別做相應的響應;當向目的ip傳送乙個資料報的時候,需要通過arp實現ip到mac位址的對映,必要時,需要傳送廣播資料報獲得目標機器的mac位址。

lwip利用netif.input指向的函式接收乙太網資料報,通常這個函式是ethernet_input。注意,這裡並不是說ethernet_input直接與底層硬體互動接收資料報,而是更底層的函式接收到資料報後將資料報遞交給ethernet_inputethernet_input再對其進行處理。

乙太網的幀型別可以是:ip,arp,甚至可以是pppoewlan等。這裡主要分析ip和arp兩種型別的資料報。ethernet_input根據乙太網首部的型別字段判斷收到的資料報的型別,如果是ip包,則將該包遞交給etharp_ip_input,如果是arp包,則將該包遞交給etharp_arp_input

對於ip型別的資料報,etharp_ip_input首先檢查是否開啟了etharp_trust_ip_mac這個選項,如果開啟了就是要用這個幀中的資訊和update_arp_entry函式來更新arp表(利用幀首部的源mac位址和幀資料中ip報文中的源ip位址),然後丟棄乙太網幀首部,將ip報文通過ip_input函式遞交給ip層。

對於arp型別的資料報,etharp_arp_input函式首先利用資料報頭資訊更新arp表的內容,

然後再判斷該arp資料報的型別,如果是arp請求包,則首先判斷這個包是不是給自己的,如果是給自己的,則在原有包的基礎上重組乙個arp應答包傳送出去(注意此處並沒有重新分配乙個pbuf,而是借用了原來的緩衝結構)。如果不是給自己的,則直接忽略。如果是arp應答包,主要的工作就是更新arp表,但是這一步已經在arp包剛進來的時候就處理了,所以這裡不需要再重複做,這樣arp包的處理也完畢。

lwip利用netif.output指向的函式傳送ip資料報,通常這個函式是etharp_output。注意,這裡並不是說etharp_output直接與底層硬體互動傳送資料報,而是將資料報做相應的處理,最終遞交給netif.linkoutput函式來傳送的。

etharp_output函式接收ip層要傳送的資料報,並將資料報傳送出去。由於是傳送ip資料報,所以函式一開始需要增加緩衝區大小,大小為乙太網的資料首部的大小。然後檢查ip位址,可以分為廣播包,多播包,單播包(單播包又分為是區域網內部還是區域網外面)。

廣播包:判斷目的ip位址是不是為全1,或者是全0(老版本中使用的),如果是廣播包則目的ip的mac位址不需要查詢arp表,直接將mac位址設定為全1傳送即可,即mac六個位元組值為0xff,0xff,0xff,0xff,0xff,0xff

多播包:判斷目的ip位址是不是d類位址,即0xe******x,如果是多播的話,mac位址也是確定的,即將mac位址01-00-5e-00-00-00的低23位設定為ip位址的低23位。對於以上的兩種資料報,etharp_output直接呼叫函式etharp_send_ip將資料報傳送出去。

單播包:要比較目的ip和本地ip位址,看是否是區域網內的,不是區域網內的,則將目的ip位址設定為預設閘道器的位址,然後再統一呼叫etharp_query函式將資料報傳送出去,注意這些資料報在這種情況下可能被連線在相關arp表項的傳送鍊錶上,等待傳送。

LwIP中的ARP協議實現(2)

lwip中的arp實現 1 之 arp快取表的資料結構 lwip中的arp實現 2 之 arp快取表的超時處理 lwip中的arp實現 3 之 傳送arp請求包 lwip中的arp實現 4 之 arp資料報接收 lwip中的arp實現 5 之 arp資料報傳送 arp表項的生存時間是5分鐘,而arp...

LWIP協議棧學習 一 ARP協議

arp所實現的功能就是通過ip位址獲取到mac位址,並且將ip和mac對映到一起,儲存到arp表中.dest mac src mac frame type hardware type protocol type hardware addr len protocol addr len opsend m...

LWIP協議 TCP建立流程

如果客戶端發來tcp連線請求,那麼伺服器端就會呼叫tcp new函式來建立乙個tcp塊。tcp new函式的主體內容就是tcp alloc tcp prio normal 函式,傳遞預設的tcp塊優先順序為64 優先順序範圍1 127 tcp alloc pcb struct tcp pcb mem...