#include "board.h" #include "api.h" #include "sockets.h" typedef struct icmp_hdr { unsigned char icmp_type; // 消息类型 unsigned char icmp_code; // 代码 unsigned short icmp_checksum; // 校验和 // 下面是回显头 unsigned short icmp_id; // 用来惟一标识此请求的ID号 unsigned short icmp_sequence; // 序列号 unsigned long icmp_timestamp; // 时间戳 } ICMP_HDR, *PICMP_HDR; typedef struct _IPHeader// 20字节的IP头 { uint8_t iphVerLen; // 版本号和头长度(各占4位) uint8_t ipTOS; // 服务类型 uint16_t ipLength; // 封包总长度,即整个IP报的长度 uint16_t ipID; // 封包标识,惟一标识发送的每一个数据报 uint16_t ipFlags; // 标志 uint8_t ipTTL; // 生存时间,就是TTL uint8_t ipProtocol; // 协议,可能是TCP、UDP、ICMP等 uint16_t ipChecksum; // 校验和 uint32_t ipSource; // 源IP地址 uint32_t ipDestination; // 目标IP地址 } IPHeader, *PIPHeader; typedef int SOCKET; void ping_test(void) { const char * szDestIp = "192.168.137.1"; long nRet = 0; ICMP_HDR* pIcmp = NULL; char buff[sizeof(ICMP_HDR) + 32]; socklen_t nLen = 0; ICMP_HDR* pRecvIcmp = NULL; /*****************第一步:申请SOCKET************************************/ uint32_t ip = inet_addr(szDestIp); SOCKET sRaw = lwip_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if(sRaw == -1) { printf("Cannot create socket! Error %d\r\n", errno); goto exit; } // 设置接收超时 struct timeval tv_out; tv_out.tv_sec = 10; tv_out.tv_usec = 0; nRet = setsockopt(sRaw, SOL_SOCKET,SO_RCVTIMEO, &tv_out, sizeof(tv_out)); if(-1 == nRet) { printf("Cannot set timeout! %d \r\n",errno); } /*****************第二步:组ICMP包************************************/ // 创建ICMP封包 pIcmp = (ICMP_HDR*)buff; // 填写ICMP封包数据 pIcmp->icmp_type = 8; // 请求一个ICMP回显 pIcmp->icmp_code = 0; pIcmp->icmp_id = (uint16_t)0x1234; pIcmp->icmp_checksum = 0; pIcmp->icmp_sequence = 0; pIcmp->icmp_timestamp = 0xffff; // 填充数据部分,可以为任意 memset(&buff[sizeof(ICMP_HDR)], 'E', 32); /*****************第三步:发送ICMP包************************************/ //设置目的地址 struct sockaddr_in dest; dest.sin_family = AF_INET; dest.sin_port = htons(0); dest.sin_addr.s_addr = ip; //pIcmp->icmp_checksum = checksum((uint16_t*)buff, sizeof(ICMP_HDR) + 32); //如果ping过去没回应需要屏蔽这条 //printf("icmp_checksum = %x\r\n",pIcmp->icmp_checksum); nRet = (long)sendto(sRaw, buff, sizeof(ICMP_HDR) + 32, 0, (struct sockaddr *)&dest, sizeof(dest)); if(nRet == -1) { printf(" sendto() failed: %d \r\n", errno); goto exit; } printf("sendto = %ld\r\n",nRet); /*****************第四步:接收ICMP包************************************/ char recvBuf[1024]; struct sockaddr_in from; nLen = sizeof(from); nRet = (long)recvfrom(sRaw, recvBuf, 1024, 0, (struct sockaddr *)&from, &nLen); if(nRet == -1) { printf(" recvfrom() failed: %d\r\n", errno); goto exit; } printf("recvfrom = %ld\r\n",nRet); /*****************第五步:解析ICMP包************************************/ if(nRet < sizeof(IPHeader) + sizeof(ICMP_HDR)) { printf(" Too few bytes from %s \r\n", inet_ntoa(from.sin_addr)); } #if 0 // IP头解析 IPHeader * header = (IPHeader*)recvBuf; struct in_addr a; a.s_addr = header->ipSource; printf("source ip %s\n", inet_ntoa(a)); a.s_addr = header->ipDestination; printf("dest ip %s\n", inet_ntoa(a)); #endif pRecvIcmp = (ICMP_HDR*)(recvBuf + 20); // 接收到的数据中包含IP头,IP头大小为20个字节,所以加20得到ICMP头 if(pRecvIcmp->icmp_type != 0) { // 回显 printf("nonecho type %d recvd \r\n", pRecvIcmp->icmp_type); goto exit; } if(pRecvIcmp->icmp_id != 0x1234) { printf(" someone else's packet! \r\n"); goto exit; } printf(" %d bytes from %s:", (int)nRet, inet_ntoa(from.sin_addr)); printf(" icmp_seq = %d. ", pRecvIcmp->icmp_sequence); printf(" \r\n"); exit: if (sRaw != -1) lwip_close(sRaw); return ; }