《LwIP協(xié)議棧源碼詳解——TCP/IP協(xié)議的實(shí)現(xiàn)》IP層輸入

姓名:朱小鵬 ? ?學(xué)號(hào):16010130023

轉(zhuǎn)載:

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

【嵌牛導(dǎo)讀】:對(duì)于IP層主要討論信息包的接收草描、分片數(shù)據(jù)包重裝适篙、信息包的發(fā)送和轉(zhuǎn)發(fā)三個(gè)內(nèi)容趣惠。IP數(shù)據(jù)報(bào)頭結(jié)構(gòu)如下所示,其中,選項(xiàng)字段是可以沒(méi)有的,所以通常的IP數(shù)據(jù)報(bào)頭長(zhǎng)度為20個(gè)字節(jié)。

【嵌牛鼻子】:IP層

【嵌牛提問(wèn)】:LWIP中的IP層如何進(jìn)行信息包的接收舔琅、分片數(shù)據(jù)包重裝、信息包的發(fā)送和轉(zhuǎn)發(fā)洲劣?

【嵌牛正文】:

對(duì)于IP層主要討論信息包的接收备蚓、分片數(shù)據(jù)包重裝、信息包的發(fā)送和轉(zhuǎn)發(fā)三個(gè)內(nèi)容囱稽。IP數(shù)據(jù)報(bào)頭結(jié)構(gòu)如下所示郊尝,其中,選項(xiàng)字段是可以沒(méi)有的战惊,所以通常的IP數(shù)據(jù)報(bào)頭長(zhǎng)度為20個(gè)字節(jié)流昏。

第一個(gè)字段是4bit的版本號(hào),對(duì)于IPv4吞获,該值為4况凉;對(duì)于IPv6,該值為6各拷。

接下來(lái)的4bit字段用于記錄首部長(zhǎng)度刁绒,以字為單位。所以對(duì)于不含任何選項(xiàng)字段的IP報(bào)頭烤黍,則該長(zhǎng)度值為5膛锭,由于該字段最大值為15,所以其能描述的最大IP報(bào)頭長(zhǎng)度為15*4=60字節(jié)蚊荣。

再下來(lái)是一個(gè)8bit的服務(wù)類型字段,該字段主要用于描述該IP數(shù)據(jù)包急需的服務(wù)類型莫杈,如最小延時(shí)互例、最大吞吐量、最高可靠性筝闹、最小費(fèi)用等媳叨。這個(gè)字段在LWIP中沒(méi)啥用處腥光。

16位的總長(zhǎng)度字段描述了整個(gè)IP數(shù)據(jù)報(bào),包括IP數(shù)據(jù)報(bào)頭的總字節(jié)數(shù)糊秆。理論上說(shuō)武福,IP數(shù)據(jù)包總長(zhǎng)度最大可達(dá)65535字節(jié),但在實(shí)際應(yīng)用中痘番,底層鏈路可不允許這么大的數(shù)據(jù)包出現(xiàn)在鏈路上捉片,因?yàn)檫@會(huì)大大增加數(shù)據(jù)出錯(cuò)的可能性,所以在鏈路層往往會(huì)對(duì)大的IP數(shù)據(jù)包進(jìn)行分片汞舱,當(dāng)然這些都是后話伍纫。

接下來(lái)的16位標(biāo)識(shí)字段用于標(biāo)識(shí)IP層發(fā)送出去的每一份IP數(shù)據(jù)報(bào),每發(fā)送一份報(bào)文昂芜,則該值加1莹规。然后的3位標(biāo)志和13位片偏移字段用于在IP數(shù)據(jù)包分片時(shí)使用,這里先不討論泌神。LWIP的較高版本才支持IP分片功能良漱。

TTL字段描述該IP數(shù)據(jù)包最多能被轉(zhuǎn)發(fā)的次數(shù),每經(jīng)過(guò)一次轉(zhuǎn)發(fā)欢际,該值會(huì)減1母市,當(dāng)該值為0時(shí),一個(gè)ICMP報(bào)文會(huì)被返回至源主機(jī)幼苛。

8位協(xié)議字段用來(lái)描述該IP數(shù)據(jù)包是來(lái)自于上層的哪個(gè)協(xié)議窒篱,該值為1表示為ICMP協(xié)議,該值為2表示IGMP協(xié)議舶沿,該值為6表示TCP協(xié)議墙杯,該值為17表UDP協(xié)議。

16位首部校驗(yàn)和只針對(duì)IP首部做校驗(yàn)括荡,它并不關(guān)心其內(nèi)部數(shù)據(jù)在傳輸過(guò)程中出錯(cuò)與否高镐,對(duì)于數(shù)據(jù)的校驗(yàn)是上層協(xié)議負(fù)責(zé)的,如ICMP畸冲、IGMP嫉髓、TCP、UDP協(xié)議都會(huì)計(jì)算它們頭部以及整個(gè)數(shù)據(jù)區(qū)的長(zhǎng)度邑闲。這里再COPY一段這個(gè)校驗(yàn)和是怎樣生成以及在接收端是如何實(shí)驗(yàn)校驗(yàn)的算行。

在發(fā)送端為了計(jì)算一份數(shù)據(jù)報(bào)的IP檢驗(yàn)和,首先把檢驗(yàn)和字段置為0苫耸。然后州邢,對(duì)首部中每個(gè)16 bit進(jìn)行二進(jìn)制反碼求和(整個(gè)首部看成是由一串16 bit的字組成),結(jié)果存在檢驗(yàn)和字段中褪子。當(dāng)接收端收到一份I P數(shù)據(jù)報(bào)后量淌,同樣對(duì)首部中每個(gè)16 bit進(jìn)行二進(jìn)制反碼的求和骗村。由于接收方在計(jì)算過(guò)程中包含了發(fā)送方保存在首部中的檢驗(yàn)和字段,因此呀枢,如果首部在傳輸過(guò)程中沒(méi)有發(fā)生任何差錯(cuò)胚股,那么接收方計(jì)算的結(jié)果應(yīng)該為全1。如果結(jié)果不是全1(即檢驗(yàn)和錯(cuò)誤)裙秋,那么IP就丟棄收到的數(shù)據(jù)報(bào)琅拌。但是不生成差錯(cuò)報(bào)文,由上層去發(fā)現(xiàn)丟失的數(shù)據(jù)報(bào)并進(jìn)行重傳残吩。

接下來(lái)是兩個(gè)32位的IP地址财忽,不啰嗦了。最后一個(gè)字段是任選字段泣侮,不同的協(xié)議會(huì)選擇性的使用該字段即彪,這里也不討論。

現(xiàn)在來(lái)看看LWIP中是怎么樣來(lái)描述這個(gè)IP數(shù)據(jù)報(bào)頭的活尊,使用的結(jié)構(gòu)體叫ip_hdr:

struct ip_hdr {

PACK_STRUCT_FIELD(u16_t _v_hl_tos);//前三個(gè)字段:版本號(hào)隶校、首部長(zhǎng)度、服務(wù)類型

PACK_STRUCT_FIELD(u16_t _len);//總長(zhǎng)度

PACK_STRUCT_FIELD(u16_t _id);//標(biāo)識(shí)字段

PACK_STRUCT_FIELD(u16_t _offset); // 3位標(biāo)志和13位片偏移字段

#define IP_RF 0x8000//

#define IP_DF 0x4000//不分組標(biāo)識(shí)位掩碼

#define IP_MF 0x2000//后續(xù)有分組到來(lái)標(biāo)識(shí)位掩碼

#define IP_OFFMASK 0x1fff//獲取13位片偏移字段的掩碼

PACK_STRUCT_FIELD(u16_t _ttl_proto);// TTL字段和協(xié)議字段

PACK_STRUCT_FIELD(u16_t _chksum);//首部校驗(yàn)和字段

PACK_STRUCT_FIELD(struct ip_addr src);//源IP地址

PACK_STRUCT_FIELD(struct ip_addr dest);//目的IP地址

} PACK_STRUCT_STRUCT;

注意結(jié)構(gòu)體聲明的時(shí)候定義了幾個(gè)宏定義:IP_RF蛹锰、IP_DF深胳、IP_MF、IP_OFFMASK铜犬,它們是在求與分組相關(guān)兩個(gè)字段時(shí)要用到的掩碼舞终,也可以在結(jié)構(gòu)體的外面進(jìn)行定義,無(wú)影響癣猾。

前面講過(guò)敛劝,從以太網(wǎng)底層進(jìn)來(lái)的數(shù)據(jù)包經(jīng)過(guò)ethernet_input函數(shù)分發(fā)給IP模塊或者ARP模塊,分發(fā)給IP模塊是通過(guò)調(diào)用ip_input函數(shù)完成的纷宇,當(dāng)然在遞交前夸盟,ethernet_input需要將數(shù)據(jù)包去掉以太網(wǎng)頭。現(xiàn)在來(lái)看看數(shù)據(jù)包傳遞給ip_input后像捶,該函數(shù)進(jìn)行了哪些方面的工作上陕。這里我們先不涉及其內(nèi)部關(guān)于DHCP協(xié)議的相關(guān)處理。

第一件事是檢查IP頭部的版本號(hào)拓春,如果該值不為4释簿,則立即丟棄該數(shù)據(jù)包。更高版本的LWIP協(xié)議椗鹈В可以支持IPv6辕万,但這里我們只討論IPv4。接下來(lái)函數(shù)檢查IP數(shù)據(jù)報(bào)頭是否只保存于一個(gè)pbuf中,如果不是 渐尿,也直接丟棄該IP包,這是因?yàn)長(zhǎng)WIP不允許IP數(shù)據(jù)包頭被分裝在不同的pbuf里面矾瑰。同時(shí)砖茸,函數(shù)檢查IP報(bào)頭中的總長(zhǎng)度字段是否大于遞交上來(lái)的數(shù)據(jù)包總長(zhǎng)度,如果是殴穴,則說(shuō)明存在傳輸錯(cuò)誤凉夯,直接丟棄數(shù)據(jù)包。

然后是對(duì)IP數(shù)據(jù)報(bào)頭做校驗(yàn)采幌,該工作是函數(shù)inet_chksum完成的劲够,如果校驗(yàn)不通過(guò)則直接丟棄數(shù)據(jù)包。inet_chksum函數(shù)在后續(xù)有需要時(shí)會(huì)詳細(xì)講解休傍。

接著征绎,需要在這里對(duì)數(shù)據(jù)包進(jìn)行截?cái)嗖僮鳎凑誌P包頭記錄的總長(zhǎng)度字段截取數(shù)據(jù)包磨取,因?yàn)榻?jīng)過(guò)ethernet_input傳遞上來(lái)的數(shù)據(jù)包只被去除了以太網(wǎng)數(shù)據(jù)包頭部人柿,而對(duì)于可能存在的以太網(wǎng)填充字段和一定存在的以太網(wǎng)校驗(yàn)字段(最后一字節(jié))沒(méi)做處理,我們?cè)谶@里對(duì)它們進(jìn)行截?cái)嗝ρ幔玫酵暾麩o(wú)冗余的IP數(shù)據(jù)包凫岖。

然后,函數(shù)檢測(cè)IP數(shù)據(jù)包中的目的IP地址是否與本機(jī)的相符逢净,本機(jī)的IP地址是保存在netif結(jié)構(gòu)體變量中的哥放,一個(gè)系統(tǒng)可能有著多個(gè)網(wǎng)卡設(shè)備,這就意味著它有多個(gè)netif結(jié)構(gòu)體變量分別用于描述這些網(wǎng)卡設(shè)備爹土,也意味著本機(jī)有著多個(gè)IP地址甥雕,這些netif結(jié)構(gòu)體是被連接在netif_list鏈表上的。ip_input函數(shù)會(huì)遍歷netif_list鏈表上的netif結(jié)構(gòu)以找到匹配的IP地址着饥,并記錄該netif結(jié)構(gòu)體變量犀农,也即記錄該網(wǎng)卡。從這點(diǎn)看來(lái)宰掉,在ARP部分內(nèi)容中呵哨,對(duì)于某個(gè)接收到的ARP請(qǐng)求包,也應(yīng)該按照這種方式進(jìn)行遍歷后再給出ARP相應(yīng)更好轨奄,而源代碼并沒(méi)有這樣做孟害,當(dāng)然,這只是個(gè)人意見(jiàn)挪拟。當(dāng)遍歷完成后挨务,如果依舊沒(méi)有得到與匹配的netif結(jié)構(gòu)體變量,這說(shuō)明該數(shù)據(jù)包不是給本機(jī)的,此時(shí)需要對(duì)數(shù)據(jù)包進(jìn)行轉(zhuǎn)發(fā)或者丟棄工作谎柄,這是通過(guò)宏定義IP_FORWARD來(lái)完成的丁侄,這里注意不要對(duì)廣播數(shù)據(jù)包進(jìn)行轉(zhuǎn)發(fā)。

再接下來(lái)朝巫,根據(jù)目標(biāo)IP地址判斷數(shù)據(jù)包是否為廣播或多播IP數(shù)據(jù)包鸿摇,LWIP不對(duì)這些類型的數(shù)據(jù)包進(jìn)行相應(yīng)。

再接下來(lái)的工作可以說(shuō)是ip_input函數(shù)中最復(fù)雜最難理解的部分劈猿,這就是IP分片數(shù)據(jù)包的重裝拙吉,ip_input函數(shù)通過(guò)數(shù)據(jù)包的3位標(biāo)志和13位片偏移字段判斷發(fā)給自己的該IP包是不是分片包,如果是揪荣,則需要將該分片包暫存筷黔,等到接收完所有分片包后,統(tǒng)一將整個(gè)數(shù)據(jù)包遞交給上層應(yīng)用程序仗颈。這是萬(wàn)言難盡得過(guò)程佛舱,先在這里打住,我們?cè)谝院蟮膬?nèi)容里面細(xì)細(xì)討論揽乱。如果是分片包名眉,且不是最后一片,則函數(shù)到這里就返回了凰棉。

終于损拢,能到達(dá)這一步的數(shù)據(jù)包必然是未分片的或經(jīng)過(guò)分片完整重裝后的數(shù)據(jù)包。此時(shí)撒犀,ip_input函數(shù)根據(jù)IP數(shù)據(jù)包頭內(nèi)部的協(xié)議字段判斷該數(shù)據(jù)包應(yīng)該被遞交給哪個(gè)上層協(xié)議福压,并調(diào)用相應(yīng)的函數(shù)遞交數(shù)據(jù)包。是UDP協(xié)議或舞,則調(diào)用udp_input函數(shù)荆姆;是TCP協(xié)議,則調(diào)用tcp_input函數(shù)映凳;是ICMP協(xié)議胆筒,則調(diào)用icmp_input函數(shù);是IGMP協(xié)議诈豌,則調(diào)用igmp_input函數(shù)仆救;如果都不是,則調(diào)用函數(shù)icmp_dest_unreach返回一個(gè)協(xié)議不可達(dá)ICMP數(shù)據(jù)包給源主機(jī)矫渔,同時(shí)刪除數(shù)據(jù)包彤蔽。

寫完收工!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末庙洼,一起剝皮案震驚了整個(gè)濱河市顿痪,隨后出現(xiàn)的幾起案子镊辕,更是在濱河造成了極大的恐慌,老刑警劉巖蚁袭,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件征懈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡揩悄,警方通過(guò)查閱死者的電腦和手機(jī)受裹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事求橄∨チ” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵袜啃,是天一觀的道長(zhǎng)汗侵。 經(jīng)常有香客問(wèn)我,道長(zhǎng)群发,這世上最難降的妖魔是什么晰韵? 我笑而不...
    開(kāi)封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮熟妓,結(jié)果婚禮上雪猪,老公的妹妹穿的比我還像新娘。我一直安慰自己起愈,他們只是感情好只恨,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著抬虽,像睡著了一般官觅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上阐污,一...
    開(kāi)封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天休涤,我揣著相機(jī)與錄音,去河邊找鬼笛辟。 笑死功氨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的隘膘。 我是一名探鬼主播疑故,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼弯菊!你這毒婦竟也來(lái)了纵势?” 一聲冷哼從身側(cè)響起踱阿,我...
    開(kāi)封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钦铁,沒(méi)想到半個(gè)月后软舌,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牛曹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年佛点,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片黎比。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡超营,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出阅虫,到底是詐尸還是另有隱情演闭,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布颓帝,位于F島的核電站米碰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏购城。R本人自食惡果不足惜吕座,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瘪板。 院中可真熱鬧吴趴,春花似錦、人聲如沸篷帅。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)魏身。三九已至惊橱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間箭昵,已是汗流浹背税朴。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留家制,地道東北人正林。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像颤殴,于是被迫代替她去往敵國(guó)和親觅廓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

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