hwsim_test.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*
  2. * hwsim_test - Data connectivity test for mac80211_hwsim
  3. * Copyright (c) 2009, Atheros Communications
  4. *
  5. * This software may be distributed under the terms of the BSD license.
  6. * See README for more details.
  7. */
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <unistd.h>
  12. #include <sys/ioctl.h>
  13. #include <sys/socket.h>
  14. #include <sys/select.h>
  15. #include <netpacket/packet.h>
  16. #include <net/ethernet.h>
  17. #include <net/if.h>
  18. #include <arpa/inet.h>
  19. #include <netinet/ip.h>
  20. #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
  21. #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
  22. #define HWSIM_ETHERTYPE ETHERTYPE_IP
  23. #define HWSIM_PACKETLEN 1500
  24. static unsigned char addr1[ETH_ALEN], addr2[ETH_ALEN], bcast[ETH_ALEN];
  25. static u_int16_t checksum(const void *buf, size_t len)
  26. {
  27. size_t i;
  28. u_int32_t sum = 0;
  29. const u_int16_t *pos = buf;
  30. for (i = 0; i < len / 2; i++)
  31. sum += *pos++;
  32. while (sum >> 16)
  33. sum = (sum & 0xffff) + (sum >> 16);
  34. return sum ^ 0xffff;
  35. }
  36. static void tx(int s, const char *ifname, int ifindex,
  37. const unsigned char *src, const unsigned char *dst,
  38. u_int8_t tos)
  39. {
  40. char buf[HWSIM_PACKETLEN], *pos;
  41. struct ether_header *eth;
  42. struct iphdr *ip;
  43. int i;
  44. printf("TX: %s(ifindex=%d) " MACSTR " -> " MACSTR "\n",
  45. ifname, ifindex, MAC2STR(src), MAC2STR(dst));
  46. eth = (struct ether_header *) buf;
  47. memcpy(eth->ether_dhost, dst, ETH_ALEN);
  48. memcpy(eth->ether_shost, src, ETH_ALEN);
  49. eth->ether_type = htons(HWSIM_ETHERTYPE);
  50. ip = (struct iphdr *) (eth + 1);
  51. memset(ip, 0, sizeof(*ip));
  52. ip->ihl = 5;
  53. ip->version = 4;
  54. ip->ttl = 64;
  55. ip->tos = tos;
  56. ip->tot_len = htons(HWSIM_PACKETLEN - sizeof(*eth));
  57. ip->protocol = 1;
  58. ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1);
  59. ip->daddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 2);
  60. ip->check = checksum(ip, sizeof(*ip));
  61. pos = (char *) (ip + 1);
  62. for (i = 0; i < sizeof(buf) - sizeof(*eth) - sizeof(*ip); i++)
  63. *pos++ = i;
  64. if (send(s, buf, sizeof(buf), 0) < 0)
  65. perror("send");
  66. }
  67. struct rx_result {
  68. unsigned int rx_unicast1:1;
  69. unsigned int rx_broadcast1:1;
  70. unsigned int rx_unicast2:1;
  71. unsigned int rx_broadcast2:1;
  72. };
  73. static void rx(int s, int iface, const char *ifname, int ifindex,
  74. struct rx_result *res)
  75. {
  76. char buf[HWSIM_PACKETLEN + 1], *pos;
  77. struct ether_header *eth;
  78. struct iphdr *ip;
  79. int len, i;
  80. len = recv(s, buf, sizeof(buf), 0);
  81. if (len < 0) {
  82. perror("recv");
  83. return;
  84. }
  85. eth = (struct ether_header *) buf;
  86. printf("RX: %s(ifindex=%d) " MACSTR " -> " MACSTR " (len=%d)\n",
  87. ifname, ifindex,
  88. MAC2STR(eth->ether_shost), MAC2STR(eth->ether_dhost), len);
  89. if (len != HWSIM_PACKETLEN) {
  90. printf("Ignore frame with unexpected RX length (%d)\n", len);
  91. return;
  92. }
  93. ip = (struct iphdr *) (eth + 1);
  94. pos = (char *) (ip + 1);
  95. for (i = 0; i < sizeof(buf) - 1 - sizeof(*eth) - sizeof(*ip); i++) {
  96. if ((unsigned char) *pos != (unsigned char) i) {
  97. printf("Ignore frame with unexpected contents\n");
  98. printf("i=%d received=0x%x expected=0x%x\n",
  99. i, (unsigned char) *pos, (unsigned char) i);
  100. return;
  101. }
  102. pos++;
  103. }
  104. if (iface == 1 &&
  105. memcmp(eth->ether_dhost, addr1, ETH_ALEN) == 0 &&
  106. memcmp(eth->ether_shost, addr2, ETH_ALEN) == 0)
  107. res->rx_unicast1 = 1;
  108. else if (iface == 1 &&
  109. memcmp(eth->ether_dhost, bcast, ETH_ALEN) == 0 &&
  110. memcmp(eth->ether_shost, addr2, ETH_ALEN) == 0)
  111. res->rx_broadcast1 = 1;
  112. else if (iface == 2 &&
  113. memcmp(eth->ether_dhost, addr2, ETH_ALEN) == 0 &&
  114. memcmp(eth->ether_shost, addr1, ETH_ALEN) == 0)
  115. res->rx_unicast2 = 1;
  116. else if (iface == 2 &&
  117. memcmp(eth->ether_dhost, bcast, ETH_ALEN) == 0 &&
  118. memcmp(eth->ether_shost, addr1, ETH_ALEN) == 0)
  119. res->rx_broadcast2 = 1;
  120. }
  121. static void usage(void)
  122. {
  123. fprintf(stderr, "usage: hwsim_test [-D<DSCP>] [-t<tos>] <ifname1> <ifname2>\n");
  124. }
  125. int main(int argc, char *argv[])
  126. {
  127. int s1 = -1, s2 = -1, ret = -1, c;
  128. struct ifreq ifr;
  129. int ifindex1, ifindex2;
  130. struct sockaddr_ll ll;
  131. fd_set rfds;
  132. struct timeval tv;
  133. struct rx_result res;
  134. char *s_ifname, *d_ifname, *end;
  135. int tos = 0;
  136. for (;;) {
  137. c = getopt(argc, argv, "D:t:");
  138. if (c < 0)
  139. break;
  140. switch (c) {
  141. case 'D':
  142. tos = strtol(optarg, &end, 0) << 2;
  143. if (*end) {
  144. usage();
  145. return -1;
  146. }
  147. break;
  148. case 't':
  149. tos = strtol(optarg, &end, 0);
  150. if (*end) {
  151. usage();
  152. return -1;
  153. }
  154. break;
  155. default:
  156. usage();
  157. return -1;
  158. }
  159. }
  160. if (optind != argc - 2) {
  161. usage();
  162. return -1;
  163. }
  164. s_ifname = argv[optind];
  165. d_ifname = argv[optind + 1];
  166. memset(bcast, 0xff, ETH_ALEN);
  167. s1 = socket(PF_PACKET, SOCK_RAW, htons(HWSIM_ETHERTYPE));
  168. if (s1 < 0) {
  169. perror("socket");
  170. goto fail;
  171. }
  172. s2 = socket(PF_PACKET, SOCK_RAW, htons(HWSIM_ETHERTYPE));
  173. if (s2 < 0) {
  174. perror("socket");
  175. goto fail;
  176. }
  177. memset(&ifr, 0, sizeof(ifr));
  178. strncpy(ifr.ifr_name, s_ifname, sizeof(ifr.ifr_name));
  179. if (ioctl(s1, SIOCGIFINDEX, &ifr) < 0) {
  180. perror("ioctl[SIOCGIFINDEX]");
  181. goto fail;
  182. }
  183. ifindex1 = ifr.ifr_ifindex;
  184. if (ioctl(s1, SIOCGIFHWADDR, &ifr) < 0) {
  185. perror("ioctl[SIOCGIFHWADDR]");
  186. goto fail;
  187. }
  188. memcpy(addr1, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
  189. memset(&ifr, 0, sizeof(ifr));
  190. strncpy(ifr.ifr_name, d_ifname, sizeof(ifr.ifr_name));
  191. if (ioctl(s2, SIOCGIFINDEX, &ifr) < 0) {
  192. perror("ioctl[SIOCGIFINDEX]");
  193. goto fail;
  194. }
  195. ifindex2 = ifr.ifr_ifindex;
  196. if (ioctl(s2, SIOCGIFHWADDR, &ifr) < 0) {
  197. perror("ioctl[SIOCGIFHWADDR]");
  198. goto fail;
  199. }
  200. memcpy(addr2, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
  201. memset(&ll, 0, sizeof(ll));
  202. ll.sll_family = PF_PACKET;
  203. ll.sll_ifindex = ifindex1;
  204. ll.sll_protocol = htons(HWSIM_ETHERTYPE);
  205. if (bind(s1, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
  206. perror("bind");
  207. goto fail;
  208. }
  209. memset(&ll, 0, sizeof(ll));
  210. ll.sll_family = PF_PACKET;
  211. ll.sll_ifindex = ifindex2;
  212. ll.sll_protocol = htons(HWSIM_ETHERTYPE);
  213. if (bind(s2, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
  214. perror("bind");
  215. goto fail;
  216. }
  217. tx(s1, s_ifname, ifindex1, addr1, addr2, tos);
  218. tx(s1, s_ifname, ifindex1, addr1, bcast, tos);
  219. tx(s2, d_ifname, ifindex2, addr2, addr1, tos);
  220. tx(s2, d_ifname, ifindex2, addr2, bcast, tos);
  221. tv.tv_sec = 1;
  222. tv.tv_usec = 0;
  223. memset(&res, 0, sizeof(res));
  224. for (;;) {
  225. int r;
  226. FD_ZERO(&rfds);
  227. FD_SET(s1, &rfds);
  228. FD_SET(s2, &rfds);
  229. r = select(s2 + 1, &rfds, NULL, NULL, &tv);
  230. if (r < 0) {
  231. perror("select");
  232. goto fail;
  233. }
  234. if (r == 0)
  235. break; /* timeout */
  236. if (FD_ISSET(s1, &rfds))
  237. rx(s1, 1, s_ifname, ifindex1, &res);
  238. if (FD_ISSET(s2, &rfds))
  239. rx(s2, 2, d_ifname, ifindex2, &res);
  240. if (res.rx_unicast1 && res.rx_broadcast1 &&
  241. res.rx_unicast2 && res.rx_broadcast2) {
  242. ret = 0;
  243. break;
  244. }
  245. }
  246. if (ret) {
  247. printf("Did not receive all expected frames:\n"
  248. "rx_unicast1=%u rx_broadcast1=%u "
  249. "rx_unicast2=%u rx_broadcast2=%u\n",
  250. res.rx_unicast1, res.rx_broadcast1,
  251. res.rx_unicast2, res.rx_broadcast2);
  252. } else {
  253. printf("Both unicast and broadcast working in both "
  254. "directions\n");
  255. }
  256. fail:
  257. close(s1);
  258. close(s2);
  259. return ret;
  260. }