做嵌入式网络开发的,想必都用过电脑ping开发板测试网路是否连通,本人参考一些网上代码,完善了这个过程。
原文参考:http://blog.youkuaiyun.com/jtttl/article/details/50583462
http://bbs.21ic.com/icview-406625-1-1.html
读懂本文,需要掌握的基本知识
1.以太网ICMP数据包相关常识
2.ucos任务创建,消息邮箱的传递
3.lwip的基本知识
本文可能需要完善的地方:
1.对接收到的ping回复没有做判断,仅仅发了一个邮箱,这样网络中的其它ping回复命令它也会认为是自己的。(当然前面筛选过的话,就不会,需要验证)
先在以下函数中增加一个case分支,用来接收ping的回传。其中pingEchoReply为ucos的一个消息邮箱。ucos不是本文重点,略过。
void icmp_input(struct pbuf *p, struct netif *inp)
剩下部分直接贴上代码:
ping.c文件:
//==================================1.头文件声明开始==================================
#include "ping.h"
#include "lwip/raw.h"
#include "DataProcess.h"
#include "lwip/icmp.h"
//==================================1.头文件声明结束==================================
struct raw_pcb *ping_pcb;
OS_EVENT * pingEchoReply; //ping回复任务
//fuc:建立pcb
unsigned char icmp_pcb_init(void)
{
ping_pcb = raw_new(IP_PROTO_ICMP);
if(!ping_pcb){
return 1;
}
}
//fuc:组装icmp的报文
//fuc:发送icmp数据包
void ping_send(u8 ip_addr1,u8 ip_addr2,u8 ip_addr3,u8 ip_addr4)
{
struct pbuf *p;
struct ip_addr ipAddr;
struct icmp_echo_hdr *iecho;
//本机地址
IP4_ADDR(&ipAddr, Para.MIP[0], Para.MIP[1], Para.MIP[2], Para.MIP[3]);
ip_addr_set(&ping_pcb->local_ip, &ipAddr);
//目标地址
IP4_ADDR(&ipAddr, ip_addr1, ip_addr2, ip_addr3, ip_addr4);
ip_addr_set(&ping_pcb->remote_ip, &ipAddr);
p = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr), PBUF_RAM);
if(!p){
DebugMsg("ping send failed\r\n", 0);
return;
}
//组装icmp的报文
iecho = (struct icmp_echo_hdr *)p->payload;
iecho->type = 8; //类型
iecho->code = 0; //code
iecho->id =htons(0x0200) ; //id
iecho->seqno =htons(0x5800); //报文序列号
iecho->chksum = 0; //校验和清0
iecho->chksum = inet_chksum(p->payload, sizeof(struct icmp_echo_hdr));//从算校验和
//发送ping数据包
raw_sendto(ping_pcb, p, &ping_pcb->remote_ip);
pbuf_free(p);
}
void PingTask(void *p_arg)
{
INT8U err;
while(1)
{
OSTimeDlyHMSM(0, 0, 5, 0); //每5秒执行一次任务
ping_send(Para.GAT[0],Para.GAT[1],Para.GAT[2],Para.GAT[3]);
//ping_send(192,168,1,27);
OSSemPend(pingEchoReply,1500,&err); //请求信号量,并启动1.5s超时
if(err!=0){ //任务超时
DebugMsg("ping time out\r\n", 0);
}else{
DebugMsg("ping success\r\n", 0);
}
DebugMsg("cur pipe=%d\r\n", My.DPipe); //打印当前通道
}
}
//ping任务创建
#define PING_STACK_SIZE (1024)
#define PING_TASK_PRIO (5)
static OS_STK PingOut_stack[PING_STACK_SIZE];
void PingTaskCreate(void)
{
icmp_pcb_init();
pingEchoReply = OSSemCreate(0);
OSTaskCreate(PingTask, NULL,&PingOut_stack[PING_STACK_SIZE-1],PING_TASK_PRIO);
}
ping.h文件(可以删掉一部分东西的):
#ifndef _PING_H_
#define _PING_H_
#include "ucos_ii.h"
#ifdef __cplusplus
extern "C"
{
#endif
//====================================头文件声明开始==================================
//====================================头文件声明结束==================================
//====================================宏定义开始======================================
typedef int pid_t;
#define IPPROTO_IP 0 /* dummy for IP */
#define IPPROTO_ICMP 1 /* control message protocol */
#define IPPROTO_IGMP 2 /* internet group management protocol */
#define IPPROTO_GGP 3 /* gateway^2 (deprecated) */
#define IPPROTO_TCP 6 /* tcp */
#define IPPROTO_PUP 12 /* pup */
#define IPPROTO_UDP 17 /* user datagram protocol */
#define IPPROTO_IDP 22 /* xns idp */
#define IPPROTO_ND 77 /* UNOFFICIAL net disk proto */
#define IPPROTO_RAW 255 /* raw IP packet */
#define IPPROTO_MAX 256
//====================================宏定义结束======================================
extern OS_EVENT * pingEchoReply; //ping回复任务
#endif