RyanW5500Ping.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #define DBG_ENABLE
  2. #define DBG_SECTION_NAME ("RyanW5500Ping")
  3. #define DBG_LEVEL LOG_LVL_INFO
  4. #define DBG_COLOR
  5. #include "RyanW5500Store.h"
  6. #define Sn_PROTO(ch) (0x001408 + (ch << 5))
  7. #define WIZ_PING_DATA_LEN 32
  8. #define WIZ_PING_HEAD_LEN 8
  9. #define WIZ_PING_PORT 3000
  10. #define WIZ_PING_REQUEST 8
  11. #define WIZ_PING_REPLY 0
  12. #define WIZ_PING_CODE 0
  13. #define WIZ_PING_DELAY (1000)
  14. #define WIZ_PING_TIMEOUT (2000)
  15. struct wiz_ping_msg
  16. {
  17. uint8_t type; // 0 - Ping Reply, 8 - Ping Request
  18. uint8_t code; // Always 0
  19. uint16_t check_sum; // Check sum
  20. uint16_t id; // Identification
  21. uint16_t seq_num; // Sequence Number
  22. int8_t data[WIZ_PING_DATA_LEN]; // Ping Data : 1452 = IP RAW MTU - sizeof(type+code+check_sum+id+seq_num)
  23. };
  24. /**
  25. * @brief 计算字符串校验值
  26. *
  27. * @param src
  28. * @param len
  29. * @return uint16_t
  30. */
  31. static uint16_t wiz_checksum(uint8_t *src, uint32_t len)
  32. {
  33. uint16_t sum, tsum, i, j;
  34. uint32_t lsum;
  35. j = len >> 1;
  36. lsum = 0;
  37. for (i = 0; i < j; i++)
  38. {
  39. tsum = src[i * 2];
  40. tsum = tsum << 8;
  41. tsum += src[i * 2 + 1];
  42. lsum += tsum;
  43. }
  44. if (len % 2)
  45. {
  46. tsum = src[i * 2];
  47. lsum += (tsum << 8);
  48. }
  49. sum = lsum;
  50. sum = ~(sum + (lsum >> 16));
  51. return (uint16_t)sum;
  52. }
  53. static int wiz_ping_request(int socket)
  54. {
  55. int idx, send_len;
  56. uint16_t tmp_checksum;
  57. struct wiz_ping_msg ping_req;
  58. // 设置请求ping消息对象
  59. ping_req.type = WIZ_PING_REQUEST;
  60. ping_req.code = WIZ_PING_CODE;
  61. ping_req.id = htons(rand() % 0xffff);
  62. ping_req.seq_num = htons(rand() % 0xffff);
  63. for (idx = 0; idx < WIZ_PING_DATA_LEN; idx++)
  64. ping_req.data[idx] = (idx) % 8;
  65. ping_req.check_sum = 0;
  66. // 计算请求ping消息校验值
  67. tmp_checksum = wiz_checksum((uint8_t *)&ping_req, sizeof(ping_req));
  68. ping_req.check_sum = htons(tmp_checksum);
  69. // 发送请求ping消息
  70. send_len = wiz_send(socket, &ping_req, sizeof(ping_req), 0);
  71. if (send_len != sizeof(ping_req))
  72. return -1;
  73. return send_len - WIZ_PING_HEAD_LEN;
  74. }
  75. static int wiz_ping_reply(int socket, struct sockaddr *from)
  76. {
  77. uint16_t tmp_checksum;
  78. uint8_t recv_buf[WIZ_PING_HEAD_LEN + WIZ_PING_DATA_LEN + 1];
  79. struct wiz_ping_msg ping_rep;
  80. int recv_len;
  81. int idx;
  82. platformTimer_t pingReplyTimer = {0};
  83. platformTimerCutdown(&pingReplyTimer, WIZ_PING_TIMEOUT);
  84. while (1)
  85. {
  86. if (0 == platformTimerRemain(&pingReplyTimer))
  87. return -1;
  88. struct sockaddr *sin = (struct sockaddr *)from;
  89. socklen_t addr_len = sizeof(struct sockaddr_in);
  90. recv_len = wiz_recvfrom(socket, recv_buf, WIZ_PING_HEAD_LEN + WIZ_PING_DATA_LEN, 0, sin, &addr_len);
  91. if (recv_len < 0)
  92. return -1;
  93. break;
  94. }
  95. switch (recv_buf[0])
  96. {
  97. case WIZ_PING_REPLY:
  98. ping_rep.type = recv_buf[0];
  99. ping_rep.code = recv_buf[1];
  100. ping_rep.check_sum = (recv_buf[3] << 8) + recv_buf[2];
  101. ping_rep.id = (recv_buf[5] << 8) + recv_buf[4];
  102. ping_rep.seq_num = (recv_buf[7] << 8) + recv_buf[6];
  103. for (idx = 0; idx < recv_len - 8; idx++)
  104. ping_rep.data[idx] = recv_buf[8 + idx];
  105. tmp_checksum = ~wiz_checksum(recv_buf, recv_len);
  106. if (tmp_checksum != 0xffff)
  107. return -2;
  108. break;
  109. case WIZ_PING_REQUEST:
  110. ping_rep.code = recv_buf[1];
  111. ping_rep.type = recv_buf[2];
  112. ping_rep.check_sum = (recv_buf[3] << 8) + recv_buf[2];
  113. ping_rep.id = (recv_buf[5] << 8) + recv_buf[4];
  114. ping_rep.seq_num = (recv_buf[7] << 8) + recv_buf[6];
  115. for (idx = 0; idx < recv_len - 8; idx++)
  116. ping_rep.data[idx] = recv_buf[8 + idx];
  117. tmp_checksum = ping_rep.check_sum;
  118. ping_rep.check_sum = 0;
  119. if (tmp_checksum != ping_rep.check_sum)
  120. return -2;
  121. break;
  122. default:
  123. LOG_W("unknown ping receive message.");
  124. return -1;
  125. }
  126. return recv_len - WIZ_PING_HEAD_LEN;
  127. }
  128. int RyanW5500Ping(struct netdev *netdev, const char *host, size_t data_len, uint32_t times, struct netdev_ping_resp *ping_resp)
  129. {
  130. int result = 0,
  131. socket = 0;
  132. struct hostent *hostent = NULL;
  133. hostent = wiz_gethostbyname(host);
  134. if (NULL == hostent || NULL == hostent->h_addr_list[0])
  135. {
  136. LOG_W("hostent is NULL.");
  137. return -RT_FALSE;
  138. }
  139. struct in_addr serviceAddr = *(struct in_addr *)hostent->h_addr_list[0];
  140. // SOCK_RAW == Sn_MR_IPRAW == 3
  141. socket = wiz_socket(AF_WIZ, SOCK_RAW, 0);
  142. if (socket < 0)
  143. {
  144. LOG_W("create ping socket(%d) failed.", socket);
  145. return -1;
  146. }
  147. // 设置套接字ICMP协议
  148. IINCHIP_WRITE(Sn_PROTO(socket), IPPROTO_ICMP);
  149. struct timeval timeout = {.tv_sec = times,
  150. .tv_usec = times % 1000 * 1000};
  151. // 设置接收和发送超时选项
  152. wiz_setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout,
  153. sizeof(timeout));
  154. wiz_setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (void *)&timeout,
  155. sizeof(timeout));
  156. struct sockaddr_in server_addr = {.sin_family = AF_WIZ,
  157. .sin_port = htons(WIZ_PING_PORT),
  158. .sin_addr = serviceAddr};
  159. if (wiz_connect(socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
  160. {
  161. wiz_closesocket(socket);
  162. return -1;
  163. }
  164. result = wiz_ping_request(socket);
  165. platformTimer_t pingTimer = {0};
  166. platformTimerCutdown(&pingTimer, 0xffff);
  167. if (result > 0)
  168. {
  169. result = wiz_ping_reply(socket, (struct sockaddr *)&server_addr);
  170. ping_resp->ip_addr.addr = serviceAddr.s_addr;
  171. ping_resp->ticks = 0xffff - platformTimerRemain(&pingTimer);
  172. ping_resp->data_len = data_len;
  173. wiz_getsockopt(socket, IPPROTO_IP, IP_TTL, &ping_resp->ttl, sizeof(ping_resp->ttl));
  174. }
  175. wiz_closesocket(socket);
  176. return result;
  177. }