// IP首部总长度
#define IP_HEADER_LEN 20
// 协议类型
// ICMP协议
#define IP_PROTO_ICMP_V 0x01
// TCP协议
#define IP_PROTO_TCP_V 0x06
// UDP协议
#define IP_PROTO_UDP_V 0x11
// IPV4版本
#define IP_V4_V 0x40
#define IP_HEADER_LENGTH_V 0x05
// IP版本号位置 以太网首部2+6+6
#define IP_P 0x0E
// 首部长度
#define IP_HEADER_VER_LEN_P 0x0E
// 服务类型
#define IP_TOS_P 0x0F
// IP总长度
#define IP_TOTLEN_H_P 0x10
#define IP_TOTLEN_L_P 0x11
// IP标识
#define IP_ID_H_P 0x12
#define IP_ID_L_P 0x13
//
#define IP_FLAGS_H_P 0x14
#define IP_FLAGS_L_P 0x15
// TTL生存时间
#define IP_TTL_P 0x16
// IP协议类型 例如ICMP TCP UDP
#define IP_PROTO_P 0x17
// 首部校验和
#define IP_CHECKSUM_H_P 0x18
#define IP_CHECKSUM_L_P 0x19
// 源IP地址
#define IP_SRC_IP_P 0x1A
// 目标IP地址
#define IP_DST_IP_P 0x1E
void ip_generate_header ( BYTE *rxtx_buffer, WORD_BYTES total_length, BYTE protocol, BYTE *dest_ip )
{
BYTE i;
// 校验结果
WORD_BYTES ck;
// 版本号和首都长度
rxtx_buffer[ IP_P ] = IP_V4_V | IP_HEADER_LENGTH_V;
// 服务类型
rxtx_buffer[ IP_TOS_P ] = 0x00;
// 总长度
rxtx_buffer [ IP_TOTLEN_H_P ] = total_length.byte.high;
rxtx_buffer [ IP_TOTLEN_L_P ] = total_length.byte.low;
// IP标识
rxtx_buffer [ IP_ID_H_P ] = ip_identfier >> 8;
rxtx_buffer [ IP_ID_H_P ] = ip_identfier & 0x00ff;
// 累加
ip_identfier++;
// 标志和分片偏移
rxtx_buffer [ IP_FLAGS_H_P ] = 0x00;
rxtx_buffer [ IP_FLAGS_L_P ] = 0x00;
// 生存时间
rxtx_buffer [ IP_TTL_P ] = 128;
// set ip packettype to tcp/udp/icmp...
rxtx_buffer [ IP_PROTO_P ] = protocol;
// 设定目标地址和源地址
for ( i = 0; i < 4; i++ )
{
rxtx_buffer[ IP_DST_IP_P + i ] = dest_ip[i];
rxtx_buffer[ IP_SRC_IP_P + i ] = avr_ip.byte[ i ];
}
// 校验结果
rxtx_buffer[ IP_CHECKSUM_H_P ] = 0;
rxtx_buffer[ IP_CHECKSUM_L_P ] = 0;
ck.word = software_checksum ( &rxtx_buffer[ IP_P ], sizeof(IP_HEADER), 0 );
rxtx_buffer[ IP_CHECKSUM_H_P ] = ck.byte.high;
rxtx_buffer[ IP_CHECKSUM_L_P ] = ck.byte.low;
}BYTE ip_packet_is_ip ( BYTE *rxtx_buffer )
{
unsigned char i;
// 检查该报文是否为IP报文
if ( rxtx_buffer[ ETH_TYPE_H_P ] != ETH_TYPE_IP_H_V || rxtx_buffer[ ETH_TYPE_L_P ] != ETH_TYPE_IP_L_V)
return 0;
// 检查该报文的IP地址是否为本机IP地址,逐个检查
for ( i=0; i<sizeof(IP_ADDR); i++ )
{
if ( rxtx_buffer[ IP_DST_IP_P + i ] != avr_ip.byte[i] )
return 0;
}
// 若该报文为IP报文,且目标IP地址为本机地址,返回1
return 1;
}// 回显应答 #define ICMP_TYPE_ECHOREPLY_V 0 // 回显请求 #define ICMP_TYPE_ECHOREQUEST_V 8 // ICMP首部长度 #define ICMP_PACKET_LEN 40 // ICMP类型 #define ICMP_TYPE_P 0x22 // ICMP代码 #define ICMP_CODE_P 0x23 // ICMP首部校验和 #define ICMP_CHECKSUM_H_P 0x24 #define ICMP_CHECKSUM_L_P 0x25 // ICMP标识符 #define ICMP_IDENTIFIER_H_P 0x26 #define ICMP_IDENTIFIER_L_P 0x27 // ICMP序号 #define ICMP_SEQUENCE_H_P 0x28 #define ICMP_SEQUENCE_L_P 0x29 #define ICMP_DATA_P 0x2A
void icmp_generate_packet ( BYTE *rxtx_buffer ,BYTE type)
{
BYTE i;
WORD_BYTES ck;
// ICMP回显请求
if( type == ICMP_TYPE_ECHOREQUEST_V )
{
rxtx_buffer[ ICMP_TYPE_P ] == ICMP_TYPE_ECHOREQUEST_V;
rxtx_buffer[ ICMP_CODE_P ] = 0;
rxtx_buffer[ ICMP_IDENTIFIER_H_P ] = icmp_id;
rxtx_buffer[ ICMP_IDENTIFIER_L_P ] = 0;
rxtx_buffer[ ICMP_SEQUENCE_H_P ] = icmp_seq;
rxtx_buffer[ ICMP_SEQUENCE_L_P ] = 0;
icmp_id++;
icmp_seq++;
for ( i=0; i<ICMP_MAX_DATA; i++ )
{
rxtx_buffer[ ICMP_DATA_P + i ] = ‘A‘ + i;
}
}
// ICMP回显
if(type == ICMP_TYPE_ECHOREPLY_V)
{
rxtx_buffer[ ICMP_TYPE_P ] = ICMP_TYPE_ECHOREPLY_V;
}
// ICMP首部校验和
rxtx_buffer[ ICMP_CHECKSUM_H_P ] = 0;
rxtx_buffer[ ICMP_CHECKSUM_L_P ] = 0;
ck.word = software_checksum ( &rxtx_buffer[ ICMP_TYPE_P ], sizeof(ICMP_PACKET), 0 );
rxtx_buffer[ ICMP_CHECKSUM_H_P ] = ck.byte.high;
rxtx_buffer[ ICMP_CHECKSUM_L_P ] = ck.byte.low;
}BYTE icmp_send_reply ( BYTE *rxtx_buffer, BYTE *dest_mac, BYTE *dest_ip )
{
// IP首部中为ICMP协议类型
if ( rxtx_buffer [ IP_PROTO_P ] != IP_PROTO_ICMP_V )
return 0;
// 是否为ICMP回显请求
if ( rxtx_buffer [ ICMP_TYPE_P ] != ICMP_TYPE_ECHOREQUEST_V )
return 0;
#ifdef ICMP_DEBUG
printf("ICMP Request!\n");
printf("Ping from:%d.%d.%d.%d\n", rxtx_buffer[IP_SRC_IP_P+0],rxtx_buffer[IP_SRC_IP_P+1], rxtx_buffer[IP_SRC_IP_P+2],rxtx_buffer[IP_SRC_IP_P+3]);
#endif
// 生成以太网首部
eth_generate_header ( rxtx_buffer, (WORD_BYTES){ETH_TYPE_IP_V}, dest_mac );
// 生成IP首部
ip_generate_header ( rxtx_buffer, (WORD_BYTES){(rxtx_buffer[IP_TOTLEN_H_P]<<8)|rxtx_buffer[IP_TOTLEN_L_P]}, IP_PROTO_ICMP_V, dest_ip );
// 生成ICMP首部
icmp_generate_packet ( rxtx_buffer ,(BYTE)ICMP_TYPE_ECHOREPLY_V);
// 发送报文
enc28j60_packet_send ( rxtx_buffer, sizeof(ETH_HEADER) + sizeof(IP_HEADER) + sizeof(ICMP_PACKET) );
return 1;
}
/* 获得新的IP报文 */
plen = enc28j60_packet_receive( (BYTE*)&rxtx_buffer, MAX_RXTX_BUFFER );
if(plen==0) return;
/* 保存客服端的MAC地址 */
memcpy ( (BYTE*)&client_mac, &rxtx_buffer[ ETH_SRC_MAC_P ], sizeof(MAC_ADDR) );
/* 检查该报文是不是ARP报文 */
if ( arp_packet_is_arp( rxtx_buffer, (WORD_BYTES){ARP_OPCODE_REQUEST_V} ) )
{
/* 向客户端返回ARP报文 */
arp_send_reply ( (BYTE*)&rxtx_buffer, (BYTE*)&client_mac );
return;
}
/* 保存客服端的IP地址 */
memcpy ( (BYTE*)&client_ip, &rxtx_buffer[ IP_SRC_IP_P ], sizeof(IP_ADDR) );
/* 检查该报文是否为IP报文 */
if ( ip_packet_is_ip ( (BYTE*)&rxtx_buffer ) == 0 )
{
return;
}
/* 如果是ICMP报文 向发起方返回数据 */
if ( icmp_send_reply ( (BYTE*)&rxtx_buffer, (BYTE*)&client_mac, (BYTE*)&client_ip ) )
{
return;
}STM32NET学习笔记 IP ICMP部分,布布扣,bubuko.com
原文:http://blog.csdn.net/xukai871105/article/details/19938133