[PATCH 3/3] Enable wildcards (*) in BSSID lists

Stefan Tomanek stefan.tomanek
Mon Dec 15 04:24:43 PST 2014


In many context it seems suitable not just to enumerate a group of mac
addresses, but to use wildcards (ca:ff:ee:*:*:*).

This change expands the data structures used by mac lists to include a mask
indicating the significant (non-masked) portions of an address.

Signed-off-by: Stefan Tomanek <stefan.tomanek at wertarbyte.de>
---
 src/utils/common.c                 | 54 ++++++++++++++++++++++++++++++++------
 src/utils/common.h                 |  3 +++
 wpa_supplicant/config.c            | 22 +++++++++-------
 wpa_supplicant/events.c            | 15 +++++++++--
 wpa_supplicant/wpa_supplicant.conf |  4 +--
 5 files changed, 76 insertions(+), 22 deletions(-)

diff --git a/src/utils/common.c b/src/utils/common.c
index 422b476..243e2d8 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -44,18 +44,39 @@ int hex2byte(const char *hex)
  */
 int hwaddr_aton(const char *txt, u8 *addr)
 {
+	u8 mask[ETH_ALEN];
+	return hwaddr_wildcard_aton(txt, addr, mask, 0);
+}
+
+/**
+ * hwaddr_wildcard_aton - Convert ASCII string with wildcards to MAC address (colon-delimited format)
+ * @txt: MAC address as a string (e.g., "00:11:22:33:*:*")
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * @mask: Buffer for the MAC address mask (ETH_ALEN = 6 bytes)
+ * @wildcard: Flag to indicate whether wildcards are allowed
+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
+ */
+int hwaddr_wildcard_aton(const char *txt, u8 *addr, u8 *mask, u8 wildcard)
+{
 	int i;
 
 	for (i = 0; i < 6; i++) {
-		int a, b;
+		int a = 0;
+		int b = 0;
 
-		a = hex2num(*txt++);
-		if (a < 0)
-			return -1;
-		b = hex2num(*txt++);
-		if (b < 0)
-			return -1;
-		*addr++ = (a << 4) | b;
+		if (wildcard && *txt == '*') {
+			mask[i] = 0x00;
+			txt++;
+		} else {
+			mask[i] = 0xFF;
+			a = hex2num(*txt++);
+			if (a < 0)
+				return -1;
+			b = hex2num(*txt++);
+			if (b < 0)
+				return -1;
+		}
+		addr[i] = (a << 4) | b;
 		if (i < 5 && *txt++ != ':')
 			return -1;
 	}
@@ -143,6 +164,23 @@ int hexstr2bin(const char *hex, u8 *buf, size_t len)
 	return 0;
 }
 
+size_t hwaddr_mask_txt(char *buf, u8 *addr, u8 *mask) {
+	size_t i;
+	char *pos = buf;
+	for (i = 0; i < ETH_ALEN; i++) {
+		if (!mask[i]) {
+			*pos++ = '*';
+		} else {
+			u8 n = sprintf(pos, "%02x", addr[i]);
+			pos += n;
+		}
+		if (i < 5) {
+			*pos++ = ':';
+		}
+	}
+	*pos = '\0';
+	return pos - buf;
+}
 
 /**
  * inc_byte_array - Increment arbitrary length byte array by one
diff --git a/src/utils/common.h b/src/utils/common.h
index 70d76a9..c96d70b 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -471,6 +471,7 @@ typedef u64 __bitwise le64;
 #endif /* __must_check */
 
 int hwaddr_aton(const char *txt, u8 *addr);
+int hwaddr_wildcard_aton(const char *txt, u8 *addr, u8 *mask, u8 wildcards);
 int hwaddr_compact_aton(const char *txt, u8 *addr);
 int hwaddr_aton2(const char *txt, u8 *addr);
 int hex2byte(const char *hex);
@@ -482,6 +483,8 @@ int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
 int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
 			       size_t len);
 
+size_t hwaddr_mask_txt(char *buf, u8 *addr, u8 *mask);
+
 #ifdef CONFIG_NATIVE_WINDOWS
 void wpa_unicode2ascii_inplace(TCHAR *str);
 TCHAR * wpa_strdup_tchar(const char *str);
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 62e2948..163bfaa 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -238,10 +238,11 @@ static int wpa_config_parse_addr_list(const struct parse_data *data,
 				      struct wpa_ssid *ssid, int line,
 				      const char *value,
 				      u8 **list, size_t *num, char *name,
-				      u8 abort_on_error)
+				      u8 abort_on_error, u8 wildcards)
 {
 	const char *pos;
 	u8 *buf, *n, addr[ETH_ALEN];
+	u8 mask[ETH_ALEN];
 	size_t count;
 
 	buf = NULL;
@@ -252,7 +253,7 @@ static int wpa_config_parse_addr_list(const struct parse_data *data,
 		while (*pos == ' ')
 			pos++;
 
-		if (hwaddr_aton(pos, addr)) {
+		if (hwaddr_wildcard_aton(pos, addr, mask, wildcards)) {
 			if (abort_on_error || count == 0) {
 				wpa_printf(MSG_ERROR, "Line %d: Invalid "
 					   "%s address '%s'.",
@@ -266,14 +267,15 @@ static int wpa_config_parse_addr_list(const struct parse_data *data,
 				   "truncated %s address '%s'",
 				   line, name, pos);
 		} else {
-			n = os_realloc_array(buf, count + 1, ETH_ALEN);
+			n = os_realloc_array(buf, count + 1, 2*ETH_ALEN);
 			if (n == NULL) {
 				os_free(buf);
 				return -1;
 			}
 			buf = n;
-			os_memmove(buf + ETH_ALEN, buf, count * ETH_ALEN);
+			os_memmove(buf + 2*ETH_ALEN, buf, count * 2*ETH_ALEN);
 			os_memcpy(buf, addr, ETH_ALEN);
+			os_memcpy(buf + ETH_ALEN, mask, ETH_ALEN);
 			count++;
 			wpa_hexdump(MSG_MSGDUMP, name,
 				    addr, ETH_ALEN);
@@ -308,9 +310,9 @@ static char * wpa_config_write_addr_list(const struct parse_data *data,
 	end = value + 20 * (*num);
 
 	for (i = (*num); i > 0; i--) {
-		res = os_snprintf(pos, end - pos, MACSTR " ",
-				  MAC2STR(*list +
-					  (i - 1) * ETH_ALEN));
+		u8 *a = *list + (i-1) * 2*ETH_ALEN;
+		u8 *m = *list + (i-1) * 2*ETH_ALEN + ETH_ALEN;
+		res = hwaddr_mask_txt(pos, a, m);
 		if (os_snprintf_error(end - pos, res)) {
 			os_free(value);
 			return NULL;
@@ -373,7 +375,7 @@ static char * wpa_config_write_bssid(const struct parse_data *data,
 static int wpa_config_parse_bssid_blacklist(const struct parse_data *data,
 					    struct wpa_ssid *ssid, int line,
 					    const char *value) {
-	return wpa_config_parse_addr_list(data, ssid, line, value, &ssid->bssid_blacklist, &ssid->num_bssid_blacklist, "bssid_blacklist", 1);
+	return wpa_config_parse_addr_list(data, ssid, line, value, &ssid->bssid_blacklist, &ssid->num_bssid_blacklist, "bssid_blacklist", 1, 1);
 }
 
 #ifndef NO_CONFIG_WRITE
@@ -388,7 +390,7 @@ static char * wpa_config_write_bssid_blacklist(const struct parse_data *data,
 static int wpa_config_parse_bssid_whitelist(const struct parse_data *data,
 					    struct wpa_ssid *ssid, int line,
 					    const char *value) {
-	return wpa_config_parse_addr_list(data, ssid, line, value, &ssid->bssid_whitelist, &ssid->num_bssid_whitelist, "bssid_whitelist", 1);
+	return wpa_config_parse_addr_list(data, ssid, line, value, &ssid->bssid_whitelist, &ssid->num_bssid_whitelist, "bssid_whitelist", 1, 1);
 }
 
 #ifndef NO_CONFIG_WRITE
@@ -1573,7 +1575,7 @@ static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
 					    struct wpa_ssid *ssid, int line,
 					    const char *value)
 {
-	return wpa_config_parse_addr_list(data, ssid, line, value, &ssid->p2p_client_list, &ssid->num_p2p_clients, "p2p_client_list", 0);
+	return wpa_config_parse_addr_list(data, ssid, line, value, &ssid->p2p_client_list, &ssid->num_p2p_clients, "p2p_client_list", 0, 0);
 }
 
 
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 3a01d23..0dae38c 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -705,11 +705,22 @@ static int bss_is_ess(struct wpa_bss *bss)
 		IEEE80211_CAP_ESS);
 }
 
+static int match_mac_mask(u8 *addrA, u8 *addrB, u8 *mask) {
+	size_t i;
+	for (i = 0; i < ETH_ALEN; i++) {
+		if ((addrA[i] & mask[i]) != (addrB[i] & mask[i])) {
+			return 0;
+		}
+	}
+	return 1;
+}
+
 static int addr_in_list(u8 *addr, u8 *list, size_t num) {
 	size_t i;
 	for (i = 0; i < num; i++) {
-		u8 *a = list + (i*ETH_ALEN);
-		if (os_memcmp(a, addr, ETH_ALEN) == 0) {
+		u8 *a = list + (i*ETH_ALEN*2);
+		u8 *m = list + (i*ETH_ALEN*2) + ETH_ALEN;
+		if (match_mac_mask(a, addr, m)) {
 			return 1;
 		}
 	}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 4ed7865..8595028 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1436,11 +1436,11 @@ network={
 }
 
 # Example configuration limiting AP selection to a specific set of APs;
-# any other AP will be ignored for this network entry
+# any other AP not matching the wildcard will be ignored for this network entry
 network={
 	ssid="example"
 	psk="very secret passphrase"
-	bssid_whitelist=ca:fe:ba:be:d0:0d de:ad:be:ef:00:00
+	bssid_whitelist=ca:fe:ba:be:*:*
 }
 
 # Example config file that will only scan on channel 36.
-- 
2.1.1



More information about the Hostap mailing list