一、以太网IP包报文格式

  IP包是连接在以太网首部(以太网目的MAC地址(6个字节)+以太网源MAC地址(6个字节)+帧类型(2个字节))之后。

  IP报文中各个字段分析如下:

  ①、版本:在IP报文中,版本占了4个bit位,用来表示该协议采用的是哪一个版本的IP,相同版本的IP才能进行通信。一般此处的值为4,表示IPv4。

  ②、头长度:指IP报文中头部的长度,占了4个bit位,一个数值单位表示4个字节(32个bit)。如果忽略可选项,此处的值为5,表示IP包头部为20个字节。

  ③、服务类型:指所需要服务的质量,占1个字节。

    优先(0~2比特位):该值越大,数据报相对于其他数据报的优先级越高。

    时延(3比特位):如果需要较低的时延,需将该位置1,否则置0。

    吞吐量(4比特位):如果需要较高的吞吐量,需要将该位置1,否则置0。

    可靠性(5比特位):如果需要较高的可靠性,需将该位置1,否则置0。

    保留(6,7比特位):未使用。

  ④、总长度:指IP数据报的总长度,占2个字节。最大为65535字节,单位:字节。

  ⑤、标识:在分片中使用,同一报文的所有分片具有相同的标识号,占2个字节,方便IP分片的重组。

  ⑥、标志:占3个bit。该字段是与IP分片有关的。只有两位是有效的,分别为MF和DF。MF标识后面是否还有分片,为1时,表示后面还有分片。DF标识是否能分片,为0表示可以分片。保留(0比特位)表示未使用;不分                                片(1比特位)指该数据报信息字段不能分片;还有分片(2比特位)指如果该位置1表示后面还有分片,如果为0,表示该数据包为最后一个分片或者数据报未分片。

  ⑦、段偏移:该字段是与IP分片后,相应的IP片在总的IP片的位置。该字段的单位是8字节。比如,一个长度为4000字节的IP报文,到达路由器。这是超过了链路层的MTU,需要进行分片,4000字节中,20字节为包头,                                      3980字节为数据,需要分成3个IP片(链路层MTU为1500),那么第一个分片的片偏移就是0,表示该分片在3980的第0位开始,第1479位结束。第二个IP片的片偏移为185(1480/8),表示该分片开始的位                                    置在原来IP的第1480位,结束在2959。第三个IP片的片偏移为370(2960/8),表示开始的时候是2960位,结束的时候在3979位。

  ⑧、生存时间(TTL):占1个字节。IP数据包每经过一个路由器,该值减1,如果该值减为0,那么该数据包将被丢弃。Windows系统该值默认为128。

  ⑨、协议:占1个字节。协议值如下表所示。

    

  ⑩、校验和:占2个字节。该值是对整个数据包的包头进行的校验。将整个IP报头部一个字节一个字节相加,最后结果将超过16位的数据取出,加到数据尾部。然后对结果进行取反。

  11、源IP地址:占4个字节。目的IP地址:占4个字节。

  12、可选项:占4个字节。

  13、数据:长度可变,要发送的数据部分内容(原始数据报被分片后的一个分片数据部分)。

二、ICMP报的请求与响应

  ICMP报文是放在IP报的数据部分,ICMP报格式如下:

  ①、类型:占1个字节。类型值有如下:

  ②、代码:占1个字节,指示不同的“子类型”。

  ③、校验和:占2个字节。为ICMP报文提供错误检测,它是ICMP报文从ICMP类型开始计算的16位反码和的密码。为了计算该校验和,校验和字段应为0。

  ④、数据:取决于报文的类型。一般情况下,在差错报告报文中,该字段包含不能被交付的原始IP数据报的一部分。

  ICMP请求:

  第一步:将LPC1850网口与电脑网口相连接,将电脑IP改成与板子IP在同一个网段,如:板子IP为192.168.1.190,则电脑IP可以改为192.168.1.2。

  主程序代码如下:

 #include "LPC18xx.h"
#include "led.h" extern void taskEth (void); int main(void)
{
SystemInit(); ledInit();
SysTick_Config(GetCoreClock() / ); taskEth(); while ();
} void SysTick_Handler(void)
{
static int counter = ; counter++;
if (counter >= )
{
counter = ;
ledRolling();
}
}
 #include <stdlib.h>
#include <lpc18xx.h>
#include "lpc18xx_emac.h"
#include "lpc18xx_debug.h" extern uint32_t ipatol(char * p_input);
extern void ipInit(uint8_t * mac, uint32_t ip);
extern uint32_t ipRcvMacFrame(uint8_t * block, uint32_t frameLen); uint8_t gFlag = ; uint8_t g_emacBuffer[]; uint8_t g_ethMac[]; // EMAC接口接收到数据,通知应用层回调函数
void ethReadReadyCb()
{
gFlag = ;
} void taskEth (void)
{
uint32_t len; g_ethMac[] = 0x11;
g_ethMac[] = 0x1F;
g_ethMac[] = 0xE0;
g_ethMac[] = 0x12;
g_ethMac[] = 0x1E;
g_ethMac[] = 0x0F; debugComInit();
uartPrint("uart init\r\n"); while (ethInit(ethReadReadyCb, g_ethMac) == ); uartPrint("eth init complete\r\n");
//为以太网接口指定MAC地址和IP地址
ipInit(g_ethMac, 0xBE01A8C0); // 192.168.1.190 while ()
{
if (!gFlag)
{
continue;
} len = ethRead(g_emacBuffer, );
if (len)
{
ipRcvMacFrame((uint8_t *)g_emacBuffer, len);
} gFlag = ;
}
}

  IP代码如下:

 #include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "lpc18xx_emac.h"
#include "lpc18xx_debug.h"
//#include "shell.h" #define MAC_TYPE_IP 0x0800 //ipÀàÐÍ
#define MAC_TYPE_ARP 0x0806 //macÀàÐÍ #define ARP_REQ 0x0001 //ARPÇëÇó
#define ARP_RSP 0x0002 //ARPÏìÓ¦ #define ICMP_ECHO_REQUEST 8 // message is an echo request
#define ICMP_ECHO_REPLY 0 // message is an echo reply #define PROT_ICMP 1 // Internet Control Message Protocol
#define PROT_TCP 6 // Transmission Control Protocol
#define PROT_UDP 17 // User Datagram Protocol #define DONT_FRAGMENT 0x4000 //fragment
#define MORE_FRAGMENT 0x2000
#define FRAGMENT_OFFSET 0x1FFF uint8_t g_ethMacAddr[];
uint32_t g_ethIpAddr; uint32_t g_ipSndBuffer[]; uint16_t g_ipIdentifier = ; // ½«×Ö´ÓÖ÷»úÐòתΪÍøÂçÐò
uint16_t htons(uint16_t word)
{
return ((word >> ) & 0x00FF) | ((word << ) & 0xFF00);
} // ½«×Ö´ÓÍøÂçÐòתΪÖ÷»úÐò
uint16_t ntohs(uint16_t word)
{
return ((word >> ) & 0x00FF) | ((word << ) & 0xFF00);
} uint16_t calcChecksum(uint16_t * buffer, uint32_t size)
{
uint32_t cksum; cksum = ; while (size > )
{
cksum += *buffer++;
size -= sizeof(uint16_t);
} if (size)
{
cksum += *(uint8_t*)buffer;
} cksum = (cksum >> ) + (cksum & 0xffff);
cksum += (cksum >>); return (uint16_t)(~cksum);
} // ·¢ËÍARPÏìÓ¦
void arpSndRsp(uint32_t dstIp, uint8_t * mac)
{
uint8_t * block;
//uint32_t blockLen; block = (uint8_t *)g_ipSndBuffer; memcpy(block, mac, ); memcpy(block + , g_ethMacAddr, ); // arp type
*(uint16_t *)&block[] = htons(MAC_TYPE_ARP); // --------- ARP ²ã // Hardway type : Ethernet
block[] = 0x00;
block[] = 0x01; // ip type
*(uint16_t *)&block[] = htons(MAC_TYPE_IP); // Hardway size
block[] = 0x06; // Protocal size
block[] = 0x04; // arp reply
*(uint16_t *)&block[] = htons(ARP_RSP); // Sender MAC address
memcpy(block + , g_ethMacAddr, ); // Sender IP address
*(uint32_t *)&block[] = g_ethIpAddr; // Target MAC address
memcpy(block + , mac, ); // Target IP address : 192.168.0.67
block[] = (uint8_t)dstIp;
block[] = (uint8_t)(dstIp >> );
block[] = (uint8_t)(dstIp >> );
block[] = (uint8_t)(dstIp >> ); // 18¸öÌî³ä×Ö½Ú
memset(block + , , ); ethWrite((uint8_t *)block, );
} void arpRcv(uint8_t * block, uint32_t frameLen)
{
uint32_t srcIp, dstIp;
uint16_t msgType; msgType = ntohs(*(uint16_t *)(block+)); srcIp = (uint32_t)*(uint16_t *)(block + );
srcIp|= ((uint32_t)*(uint16_t *)(block + )) << ; dstIp = (uint32_t)*(uint16_t *)(block + );
dstIp|= ((uint32_t)*(uint16_t *)(block + )) << ; if (dstIp != g_ethIpAddr)
{
return;
} if (msgType == ARP_REQ)
{
arpSndRsp(srcIp, block + );
}
} // ²»¹Ü³É¹¦Óë·ñ,¶¼ÓÉIP²ãÀ´ÊÍ·ÅÊý¾Ý°ü¡£
void ipSnd(uint32_t dstIp, uint8_t * block, uint32_t len, uint8_t protoType, uint8_t * mac)
{
block-= ;
len+= ; // ------------ IP ²ã block[] = 0x45; // IP V4. length 20(5*4) block[] = 0x00; // service *(uint16_t *)&block[] = htons(len); *(uint16_t *)&block[] = htons((uint16_t)g_ipIdentifier++); // identification *(uint16_t *)&block[] = 0x0040; // flag and fragment block[] = ; // TTL block[] = protoType; *(uint16_t *)&block[] = ; // УÑéºÍÏÈÌîÉÏ0 *(uint16_t *)&block[] = (uint16_t)g_ethIpAddr;
*(uint16_t *)&block[] = (uint16_t)(g_ethIpAddr >> ); *(uint16_t *)&block[] = (uint16_t)dstIp;
*(uint16_t *)&block[] = (uint16_t)(dstIp >> ); *(uint16_t *)&block[] = calcChecksum((uint16_t *)block, ); // ------------ MAC ²ã block-= ;
len+= ; memcpy(block, mac , ); memcpy(block + , g_ethMacAddr, ); *(uint16_t *)&block[] = htons(MAC_TYPE_IP); if (len < )
{
// MACÖ¡Ì«¶Ì£¬²¹µ½×î¶Ì³¤¶È¡£
memset(block + len, , - len);
len = ;
} ethWrite((uint8_t *)block, len);
} // ICMPÊÕµ½ÇëÇó£¬ÐèÒª»ØÏìÓ¦¡£
void icmpRcvRequest(uint32_t srcIp, uint8_t * icmp, uint32_t len, uint8_t * mac)
{
uint8_t * block; block = (uint8_t *)g_ipSndBuffer; // Áô³ö 14(MAC)+20(IP)¸ö×Ö½Ú
block+=(+); // ----------- ICMP ²ã
icmp[]='R';
icmp[]='e';
icmp[]='c';
icmp[]='e';
icmp[]='i';
icmp[]='v';
icmp[]='e';
icmp[]='d'; icmp[]=' ';
icmp[]='I';
icmp[]='C';
icmp[]='M';
icmp[]='P';
icmp[]=' ';
icmp[]='R';
icmp[]='e';
icmp[]='q';
icmp[]='u';
icmp[]='e';
icmp[]='s';
icmp[]='t';
icmp[]='!'; memcpy(block, icmp, len); block[] = ICMP_ECHO_REPLY;
block[] = ; // code *(uint16_t *)&block[] = ; // УÑéºÍÏÈÌîÉÏ0 *(uint16_t *)&block[] = calcChecksum((uint16_t *)block, len);
uartPrint("The ICMP response!\r\n");
ipSnd(srcIp, (void *)block, len, PROT_ICMP, mac);
} // ½ÓÊÕµ½IP°üµÄ´¦Àí
void ipRcv(uint8_t * frame, uint32_t frameLen, uint8_t * mac)
{
uint16_t ipLength, flag,i;
uint32_t srcIp, dstIp; if (frameLen < )
{
return;
} if (calcChecksum((uint16_t *)frame, ))
{
// УÑéºÍ²»ÕýÈ·
return;
} if (frame[] != 0x45)
{
// IP VERSION ӦΪ4£¬³¤¶ÈӦΪ20£¨5¸öbit32£©×Ö½Ú¡£
return;
} // ignore Type Of Service ipLength = ntohs(*(uint16_t *)&frame[]);
// ignore identification flag = ntohs(*(uint16_t *)&frame[]); if (!(flag & DONT_FRAGMENT))
{
// IP¿ÉÒÔ±»·Ö°ü£¬µ«ÎÒÃÇÖ»´¦Àí²»·Ö°üµÄÇé¿ö¡£ if (flag & MORE_FRAGMENT)
{
// ·Ç×îºóµÄÒ»°ü£¬¶ªÆú¡£
return;
} // ÊÇ×îºóÒ»°ü¡£ if (flag & FRAGMENT_OFFSET)
{
// ÊÇ×îºóÒ»°ü£¬ÇÒÆ«ÒÆÁ¿²»Îª0£¬Ò²¶ªÆú¡£
return;
} // ×îºóÒ»°ü£¬ÇÒÆ«ÒÆÁ¿Îª0£¬ÊÇÕû°ü£¬´¦Àí£¡
} if (frameLen < ipLength)
{
return;
} // ignore fragment offset //ttl = (uint32_t)frame[8]; //srcIp = (frame[12] | (frame[13]<< 8) | (frame[14] << 16) | (frame[15] << 24));
//dstIp = (frame[16] | (frame[17]<< 8) | (frame[18] << 16) | (frame[19] << 24)); srcIp = *(uint16_t *)(frame + ) | ((uint32_t)*(uint16_t *)(frame + ) << );
dstIp = *(uint16_t *)(frame + ) | ((uint32_t)*(uint16_t *)(frame + ) << ); if ((dstIp != g_ethIpAddr) && (dstIp != 0x0100007F) && (dstIp != 0xffffffff))
{
return;
} if (frame[] != PROT_ICMP)
{
// ·ÇICMP°ü£¬Ôݲ»´¦Àí
return;
}
//ÊÕµ½ICMPÇëÇ󣬴òÓ¡³öICMP°ü
if (frame[] == ICMP_ECHO_REQUEST)
{
uartPrint("ICMP Header:\r\n");
uartPrint("Type:%d\r\n",*(frame+));
uartPrint("Code:%d\r\n",*(frame+));
uartPrint("Checksum:0x%04x\r\n",ntohs(*(uint16_t *)(frame+)));
uartPrint("Id:0x%04x\r\n",ntohs(*(uint16_t *)(frame+)));
uartPrint("Sequence:%d\r\n",ntohs(*(uint16_t *)(frame+)));
uartPrint("Data:\r\n");
for(i=;i<ipLength-;i++)
{
uartPrint("%c",frame[+i]);
}
uartPrint("\r\n---------------------------------\r\n");
icmpRcvRequest(srcIp, frame + , ipLength - , mac);
}
} // IP²ã½ÓÊÕMAC²ãÊý¾ÝÖ¡µÄº¯Êý
uint32_t ipRcvMacFrame(uint8_t * block, uint32_t frameLen)
{
//0xFFFF ¹ã²¥·½Ê½
if ( ((*(uint16_t *)block == 0xFFFF) && (*(uint16_t *)(block + ) == 0xFFFF) && (*(uint16_t *)(block + ) == 0xFFFF))
||(memcmp(block, g_ethMacAddr, ) == ))
{
// ÊÇ·¢¸ø±¾»úµÄ¡£
switch (ntohs(*(uint16_t *)(block+)))
{
case MAC_TYPE_ARP:
arpRcv(block + , frameLen -);
break;
case MAC_TYPE_IP:
ipRcv(block + , frameLen - , block+);
break;
default:
break;
}
} return ;
} void ipInit(uint8_t * mac, uint32_t ip)
{
memcpy(g_ethMacAddr, mac, );
g_ethIpAddr = ip;
}

  将程序烧写到PLC1850板子上,将板子与电脑用网线,串口线连接。打开cmd,输入ping 192.168.1.190回车。串口将打印出电脑请求的ICMP报的信息。同时可使用wireshark软件查看相关信息。

基于PLC1850平台的ICMP包请求与响应的更多相关文章

  1. 基于PLC1850平台的ARP包请求与响应

    一.以太网ARP报文格式 ①.以太网目的地址:占6个字节(接收方的MAC地址,不清楚时发广播地址:FF-FF-FF-FF-FF-FF) ②.以太网源地址:占6个字节(发送方的MAC地址) ③.帧类型: ...

  2. 基于PLC1850平台的UDP报文接收与发送

    一.UDP报文格式 源端口(2个字节):发送报文的进程的16位端口号. 目的端口(2个字节):目的设备上的接收进程的16位端口号. 长度(2个字节):整个UDP数据报的长度,包括首都和数据字段. 校验 ...

  3. 基于Linux平台的libpcap源码分析和优化

    目录 1..... libpcap简介... 1 2..... libpcap捕包过程... 2 2.1        数据包基本捕包流程... 2 2.2        libpcap捕包过程... ...

  4. 基于Android 平台简易即时通讯的研究与设计[转]

    摘要:论文简单介绍Android 平台的特性,主要阐述了基于Android 平台简易即时通讯(IM)的作用和功能以及实现方法.(复杂的通讯如引入视频音频等可以考虑AnyChat SDK~)关键词:An ...

  5. 【网络编程2】网络编程基础-发送ICMP包(Ping程序)

    IP协议 网络地址和主机协议 位于网络层的协议,主要目的是使得网络能够互相通信,该协议使用逻辑地址跨网络通信,目前有两个版本IPV4,IPV6. 在IPV4协议中IP地址是一个32位的数备,采用点分四 ...

  6. 基于java平台的常用资源整理

    这里整理了基于java平台的常用资源 翻译 from :akullpp | awesome-java 大家一起学习,共同进步. 如果大家觉得有用,就mark一下,赞一下,或评论一下,让更多的人知道.t ...

  7. 基于X86平台的PC机通过网络发送一个int(32位)整数的字节顺序

    1.字节顺序 字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端.大端两种字节顺序.小端字节序指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处:大端字节序是高字节数据存 ...

  8. 这里整理了基于java平台的常用资源

    这里整理了基于java平台的常用资源 翻译 from :akullpp | awesome-java 大家一起学习,共同进步. 如果大家觉得有用,就mark一下,赞一下,或评论一下,让更多的人知道.t ...

  9. 002.ICMP--拼接ICMP包,实现简单Ping程序(原始套接字)

    一.大致流程: 将ICMP头和时间数据设置好后,通过创建好的原始套接字socket发出去.目的主机计算效验和后会将数据原样返回,用当前时间和返回的数据结算时间差,计算出rtt. 二.数据结构: ICM ...

随机推荐

  1. CSS,浮动及其影响

    浮动(float): 让默认文档流(标准文档流)下的元素漂浮起来,水平排列. 通俗点来说,浮动可以让元素浮到第二层,而其他没有浮动的元素就往上排,而我们是俯视去看的,所以往上顶的那个元素就会被遮住,这 ...

  2. mobile_5 种常见适配_设备兼容

    em  参照本身元素的 font-size rem 参照 html 根元素 的 font-size 1. rem 适配   (同一元素,在不同设备上,效果一样) 适用情况: 当页面大于 独立像素375 ...

  3. Docker 安装以及运用

    Docker 运行在 CentOS 7 上,要求系统为64位.系统内核版本为 3.10 以上.Docker 运行在 CentOS-6.5 或更高的版本的 CentOS 上,要求系统为64位.系统内核版 ...

  4. android发送短信验证码并自动获取验证码填充文本框

    android注册发送短信验证码并自动获取短信,截取数字验证码填充文本框. 一.接入短信平台 首先需要选择短信平台接入,这里使用的是榛子云短信平台(http://smsow.zhenzikj.com) ...

  5. Nginx基本安装

    Windows安装Nginx 解压:nginx-windows 双击: nginx.exe 能看到nginx欢迎界面说明,nginx安装成功 演示下 nginx做静态服务器 启动Nginx C:\se ...

  6. Dapp开发教程一 Asch Dapp Hello World

    1 基本流程 Asch有三种net,localnet,testnet,mainnet,后两种是发布到线上的,可通过公网访问. 第一种localnet是运行在本地的.只有一个节点的私链,主要是为了方便本 ...

  7. Jmeter-----参数配置

    参数化配置: 设置为3个线程后,三个用户均能运行

  8. SSZipArchive解压乱码

    https://www.twblogs.net/a/5b7e01e22b7177683854b7b8/zh-cn 搜索   CFStringConvertEncodingToNSStringEncod ...

  9. NodeJS笔记(五) 使用React Native 创建第一个 Android APP

    参考:原文地址 几个月前官方推出了快速创建工具包,由于对React Native不熟悉这里直接使用这2个工具包进行创建 1. create-react-native-app(下文简称CRNA): 2. ...

  10. mysql主从服务搭建

    一.安装mysql 检测当前centos是否安装了mysql:yum list installed | grep mysql yum list installed | grep mariadb    ...