rx_ip.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*
  2. * Received Data frame processing for IPv4 packets
  3. * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  4. *
  5. * This software may be distributed under the terms of the BSD license.
  6. * See README for more details.
  7. */
  8. #include "utils/includes.h"
  9. #include <netinet/ip.h>
  10. #include <netinet/ip_icmp.h>
  11. #include "utils/common.h"
  12. #include "wlantest.h"
  13. static void ping_update(struct wlantest *wt, struct wlantest_sta *sta, int req,
  14. u32 src, u32 dst, u16 id, u16 seq)
  15. {
  16. if (req) {
  17. sta->icmp_echo_req_src = src;
  18. sta->icmp_echo_req_dst = dst;
  19. sta->icmp_echo_req_id = id;
  20. sta->icmp_echo_req_seq = seq;
  21. return;
  22. }
  23. if (sta->icmp_echo_req_src == dst &&
  24. sta->icmp_echo_req_dst == src &&
  25. sta->icmp_echo_req_id == id &&
  26. sta->icmp_echo_req_seq == seq) {
  27. sta->counters[WLANTEST_STA_COUNTER_PING_OK]++;
  28. if (sta->counters[WLANTEST_STA_COUNTER_ASSOCREQ_TX] == 0 &&
  29. sta->counters[WLANTEST_STA_COUNTER_REASSOCREQ_TX] == 0)
  30. sta->counters[
  31. WLANTEST_STA_COUNTER_PING_OK_FIRST_ASSOC]++;
  32. add_note(wt, MSG_DEBUG, "ICMP echo (ping) match for STA "
  33. MACSTR, MAC2STR(sta->addr));
  34. }
  35. }
  36. static void rx_data_icmp(struct wlantest *wt, const u8 *bssid,
  37. const u8 *sta_addr, u32 dst, u32 src,
  38. const u8 *data, size_t len, const u8 *peer_addr)
  39. {
  40. struct in_addr addr;
  41. char buf[20];
  42. const struct icmphdr *hdr;
  43. u16 id, seq;
  44. struct wlantest_bss *bss;
  45. struct wlantest_sta *sta;
  46. hdr = (const struct icmphdr *) data;
  47. if (len < 4)
  48. return;
  49. /* TODO: check hdr->checksum */
  50. if (hdr->type != ICMP_ECHOREPLY && hdr->type != ICMP_ECHO)
  51. return;
  52. if (len < 8)
  53. return;
  54. id = ntohs(hdr->un.echo.id);
  55. seq = ntohs(hdr->un.echo.sequence);
  56. addr.s_addr = dst;
  57. snprintf(buf, sizeof(buf), "%s", inet_ntoa(addr));
  58. addr.s_addr = src;
  59. add_note(wt, MSG_DEBUG, "ICMP echo %s %s -> %s id=%04x seq=%u len=%u%s",
  60. hdr->type == ICMP_ECHO ? "request" : "response",
  61. inet_ntoa(addr), buf, id, seq, (unsigned) len - 8,
  62. peer_addr ? " [DL]" : "");
  63. bss = bss_find(wt, bssid);
  64. if (bss == NULL) {
  65. add_note(wt, MSG_INFO, "No BSS " MACSTR
  66. " known for ICMP packet", MAC2STR(bssid));
  67. return;
  68. }
  69. if (sta_addr == NULL)
  70. return; /* FromDS broadcast ping */
  71. sta = sta_find(bss, sta_addr);
  72. if (sta == NULL) {
  73. add_note(wt, MSG_INFO, "No STA " MACSTR
  74. " known for ICMP packet", MAC2STR(sta_addr));
  75. return;
  76. }
  77. ping_update(wt, sta, hdr->type == ICMP_ECHO, src, dst, id, seq);
  78. if (peer_addr && (sta = sta_find(bss, peer_addr)))
  79. ping_update(wt, sta, hdr->type == ICMP_ECHO, src, dst, id, seq);
  80. }
  81. static int hwsim_test_packet(const u8 *data, size_t len)
  82. {
  83. size_t i;
  84. if (len != 1500 - 14)
  85. return 0;
  86. for (i = 0; i < len; i++) {
  87. if (data[i] != (i & 0xff))
  88. return 0;
  89. }
  90. return 1;
  91. }
  92. void rx_data_ip(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr,
  93. const u8 *dst, const u8 *src, const u8 *data, size_t len,
  94. const u8 *peer_addr)
  95. {
  96. const struct iphdr *ip;
  97. const u8 *payload;
  98. size_t plen;
  99. u16 frag_off, tot_len;
  100. ip = (const struct iphdr *) data;
  101. if (len < sizeof(*ip))
  102. return;
  103. if (ip->version != 4) {
  104. if (hwsim_test_packet(data, len)) {
  105. add_note(wt, MSG_INFO, "hwsim_test package");
  106. return;
  107. }
  108. add_note(wt, MSG_DEBUG, "Unexpected IP protocol version %u in "
  109. "IPv4 packet (bssid=" MACSTR " str=" MACSTR
  110. " dst=" MACSTR ")", ip->version, MAC2STR(bssid),
  111. MAC2STR(src), MAC2STR(dst));
  112. return;
  113. }
  114. if (ip->ihl * 4 < sizeof(*ip)) {
  115. add_note(wt, MSG_DEBUG, "Unexpected IP header length %u in "
  116. "IPv4 packet (bssid=" MACSTR " str=" MACSTR
  117. " dst=" MACSTR ")", ip->ihl, MAC2STR(bssid),
  118. MAC2STR(src), MAC2STR(dst));
  119. return;
  120. }
  121. if (ip->ihl * 4 > len) {
  122. add_note(wt, MSG_DEBUG, "Truncated IP header (ihl=%u len=%u) "
  123. "in IPv4 packet (bssid=" MACSTR " str=" MACSTR
  124. " dst=" MACSTR ")", ip->ihl, (unsigned) len,
  125. MAC2STR(bssid), MAC2STR(src), MAC2STR(dst));
  126. return;
  127. }
  128. /* TODO: check header checksum in ip->check */
  129. frag_off = be_to_host16(ip->frag_off);
  130. if (frag_off & 0x1fff) {
  131. wpa_printf(MSG_EXCESSIVE, "IP fragment reassembly not yet "
  132. "supported");
  133. return;
  134. }
  135. tot_len = be_to_host16(ip->tot_len);
  136. if (tot_len > len)
  137. return;
  138. if (tot_len < len)
  139. len = tot_len;
  140. payload = data + 4 * ip->ihl;
  141. plen = len - 4 * ip->ihl;
  142. switch (ip->protocol) {
  143. case IPPROTO_ICMP:
  144. rx_data_icmp(wt, bssid, sta_addr, ip->daddr, ip->saddr,
  145. payload, plen, peer_addr);
  146. break;
  147. }
  148. }