2 * hwsim_test - Data connectivity test for mac80211_hwsim
3 * Copyright (c) 2009, Atheros Communications
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
13 #include <sys/ioctl.h>
14 #include <sys/socket.h>
15 #include <sys/select.h>
16 #include <netpacket/packet.h>
17 #include <net/ethernet.h>
19 #include <arpa/inet.h>
20 #include <netinet/ip.h>
22 #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
23 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
25 #define HWSIM_ETHERTYPE ETHERTYPE_IP
26 #define HWSIM_PACKETLEN 1500
28 static unsigned char addr1[ETH_ALEN], addr2[ETH_ALEN], bcast[ETH_ALEN];
30 static u_int16_t checksum(const void *buf, size_t len)
34 const u_int16_t *pos = buf;
36 for (i = 0; i < len / 2; i++)
40 sum = (sum & 0xffff) + (sum >> 16);
46 static void tx(int s, const char *ifname, int ifindex,
47 const unsigned char *src, const unsigned char *dst,
50 char buf[HWSIM_PACKETLEN], *pos;
51 struct ether_header *eth;
55 printf("TX: %s(ifindex=%d) " MACSTR " -> " MACSTR "\n",
56 ifname, ifindex, MAC2STR(src), MAC2STR(dst));
58 eth = (struct ether_header *) buf;
59 memcpy(eth->ether_dhost, dst, ETH_ALEN);
60 memcpy(eth->ether_shost, src, ETH_ALEN);
61 eth->ether_type = htons(HWSIM_ETHERTYPE);
62 ip = (struct iphdr *) (eth + 1);
63 memset(ip, 0, sizeof(*ip));
68 ip->tot_len = htons(HWSIM_PACKETLEN - sizeof(*eth));
70 ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1);
71 ip->daddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 2);
72 ip->check = checksum(ip, sizeof(*ip));
73 pos = (char *) (ip + 1);
74 for (i = 0; i < sizeof(buf) - sizeof(*eth) - sizeof(*ip); i++)
77 if (send(s, buf, sizeof(buf), 0) < 0)
83 unsigned int rx_unicast1:1;
84 unsigned int rx_broadcast1:1;
85 unsigned int rx_unicast2:1;
86 unsigned int rx_broadcast2:1;
90 static void rx(int s, int iface, const char *ifname, int ifindex,
91 struct rx_result *res)
93 char buf[HWSIM_PACKETLEN + 1], *pos;
94 struct ether_header *eth;
98 len = recv(s, buf, sizeof(buf), 0);
103 eth = (struct ether_header *) buf;
105 printf("RX: %s(ifindex=%d) " MACSTR " -> " MACSTR " (len=%d)\n",
107 MAC2STR(eth->ether_shost), MAC2STR(eth->ether_dhost), len);
109 if (len != HWSIM_PACKETLEN) {
110 printf("Ignore frame with unexpected RX length (%d)\n", len);
114 ip = (struct iphdr *) (eth + 1);
115 pos = (char *) (ip + 1);
116 for (i = 0; i < sizeof(buf) - 1 - sizeof(*eth) - sizeof(*ip); i++) {
117 if ((unsigned char) *pos != (unsigned char) i) {
118 printf("Ignore frame with unexpected contents\n");
119 printf("i=%d received=0x%x expected=0x%x\n",
120 i, (unsigned char) *pos, (unsigned char) i);
127 memcmp(eth->ether_dhost, addr1, ETH_ALEN) == 0 &&
128 memcmp(eth->ether_shost, addr2, ETH_ALEN) == 0)
129 res->rx_unicast1 = 1;
130 else if (iface == 1 &&
131 memcmp(eth->ether_dhost, bcast, ETH_ALEN) == 0 &&
132 memcmp(eth->ether_shost, addr2, ETH_ALEN) == 0)
133 res->rx_broadcast1 = 1;
134 else if (iface == 2 &&
135 memcmp(eth->ether_dhost, addr2, ETH_ALEN) == 0 &&
136 memcmp(eth->ether_shost, addr1, ETH_ALEN) == 0)
137 res->rx_unicast2 = 1;
138 else if (iface == 2 &&
139 memcmp(eth->ether_dhost, bcast, ETH_ALEN) == 0 &&
140 memcmp(eth->ether_shost, addr1, ETH_ALEN) == 0)
141 res->rx_broadcast2 = 1;
145 static void usage(void)
147 fprintf(stderr, "usage: hwsim_test [-D<DSCP>] [-t<tos>] <ifname1> <ifname2>\n");
151 int main(int argc, char *argv[])
153 int s1 = -1, s2 = -1, ret = -1, c;
155 int ifindex1, ifindex2;
156 struct sockaddr_ll ll;
159 struct rx_result res;
160 char *s_ifname, *d_ifname, *end;
164 c = getopt(argc, argv, "D:t:");
169 tos = strtol(optarg, &end, 0) << 2;
176 tos = strtol(optarg, &end, 0);
188 if (optind != argc - 2) {
193 s_ifname = argv[optind];
194 d_ifname = argv[optind + 1];
196 memset(bcast, 0xff, ETH_ALEN);
198 s1 = socket(PF_PACKET, SOCK_RAW, htons(HWSIM_ETHERTYPE));
204 s2 = socket(PF_PACKET, SOCK_RAW, htons(HWSIM_ETHERTYPE));
210 memset(&ifr, 0, sizeof(ifr));
211 strncpy(ifr.ifr_name, s_ifname, sizeof(ifr.ifr_name));
212 if (ioctl(s1, SIOCGIFINDEX, &ifr) < 0) {
213 perror("ioctl[SIOCGIFINDEX]");
216 ifindex1 = ifr.ifr_ifindex;
217 if (ioctl(s1, SIOCGIFHWADDR, &ifr) < 0) {
218 perror("ioctl[SIOCGIFHWADDR]");
221 memcpy(addr1, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
223 memset(&ifr, 0, sizeof(ifr));
224 strncpy(ifr.ifr_name, d_ifname, sizeof(ifr.ifr_name));
225 if (ioctl(s2, SIOCGIFINDEX, &ifr) < 0) {
226 perror("ioctl[SIOCGIFINDEX]");
229 ifindex2 = ifr.ifr_ifindex;
230 if (ioctl(s2, SIOCGIFHWADDR, &ifr) < 0) {
231 perror("ioctl[SIOCGIFHWADDR]");
234 memcpy(addr2, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
236 memset(&ll, 0, sizeof(ll));
237 ll.sll_family = PF_PACKET;
238 ll.sll_ifindex = ifindex1;
239 ll.sll_protocol = htons(HWSIM_ETHERTYPE);
240 if (bind(s1, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
245 memset(&ll, 0, sizeof(ll));
246 ll.sll_family = PF_PACKET;
247 ll.sll_ifindex = ifindex2;
248 ll.sll_protocol = htons(HWSIM_ETHERTYPE);
249 if (bind(s2, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
254 tx(s1, s_ifname, ifindex1, addr1, addr2, tos);
255 tx(s1, s_ifname, ifindex1, addr1, bcast, tos);
256 tx(s2, d_ifname, ifindex2, addr2, addr1, tos);
257 tx(s2, d_ifname, ifindex2, addr2, bcast, tos);
262 memset(&res, 0, sizeof(res));
269 r = select(s2 + 1, &rfds, NULL, NULL, &tv);
278 if (FD_ISSET(s1, &rfds))
279 rx(s1, 1, s_ifname, ifindex1, &res);
280 if (FD_ISSET(s2, &rfds))
281 rx(s2, 2, d_ifname, ifindex2, &res);
283 if (res.rx_unicast1 && res.rx_broadcast1 &&
284 res.rx_unicast2 && res.rx_broadcast2) {
291 printf("Did not receive all expected frames:\n"
292 "rx_unicast1=%u rx_broadcast1=%u "
293 "rx_unicast2=%u rx_broadcast2=%u\n",
294 res.rx_unicast1, res.rx_broadcast1,
295 res.rx_unicast2, res.rx_broadcast2);
297 printf("Both unicast and broadcast working in both "