icmp.c
来自「本程序是一个RS232转网口的。是一个透明传输的模块」· C语言 代码 · 共 273 行
C
273 行
/*
*****************************************************************************************************
*
* File name: icmp.c
*****************************************************************************************************
*/
#include "..\head\includes.h"
#define MaxLenPingBuf 10 //PING缓冲区长度
xdata struct ping_table_type ping_table[MaxLenPingBuf]; //ping表,在外部RAM里
xdata union Ethernet_address ping_ethernet_address; //用来ping的以太网地址
xdata union IP_address ping_ip_address; //用于ping命令
/*
*****************************************************************************************************
*FUNC: 初始化PING表
*NOTE:
*****************************************************************************************************
*/
void InitPingTable(void)
{
unsigned char i;
for (i=0; i<MaxLenPingBuf; i++) {
ping_table[i].status=0;
}
}
/*
*****************************************************************************************************
*FUNC: 生成ICMP包头CRC校验
*NOTE: 返回值: CRC校验值
*****************************************************************************************************
*/
unsigned int createicmpcrc()//生成ICMP包CRC校验
{
unsigned char i;
union w crctemp;
crctemp.dwords=0;
for(i=19;i<39;i++)
crctemp.dwords=crctemp.dwords+txdnet.words.wordbuf[i];
while(crctemp.words.high>0)
crctemp.dwords=(unsigned long)(crctemp.words.high+crctemp.words.low);
crctemp.words.low=0xffff-crctemp.words.low;
return(crctemp.words.low);
}
/*
*****************************************************************************************************
*FUNC: PING请求,实际上,该函数只是在缓冲区里构造一个ICMP包,然后在PING_TABLE里登记该PING
// 记录,该ICMP包的发送是在PING_CYCLE里实现的
*NOTE: 在PING_CYCLE里添查表添加PINGIP的MAC
*****************************************************************************************************
*/
void PingRequest(void)
{
unsigned char i;
// txdnet.etherframe.destnodeid[0]=ping_ethernet_address.words[0];
// txdnet.etherframe.destnodeid[1]=ping_ethernet_address.words[1];
// txdnet.etherframe.destnodeid[2]=ping_ethernet_address.words[2];
txdnet.etherframe.protocal=0x0800;
txdnet.ipframe.verandihl=0x45;
txdnet.ipframe.typeofserver=0x00;
txdnet.ipframe.totallength=60;
txdnet.ipframe.ttl=0x80;
txdnet.ipframe.frameindex=frameindex;
frameindex++;
txdnet.ipframe.segment=0x0000;
txdnet.ipframe.protocal=0x0001; //icmp
txdnet.ipframe.crc=0;
txdnet.ipframe.destip[0]=ping_ip_address.words[0]; //PING ip
txdnet.ipframe.destip[1]=ping_ip_address.words[1];
txdnet.ipframe.sourceip[0]=my_ip_address.words[0];
txdnet.ipframe.sourceip[1]=my_ip_address.words[1];
txdnet.ipframe.crc=createipheadcrc(&txdnet);
txdnet.icmpframe.type=0x08; // is icmp request;
txdnet.icmpframe.option=0x00; //该句由Mingtree加
txdnet.icmpframe.crc=0;
txdnet.icmpframe.id=0x0300;
txdnet.icmpframe.seq=frameindex;
txdnet.icmpframe.crc=createicmpcrc();
for (i=0; i<MaxLenPingBuf; i++) { //将该包登记入ping表里
if (ping_table[i].status == 0) {
ping_table[i].times=0x3; //测试4次
ping_table[i].ip.dwords=ping_ip_address.dwords; //ping命令传入的IP地址;
ping_table[i].pack=&txdnet; //发送缓冲区地址
ping_table[i].status=4; //第一次准备发(用于同步1秒时钟)
break;
}
}
}
/*
*****************************************************************************************************
*FUNC: PING应答
*NOTE: //从16开始的原因:1字节的接收状态,1字节下一页指针,2字节以太网包长度,
//12字节MAC地址,加起来为16字节.接着的信息为包类型,可以拷贝
*****************************************************************************************************
*/
void PingAnswer(void)
{
unsigned char i;
if (rxdnet.icmpframe.type == 0x08) { //表示是ping请求
for (i=16;i<rxdnet.etherframe.uLength;i++) { //将数据复制到发送缓冲区
txdnet.bytes.bytebuf[i]=rxdnet.bytes.bytebuf[i];
}
txdnet.etherframe.uDestID[0]=rxdnet.etherframe.uSourceID[0]; //目的MAC
txdnet.etherframe.uDestID[1]=rxdnet.etherframe.uSourceID[1];
txdnet.etherframe.uDestID[2]=rxdnet.etherframe.uSourceID[2];
txdnet.etherframe.uSourceID[0]=rxdnet.etherframe.uDestID[0]; //源MAC
txdnet.etherframe.uSourceID[1]=rxdnet.etherframe.uDestID[1];
txdnet.etherframe.uSourceID[2]=rxdnet.etherframe.uDestID[2];
txdnet.ipframe.ttl=txdnet.ipframe.ttl-1; //生存时间
txdnet.ipframe.crc=0;
txdnet.ipframe.destip[0]=rxdnet.ipframe.sourceip[0];
txdnet.ipframe.destip[1]=rxdnet.ipframe.sourceip[1];
txdnet.ipframe.sourceip[0]=my_ip_address.words[0];
txdnet.ipframe.sourceip[1]=my_ip_address.words[1];
txdnet.ipframe.crc=createipheadcrc(&txdnet);
txdnet.icmpframe.type=0x00; // 0:ACK 8:请求
txdnet.icmpframe.option=0x00; // 固定为0配合TYPE
txdnet.icmpframe.crc=0;
txdnet.icmpframe.crc=createicmpcrc();
send_packet(&txdnet,rxdnet.etherframe.uLength);
}
}
/*
*****************************************************************************************************
*FUNC: 重新建立PING数据包
*NOTE: 入参: 需要重构的表索引
//注意: 在进行ping时,如果要先发送一个ARP数据包,则会对由ping_requeset()函数形成的
// PING包进行破坏,该函数的功能就是重新构造PING包。构造该包的信息在PING_TABLE里
*****************************************************************************************************
*/
void reconstruct_ping(unsigned char table_index)
{
txdnet.etherframe.protocal=0x0800;
txdnet.ipframe.verandihl=0x45;
txdnet.ipframe.typeofserver=0x00;
txdnet.ipframe.totallength=60;
txdnet.ipframe.ttl=0x80;
txdnet.ipframe.frameindex=frameindex;
frameindex++;
txdnet.ipframe.segment=0x0000;
txdnet.ipframe.protocal=0x0001;//icmp
txdnet.ipframe.crc=0;
txdnet.ipframe.destip[0]=ping_table[table_index].ip.words[0];
txdnet.ipframe.destip[1]=ping_table[table_index].ip.words[1];
txdnet.ipframe.sourceip[0]=my_ip_address.words[0];
txdnet.ipframe.sourceip[1]=my_ip_address.words[1];
txdnet.ipframe.crc=createipheadcrc(&txdnet);
txdnet.icmpframe.type=0x08;// is icmp request;
txdnet.icmpframe.option=0x00; //该句由Mingtree加
txdnet.icmpframe.crc=0;
txdnet.icmpframe.id=0x0300;
txdnet.icmpframe.seq=frameindex;
txdnet.icmpframe.crc=createicmpcrc();
}
/*
*****************************************************************************************************
*FUNC: PING回显,该函数在收到包,判断包为PING回显后调用,对PING表里的状态进行改变
*NOTE: //PING应答收到后回显
*****************************************************************************************************
*/
void PingEcho(void)
{
unsigned char i;
temp_ip_address.words[0]=rxdnet.ipframe.sourceip[0];
temp_ip_address.words[1]=rxdnet.ipframe.sourceip[1];
for (i=0; i<MaxLenPingBuf; i++) {
if ((ping_table[i].status == 1) && (ping_table[i].ip.dwords == temp_ip_address.dwords)) {
ping_table[i].status=2;
break;
}
}
HintMsg(1,PingIpStr);
}
/*
*****************************************************************************************************
*FUNC: 定时操作,放在1秒循环任务中
*NOTE: 用于对PING_TABLE进行操作,该函数是处理PING的最重要函数
for (i=0; i<MaxLenPingBuf; i++) { //将该包登记入ping表里
if (ping_table[i].status == 0) {
ping_table[i].times=0x4; //测试4次
ping_table[i].ip.dwords=ping_ip_address.dwords; //ping命令传入的IP地址;
ping_table[i].pack=&txdnet; //发送缓冲区地址
ping_table[i].status=4; //第一次准备发(用于同步1秒时钟)
break;
}
}
1:准备PIN时,置状态为4:
2:要4时,如果有对应的MAC,置1,如果没有发ARP请求,置3
3:下一秒进来时,如果是3,查找对应的MAC,如果没有说明ARP没响应,状态置1
4:发完一包,状态置1
如果收到PING应答包,会处理void PingEcho(void),如果是该PING IP的应答包,置2说明PING成功
*****************************************************************************************************
*/
void CopyMac2PingTable(unsigned char num)
{
unsigned char i;
for (i=0; i<3; i++) {
ping_table[num].pack->etherframe.uDestID[i]=ping_ethernet_address.words[i]; //填写发送包的MAC地址
ping_table[num].pack->etherframe.uSourceID[i]=my_ethernet_address.words[i]; //网卡地址
}
#if 0
ping_table[i].pack->etherframe.uDestID[0]=ping_ethernet_address.words[0]; //填写发送包的MAC地址
ping_table[i].pack->etherframe.uDestID[1]=ping_ethernet_address.words[1];
ping_table[i].pack->etherframe.uDestID[2]=ping_ethernet_address.words[2];
ping_table[i].pack->etherframe.uSourceID[0]=my_ethernet_address.words[0]; //网卡地址
ping_table[i].pack->etherframe.uSourceID[1]=my_ethernet_address.words[1];
ping_table[i].pack->etherframe.uSourceID[2]=my_ethernet_address.words[2];
#endif
}
void PingCycle(void) //定时操作,放在1秒循环任务中
{
unsigned char i;
for (i=0; i<MaxLenPingBuf; i++) { //对PING_TABLE表进行扫
switch (ping_table[i].status) {
case 0: //空闲,直接返回
break;
case 1: //已发出但无应答(过了1s还未应答),输出超时
HintMsg(2,PingIpStr); //在这里添加串口发送代码,先上位机显示主机不可达
//break; //失败PING 4 次
case 2: //发出且应答.注意,如果收到回显应答,则在PING_ECHO里进行处理,对状态进行修改
if (ping_table[i].times > 0) {
ping_table[i].times--; //成功PING 4 次
} else {
ping_table[i].status=0;
break;
}
case 4: //第一次准备发(用于同步1秒时钟)
if (FindMac(ping_table[i].ip,&ping_ethernet_address)) { //查ARP缓存
reconstruct_ping(i); //因为发送缓冲区的内容已经发生改变,因此重新构造PING包
CopyMac2PingTable(i); //拷贝MAC到ETH头部
send_packet(ping_table[i].pack,74); //进行发送
ping_table[i].status=1; //改变状态
} else {
ArpRequest(ping_table[i].ip); //ARP表里没有对应项,发送ARP请求
ping_table[i].status=3; //改变状态
}
break;
case 3: //等待ARP
if (FindMac(ping_table[i].ip,&ping_ethernet_address)) { //查ARP缓存
reconstruct_ping(i); //因为发送缓冲区的内容已经发生改变,因此重新构造PING包
CopyMac2PingTable(i);
send_packet(ping_table[i].pack,74); //进行发送
}
ping_table[i].status=1; //已经发出ARP,但是没发回,改变状态
break;
default:
ping_table[i].status=0;
break;
}
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?