2 * hwsim_test - Data connectivity test for mac80211_hwsim
3 * Copyright (c) 2009, Atheros Communications
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
19 #include <sys/ioctl.h>
20 #include <sys/socket.h>
21 #include <sys/select.h>
22 #include <netpacket/packet.h>
23 #include <net/ethernet.h>
25 #include <arpa/inet.h>
27 #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
28 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
30 #define HWSIM_ETHERTYPE ETHERTYPE_IP
31 #define HWSIM_PACKETLEN 1500
33 static unsigned char addr1
[ETH_ALEN
], addr2
[ETH_ALEN
], bcast
[ETH_ALEN
];
35 static void tx(int s
, const char *ifname
, int ifindex
,
36 const unsigned char *src
, const unsigned char *dst
)
38 char buf
[HWSIM_PACKETLEN
], *pos
;
39 struct ether_header
*eth
;
42 printf("TX: %s(ifindex=%d) " MACSTR
" -> " MACSTR
"\n",
43 ifname
, ifindex
, MAC2STR(src
), MAC2STR(dst
));
45 eth
= (struct ether_header
*) buf
;
46 memcpy(eth
->ether_dhost
, dst
, ETH_ALEN
);
47 memcpy(eth
->ether_shost
, src
, ETH_ALEN
);
48 eth
->ether_type
= htons(HWSIM_ETHERTYPE
);
49 pos
= (char *) (eth
+ 1);
50 for (i
= 0; i
< sizeof(buf
) - sizeof(*eth
); i
++)
53 if (send(s
, buf
, sizeof(buf
), 0) < 0)
66 static void rx(int s
, int iface
, const char *ifname
, int ifindex
,
67 struct rx_result
*res
)
69 char buf
[HWSIM_PACKETLEN
+ 1], *pos
;
70 struct ether_header
*eth
;
73 len
= recv(s
, buf
, sizeof(buf
), 0);
78 eth
= (struct ether_header
*) buf
;
80 printf("RX: %s(ifindex=%d) " MACSTR
" -> " MACSTR
" (len=%d)\n",
82 MAC2STR(eth
->ether_shost
), MAC2STR(eth
->ether_dhost
), len
);
84 if (len
!= HWSIM_PACKETLEN
) {
85 printf("Ignore frame with unexpected RX length\n");
89 pos
= (char *) (eth
+ 1);
90 for (i
= 0; i
< sizeof(buf
) - 1 - sizeof(*eth
); i
++) {
91 if ((unsigned char) *pos
!= (unsigned char) i
) {
92 printf("Ignore frame with unexpected contents\n");
93 printf("i=%d received=0x%x expected=0x%x\n",
94 i
, (unsigned char) *pos
, (unsigned char) i
);
101 memcmp(eth
->ether_dhost
, addr1
, ETH_ALEN
) == 0 &&
102 memcmp(eth
->ether_shost
, addr2
, ETH_ALEN
) == 0)
103 res
->rx_unicast1
= 1;
104 else if (iface
== 1 &&
105 memcmp(eth
->ether_dhost
, bcast
, ETH_ALEN
) == 0 &&
106 memcmp(eth
->ether_shost
, addr2
, ETH_ALEN
) == 0)
107 res
->rx_broadcast1
= 1;
108 else if (iface
== 2 &&
109 memcmp(eth
->ether_dhost
, addr2
, ETH_ALEN
) == 0 &&
110 memcmp(eth
->ether_shost
, addr1
, ETH_ALEN
) == 0)
111 res
->rx_unicast2
= 1;
112 else if (iface
== 2 &&
113 memcmp(eth
->ether_dhost
, bcast
, ETH_ALEN
) == 0 &&
114 memcmp(eth
->ether_shost
, addr1
, ETH_ALEN
) == 0)
115 res
->rx_broadcast2
= 1;
119 int main(int argc
, char *argv
[])
121 int s1
= -1, s2
= -1, ret
= -1;
123 int ifindex1
, ifindex2
;
124 struct sockaddr_ll ll
;
127 struct rx_result res
;
130 fprintf(stderr
, "usage: hwsim_test <ifname1> <ifname2>\n");
134 memset(bcast
, 0xff, ETH_ALEN
);
136 s1
= socket(PF_PACKET
, SOCK_RAW
, htons(HWSIM_ETHERTYPE
));
142 s2
= socket(PF_PACKET
, SOCK_RAW
, htons(HWSIM_ETHERTYPE
));
148 memset(&ifr
, 0, sizeof(ifr
));
149 strncpy(ifr
.ifr_name
, argv
[1], sizeof(ifr
.ifr_name
));
150 if (ioctl(s1
, SIOCGIFINDEX
, &ifr
) < 0) {
151 perror("ioctl[SIOCGIFINDEX]");
154 ifindex1
= ifr
.ifr_ifindex
;
155 if (ioctl(s1
, SIOCGIFHWADDR
, &ifr
) < 0) {
156 perror("ioctl[SIOCGIFHWADDR]");
159 memcpy(addr1
, ifr
.ifr_hwaddr
.sa_data
, ETH_ALEN
);
161 memset(&ifr
, 0, sizeof(ifr
));
162 strncpy(ifr
.ifr_name
, argv
[2], sizeof(ifr
.ifr_name
));
163 if (ioctl(s2
, SIOCGIFINDEX
, &ifr
) < 0) {
164 perror("ioctl[SIOCGIFINDEX]");
167 ifindex2
= ifr
.ifr_ifindex
;
168 if (ioctl(s2
, SIOCGIFHWADDR
, &ifr
) < 0) {
169 perror("ioctl[SIOCGIFHWADDR]");
172 memcpy(addr2
, ifr
.ifr_hwaddr
.sa_data
, ETH_ALEN
);
174 memset(&ll
, 0, sizeof(ll
));
175 ll
.sll_family
= PF_PACKET
;
176 ll
.sll_ifindex
= ifindex1
;
177 ll
.sll_protocol
= htons(HWSIM_ETHERTYPE
);
178 if (bind(s1
, (struct sockaddr
*) &ll
, sizeof(ll
)) < 0) {
183 memset(&ll
, 0, sizeof(ll
));
184 ll
.sll_family
= PF_PACKET
;
185 ll
.sll_ifindex
= ifindex2
;
186 ll
.sll_protocol
= htons(HWSIM_ETHERTYPE
);
187 if (bind(s2
, (struct sockaddr
*) &ll
, sizeof(ll
)) < 0) {
192 tx(s1
, argv
[1], ifindex1
, addr1
, addr2
);
193 tx(s1
, argv
[1], ifindex1
, addr1
, bcast
);
194 tx(s2
, argv
[2], ifindex2
, addr2
, addr1
);
195 tx(s2
, argv
[2], ifindex2
, addr2
, bcast
);
200 memset(&res
, 0, sizeof(res
));
207 r
= select(s2
+ 1, &rfds
, NULL
, NULL
, &tv
);
216 if (FD_SET(s1
, &rfds
))
217 rx(s1
, 1, argv
[1], ifindex1
, &res
);
218 if (FD_SET(s2
, &rfds
))
219 rx(s2
, 2, argv
[2], ifindex2
, &res
);
221 if (res
.rx_unicast1
&& res
.rx_broadcast1
&&
222 res
.rx_unicast2
&& res
.rx_broadcast2
) {
229 printf("Did not receive all expected frames:\n"
230 "rx_unicast1=%d rx_broadcast1=%d "
231 "rx_unicast2=%d rx_broadcast2=%d\n",
232 res
.rx_unicast1
, res
.rx_broadcast1
,
233 res
.rx_unicast2
, res
.rx_broadcast2
);
235 printf("Both unicast and broadcast working in both "