LWIP的ICMP協議

ICMP協議簡介

ICMP協議是一個網絡層協議

背景:如果丟包了,IP協議并不能通知傳輸層是否丟包以及丟包的原因。因此我們需要ICMP協議來完成這樣的功能

為什么需要ICMP協議

1IP 協議本身不提供差錯報告和差錯控制機制來保證數據報遞交的有效性,例如:數據報在網絡中被丟棄了,源主機更希望等到該數據報遞交過程中的異常信息

2IP 協議不能進行主機管理與查詢機制,例如:不知道對方主機或者路由器的活躍,對

于不活躍的主機和路由器就沒有必要發送數據報類似于電腦cmdping

ICMP協議類型與結構

ICMP協議類型

類型

應用

差錯報告報文

目的不可達、源站抑制、重定向、超時、參數錯誤

詢問報文

回送請求/回答(類似ping)、時間戳請求/回答

消息幀結構:差錯/詢問一樣(前4

ICMP 差錯報文

用于檢測IP數據報在傳輸過程的異常信息(目的不可達、源站抑制、重定向、超時、參數錯誤)

ICMP類型

代碼值

描述

3

0

網絡不可達(找不到地方)

1

主機不可達(找到地方,找不到人)

2

協議不可達(找到地方且找到人,但口令對不上)

3

端口不可達(找到地方且找到人以及口令對上,但事情對不上)

4

需要分片但設置了不分片(發不了)

5

源站路由失敗(速度慢了)

11

0

傳輸期間生存時間為0

1

數據報組裝期間生存時間為0

ICMP 查詢報文

用于診斷兩個網絡設備之間彼此是否能夠通信

ICMP類型

報文結構

描述

08

回顯請求/應答

lwip處理

910

路由器查詢/通告

lwIP不處理

1314

時間戳請求/應答

1416

信息請求/應答

1718

地址掩碼請求/應答

目的主機(stm)收到 ICMP 回送請求報文后立刻回送應答報文,若源主機電腦收到 ICMP 回送應答報文,則說明到達該主機的網絡正常(PING

ICMP差錯報文源碼
?

ICMP報文數據結構

struct icmp_echo_hdr 
{ 
PACK_STRUCT_FLD_8(u8_t type); 		/* 類型 */
PACK_STRUCT_FLD_8(u8_t code); 		/* 代碼 */
PACK_STRUCT_FIELD(u16_t chksum); 	/* 校驗和 */
PACK_STRUCT_FIELD(u16_t id); 		/* 標志符 */
PACK_STRUCT_FIELD(u16_t seqno); 	/* 序號 */
} 
PACK_STRUCT_STRUCT; 

差錯報文結構

查詢報文結構

個人理解:數據里面,有一幀,請求;應答是重復這個報文(這個是錯誤理解,參考下一節ICMP查詢章節描述

ICMP的差錯報文

lwIP實現1目的不可達2超時差錯報文,它們分別為icmp_dest_unreachicmp_time_exceeded函數

差錯報文

類型

描述

目的不可達

在傳遞過程中出錯,不能到達目標主機,

或到達目標主機后無法傳遞至上層協議

超時差錯

IP首部的“TTL”字段記錄著該數據報的生命值,

該數據報每被轉發一次,TTL值減1。直到為0,丟棄該報

這兩種差錯報文最終都是調用icmp_send_response函數發送

\Middlewares\lwip\src\core\ipv4\icmp.c

不可到達函數icmp_dest_unreach

void
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
{MIB2_STATS_INC(mib2.icmpoutdestunreachs);icmp_send_response(p, ICMP_DUR, t);// 參2: 類型不可到達    宏定義3   為0為網絡不可到達      
}

不可到達類型枚舉

\Middlewares\lwip\src\include\lwip\icmp.h

/** ICMP destination unreachable codes */
enum icmp_dur_type {/** net unreachable */ICMP_DUR_NET   = 0,/** host unreachable */ICMP_DUR_HOST  = 1,/** protocol unreachable */ICMP_DUR_PROTO = 2,/** port unreachable */ICMP_DUR_PORT  = 3,/** fragmentation needed and DF set */ICMP_DUR_FRAG  = 4,/** source route failed */ICMP_DUR_SR    = 5
};

?ICMP超時枚舉

\Middlewares\lwip\src\include\lwip\icmp.h

/** ICMP time exceeded codes */
enum icmp_te_type {/** time to live exceeded in transit */ICMP_TE_TTL  = 0,/** fragment reassembly time exceeded */ICMP_TE_FRAG = 1
};

差錯報文的原理

把丟棄的數據包IP首部和數據區域(前8字節)拷貝到差錯報文當中

差錯報文主要函數icmp_send_response

static void
icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
{
struct pbuf *q;
struct ip_hdr *iphdr;
struct icmp_echo_hdr *icmphdr;
ip4_addr_t iphdr_src;
struct netif *netif;
u16_t response_pkt_len;
MIB2_STATS_INC(mib2.icmpoutmsgs);
/* response_pkt_len = 20 + 8 = 28*/
response_pkt_len = IP_HLEN + ICMP_DEST_UNREACH_DATASIZE;
if (p->tot_len < response_pkt_len) {
response_pkt_len = p->tot_len;
} /
* 申請pbuf內存 */
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + response_pkt_len,
PBUF_RAM);
if (q == NULL) {
MIB2_STATS_INC(mib2.icmpouterrors);
return;
} /
* 獲取對方主機數據報的IP首部 */
iphdr = (struct ip_hdr *)p->payload;
/* 在q->payload地址附加icmp_echo_hdr結構體 */
icmphdr = (struct icmp_echo_hdr *)q->payload;
/* 設置ICMP首部信息 */
icmphdr->type = type;
icmphdr->code = code;
icmphdr->id = 0;
icmphdr->seqno = 0;
/* 把對方主機的數據復制IP首部和前8字節數據到新申請的pbuf當中 */
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
response_pkt_len);
/* 復制目標地址 */
ip4_addr_copy(iphdr_src, iphdr->src);
/* 判斷是否同一網段 */
netif = ip4_route(&iphdr_src);
if (netif != NULL) {
icmphdr->chksum = 0;
ICMP_STATS_INC(icmp.xmit);
/* 發送ICMP差錯報文 */
ip4_output_if(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP, netif);
}申請pbuf內存
添加ICMP首部
調用ip4_output_if函數發送數據,注:目標IP地址不為NULL
pbuf_free(q);
}

申請pbuf內存
?

添加ICMP首部
?

調用ip4_output_if函數發送數據,注:目標IP地址不為NULL
?

ICMP查詢報文

請求報文發送,應答報文重復。簡單來講,應答包是在請求包的基礎上修改得來

原理,最終形成第三個結構效果

查詢報文主函數icmp_input

void
icmp_input(struct pbuf *p, struct netif *inp)
{
u8_t type;
struct icmp_echo_hdr *iecho;
const struct ip_hdr *iphdr_in;
u16_t hlen;
const ip4_addr_t *src;
ICMP_STATS_INC(icmp.recv);
MIB2_STATS_INC(mib2.icmpinmsgs);
iphdr_in = ip4_current_header();
/* 獲取IP首部 */
hlen = IPH_HL_BYTES(iphdr_in);
if (hlen < IP_HLEN) {
goto lenerr;
} i
f (p->len < sizeof(u16_t) * 2) {
goto lenerr;
} /
* 獲取 ICMP 的類型字段 */
type = *((u8_t *)p->payload);
switch (type) {
case ICMP_ER:/* 回送應答 */
MIB2_STATS_INC(mib2.icmpinechoreps);
break;
case ICMP_ECHO:/* 回送請求 */
MIB2_STATS_INC(mib2.icmpinechos);
/* 獲取IP地址 */
src = ip4_current_dest_addr();
/* 判斷是否為多播地址 */
if (ip4_addr_ismulticast(ip4_current_dest_addr())) {
goto icmperr;
} /
* 判斷是否為廣播地址 */
if (ip4_addr_isbroadcast(ip4_current_dest_addr(), ip_current_netif())) {
goto icmperr;
} /
* 判斷這個pbuf的總長度是否小于icmp首部 */
if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
goto lenerr;
}
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
/* 偏移paylosd指針 = IP首部(20) + 14 + 0 = 34 */
if (pbuf_add_header(p, hlen + PBUF_LINK_HLEN +
PBUF_LINK_ENCAPSULATION_HLEN)) {
struct pbuf *r;/* 申請大小 = p->tot_len + hlen */
u16_t alloc_len = (u16_t)(p->tot_len + hlen);
if (alloc_len < p->tot_len) {
goto icmperr;
} /
* 申請pbuf */
r = pbuf_alloc(PBUF_LINK, alloc_len, PBUF_RAM);
if (r == NULL) {
goto icmperr;
} i
f (r->len < hlen + sizeof(struct icmp_echo_hdr)) {
pbuf_free(r);
goto icmperr;
} /
* 拷貝IP首部到新申請的pbuf當中 */
MEMCPY(r->payload, iphdr_in, hlen);
/* 偏移paylosd指針 */
if (pbuf_remove_header(r, hlen)) {
pbuf_free(r);
goto icmperr;
} /
* 復制沒有ip首部的其余數據包 */
if (pbuf_copy(r, p) != ERR_OK) {
pbuf_free(r);
goto icmperr;
} /
* 釋放pbuf(p) */
pbuf_free(p);
/* p -> r */
p = r;
} else {
/* 偏移paylosd指針 IP首部(20) + 14 + 0 = 34 */
if (pbuf_remove_header(p, hlen + PBUF_LINK_HLEN +
PBUF_LINK_ENCAPSULATION_HLEN)) {
goto icmperr;
}
}
#endif
/* p->payload地址上附加icmp_echo_hdr結構體 */
iecho = (struct icmp_echo_hdr *)p->payload;
/* 添加IP首部 */
if (pbuf_add_header(p, hlen)) {
} else {
err_t ret;
/* 設置IP首部信息 */
struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
ip4_addr_copy(iphdr->src, *src);
ip4_addr_copy(iphdr->dest, *ip4_current_src_addr());
/* 設置ICMP首部信息 */
ICMPH_TYPE_SET(iecho, ICMP_ER);
iecho->chksum = 0;
/* 設置生存時間 */
IPH_TTL_SET(iphdr, ICMP_TTL);IP數據包遞交給icmp_input函數之前的pbuf示意圖
IPH_CHKSUM_SET(iphdr, 0);
ICMP_STATS_INC(icmp.xmit);
MIB2_STATS_INC(mib2.icmpoutmsgs);
MIB2_STATS_INC(mib2.icmpoutechoreps);
/* 發送ICMP回顯應答包 */
ret = ip4_output_if(p, src, LWIP_IP_HDRINCL,
ICMP_TTL, 0, IP_PROTO_ICMP, inp);
if (ret != ERR_OK) {
}
} b
reak;
default: /* lwIP不作處理 */
if (type == ICMP_DUR) {
MIB2_STATS_INC(mib2.icmpindestunreachs);
} else if (type == ICMP_TE) {
MIB2_STATS_INC(mib2.icmpintimeexcds);
} else if (type == ICMP_PP) {
MIB2_STATS_INC(mib2.icmpinparmprobs);
} else if (type == ICMP_SQ) {
MIB2_STATS_INC(mib2.icmpinsrcquenchs);
} else if (type == ICMP_RD) {
MIB2_STATS_INC(mib2.icmpinredirects);
} else if (type == ICMP_TS) {
MIB2_STATS_INC(mib2.icmpintimestamps);
} else if (type == ICMP_TSR) {
MIB2_STATS_INC(mib2.icmpintimestampreps);
} else if (type == ICMP_AM) {
MIB2_STATS_INC(mib2.icmpinaddrmasks);
} else if (type == ICMP_AMR) {
MIB2_STATS_INC(mib2.icmpinaddrmaskreps);
}
} p
buf_free(p);
return;
lenerr:
pbuf_free(p);
ICMP_STATS_INC(icmp.lenerr);
MIB2_STATS_INC(mib2.icmpinerrors);
return;
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN || !LWIP_MULTICAST_PING ||
!LWIP_BROADCAST_PING
icmperr:
pbuf_free(p);
ICMP_STATS_INC(icmp.err);
MIB2_STATS_INC(mib2.icmpinerrors);
return;
#endif
}

各個操作的效果圖

IP數據包遞交給icmp_input函數之前的pbuf示意圖
?

如果該數據包為回送請求包,則修改ICMP首部的類型

lwIP內核對該數據包的payload指針偏移20字節,添加IP首部
?

設置IP首部的字段信息,設置完成之后調用ip4_output_if函數發送ICMP回送應答包。注:目標IP地址為NULL
?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/80553.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/80553.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/80553.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

具身智能機器人開源陪跑計劃(機器人實戰落地)

Who&#xff1a;我們是誰&#xff1f; 主理人背景 華南理工大學碩士畢業&#xff0c;10年機器人研發經驗&#xff0c;5年“互聯網機器人”創業經歷 累計牽頭落地的機器人30多款&#xff0c;累計授權專利80余項&#xff0c;累計論文發表10余篇。 技術履歷 C#、Sql server、SPSS…

Dify 配置網絡爬蟲為知識庫數據來源 (以Jina Reader為例) - 隨筆

API獲取 進入官網獲取免費的API密鑰 官網鏈接&#xff1a;https://jina.ai/reader/ 點擊“<> API”按鈕 點擊復制文本框中的API Key&#xff1a; 進入Dify的知識庫頁面 → 選擇“同步自Web站點” → 選擇“Jina Reader” → 點擊“配置”按鈕 選擇數據來源為Jina …

基于網絡爬蟲+Spark+Hadoop等大數據和SpringBoot技術實現的的汽車行業大數據分析與可視化平臺系統(源碼+論文+PPT+部署文檔教程等)

博主介紹&#xff1a;CSDN畢設輔導第一人、全網粉絲50W,csdn特邀作者、博客專家、騰訊云社區合作講師、CSDN新星計劃導師、Java領域優質創作者,博客之星、掘金/華為云/阿里云/InfoQ等平臺優質作者、專注于Java技術領域和學生畢業項目實戰,高校老師/講師/同行前輩交流? 技術范圍…

React學習路線圖-Gemini版

前端開發學習路線圖 (針對編程新手&#xff0c;主攻 React 框架) 總原則&#xff1a;先打好地基&#xff0c;再蓋樓。 無論學習哪個框架&#xff0c;扎實的 HTML、CSS 和 JavaScript 基礎是成功的關鍵。React 是基于 JavaScript 構建的&#xff0c;所以深入理解 JS 至關重要。…

空間計算:開啟人機交互新紀元的下一代技術范式

引言 當蘋果CEO蒂姆庫克在2023年WWDC大會上宣布Apple Vision Pro將引領“空間計算時代”時&#xff0c;這一宣言不僅標志著技術范式的迭代&#xff0c;更預示著一場融合虛實世界的革命已悄然來臨。 空間計算&#xff08;Spatial Computing&#xff09;作為連接物理世界與數字…

大語言模型訓練的兩個階段

先說結論&#xff1a;第一階段在云平臺訓練至收斂 第二階段本地GPU微調 一、階段劃分的核心邏輯 階段目標資源特點典型耗時占比成本敏感度預訓練獲取通用表征能力需要大規模分布式計算70-90%高&#xff08;追求每美元算力&#xff09;微調適配特定任務需要領域數據安全/低延遲…

【AI News | 20250512】每日AI進展

AI Repos 1、UI-TARS UI-TARS-1.5 是字節跳動開源的多模態智能體&#xff0c;基于強大的視覺語言模型構建&#xff0c;通過強化學習實現高級推理&#xff0c;顯著提升了在虛擬世界中執行多樣化任務的能力和適應性。相較前期模型&#xff0c;1.5 版本在 OSWorld、Windows Agent…

[git]如何關聯本地分支和遠程分支

主題 本文總結如何關聯git本地分支和遠程分支的相關知識點。 詳情 查看本地分支 git branch 查看遠程分支 git branch -r 查看所有分支(本地遠程) git branch -a 查看本地分支及其關聯的遠程分支(如有) git branch -vv 關聯本地分支到遠程分支&#xff1a; git branch …

CC53.【C++ Cont】二分查找的普通模版

目錄 1.知識回顧 2.關鍵點 特點 三個模版 普通的模版(有局限) 以LeetCode上的一道題為例:704. 二分查找 分析 引入二段性:分兩段,舍一段,操作另一段(這個是二分查找的本質!) 代碼 提交結果 當然也可以使用隨機數來分兩段 普通模版總結 1.知識回顧 之前在C語言專欄…

lua腳本+Redission實現分布式鎖

實現分布式鎖最簡單的一種方式&#xff1a;基于Redis 不論是本地鎖還是分布式鎖&#xff0c;核心都在于“互斥”。 在 Redis 中&#xff0c; SETNX 命令是可以幫助我們實現互斥。SETNX 即 set if not exists (對應 Java 中的 setIfAbsent 方法)&#xff0c;如果 key 不存在的…

設計模式之工廠模式(二):實際案例

設計模式之工廠模式(一) 在閱讀Qt網絡部分源碼時候&#xff0c;發現在某處運用了工廠模式&#xff0c;而且編程技巧也用的好&#xff0c;于是就想分享出來&#xff0c;供大家參考&#xff0c;理解的不對的地方請多多指點。 以下是我整理出來的類圖&#xff1a; 關鍵說明&#x…

MultiTTS 1.7.6 | 最強離線語音引擎,提供多音色無障礙朗讀功能,附帶語音包

MultiTTS是一款免費且支持離線使用的文本轉語音&#xff08;TTS&#xff09;工具&#xff0c;旨在為用戶提供豐富的語音包選項&#xff0c;實現多音色無障礙朗讀功能。這款應用程序特別適合用于閱讀軟件中的離線聽書體驗&#xff0c;提供了多樣化的語音選擇&#xff0c;使得聽書…

歌曲《忘塵谷》基于C語言的歌曲調性檢測技術解析

引言 在音樂分析與數字信號處理領域&#xff0c;自動檢測歌曲調性是一項基礎且關鍵的任務。本文以C語言為核心&#xff0c;結合音頻處理庫&#xff08;libsndfile&#xff09;和快速傅里葉變換庫&#xff08;FFTW&#xff09;&#xff0c;探討如何實現調性檢測&#xff0c;并通…

大某麥演唱會門票如何自動搶

引言 僅供學習研究&#xff0c;歡迎交流 搶票難&#xff0c;難于上青天&#xff01;無論是演唱會、話劇還是體育賽事&#xff0c;大麥網的票總是秒光。大麥網是國內知名的票務平臺&#xff0c;熱門演出票往往一票難求。手動搶票不僅耗時&#xff0c;還容易錯過機會。作為一名…

1.3.3 tinyalsa詳細介紹

一、TinyALSA 的背景與設計目標 1. 誕生背景 Android 音頻需求的演變&#xff1a;早期 Android 系統使用標準 ALSA&#xff08;Advanced Linux Sound Architecture&#xff09;的用戶空間庫 alsa-lib&#xff0c;但因其復雜性&#xff08;代碼龐大、依賴較多&#xff09;和資…

超越合并速度(merge speed):AI如何重塑開發者協作

李升偉 編譯 AI 關于現代開發的討論通常圍繞著單一指標&#xff1a;合并速度&#xff08;merge speed&#xff09;。但在這一表面測量之下&#xff0c;隱藏著開發團隊工作方式的一種更深刻的變革。讓我們探討開發者協作的微妙演變方式以及為什么傳統生產力指標只講述了一部分故…

如何找正常運行虛擬機

1.新建虛擬機。Linux centos7&#xff0c;給虛擬機改個名字不要放在c盤 2.安裝操作系統。cd/dvd->2009.iso 啟動虛擬機

深度學習:系統性學習策略(二)

深度學習的系統性學習策略 基于《認知覺醒》與《認知驅動》的核心方法論,結合深度學習的研究實踐,從認知與技能雙重維度總結以下系統性學習策略: 一、認知覺醒:構建深度學習的思維操作系統 三重腦區協同法則 遵循**本能腦(舒適區)-情緒腦(拉伸區)-理智腦(困難區)**的…

如何使用CSS解決一行有三個元素,前兩個元素靠左排列,第三個元素靠右排列的問題

如圖所示&#xff0c;我要把左邊的場館和區域信息靠左排列&#xff0c;價格信息靠右排列。如何使用CSS實現這種效果&#xff1f; 在這里&#xff0c;我使用了flexbox彈性布局&#xff0c;以下是我的實現代碼 .name-info {display: flex;gap: 2px;justify-content: space-betwee…

USB傳輸模式

USB有四種傳輸模式: 控制傳輸, 中斷傳輸, 同步傳輸, 批量傳輸 1. 中斷傳輸 中斷傳輸一般用于小批量, 非連續的傳輸. 對實時性要求較高. 常見的使用此傳輸模式的設備有: 鼠標, 鍵盤等. 要注意的是, 這里的 “中斷” 和我們常見的中斷概念有差異. Linux中的中斷是設備主動發起的…