PingTest.c
上传用户:yyyd609
上传日期:2022-07-18
资源大小:183k
文件大小:5k
源码类别:

微处理器开发

开发平台:

C/C++

  1. /*****************************************************************************
  2. *                                                                             *
  3. *  以太网控制器测试模块                                                       *
  4. *                                                                             *
  5. *  该模块实现了基于以太网的ARP回应和ICMP回应                                  *
  6. *                                                                             *
  7. *****************************************************************************/
  8. #include "PingTest.h"
  9. #include "Ethernet.h"
  10. // 本地IP地址
  11. // TODO: 可根据需要改为其它地址
  12. IP_ADDR g_LocalIPAddr = 192u << 24 | 168u << 16 | 196u << 8 | 200u;
  13. // 以太网协议头
  14. typedef struct eth_hdr {
  15. u16 padding;
  16. ETH_ADDR dest, src;
  17. u16 type;
  18. } ETH_HDR;
  19. #define ETHTYPE_ARP 0x0806
  20. #define ETHTYPE_IP 0x0800
  21. // ARP协议头
  22. typedef struct arp_hdr {
  23. u16 hwtype;
  24. u16 proto;
  25. u16 _hwlen_protolen;
  26. u16 opcode;
  27. ETH_ADDR shwaddr;
  28. u16 sip_h, sip_l;
  29. ETH_ADDR dhwaddr;
  30. u16 dip_h, dip_l;
  31. } ARP_HDR;
  32. #define ARP_REQUEST 1
  33. #define ARP_REPLY 2
  34. // IP协议头
  35. typedef struct ip_hdr {
  36. u16 _v_hl_tos; // version / header length / type of service
  37. u16 len; // total length
  38. u16 id; // identification
  39. u16 offset; // fragment offset field
  40. #define IP_RF 0x8000 // reserved fragment flag
  41. #define IP_DF 0x4000 // dont fragment flag
  42. #define IP_MF 0x2000 // more fragments flag
  43. #define IP_OFFMASK 0x1fff // mask for fragmenting bits
  44. u8 ttl, proto; // time to live / protocol
  45. u16 chksum; // checksum
  46. IP_ADDR src, dest; // source and destination IP addresses
  47. } IP_HDR;
  48. #define IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12)
  49. #define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 6) & 0x3c)
  50. #define IP_PROTO_ICMP 1
  51. // ICMP协议头
  52. typedef struct icmp_hdr {
  53. u8 type, code;
  54. u16 chksum;
  55. u16 id;
  56. u16 seqno;
  57. } ICMP_HDR;
  58. #define ICMP_ER 0
  59. #define ICMP_ECHO 8
  60. // 交换字节顺序(双字节)
  61. __inline u16 bswap16(u16 x)
  62. {
  63. return x << 8 | x >> 8;
  64. }
  65. // 交换字节顺序(四字节)
  66. __inline u32 bswap32(u32 x)
  67. {
  68. return x << 24 | x << 8 & 0x00ff0000
  69. | x >> 8 & 0x0000ff00 | x >> 24;
  70. }
  71. #define htons bswap16
  72. #define htonl bswap32
  73. #define ntohs htons
  74. #define ntohl htonl
  75. // 计算校验和
  76. static u32 inet_chksum(void *dataptr, int len)
  77. {
  78. u32 acc;
  79. for(acc = 0; len > 1; len -= 2)
  80. {
  81. acc += *(u16 *)dataptr;
  82. dataptr = (u16 *)dataptr + 1;
  83. }
  84. if(len)
  85. acc += htons((*(u8 *)dataptr) << 8);
  86. while(acc >> 16)
  87. acc = (acc & 0xffff) + (acc >> 16);
  88. return acc ^ 0xffff;
  89. }
  90. // 回应IP包
  91. static void ip_reply(IP_HDR *iphdr, int len)
  92. {
  93. ETH_HDR *ethhdr = (ETH_HDR *)iphdr - 1;
  94. int i;
  95. iphdr->dest = iphdr->src;
  96. iphdr->src = htonl(g_LocalIPAddr);
  97. iphdr->len = htons(len);
  98. iphdr->id = 0;
  99. iphdr->offset = htons(IP_DF);
  100. iphdr->chksum = 0;
  101. iphdr->chksum = inet_chksum(iphdr, sizeof(IP_HDR));
  102. for(i = 0; i < 3; i++)
  103. {
  104. ethhdr->dest[i] = ethhdr->src[i];
  105. ethhdr->src[i] = local_eth_addr[i];
  106. }
  107. NIC_SendPack((u16 *)ethhdr + 1, len + (sizeof(ETH_HDR) - 2));
  108. }
  109. // 处理ICMP输入
  110. static void icmp_input(IP_HDR *iphdr, int len)
  111. {
  112. ICMP_HDR *icmphdr;
  113. if(len < sizeof(IP_HDR) + sizeof(ICMP_HDR))
  114. return;
  115. icmphdr = (ICMP_HDR *)(iphdr + 1);
  116. if(icmphdr->type != ICMP_ECHO)
  117. return;
  118. if(inet_chksum(icmphdr, len - sizeof(IP_HDR)))
  119. return;
  120. icmphdr->type = ICMP_ER;
  121. if(icmphdr->chksum >= htons(0xffff - (ICMP_ECHO << 8)))
  122. icmphdr->chksum += htons(ICMP_ECHO << 8) + 1;
  123. else
  124. icmphdr->chksum += htons(ICMP_ECHO << 8);
  125. ip_reply(iphdr, len);
  126. }
  127. // 处理IP输入
  128. static void ip_input(IP_HDR *iphdr, int len)
  129. {
  130. if(IPH_V(iphdr) != 4)
  131. return;
  132. if(IPH_HL(iphdr) != sizeof(IP_HDR))
  133. return;
  134. if(inet_chksum(iphdr, sizeof(IP_HDR)))
  135. return;
  136. if(iphdr->offset & htons(IP_OFFMASK | IP_MF))
  137. return;
  138. switch(iphdr->proto)
  139. {
  140. case IP_PROTO_ICMP:
  141. icmp_input(iphdr, len);
  142. break;
  143. }
  144. }
  145. // 处理ARP输入
  146. static void arp_input(ETH_HDR *ethhdr, int len)
  147. {
  148. int i;
  149. ARP_HDR *arphdr;
  150. if(len < sizeof(ETH_HDR) + sizeof(ARP_HDR))
  151. return;
  152. arphdr = (ARP_HDR *)(ethhdr + 1);
  153. if((ntohs(arphdr->dip_h) << 16 | ntohs(arphdr->dip_l)) != g_LocalIPAddr)
  154. return;
  155. switch(ntohs(arphdr->opcode))
  156. {
  157. case ARP_REQUEST:
  158. arphdr->opcode = htons(ARP_REPLY);
  159. arphdr->dip_h = arphdr->sip_h;
  160. arphdr->dip_l = arphdr->sip_l;
  161. arphdr->sip_h = htons(g_LocalIPAddr >> 16);
  162. arphdr->sip_l = htons(g_LocalIPAddr & 0xffff);
  163. for(i = 0; i < 3; i++)
  164. {
  165. ethhdr->dest[i] = arphdr->dhwaddr[i] = arphdr->shwaddr[i];
  166. ethhdr->src[i] = arphdr->shwaddr[i] = local_eth_addr[i];
  167. }
  168. NIC_SendPack((u16 *)ethhdr + 1, len - 2);
  169. break;
  170. }
  171. }
  172. // 处理以太网输入
  173. static void eth_input(ETH_HDR *ethhdr, int len)
  174. {
  175. switch(htons(ethhdr->type))
  176. {
  177. case ETHTYPE_ARP:
  178. arp_input(ethhdr, len);
  179. break;
  180. case ETHTYPE_IP:
  181. ip_input((IP_HDR *)(ethhdr + 1), len - sizeof(ETH_HDR));
  182. break;
  183. }
  184. }
  185. ///////////////////////////////////////////////////////////////////////////////
  186. //
  187. // 功能:
  188. // 以太网测试入口函数
  189. // 参数:
  190. // buf 以太网数据包地址,必须按4字节对齐,必须在开头包含2字节填充
  191. // len 数据包长度(包括2字节填充)
  192. // 返回值:
  193. // 无
  194. //
  195. void PingTest_Input(void *buf, int len)
  196. {
  197. eth_input((ETH_HDR *)buf, len);
  198. }