前面为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相关推荐

  1. babyos2(35) network(1) -- simple RTL8139 nic driver

    要为babyos2实现网络,首先要支持网卡,之前选了RTL8139,为此前面做了PCI相关的一些东西,这次要实现简单的网卡驱动. 1.从PCI获取设备信息 uint32 rtl8139_t::get_ ...

  2. 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(39)-在线人数统计探讨

    原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(39)-在线人数统计探讨 系列目录 基于web的网站在线统计一直处于不是很精准的状态!基本上没有一种方法可 ...

  3. ROS笔记(39) 串口配置

    ROS笔记(39) 串口配置 1. 前言 2. 串口通讯 3. C++配置 3.1. 安装serial 3.2. 配置 3.3. 编译 3.4. 通讯测试 4. Python配置 4.1. 安装pys ...

  4. 视觉SLAM笔记(39) 求解 ICP

    视觉SLAM笔记(39) 求解 ICP 1. SVD 方法 2. 非线性优化方法 1. SVD 方法 使用 SVD 以及非线性优化来求解 ICP 使用两个 RGB-D 图像,通过特征匹配获取两组 3D ...

  5. 深度学习笔记(39) Anchor Boxes

    深度学习笔记(39) Anchor Boxes 1. 一个格子多个对象检测问题 2. Anchor box 3. 对象形状交并比 3. 一个格子一个对象检测问题 4. 额外的细节 5. Anchor ...

  6. (39)FPGA四种常用逻辑门(与非门)

    (39)FPGA四种常用逻辑门(与非门) 1 文章目录 1)文章目录 2)FPGA入门与提升课程介绍 3)FPGA简介 4)FPGA四种常用逻辑门(与非门) 5)技术交流 6)参考资料 2 FPGA入 ...

  7. (39)时钟抖动约束

    (39)时钟抖动约束 1 文章目录 1)文章目录 2)时序约束引言 3)FPGA时序约束课程介绍 4)时钟抖动约束 5)技术交流 6)参考资料 2 时序约束引言 1)什么是静态时序分析? 通俗来说:在 ...

  8. (39)FPGA按键设计(第8天)

    (39)FPGA按键设计(第8天) 1 文章目录 1)文章目录 2)FPGA初级课程介绍 3)FPGA初级课程架构 4)FPGA按键设计(第8天) 5)技术交流 6)参考资料 2 FPGA初级课程介绍 ...

  9. (39)System Verilog线程停止(disable)

    (39)System Verilog线程停止(disable) 1.1 目录 1)目录 2)FPGA简介 3)System Verilog简介 4)System Verilog线程停止(disable ...

最新文章

  1. Oracle大数据量分页通用存储过程
  2. PS网页设计教程——30个优秀的PS网页设计教程的中文翻译教程
  3. java继承类型的用法_详解Java中使用externds关键字继承类的用法
  4. html asp textbox,ASP.NET中 TextBox 文本输入框控件的使用方法
  5. 哈尔滨工业大学(深圳)姜欣副教授课题组招收客座硕士-机器人方向
  6. Redis集成到Maven工程(Jedis客户端)
  7. 神马专车喊话特斯拉:修不修、赔不赔、认不认?
  8. mysql 写不进数据库_求助,为何我的数据不能写入数据库
  9. fiddler实现将http请求的js转为本地的js文件
  10. 机器学习之amp;amp;Andrew Ng课程复习--- 聚类——Clustering
  11. android videoview 拉伸,android - 在ExoPlayer中轻按全屏时,视频会拉伸和旋转 - 堆栈内存溢出...
  12. C#设置点击打开外部exe程序,并判断是否程序已开启,未开启的话打开,已经在运行了就前置
  13. Visual Studio 插件番茄助手2个优秀的特性
  14. 2021window10下的IDEA安装
  15. 普适计算机技术特征的事例,普适计算、物联网、云计算与未来社会信息化需求分析...
  16. java里的椭圆拟合_[求助]椭圆的跟踪拟合
  17. “小度小度”开启AI硬件的“量贩”时代
  18. 数据解惑 · 带你认识数字高程模型(DEM)
  19. C++ 数据结构——BF算法
  20. 深入浅出CChart 每日一课——快乐高四第二十四课 武当梯云纵,移花接木之Visual Basic.Net

热门文章

  1. 基于bert bert-wmm的微博评论情感分析
  2. 《大型网站技术架构原理与解析》第八章 固若金汤:网站的安全架构
  3. 系统安全-使你的电脑固若金汤,百毒不侵
  4. 网页骨架屏自动生成方案(dps)
  5. Windows API Hook
  6. jquery.gritter.js简介
  7. 手机内屏外屏有什么区别?
  8. TP5学习(四):控制器
  9. HDFS shell命令操作大全
  10. 同类方法调用 @Transactional 失效与解决