aboutsummaryrefslogtreecommitdiff
path: root/tools/tools
diff options
context:
space:
mode:
authorAdrian Chadd <adrian@FreeBSD.org>2017-07-31 17:33:57 +0000
committerAdrian Chadd <adrian@FreeBSD.org>2017-07-31 17:33:57 +0000
commit495842b11764e04bfcb1f06fcddce8c318b9de81 (patch)
tree0d533ec21f0fe0eca66643cca30cd55d749e5fb8 /tools/tools
parent2068b2aa887b614dd248cbe6d50e84cb6517067d (diff)
downloadsrc-495842b11764e04bfcb1f06fcddce8c318b9de81.tar.gz
src-495842b11764e04bfcb1f06fcddce8c318b9de81.zip
[wlanwds] allow for a DWDS AP VAP to be not be the first VAP on a NIC.
The wlanwds code was just creating a clone VAP without specifying the MAC address to use for said clone VAP. This meant that if an interface was cloned from an AP interface that wasn't the first created VAP (which shares the same MAC as the parent physical interface by default) then the cloned interface would have the wrong MAC and traffic wouldn't work. Besides chip bugs (ha!) this isn't a requirement. So, teach wlanwds to: * look up the link layer address for a given interface (which really should be a library interface, and will likely quickly become one); * use this when creating a cloned interface for a DWDS peer; * (net80211 already has the infrastructure to do this, it just needed to be used); * add some extra logging to see what MAC addresses, parent interfaces, etc are being created. Whilst here, add a reminder that I should extend this to include monitoring a specific VAP for DWDS updates rather than just the parent interface. This is the first step in allowing for multiple DWDS hops, which is a pre-requisite for adrian's house having wifi in the single upstairs room. Tested: * AR9380, DWDS AP + AP mode - with DWDS AP being the second VAP created with a different MAC address; * AR9331 (Carambola2), AP + DWDS STA; * passing traffic TODO: * fix 802.11s so this DWDS stuff is no longer required!
Notes
Notes: svn path=/head/; revision=321800
Diffstat (limited to 'tools/tools')
-rw-r--r--tools/tools/net80211/wlanwds/wlanwds.c116
1 files changed, 109 insertions, 7 deletions
diff --git a/tools/tools/net80211/wlanwds/wlanwds.c b/tools/tools/net80211/wlanwds/wlanwds.c
index 177f92a6d2ac..86246c21f5c7 100644
--- a/tools/tools/net80211/wlanwds/wlanwds.c
+++ b/tools/tools/net80211/wlanwds/wlanwds.c
@@ -55,6 +55,9 @@
#include <arpa/inet.h>
#include <netdb.h>
+#include <net/if.h>
+#include <net/if_types.h>
+
#include <ctype.h>
#include <err.h>
#include <errno.h>
@@ -90,7 +93,8 @@ static void wds_discovery(const char *ifname,
const uint8_t bssid[IEEE80211_ADDR_LEN]);
static void wds_destroy(const char *ifname);
static void wds_leave(const uint8_t bssid[IEEE80211_ADDR_LEN]);
-static int wds_vap_create(const char *ifname, struct wds *);
+static int wds_vap_create(const char *ifname, uint8_t macaddr[ETHER_ADDR_LEN],
+ struct wds *);
static int wds_vap_destroy(const char *ifname);
static void
@@ -201,6 +205,11 @@ getparent(const char *ifname, char parent[IFNAMSIZ+1])
* Check if the specified ifnet is one we're supposed to monitor.
* The ifnet is assumed to be a vap; we find it's parent and check
* it against the set of ifnet's specified on the command line.
+ *
+ * TODO: extend this to also optionally allow the specific DWDS
+ * VAP to be monitored, instead of assuming all VAPs on a parent
+ * physical interface are being monitored by this instance of
+ * wlanwds.
*/
static int
checkifnet(const char *ifname, int complain)
@@ -257,6 +266,70 @@ getbssid(int s, const char *ifname, uint8_t bssid[IEEE80211_ADDR_LEN])
}
/*
+ * Fetch the mac address configured for a given ifnet.
+ * (Note - the current link level address, NOT hwaddr.)
+ *
+ * This is currently, sigh, O(n) because there's no current kernel
+ * API that will do it for a single interface.
+ *
+ * Return 0 if successful, -1 if failure.
+ */
+static int
+getlladdr(const char *ifname, uint8_t macaddr[ETHER_ADDR_LEN])
+{
+ struct ifaddrs *ifap, *ifa;
+ struct sockaddr_dl *sdl;
+
+ if (getifaddrs(&ifap) < 0) {
+ warn("%s: getifaddrs", __func__);
+ return (-1);
+ }
+
+ /* Look for a matching interface */
+ for (ifa = ifap; ifa != NULL; ifa++) {
+ if (strcmp(ifname, ifa->ifa_name) != 0)
+ continue;
+
+ /* Found it - check if there's an ifa_addr */
+ if (ifa->ifa_addr == NULL) {
+ syslog(LOG_CRIT, "%s: ifname %s; ifa_addr is NULL\n",
+ __func__, ifname);
+ goto err;
+ }
+
+ /* Check address family */
+ sdl = (struct sockaddr_dl *) ifa->ifa_addr;
+ if (sdl->sdl_type != IFT_ETHER) {
+ syslog(LOG_CRIT, "%s: %s: unknown aftype (%d)\n",
+ __func__,
+ ifname,
+ sdl->sdl_type);
+ goto err;
+ }
+ if (sdl->sdl_alen != ETHER_ADDR_LEN) {
+ syslog(LOG_CRIT, "%s: %s: aflen too short (%d)\n",
+ __func__,
+ ifname,
+ sdl->sdl_alen);
+ goto err;
+ }
+
+ /* Ok, found it */
+ memcpy(macaddr, (void *) LLADDR(sdl), ETHER_ADDR_LEN);
+ goto ok;
+ }
+ syslog(LOG_CRIT, "%s: couldn't find ifname %s\n", __func__, ifname);
+ /* FALLTHROUGH */
+err:
+ freeifaddrs(ifap);
+ return (-1);
+
+ok:
+ freeifaddrs(ifap);
+ return (0);
+}
+
+/*
* Scan the system for WDS vaps associated with the ifnet's we're
* supposed to monitor. Any vaps are added to our internal table
* so we can find them (and destroy them) on station leave.
@@ -374,6 +447,7 @@ wds_discovery(const char *ifname, const uint8_t bssid[IEEE80211_ADDR_LEN])
struct wds *p;
char parent[256];
char cmd[1024];
+ uint8_t macaddr[ETHER_ADDR_LEN];
int status;
for (p = wds; p != NULL; p = p->next)
@@ -388,13 +462,19 @@ wds_discovery(const char *ifname, const uint8_t bssid[IEEE80211_ADDR_LEN])
return;
}
+ if (getlladdr(ifname, macaddr) < 0) {
+ syslog(LOG_ERR, "%s: couldn't get lladdr for parent interface: %m",
+ ifname);
+ return;
+ }
+
p = malloc(sizeof(struct wds));
if (p == NULL) {
syslog(LOG_ERR, "%s: malloc failed: %m", __func__);
return;
}
IEEE80211_ADDR_COPY(p->bssid, bssid);
- if (wds_vap_create(parent, p) < 0) {
+ if (wds_vap_create(parent, macaddr, p) < 0) {
free(p);
return;
}
@@ -403,8 +483,11 @@ wds_discovery(const char *ifname, const uint8_t bssid[IEEE80211_ADDR_LEN])
*/
p->next = wds;
wds = p;
- syslog(LOG_INFO, "[%s] create wds vap %s", ether_sprintf(bssid),
- p->ifname);
+ syslog(LOG_INFO, "[%s] create wds vap %s, parent %s (%s)",
+ ether_sprintf(bssid),
+ p->ifname,
+ ifname,
+ parent);
if (script != NULL) {
snprintf(cmd, sizeof(cmd), "%s %s", script, p->ifname);
status = system(cmd);
@@ -454,17 +537,35 @@ wds_leave(const uint8_t bssid[IEEE80211_ADDR_LEN])
}
static int
-wds_vap_create(const char *parent, struct wds *p)
+wds_vap_create(const char *parent, uint8_t macaddr[ETHER_ADDR_LEN],
+ struct wds *p)
{
struct ieee80211_clone_params cp;
struct ifreq ifr;
int s, status;
+ char bssid_str[32], macaddr_str[32];
memset(&cp, 0, sizeof(cp));
+
+ /* Parent interface */
strncpy(cp.icp_parent, parent, IFNAMSIZ);
+
+ /* WDS interface */
cp.icp_opmode = IEEE80211_M_WDS;
+
+ /* BSSID for the current node */
IEEE80211_ADDR_COPY(cp.icp_bssid, p->bssid);
+ /*
+ * Set the MAC address to match the actual interface
+ * that we received the discovery event from.
+ * That way we can run WDS on any VAP rather than
+ * only the first VAP and then correctly set the
+ * MAC address.
+ */
+ cp.icp_flags |= IEEE80211_CLONE_MACADDR;
+ IEEE80211_ADDR_COPY(cp.icp_macaddr, macaddr);
+
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "wlan", IFNAMSIZ);
ifr.ifr_data = (void *) &cp;
@@ -477,9 +578,10 @@ wds_vap_create(const char *parent, struct wds *p)
status = 0;
} else {
syslog(LOG_ERR, "SIOCIFCREATE2("
- "mode %u flags 0x%x parent %s bssid %s): %m",
+ "mode %u flags 0x%x parent %s bssid %s macaddr %s): %m",
cp.icp_opmode, cp.icp_flags, parent,
- ether_sprintf(cp.icp_bssid));
+ ether_ntoa_r((void *) cp.icp_bssid, bssid_str),
+ ether_ntoa_r((void *) cp.icp_macaddr, macaddr_str));
}
close(s);
} else