《LwIP協(xié)議棧源碼詳解——TCP/IP協(xié)議的實現(xiàn)》IP分片重裝2

姓名:朱小鵬 ? ?學號:16010130023

轉(zhuǎn)載:

http://blog.sina.com.cn/s/blog_62a85b950101anwr.html

【嵌牛導讀】:上一節(jié)還遺留有一個問題:IP分片包是怎么被插入相應的組裝鏈表的库继。這里用一個直觀的圖形來解釋這一過程行疏。

【嵌牛鼻子】:IP層

【嵌牛提問】:LWIP中的IP層如何進行信息包的接收耕皮、分片數(shù)據(jù)包重裝翰守、信息包的發(fā)送和轉(zhuǎn)發(fā)煤杀?

【嵌牛正文】:

上一節(jié)還遺留有一個問題:IP分片包是怎么被插入相應的組裝鏈表的钮追。這里用一個直觀的圖形來解釋這一過程晃财。VISO表示不太會用痹升,圖畫得亂78糟的建炫。

圖中展示了有兩個數(shù)據(jù)包正在被組裝的過程,兩個ip_reassdata結(jié)構(gòu)分別用于兩個數(shù)據(jù)包的組裝過程疼蛾。第一個數(shù)據(jù)包已經(jīng)組裝好了兩個分片數(shù)據(jù)肛跌,第二個組裝好了一個分片數(shù)據(jù)。LWIP并不像標準協(xié)議中描述的那樣察郁,另外分配一個數(shù)據(jù)結(jié)構(gòu)來描述各個分片數(shù)據(jù)衍慎,而是直接利用各個分片數(shù)據(jù),將數(shù)據(jù)中IP頭部的前八個字節(jié)拿來存儲組裝過程中的相關(guān)信息皮钠,因此每個進來的IP分片數(shù)據(jù)包頭都被改變了稳捆,也因此要使用ip_reassdata結(jié)構(gòu)中的iphdr字段來暫時保存IP數(shù)據(jù)包的完整頭部。

這八個字節(jié)被變成了什么值呢麦轰,這就是結(jié)構(gòu)體ip_reass_helper的內(nèi)容了乔夯。這個結(jié)構(gòu)體就是組裝過程中最為重要的結(jié)構(gòu)體了砖织。看看末荐,這恐怕是最簡單的一個結(jié)構(gòu)體了侧纯。

struct ip_reass_helper {

struct pbuf *next_pbuf;

u16_t start;

u16_t end;

};

next_pbuf字段在組裝過程中用來連接各個分片數(shù)據(jù)包;start字段用來記錄該分片數(shù)據(jù)包數(shù)據(jù)在整個IP包中的起始位置甲脏;同理眶熬,end字段表示在IP包中的結(jié)束位置。

函數(shù)ip_reass_chain_frag_into_datagram_and_validate(PS:神块请,這個函數(shù)名太長了)用來向一個ip_reassdata結(jié)構(gòu)中插入一個IP分片包pbuf聋涨,插入后檢查該IP包是否被組裝完畢,未組裝完畢則返回0负乡,否則返回非0值牍白。很明顯,這個函數(shù)的輸入?yún)?shù)有兩個抖棘,ip_reassdata結(jié)構(gòu)和分片包pbuf茂腥。下面仔細看看這個函數(shù)名最長的函數(shù)到底干了些什么工作。

首先它會從該IP分片包的頭部中提取信息切省,包括分片數(shù)據(jù)的起始偏移地址offset和分片數(shù)據(jù)的長度len最岗,之后它將該IP分片包的頭部得前八個字節(jié)強制轉(zhuǎn)換為ip_reass_helper結(jié)構(gòu),并將start字段的值置為offset朝捆;end字段的值置為offset+len般渡;next_pbuf字段的值置為NULL。到這里芙盘,進來的這個分片包已經(jīng)被改變面貌了驯用,它的IP頭部已經(jīng)被毀壞,下面就會將這個改頭換面的分片包進行插入操作了儒老。插入操作主要是利用比較各個ip_reass_helper的start和end字段的值以確定這個分片包被插在鏈表中的哪個位置蝴乔,插入位置的尋找是整個組裝過程中最難理解的部分了,但從原理上看是很簡單的一個過程驮樊,這里不再對查找插入位置及插入操作的源碼做解析薇正。

到這步,分片的數(shù)據(jù)包已經(jīng)被插入到相應的ip_reassdata結(jié)構(gòu)后的鏈表中了囚衔,此時這個函數(shù)名最長的函數(shù)要檢查是否這個ip_reassdata對應的數(shù)據(jù)包已經(jīng)組裝完畢挖腰。這里要分兩步來看,第一是判斷該數(shù)據(jù)包的最后一個分片包是否已經(jīng)到來练湿,在上面一節(jié)中已經(jīng)講過猴仑,當收到的IP分片包為某個IP包的最后一個分片時,函數(shù)ip_reass會把對應ip_reassdata結(jié)構(gòu)的flags字段置1鞠鲜,所以宁脊,如果檢測到某個ip_reassdata結(jié)構(gòu)的flags字段仍為0断国,說明最后一個分片還未被收到贤姆,IP數(shù)據(jù)包組裝肯定還未完成榆苞,此時,函數(shù)名最長的函數(shù)直接返回0即可霞捡。第二步坐漏,如果發(fā)現(xiàn)flags字段置1,說明最后一個分片包已經(jīng)收到碧信,但是整個IP是否被組裝完畢還是未知赊琳,因為在網(wǎng)絡上,分片包不是每次都能按次序到達砰碴,因此躏筏,收到的最后一個分片數(shù)據(jù)包不一定是最后一個分片包。此時需要遍歷ip_reassdata結(jié)構(gòu)后面的各個分片包鏈表呈枉,以檢測是否還有分片包未被接收到趁尼。

到這步,ip_reass_chain_frag_into_datagram_and_validate函數(shù)就完成工作了猖辫,它將分片的數(shù)據(jù)插入了某個ip_reassdata結(jié)構(gòu)的數(shù)據(jù)分片鏈表酥泞,并檢測該IP數(shù)據(jù)包是否被組裝完畢,組裝完畢則返回一個非0值啃憎,否則返回0值芝囤。

這里,我們有回到了ip_reass函數(shù)辛萍,ip_reass通過函數(shù)調(diào)用將某個分片數(shù)據(jù)包插入相應的個ip_reassdata結(jié)構(gòu)后悯姊,通過函數(shù)的返回值來決定要做的下一步操作。如果數(shù)據(jù)包組裝未完成贩毕,ip_reass函數(shù)需要向調(diào)用它的函數(shù)返回一個空指針挠轴,如果數(shù)據(jù)包組裝完成,它就要向調(diào)用它的函數(shù)返回這個組裝好的數(shù)據(jù)包耳幢。從上面的圖中可以看出岸晦,被組裝好的數(shù)據(jù)包是全部分片被掛接在一個ip_reassdata結(jié)構(gòu)上的,ip_reass函數(shù)需要從這個ip_reassdata結(jié)構(gòu)上取下相應的各個分片數(shù)據(jù)睛藻,并刪除各個分片中的不必要信息启上,然后將整個數(shù)據(jù)包返回給調(diào)用者。為了完成這個任務店印,ip_reass函數(shù)進行了下面的工作冈在。

先將ip_reassdata結(jié)構(gòu)中的iphdr字段各個值做相應的修正,如修正報文總長度按摘、校驗和包券,然后將iphdr字段全部拷貝到第一個分片包的IP頭部字段中纫谅,這樣整個IP數(shù)據(jù)包的頭部就出現(xiàn)在第一個分片信息包中了,接下來從第二個分片包開始溅固,將它們的IP頭部信息刪除付秕,這樣,一個完整的IP數(shù)據(jù)包就重新組裝好了侍郭。最后询吴,調(diào)用ip_reass_dequeue_datagram函數(shù)刪除數(shù)據(jù)包組裝過程中使用的ip_reassdata結(jié)構(gòu)體,即從上圖所述的reassdatagrams鏈表刪除對應reassdata的節(jié)點亮元。好了猛计,功德圓滿!

這個圈子繞得有點大爆捞,本來是在講ip_input函數(shù)的奉瘤,結(jié)果就講到了ip_reass函數(shù),后來又講到了ip_reass_chain_frag_into_datagram_and_validate函數(shù)煮甥。沒辦法盗温,誰讓后面兩個函數(shù)是為ip_input函數(shù)服務的呢!ip_input函數(shù)使用ip_reass組裝好的數(shù)據(jù)包遞交到上層TCP或UDP等應用中去苛秕,在前面已經(jīng)講過了肌访。

現(xiàn)在我們還是要回到原路上,走上ip_input這條道路艇劫。ip_input的基本流程已經(jīng)在前面講得很清楚了吼驶,還有一個函數(shù)為它服務,即ip_forward函數(shù)店煞,它主要是完成數(shù)據(jù)包的轉(zhuǎn)發(fā)工作蟹演,當設備接收到的數(shù)據(jù)包不是給自己的時候,它就可以選擇將該數(shù)據(jù)包轉(zhuǎn)發(fā)出去顷蟀,本來這里沒有必要講ip_forward函數(shù)的酒请,因為在一般的應用中,這項功能會被禁止鸣个,設備收到不是給自己的數(shù)據(jù)包時羞反,將在ip_input函數(shù)處理的初期被丟棄。但到目前囤萤,我們還未涉及到任何關(guān)于IP數(shù)據(jù)包發(fā)送的內(nèi)容昼窗,考慮了很久,還是覺得應該把ip_forward函數(shù)講解一下涛舍,因為數(shù)據(jù)包的轉(zhuǎn)發(fā)與數(shù)據(jù)包的發(fā)送是完全一樣的原理澄惊,使用了完全相同的接口函數(shù),因此講解了ip_forward函數(shù)就等于講解了IP層數(shù)據(jù)包發(fā)送的所有工作細節(jié)。在TCP層或UDP層必然涉及到數(shù)據(jù)包的發(fā)送工作掸驱,在這里就利用ip_forward函數(shù)將IP層數(shù)據(jù)包發(fā)送的整個過程講解清楚肛搬,這樣邏輯清楚,利于理解毕贼!

當收到一個IP數(shù)據(jù)包后温赔,LWIP會遍歷所有網(wǎng)絡接口的IP地址,判斷這個數(shù)據(jù)包是不是給自己的帅刀,如果不是让腹,就要調(diào)用收到該數(shù)據(jù)包的那個網(wǎng)絡接口將數(shù)據(jù)包轉(zhuǎn)發(fā)出去远剩。但是不慌扣溺,轉(zhuǎn)發(fā)前還要檢測這個包是不是一個廣播包,如果是瓜晤,直接丟棄锥余,不做處理。現(xiàn)在來看看數(shù)據(jù)包轉(zhuǎn)發(fā)函數(shù)ip_forward做了哪些工作呢痢掠,這個函數(shù)的輸入?yún)?shù)有三個:要轉(zhuǎn)發(fā)的數(shù)據(jù)包指針驱犹,要轉(zhuǎn)發(fā)的數(shù)據(jù)包的IP報頭指針,收到該數(shù)據(jù)包的的網(wǎng)絡接口數(shù)據(jù)結(jié)構(gòu)netif指針足画。

首先雄驹,調(diào)用ip_route函數(shù)找到轉(zhuǎn)發(fā)該數(shù)據(jù)包應該使用的網(wǎng)絡接口,ip_route函數(shù)以數(shù)據(jù)包IP報頭中的目標地址為參數(shù)淹辞,查找應該使用的相關(guān)結(jié)構(gòu)医舆。如果找不到滿足要求的接口,則選擇缺省網(wǎng)絡接口象缀。ip_route函數(shù)現(xiàn)在這里打住蔬将,在講完ip_forward函數(shù)之后,再對它進行詳細的講解央星。

ip_forward檢查ip_route函數(shù)找到的網(wǎng)絡接口是否為有效霞怀,所謂有效,即不能為空莉给,也不能為接收到該IP包的那個接口毙石。當判定網(wǎng)絡接口為無效時,數(shù)據(jù)包不會被轉(zhuǎn)發(fā)颓遏。當可以用某個網(wǎng)絡接口轉(zhuǎn)發(fā)數(shù)據(jù)包時徐矩,ip_forward先將該IP報頭中TTL字段值減1,若TTL變?yōu)?州泊,則需要向源主機發(fā)送一份超時ICMP信息丧蘸,表示當前數(shù)據(jù)包的生存周期到了,這個數(shù)據(jù)包在這里被丟棄,不會被轉(zhuǎn)發(fā)出去力喷。至于怎樣發(fā)送這個超時的ICMP信息包刽漂,這就涉及到IP層數(shù)據(jù)包的發(fā)送函數(shù)ip_output了,我們將在后面慢慢道來弟孟。

接下來函數(shù)重新計算頭部校驗和贝咙,因為頭部TTL字段的值已經(jīng)被修改,最后調(diào)用netif結(jié)構(gòu)注冊的output函數(shù)拂募,該函數(shù)將數(shù)據(jù)包組裝成以太網(wǎng)數(shù)據(jù)幀并發(fā)送出去庭猩。前面說過了,這個函數(shù)就是etharp_output陈症。

到這里ip_forward函數(shù)的工作就完成了蔼水,還剩下兩個問題,ip_route函數(shù)和怎樣發(fā)送一個超時的ICMP信息包出去录肯。這里講解第一個問題趴腋,第二個問題放在ICMP部分。ip_route函數(shù)以目標IP地址為輸入?yún)?shù)论咏,然后在網(wǎng)絡接口結(jié)構(gòu)鏈表netif_list上找尋與該IP地址在同一子網(wǎng)上的網(wǎng)絡接口优炬,若找到則返回滿足要求的網(wǎng)絡接口,若找不到則返回缺省網(wǎng)絡接口厅贪。如此的簡單蠢护,不多說。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末养涮,一起剝皮案震驚了整個濱河市葵硕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌单寂,老刑警劉巖贬芥,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異宣决,居然都是意外死亡蘸劈,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門尊沸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來威沫,“玉大人,你說我怎么就攤上這事洼专“袈樱” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵屁商,是天一觀的道長烟很。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么雾袱? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任恤筛,我火速辦了婚禮,結(jié)果婚禮上芹橡,老公的妹妹穿的比我還像新娘毒坛。我一直安慰自己,他們只是感情好林说,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布煎殷。 她就那樣靜靜地躺著,像睡著了一般腿箩。 火紅的嫁衣襯著肌膚如雪豪直。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天度秘,我揣著相機與錄音顶伞,去河邊找鬼饵撑。 笑死剑梳,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的滑潘。 我是一名探鬼主播垢乙,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼语卤!你這毒婦竟也來了追逮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤粹舵,失蹤者是張志新(化名)和其女友劉穎钮孵,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體眼滤,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡巴席,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了诅需。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漾唉。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖堰塌,靈堂內(nèi)的尸體忽然破棺而出赵刑,到底是詐尸還是另有隱情,我是刑警寧澤场刑,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布般此,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏铐懊。R本人自食惡果不足惜屎勘,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望居扒。 院中可真熱鬧概漱,春花似錦、人聲如沸喜喂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玉吁。三九已至照弥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間进副,已是汗流浹背这揣。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留影斑,地道東北人给赞。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像矫户,于是被迫代替她去往敵國和親片迅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容