diff options
author | Jouni Malinen <jouni.malinen@atheros.com> | 2009-05-07 17:59:53 +0300 |
---|---|---|
committer | Jouni Malinen <j@w1.fi> | 2009-05-07 17:59:53 +0300 |
commit | 9e8cda5a46edc708b21589ad3c66ab869febb299 (patch) | |
tree | b82dd3ec16055349293dcca83536ea969d16df89 /mac80211_hwsim | |
parent | 92305c5d9a79a783d9f495f29e3e0fc06e66ed0a (diff) | |
download | external_wpa_supplicant_8_ti-9e8cda5a46edc708b21589ad3c66ab869febb299.zip external_wpa_supplicant_8_ti-9e8cda5a46edc708b21589ad3c66ab869febb299.tar.gz external_wpa_supplicant_8_ti-9e8cda5a46edc708b21589ad3c66ab869febb299.tar.bz2 |
hwsim_test: Tool for testing data connectivity with mac80211_hwsim
This program can be used to verify that both unicast and broadcast
data frames can be transmitted successfully through mac80211_hwsim
interfaces.
Diffstat (limited to 'mac80211_hwsim')
-rw-r--r-- | mac80211_hwsim/tools/Makefile | 11 | ||||
-rw-r--r-- | mac80211_hwsim/tools/hwsim_test.c | 244 |
2 files changed, 255 insertions, 0 deletions
diff --git a/mac80211_hwsim/tools/Makefile b/mac80211_hwsim/tools/Makefile new file mode 100644 index 0000000..ec0d2dc --- /dev/null +++ b/mac80211_hwsim/tools/Makefile @@ -0,0 +1,11 @@ +all: hwsim_test + +ifndef CC +CC=gcc +endif + +ifndef CFLAGS +CFLAGS = -O2 -Wall -g +endif + +hwsim_test: hwsim_test.o diff --git a/mac80211_hwsim/tools/hwsim_test.c b/mac80211_hwsim/tools/hwsim_test.c new file mode 100644 index 0000000..1ac0173 --- /dev/null +++ b/mac80211_hwsim/tools/hwsim_test.c @@ -0,0 +1,244 @@ +/* + * hwsim_test - Data connectivity test for mac80211_hwsim + * Copyright (c) 2009, Atheros Communications + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <netpacket/packet.h> +#include <net/ethernet.h> +#include <net/if.h> +#include <arpa/inet.h> + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +#define HWSIM_ETHERTYPE ETHERTYPE_IP +#define HWSIM_PACKETLEN 1500 + +static unsigned char addr1[ETH_ALEN], addr2[ETH_ALEN], bcast[ETH_ALEN]; + +static void tx(int s, const char *ifname, int ifindex, + const unsigned char *src, const unsigned char *dst) +{ + char buf[HWSIM_PACKETLEN], *pos; + struct ether_header *eth; + int i; + + printf("TX: %s(ifindex=%d) " MACSTR " -> " MACSTR "\n", + ifname, ifindex, MAC2STR(src), MAC2STR(dst)); + + eth = (struct ether_header *) buf; + memcpy(eth->ether_dhost, dst, ETH_ALEN); + memcpy(eth->ether_shost, src, ETH_ALEN); + eth->ether_type = htons(HWSIM_ETHERTYPE); + pos = (char *) (eth + 1); + for (i = 0; i < sizeof(buf) - sizeof(*eth); i++) + *pos++ = i; + + if (send(s, buf, sizeof(buf), 0) < 0) + perror("send"); +} + + +struct rx_result { + int rx_unicast1:1; + int rx_broadcast1:1; + int rx_unicast2:1; + int rx_broadcast2:1; +}; + + +static void rx(int s, int iface, const char *ifname, int ifindex, + struct rx_result *res) +{ + char buf[HWSIM_PACKETLEN + 1], *pos; + struct ether_header *eth; + int len, i; + + len = recv(s, buf, sizeof(buf), 0); + if (len < 0) { + perror("recv"); + return; + } + eth = (struct ether_header *) buf; + + printf("RX: %s(ifindex=%d) " MACSTR " -> " MACSTR " (len=%d)\n", + ifname, ifindex, + MAC2STR(eth->ether_shost), MAC2STR(eth->ether_dhost), len); + + if (len != HWSIM_PACKETLEN) { + printf("Ignore frame with unexpected RX length\n"); + return; + } + + pos = (char *) (eth + 1); + for (i = 0; i < sizeof(buf) - 1 - sizeof(*eth); i++) { + if ((unsigned char) *pos != (unsigned char) i) { + printf("Ignore frame with unexpected contents\n"); + printf("i=%d received=0x%x expected=0x%x\n", + i, (unsigned char) *pos, (unsigned char) i); + return; + } + pos++; + } + + if (iface == 1 && + memcmp(eth->ether_dhost, addr1, ETH_ALEN) == 0 && + memcmp(eth->ether_shost, addr2, ETH_ALEN) == 0) + res->rx_unicast1 = 1; + else if (iface == 1 && + memcmp(eth->ether_dhost, bcast, ETH_ALEN) == 0 && + memcmp(eth->ether_shost, addr2, ETH_ALEN) == 0) + res->rx_broadcast1 = 1; + else if (iface == 2 && + memcmp(eth->ether_dhost, addr2, ETH_ALEN) == 0 && + memcmp(eth->ether_shost, addr1, ETH_ALEN) == 0) + res->rx_unicast2 = 1; + else if (iface == 2 && + memcmp(eth->ether_dhost, bcast, ETH_ALEN) == 0 && + memcmp(eth->ether_shost, addr1, ETH_ALEN) == 0) + res->rx_broadcast2 = 1; +} + + +int main(int argc, char *argv[]) +{ + int s1 = -1, s2 = -1, ret = -1; + struct ifreq ifr; + int ifindex1, ifindex2; + struct sockaddr_ll ll; + fd_set rfds; + struct timeval tv; + struct rx_result res; + + if (argc != 3) { + fprintf(stderr, "usage: hwsim_test <ifname1> <ifname2>\n"); + return -1; + } + + memset(bcast, 0xff, ETH_ALEN); + + s1 = socket(PF_PACKET, SOCK_RAW, htons(HWSIM_ETHERTYPE)); + if (s1 < 0) { + perror("socket"); + goto fail; + } + + s2 = socket(PF_PACKET, SOCK_RAW, htons(HWSIM_ETHERTYPE)); + if (s2 < 0) { + perror("socket"); + goto fail; + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)); + if (ioctl(s1, SIOCGIFINDEX, &ifr) < 0) { + perror("ioctl[SIOCGIFINDEX]"); + goto fail; + } + ifindex1 = ifr.ifr_ifindex; + if (ioctl(s1, SIOCGIFHWADDR, &ifr) < 0) { + perror("ioctl[SIOCGIFHWADDR]"); + goto fail; + } + memcpy(addr1, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, argv[2], sizeof(ifr.ifr_name)); + if (ioctl(s2, SIOCGIFINDEX, &ifr) < 0) { + perror("ioctl[SIOCGIFINDEX]"); + goto fail; + } + ifindex2 = ifr.ifr_ifindex; + if (ioctl(s2, SIOCGIFHWADDR, &ifr) < 0) { + perror("ioctl[SIOCGIFHWADDR]"); + goto fail; + } + memcpy(addr2, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + + memset(&ll, 0, sizeof(ll)); + ll.sll_family = PF_PACKET; + ll.sll_ifindex = ifindex1; + ll.sll_protocol = htons(HWSIM_ETHERTYPE); + if (bind(s1, (struct sockaddr *) &ll, sizeof(ll)) < 0) { + perror("bind"); + goto fail; + } + + memset(&ll, 0, sizeof(ll)); + ll.sll_family = PF_PACKET; + ll.sll_ifindex = ifindex2; + ll.sll_protocol = htons(HWSIM_ETHERTYPE); + if (bind(s2, (struct sockaddr *) &ll, sizeof(ll)) < 0) { + perror("bind"); + goto fail; + } + + tx(s1, argv[1], ifindex1, addr1, addr2); + tx(s1, argv[1], ifindex1, addr1, bcast); + tx(s2, argv[2], ifindex2, addr2, addr1); + tx(s2, argv[2], ifindex2, addr2, bcast); + + tv.tv_sec = 1; + tv.tv_usec = 0; + + memset(&res, 0, sizeof(res)); + for (;;) { + int r; + FD_ZERO(&rfds); + FD_SET(s1, &rfds); + FD_SET(s2, &rfds); + + r = select(s2 + 1, &rfds, NULL, NULL, &tv); + if (r < 0) { + perror("select"); + goto fail; + } + + if (r == 0) + break; /* timeout */ + + if (FD_SET(s1, &rfds)) + rx(s1, 1, argv[1], ifindex1, &res); + if (FD_SET(s2, &rfds)) + rx(s2, 2, argv[2], ifindex2, &res); + + if (res.rx_unicast1 && res.rx_broadcast1 && + res.rx_unicast2 && res.rx_broadcast2) { + ret = 0; + break; + } + } + + if (ret) { + printf("Did not receive all expected frames:\n" + "rx_unicast1=%d rx_broadcast1=%d " + "rx_unicast2=%d rx_broadcast2=%d\n", + res.rx_unicast1, res.rx_broadcast1, + res.rx_unicast2, res.rx_broadcast2); + } else { + printf("Both unicast and broadcast working in both " + "directions\n"); + } + +fail: + close(s1); + close(s2); + + return ret; +} |