ping_test.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #include "board.h"
  2. #include "api.h"
  3. #include "sockets.h"
  4. typedef struct icmp_hdr
  5. {
  6. unsigned char icmp_type; // 消息类型
  7. unsigned char icmp_code; // 代码
  8. unsigned short icmp_checksum; // 校验和
  9. // 下面是回显头
  10. unsigned short icmp_id; // 用来惟一标识此请求的ID号
  11. unsigned short icmp_sequence; // 序列号
  12. unsigned long icmp_timestamp; // 时间戳
  13. } ICMP_HDR, *PICMP_HDR;
  14. typedef struct _IPHeader// 20字节的IP头
  15. {
  16. uint8_t iphVerLen; // 版本号和头长度(各占4位)
  17. uint8_t ipTOS; // 服务类型
  18. uint16_t ipLength; // 封包总长度,即整个IP报的长度
  19. uint16_t ipID; // 封包标识,惟一标识发送的每一个数据报
  20. uint16_t ipFlags; // 标志
  21. uint8_t ipTTL; // 生存时间,就是TTL
  22. uint8_t ipProtocol; // 协议,可能是TCP、UDP、ICMP等
  23. uint16_t ipChecksum; // 校验和
  24. uint32_t ipSource; // 源IP地址
  25. uint32_t ipDestination; // 目标IP地址
  26. } IPHeader, *PIPHeader;
  27. typedef int SOCKET;
  28. void ping_test(void)
  29. {
  30. const char * szDestIp = "192.168.137.1";
  31. long nRet = 0;
  32. ICMP_HDR* pIcmp = NULL;
  33. char buff[sizeof(ICMP_HDR) + 32];
  34. socklen_t nLen = 0;
  35. ICMP_HDR* pRecvIcmp = NULL;
  36. /*****************第一步:申请SOCKET************************************/
  37. uint32_t ip = inet_addr(szDestIp);
  38. SOCKET sRaw = lwip_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
  39. if(sRaw == -1) {
  40. printf("Cannot create socket! Error %d\r\n", errno);
  41. goto exit;
  42. }
  43. // 设置接收超时
  44. struct timeval tv_out;
  45. tv_out.tv_sec = 10;
  46. tv_out.tv_usec = 0;
  47. nRet = setsockopt(sRaw, SOL_SOCKET,SO_RCVTIMEO, &tv_out, sizeof(tv_out));
  48. if(-1 == nRet) {
  49. printf("Cannot set timeout! %d \r\n",errno);
  50. }
  51. /*****************第二步:组ICMP包************************************/
  52. // 创建ICMP封包
  53. pIcmp = (ICMP_HDR*)buff;
  54. // 填写ICMP封包数据
  55. pIcmp->icmp_type = 8; // 请求一个ICMP回显
  56. pIcmp->icmp_code = 0;
  57. pIcmp->icmp_id = (uint16_t)0x1234;
  58. pIcmp->icmp_checksum = 0;
  59. pIcmp->icmp_sequence = 0;
  60. pIcmp->icmp_timestamp = 0xffff;
  61. // 填充数据部分,可以为任意
  62. memset(&buff[sizeof(ICMP_HDR)], 'E', 32);
  63. /*****************第三步:发送ICMP包************************************/
  64. //设置目的地址
  65. struct sockaddr_in dest;
  66. dest.sin_family = AF_INET;
  67. dest.sin_port = htons(0);
  68. dest.sin_addr.s_addr = ip;
  69. //pIcmp->icmp_checksum = checksum((uint16_t*)buff, sizeof(ICMP_HDR) + 32); //如果ping过去没回应需要屏蔽这条
  70. //printf("icmp_checksum = %x\r\n",pIcmp->icmp_checksum);
  71. nRet = (long)sendto(sRaw, buff, sizeof(ICMP_HDR) + 32, 0, (struct sockaddr *)&dest, sizeof(dest));
  72. if(nRet == -1) {
  73. printf(" sendto() failed: %d \r\n", errno);
  74. goto exit;
  75. }
  76. printf("sendto = %ld\r\n",nRet);
  77. /*****************第四步:接收ICMP包************************************/
  78. char recvBuf[1024];
  79. struct sockaddr_in from;
  80. nLen = sizeof(from);
  81. nRet = (long)recvfrom(sRaw, recvBuf, 1024, 0, (struct sockaddr *)&from, &nLen);
  82. if(nRet == -1) {
  83. printf(" recvfrom() failed: %d\r\n", errno);
  84. goto exit;
  85. }
  86. printf("recvfrom = %ld\r\n",nRet);
  87. /*****************第五步:解析ICMP包************************************/
  88. if(nRet < sizeof(IPHeader) + sizeof(ICMP_HDR)) {
  89. printf(" Too few bytes from %s \r\n", inet_ntoa(from.sin_addr));
  90. }
  91. #if 0 // IP头解析
  92. IPHeader * header = (IPHeader*)recvBuf;
  93. struct in_addr a;
  94. a.s_addr = header->ipSource;
  95. printf("source ip %s\n", inet_ntoa(a));
  96. a.s_addr = header->ipDestination;
  97. printf("dest ip %s\n", inet_ntoa(a));
  98. #endif
  99. pRecvIcmp = (ICMP_HDR*)(recvBuf + 20); // 接收到的数据中包含IP头,IP头大小为20个字节,所以加20得到ICMP头
  100. if(pRecvIcmp->icmp_type != 0) { // 回显
  101. printf("nonecho type %d recvd \r\n", pRecvIcmp->icmp_type);
  102. goto exit;
  103. }
  104. if(pRecvIcmp->icmp_id != 0x1234) {
  105. printf(" someone else's packet! \r\n");
  106. goto exit;
  107. }
  108. printf(" %d bytes from %s:", (int)nRet, inet_ntoa(from.sin_addr));
  109. printf(" icmp_seq = %d. ", pRecvIcmp->icmp_sequence);
  110. printf(" \r\n");
  111. exit:
  112. if (sRaw != -1)
  113. lwip_close(sRaw);
  114. return ;
  115. }