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.mzph.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中的中断是设备主动发起的…