babyos2(39) network(5) -- icmp echo request, reply, receive
前面为babyos2 实现了发送IP数据报,但只测试了同一个局域网内发送,而当目的IP跟发送发自己的IP不在同一局域网内时,babyos2会把IP数据报发往网关。而如何测试是否发送成功,首先想到的是ping。ping使用ICMP(Internet控制报文协议)。
ICMP经常被认为是 IP层的一个组成部分。它传递差错报文以及其他需要注意的信息。ICMP报文通常被 IP层或更高层协议( TCP或UDP)使用。一些 ICMP报文把差错报文返回给用户进程。
ICMP报文有多种类型,如请求回显,回显应答,目的不可达,源端被关闭,重定向,超时,地址掩码请求等。我们这里只关注请求回显和回显应答。
目前从用户态发起ping请求时机还不成熟(需要socket),暂时让babyos2从内核态发送ICMP报文,当收到请求时发送reply,及接收reply等。
1. ICMP 回显请求和回显应答报文格式
class icmp_echo_hdr_t {
public:void init(uint8 type, uint8 code, uint16 check_sum, uint16 id, uint16 seq);public:uint8 m_type;uint8 m_code;uint16 m_check_sum;uint16 m_id;uint16 m_seq_no;
};
void icmp_echo_hdr_t::init(uint8 type, uint8 code, uint16 check_sum, uint16 id, uint16 seq)
{m_type = type;m_code = code;m_check_sum = check_sum;m_id = id;m_seq_no = seq;
}
2. ICMP echo request
bool icmp_t::echo_request(uint32 ip, uint16 id, uint16 seq, uint8* data, uint32 len)
{uint32 total = len + sizeof(icmp_echo_hdr_t);net_buf_t* buffer = os()->get_net()->alloc_net_buffer(total);if (buffer == NULL) {console()->kprintf(RED, "ICMP echo_request, alloc net buffer failed, total: %u\n", total);return false;}console()->kprintf(GREEN, "send an icmp echo request to ip: ");net_t::dump_ip_addr(ip);console()->kprintf(GREEN, " seq: %u\n", seq);icmp_echo_hdr_t hdr;hdr.init(ECHO_REQUEST, /* type */0, /* code */ 0, /* check sum */net_t::htons(id), /* id */net_t::htons(seq)); /* seq no */hdr.m_check_sum = net_t::check_sum((uint8 *) &hdr, sizeof(icmp_echo_hdr_t));buffer->m_data = (uint8 *) buffer + sizeof(net_buf_t);buffer->m_data_len = total;uint8* p = buffer->m_data;memcpy(p, &hdr, sizeof(icmp_echo_hdr_t));if (data != NULL && len != 0) {p += sizeof(icmp_echo_hdr_t);memcpy(p, data, len);}os()->get_net()->get_ip()->transmit(ip, buffer->m_data, total, ip_t::PROTO_ICMP);os()->get_net()->free_net_buffer(buffer);return true;
}
代码比较简单,初始化一个报文头,
ip表示向哪个地址发送ping请求;
id是为了当系统中有多个ping同时发起请求时,当收到回复时识别是回复的那个ping的请求,一般会传进程ID,这里我们暂时只从内核发出请求,所以传0;
seq表示序列号,一般是一个递增的数字,表示序列;
data表示发送的数据,暂时不发任何数据,len为0.
准备号头后,计算校验和,然后分配一个buffer用于存储信息,最后发出去。
2. ICMP echo receive
receive表示收到一个ICMP报文,我们首先判断它的类型,根据类型做处理
void icmp_t::receive(net_buf_t* buf, uint32 ip)
{uint8 type = *(uint8 *) buf->m_data;switch (type) {case ECHO_REQUEST:echo_request_receive(buf, ip);break;case ECHO_REPLY:echo_reply_receive(buf, ip);break;default:console()->kprintf(RED, "receive an icmp package, but not support the type %x now.\n", type);break;}
}
暂时只支持 ECHO_REQUEST跟ECHO_REPLY,分别表示收到一个ICMP echo请求跟答复。
void icmp_t::echo_request_receive(net_buf_t* buf, uint32 ip)
{icmp_echo_hdr_t* hdr = (icmp_echo_hdr_t *) buf->get_data();uint16 check_sum = net_t::check_sum(buf->get_data(), buf->get_data_len());if (check_sum != 0) {console()->kprintf(RED, "receive an icmp echo request, but checksum is error: %x.\n", check_sum);return;}console()->kprintf(GREEN, "receive an icmp echo request from ip: ");net_t::dump_ip_addr(ip);console()->kprintf(GREEN, " seq: %u\n", net_t::ntohs(hdr->m_seq_no));echo_reply(ip, net_t::ntohs(hdr->m_id), net_t::ntohs(hdr->m_seq_no), NULL, 0);
}void icmp_t::echo_reply_receive(net_buf_t* buf, uint32 ip)
{icmp_echo_hdr_t* hdr = (icmp_echo_hdr_t *) buf->get_data();uint16 check_sum = net_t::check_sum((uint8 *) hdr, sizeof(icmp_echo_hdr_t));if (check_sum != 0) {console()->kprintf(RED, "receive an icmp echo reply, but checksum is error: %x.\n", check_sum);return;}console()->kprintf(WHITE, "receive an icmp echo reply from ip: ");net_t::dump_ip_addr(ip);console()->kprintf(WHITE, " seq: %u\n", net_t::ntohs(hdr->m_seq_no));
}
当收到一个请求时,需要答复,当收到一个答复时只简单打印一些信息表示收到答复。
3.ICMP echo reply
bool icmp_t::echo_reply(uint32 ip, uint16 id, uint16 seq, uint8* data, uint32 len)
{uint32 total = len + sizeof(icmp_echo_hdr_t);net_buf_t* buffer = os()->get_net()->alloc_net_buffer(total);if (buffer == NULL) {console()->kprintf(RED, "ICMP echo_reply, alloc net buffer failed, total: %u\n", total);return false;}console()->kprintf(GREEN, "send an icmp echo reply to ip: ");net_t::dump_ip_addr(ip);console()->kprintf(GREEN, " seq: %u\n", seq);icmp_echo_hdr_t hdr;hdr.init(ECHO_REPLY, /* type */0, /* code */ 0, /* check sum */net_t::htons(id), /* id */net_t::htons(seq)); /* seq no */hdr.m_check_sum = net_t::check_sum((uint8 *) &hdr, sizeof(icmp_echo_hdr_t));buffer->m_data = (uint8 *) buffer + sizeof(net_buf_t);buffer->m_data_len = total;uint8* p = buffer->m_data;memcpy(p, &hdr, sizeof(icmp_echo_hdr_t));if (data != NULL && len != 0) {p += sizeof(icmp_echo_hdr_t);memcpy(p, data, len);}os()->get_net()->get_ip()->transmit(ip, buffer->m_data, total, ip_t::PROTO_ICMP);os()->get_net()->free_net_buffer(buffer);return true;
}
答复跟请求类似,代码比较简单,不做过多解释。
4.测试
上图是启动两个虚拟机,其中一个向另一个发送ICMP echo请求,可以发现104向105发送请求,105收到请求并作出答复,104收到答复。
这是wireshark抓包的结果。
下一步是测试ping baidu,因为babyos2暂时不支持DNS,所以先在linux上ping baid.com得到它的IP,再让babyos2向这个IP发送ICMP echo请求:
可以发现向111.13.101.208发送ICMP echo request,因为该IP不在同一局域网内,将数据包发送到了网关,IP 182.168.1.1,然后收到了来自111.13.101.208的ICMP echo reply。
从抓到的包来看,确实收到了来自baidu的回显答复。
-----------------------------------------------------------------------------------------------------
到目前为止babyos2具有了简单的往某个IP发送数据报的能力,此时实现socket IF_INET的时机已基本成熟,前面实现过通过socket进行进程间通信,通过网络与之相似但要复杂一些,特别是有连接的SOCK_STREAM 需要实现TCP。但无连接的SOCK_DGRAM 跟SOCK_RAW已经能够实现。
后面的计划:
1)socket SOCK_RAW, 测试方式是用户进程ping,通过SOCK_RAW发送ICMP echo请求
2)socket SOCK_DGRAM, 需要先支持UDP
3)socket SOCK_STREAM,需要支持TCP
babyos2(39) network(5) -- icmp echo request, reply, receive相关推荐
- babyos2(35) network(1) -- simple RTL8139 nic driver
要为babyos2实现网络,首先要支持网卡,之前选了RTL8139,为此前面做了PCI相关的一些东西,这次要实现简单的网卡驱动. 1.从PCI获取设备信息 uint32 rtl8139_t::get_ ...
- 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(39)-在线人数统计探讨
原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(39)-在线人数统计探讨 系列目录 基于web的网站在线统计一直处于不是很精准的状态!基本上没有一种方法可 ...
- ROS笔记(39) 串口配置
ROS笔记(39) 串口配置 1. 前言 2. 串口通讯 3. C++配置 3.1. 安装serial 3.2. 配置 3.3. 编译 3.4. 通讯测试 4. Python配置 4.1. 安装pys ...
- 视觉SLAM笔记(39) 求解 ICP
视觉SLAM笔记(39) 求解 ICP 1. SVD 方法 2. 非线性优化方法 1. SVD 方法 使用 SVD 以及非线性优化来求解 ICP 使用两个 RGB-D 图像,通过特征匹配获取两组 3D ...
- 深度学习笔记(39) Anchor Boxes
深度学习笔记(39) Anchor Boxes 1. 一个格子多个对象检测问题 2. Anchor box 3. 对象形状交并比 3. 一个格子一个对象检测问题 4. 额外的细节 5. Anchor ...
- (39)FPGA四种常用逻辑门(与非门)
(39)FPGA四种常用逻辑门(与非门) 1 文章目录 1)文章目录 2)FPGA入门与提升课程介绍 3)FPGA简介 4)FPGA四种常用逻辑门(与非门) 5)技术交流 6)参考资料 2 FPGA入 ...
- (39)时钟抖动约束
(39)时钟抖动约束 1 文章目录 1)文章目录 2)时序约束引言 3)FPGA时序约束课程介绍 4)时钟抖动约束 5)技术交流 6)参考资料 2 时序约束引言 1)什么是静态时序分析? 通俗来说:在 ...
- (39)FPGA按键设计(第8天)
(39)FPGA按键设计(第8天) 1 文章目录 1)文章目录 2)FPGA初级课程介绍 3)FPGA初级课程架构 4)FPGA按键设计(第8天) 5)技术交流 6)参考资料 2 FPGA初级课程介绍 ...
- (39)System Verilog线程停止(disable)
(39)System Verilog线程停止(disable) 1.1 目录 1)目录 2)FPGA简介 3)System Verilog简介 4)System Verilog线程停止(disable ...
最新文章
- Oracle大数据量分页通用存储过程
- PS网页设计教程——30个优秀的PS网页设计教程的中文翻译教程
- java继承类型的用法_详解Java中使用externds关键字继承类的用法
- html asp textbox,ASP.NET中 TextBox 文本输入框控件的使用方法
- 哈尔滨工业大学(深圳)姜欣副教授课题组招收客座硕士-机器人方向
- Redis集成到Maven工程(Jedis客户端)
- 神马专车喊话特斯拉:修不修、赔不赔、认不认?
- mysql 写不进数据库_求助,为何我的数据不能写入数据库
- fiddler实现将http请求的js转为本地的js文件
- 机器学习之amp;amp;Andrew Ng课程复习--- 聚类——Clustering
- android videoview 拉伸,android - 在ExoPlayer中轻按全屏时,视频会拉伸和旋转 - 堆栈内存溢出...
- C#设置点击打开外部exe程序,并判断是否程序已开启,未开启的话打开,已经在运行了就前置
- Visual Studio 插件番茄助手2个优秀的特性
- 2021window10下的IDEA安装
- 普适计算机技术特征的事例,普适计算、物联网、云计算与未来社会信息化需求分析...
- java里的椭圆拟合_[求助]椭圆的跟踪拟合
- “小度小度”开启AI硬件的“量贩”时代
- 数据解惑 · 带你认识数字高程模型(DEM)
- C++ 数据结构——BF算法
- 深入浅出CChart 每日一课——快乐高四第二十四课 武当梯云纵,移花接木之Visual Basic.Net