Browse Source

wlantest: Maintain table of BSS information

Whenever a Beacon or Probe Response frame is observed, add or update
a BSS entry to maintain current information about the active BSSes.
Jouni Malinen 14 years ago
parent
commit
d84d389351
5 changed files with 209 additions and 4 deletions
  1. 3 0
      wlantest/Makefile
  2. 48 0
      wlantest/bss.c
  3. 118 0
      wlantest/process.c
  4. 20 4
      wlantest/wlantest.c
  5. 20 0
      wlantest/wlantest.h

+ 3 - 0
wlantest/Makefile

@@ -39,10 +39,13 @@ endif
 OBJS_lib += ../src/utils/libutils.a
 OBJS_lib += ../src/crypto/libcrypto.a
 
+OBJS += ../src/common/ieee802_11_common.o
+
 OBJS += wlantest.o
 OBJS += readpcap.o
 OBJS += monitor.o
 OBJS += process.o
+OBJS += bss.o
 OBJS += crc32.o
 
 LIBS += -lpcap

+ 48 - 0
wlantest/bss.c

@@ -0,0 +1,48 @@
+/*
+ * BSS list
+ * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ *
+ * 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 "utils/includes.h"
+
+#include "utils/common.h"
+#include "wlantest.h"
+
+
+struct wlantest_bss * bss_get(struct wlantest *wt, const u8 *bssid)
+{
+	struct wlantest_bss *bss;
+
+	if (bssid[0] & 0x01)
+		return NULL; /* Skip group addressed frames */
+
+	dl_list_for_each(bss, &wt->bss, struct wlantest_bss, list) {
+		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+			return bss;
+	}
+
+	bss = os_zalloc(sizeof(*bss));
+	if (bss == NULL)
+		return NULL;
+	os_memcpy(bss->bssid, bssid, ETH_ALEN);
+	dl_list_add(&wt->bss, &bss->list);
+	wpa_printf(MSG_DEBUG, "Discovered new BSS - " MACSTR,
+		   MAC2STR(bss->bssid));
+	return bss;
+}
+
+
+void bss_deinit(struct wlantest_bss *bss)
+{
+	dl_list_del(&bss->list);
+	os_free(bss);
+}

+ 118 - 0
wlantest/process.c

@@ -18,6 +18,7 @@
 #include "utils/radiotap.h"
 #include "utils/radiotap_iter.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
 #include "wlantest.h"
 
 
@@ -53,6 +54,114 @@ static const char * mgmt_stype(u16 stype)
 }
 
 
+static void bss_update(struct wlantest_bss *bss,
+		       struct ieee802_11_elems *elems)
+{
+	if (elems->ssid == NULL || elems->ssid_len > 32) {
+		wpa_printf(MSG_INFO, "Invalid or missing SSID in a Beacon "
+			   "frame for " MACSTR, MAC2STR(bss->bssid));
+		bss->parse_error_reported = 1;
+		return;
+	}
+
+	os_memcpy(bss->ssid, elems->ssid, elems->ssid_len);
+	bss->ssid_len = elems->ssid_len;
+
+	if (elems->rsn_ie == NULL) {
+		if (bss->rsnie[0]) {
+			wpa_printf(MSG_INFO, "BSS " MACSTR " - RSN IE removed",
+				   MAC2STR(bss->bssid));
+			bss->rsnie[0] = 0;
+		}
+	} else {
+		if (bss->rsnie[0] == 0 ||
+		    os_memcmp(bss->rsnie, elems->rsn_ie - 2,
+			      elems->rsn_ie_len + 2) != 0) {
+			wpa_printf(MSG_INFO, "BSS " MACSTR " - RSN IE "
+				   "stored", MAC2STR(bss->bssid));
+			wpa_hexdump(MSG_DEBUG, "RSN IE", elems->rsn_ie - 2,
+				    elems->rsn_ie_len + 2);
+		}
+		os_memcpy(bss->rsnie, elems->rsn_ie - 2,
+			  elems->rsn_ie_len + 2);
+	}
+
+	if (elems->wpa_ie == NULL) {
+		if (bss->wpaie[0]) {
+			wpa_printf(MSG_INFO, "BSS " MACSTR " - WPA IE removed",
+				   MAC2STR(bss->bssid));
+			bss->wpaie[0] = 0;
+		}
+	} else {
+		if (bss->wpaie[0] == 0 ||
+		    os_memcmp(bss->wpaie, elems->wpa_ie - 2,
+			      elems->wpa_ie_len + 2) != 0) {
+			wpa_printf(MSG_INFO, "BSS " MACSTR " - WPA IE "
+				   "stored", MAC2STR(bss->bssid));
+			wpa_hexdump(MSG_DEBUG, "WPA IE", elems->wpa_ie - 2,
+				    elems->wpa_ie_len + 2);
+		}
+		os_memcpy(bss->wpaie, elems->wpa_ie - 2,
+			  elems->wpa_ie_len + 2);
+	}
+}
+
+
+static void rx_mgmt_beacon(struct wlantest *wt, const u8 *data, size_t len)
+{
+	const struct ieee80211_mgmt *mgmt;
+	struct wlantest_bss *bss;
+	struct ieee802_11_elems elems;
+
+	mgmt = (const struct ieee80211_mgmt *) data;
+	bss = bss_get(wt, mgmt->bssid);
+	if (bss == NULL)
+		return;
+	if (bss->proberesp_seen)
+		return; /* do not override with Beacon data */
+	bss->capab_info = le_to_host16(mgmt->u.beacon.capab_info);
+	if (ieee802_11_parse_elems(mgmt->u.beacon.variable,
+				   len - (mgmt->u.beacon.variable - data),
+				   &elems, 0) == ParseFailed) {
+		if (bss->parse_error_reported)
+			return;
+		wpa_printf(MSG_INFO, "Invalid IEs in a Beacon frame from "
+			   MACSTR, MAC2STR(mgmt->sa));
+		bss->parse_error_reported = 1;
+		return;
+	}
+
+	bss_update(bss, &elems);
+}
+
+
+static void rx_mgmt_probe_resp(struct wlantest *wt, const u8 *data, size_t len)
+{
+	const struct ieee80211_mgmt *mgmt;
+	struct wlantest_bss *bss;
+	struct ieee802_11_elems elems;
+
+	mgmt = (const struct ieee80211_mgmt *) data;
+	bss = bss_get(wt, mgmt->bssid);
+	if (bss == NULL)
+		return;
+
+	bss->capab_info = le_to_host16(mgmt->u.probe_resp.capab_info);
+	if (ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
+				   len - (mgmt->u.probe_resp.variable - data),
+				   &elems, 0) == ParseFailed) {
+		if (bss->parse_error_reported)
+			return;
+		wpa_printf(MSG_INFO, "Invalid IEs in a Probe Response frame "
+			   "from " MACSTR, MAC2STR(mgmt->sa));
+		bss->parse_error_reported = 1;
+		return;
+	}
+
+	bss_update(bss, &elems);
+}
+
+
 static void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
 {
 	const struct ieee80211_hdr *hdr;
@@ -76,6 +185,15 @@ static void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
 		   fc & WLAN_FC_ISWEP ? " Prot" : "",
 		   MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
 		   MAC2STR(hdr->addr3));
+
+	switch (stype) {
+	case WLAN_FC_STYPE_BEACON:
+		rx_mgmt_beacon(wt, data, len);
+		break;
+	case WLAN_FC_STYPE_PROBE_RESP:
+		rx_mgmt_probe_resp(wt, data, len);
+		break;
+	}
 }
 
 

+ 20 - 4
wlantest/wlantest.c

@@ -34,6 +34,24 @@ static void usage(void)
 }
 
 
+static void wlantest_init(struct wlantest *wt)
+{
+	os_memset(wt, 0, sizeof(*wt));
+	wt->monitor_sock = -1;
+	dl_list_init(&wt->bss);
+}
+
+
+static void wlantest_deinit(struct wlantest *wt)
+{
+	struct wlantest_bss *bss, *n;
+	if (wt->monitor_sock >= 0)
+		monitor_deinit(wt);
+	dl_list_for_each_safe(bss, n, &wt->bss, struct wlantest_bss, list)
+		bss_deinit(bss);
+}
+
+
 int main(int argc, char *argv[])
 {
 	int c;
@@ -46,8 +64,7 @@ int main(int argc, char *argv[])
 	if (os_program_init())
 		return -1;
 
-	os_memset(&wt, 0, sizeof(wt));
-	wt.monitor_sock = -1;
+	wlantest_init(&wt);
 
 	for (;;) {
 		c = getopt(argc, argv, "dhi:r:q");
@@ -98,8 +115,7 @@ int main(int argc, char *argv[])
 		   "fcs_error=%u",
 		   wt.rx_mgmt, wt.rx_ctrl, wt.rx_data, wt.fcs_error);
 
-	if (ifname)
-		monitor_deinit(&wt);
+	wlantest_deinit(&wt);
 
 	eloop_destroy();
 	os_program_deinit();

+ 20 - 0
wlantest/wlantest.h

@@ -15,9 +15,26 @@
 #ifndef WLANTEST_H
 #define WLANTEST_H
 
+#include "utils/list.h"
+
+
+struct wlantest_bss {
+	struct dl_list list;
+	u8 bssid[ETH_ALEN];
+	u16 capab_info;
+	u8 ssid[32];
+	size_t ssid_len;
+	int proberesp_seen;
+	int parse_error_reported;
+	u8 wpaie[257];
+	u8 rsnie[257];
+};
+
 struct wlantest {
 	int monitor_sock;
 
+	struct dl_list bss; /* struct wlantest_bss */
+
 	unsigned int rx_mgmt;
 	unsigned int rx_ctrl;
 	unsigned int rx_data;
@@ -30,4 +47,7 @@ u32 crc32(const u8 *frame, size_t frame_len);
 int monitor_init(struct wlantest *wt, const char *ifname);
 void monitor_deinit(struct wlantest *wt);
 
+struct wlantest_bss * bss_get(struct wlantest *wt, const u8 *bssid);
+void bss_deinit(struct wlantest_bss *bss);
+
 #endif /* WLANTEST_H */