[PATCH] wpa_supplicant: Add support for pregenerated MAC

Andrzej Ostruszka amo at semihalf.com
Wed Nov 10 11:16:35 PST 2021


Add new 'mac_addr' policy (3) with which supplicant expects to also
obtain 'mac_value' with pregenerated value of MAC address to be used for
given SSID.

The main difference between this policy and policy 1 is the ability to
control persistence of the MAC address used.  For example if there is
a requirement to always use the same (but random) MAC address for given
SSID (even if user removes/forgets the network) this could be handled
outside of the wpa_supplicant by using some SSID based hashing scheme to
generate MAC (or by just storing the randomly generated one) and
providing it to wpa_supplicant together with mac_addr=3 policy.

Signed-off-by: Andrzej Ostruszka <amo at semihalf.com>
Change-Id: I4046cf1cd08c84350a44703fe1fa0ecab4c82870
---
 wpa_supplicant/config.c                 | 46 ++++++++++++++++++++++++-
 wpa_supplicant/config_ssid.h            |  9 +++++
 wpa_supplicant/dbus/dbus_new_handlers.c | 22 +++++++++++-
 wpa_supplicant/wpa_supplicant.c         | 16 +++++++--
 wpa_supplicant/wpa_supplicant_i.h       |  3 +-
 5 files changed, 90 insertions(+), 6 deletions(-)

diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index bf97de698..1d17a3a32 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2321,6 +2321,49 @@ static char * wpa_config_write_peerkey(const struct parse_data *data,
 #endif /* NO_CONFIG_WRITE */
 
 
+static int wpa_config_parse_mac_value(const struct parse_data *data,
+                                      struct wpa_ssid *ssid, int line,
+                                      const char *value)
+{
+	u8 mac_value[ETH_ALEN];
+
+	if (hwaddr_aton(value, mac_value) == 0) {
+		if (os_memcmp(mac_value, ssid->mac_value, ETH_ALEN) == 0)
+			return 1;
+		os_memcpy(ssid->mac_value, mac_value, ETH_ALEN);
+		return 0;
+	}
+
+	wpa_printf(MSG_ERROR, "Line %d: Invalid MAC address '%s'",
+		   line, value);
+	return -1;
+}
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_mac_value(const struct parse_data *data,
+                                         struct wpa_ssid *ssid)
+{
+	const size_t size = 3 * ETH_ALEN;
+	char *value;
+	int res;
+
+	if (ssid->mac_addr != 3)
+		return NULL;
+
+	value = os_malloc(size);
+	if (value == NULL)
+		return NULL;
+	res = os_snprintf(value, size, MACSTR, MAC2STR(ssid->mac_value));
+	if (os_snprintf_error(size, res)) {
+		os_free(value);
+		return NULL;
+	}
+	value[size-1] = '\0';
+	return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
 /* Helper macros for network block parser */
 
 #ifdef OFFSET
@@ -2618,7 +2661,8 @@ static const struct parse_data ssid_fields[] = {
 	{ INT(update_identifier) },
 	{ STR_RANGE(roaming_consortium_selection, 0, MAX_ROAMING_CONS_OI_LEN) },
 #endif /* CONFIG_HS20 */
-	{ INT_RANGE(mac_addr, 0, 2) },
+	{ INT_RANGE(mac_addr, 0, 3) },
+	{ FUNC_KEY(mac_value) },
 	{ INT_RANGE(pbss, 0, 2) },
 	{ INT_RANGE(wps_disabled, 0, 1) },
 	{ INT_RANGE(fils_dh_group, 0, 65535) },
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 339eead1c..61a5139ec 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -954,6 +954,7 @@ struct wpa_ssid {
 	 * 0 = use permanent MAC address
 	 * 1 = use random MAC address for each ESS connection
 	 * 2 = like 1, but maintain OUI (with local admin bit set)
+	 * 3 = use dedicated/pregenerated MAC address
 	 *
 	 * Internally, special value -1 is used to indicate that the parameter
 	 * was not specified in the configuration (i.e., default behavior is
@@ -961,6 +962,14 @@ struct wpa_ssid {
 	 */
 	int mac_addr;
 
+	/**
+	 * mac_value - specific MAC address to be used
+	 *
+	 * When mac_addr policy is equal to 3 this is the value of the MAC
+	 * address that should be used.
+	 */
+	u8 mac_value[ETH_ALEN];
+
 	/**
 	 * no_auto_peer - Do not automatically peer with compatible mesh peers
 	 *
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index db9f30c9a..c4a7ceb44 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -148,7 +148,7 @@ static const char * const dont_quote[] = {
 #ifdef CONFIG_P2P
 	"go_p2p_dev_addr", "p2p_client_list", "psk_list",
 #endif /* CONFIG_P2P */
-	NULL
+	"mac_value", NULL
 };
 
 static dbus_bool_t should_quote_opt(const char *key)
@@ -202,6 +202,8 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
 	DBusMessageIter	iter_dict;
 	char *value = NULL;
+	bool mac_addr3_set = false;
+	bool mac_value_set = false;
 
 	if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
 		return FALSE;
@@ -311,12 +313,30 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
 		else if (os_strcmp(entry.key, "priority") == 0)
 			wpa_config_update_prio_list(wpa_s->conf);
 
+		/*
+		 * MAC address policy "3" needs to come with mac_value in
+		 * the message so make sure that it is present (checked after
+		 * the loop - here we just note what has been supplied).
+		 */
+		if (os_strcmp(entry.key, "mac_addr") == 0 &&
+		    atoi(value) == 3)
+			mac_addr3_set = true;
+		if (os_strcmp(entry.key, "mac_value") == 0)
+			mac_value_set = true;
+
 	skip_update:
 		os_free(value);
 		value = NULL;
 		wpa_dbus_dict_entry_clear(&entry);
 	}
 
+	if (mac_addr3_set && !mac_value_set) {
+		wpa_printf(MSG_ERROR, "Invalid mac_addr policy config");
+		dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+				     "Invalid mac_addr policy config");
+		return FALSE;
+	}
+
 	return TRUE;
 
 error:
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index b80f1d4f0..c6f32e75f 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -2058,13 +2058,16 @@ void wpas_connect_work_done(struct wpa_supplicant *wpa_s)
 }
 
 
-int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style)
+int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style,
+			    struct wpa_ssid *ssid)
 {
 	struct os_reltime now;
 	u8 addr[ETH_ALEN];
 
 	os_get_reltime(&now);
 	if (wpa_s->last_mac_addr_style == style &&
+	    /* pregenerated addresses do not expire */
+	    wpa_s->last_mac_addr_style != 3 &&
 	    wpa_s->last_mac_addr_change.sec != 0 &&
 	    !os_reltime_expired(&now, &wpa_s->last_mac_addr_change,
 				wpa_s->conf->rand_addr_lifetime)) {
@@ -2083,6 +2086,13 @@ int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style)
 		if (random_mac_addr_keep_oui(addr) < 0)
 			return -1;
 		break;
+	case 3:
+		if (!ssid) {
+			wpa_msg(wpa_s, MSG_ERROR, "Invalid 'ssid' for address policy 3");
+			return -1;
+		}
+		os_memcpy(addr, ssid->mac_value, ETH_ALEN);
+		break;
 	default:
 		return -1;
 	}
@@ -2116,7 +2126,7 @@ int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
 	    !wpa_s->conf->preassoc_mac_addr)
 		return 0;
 
-	return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr);
+	return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr, NULL);
 }
 
 
@@ -2251,7 +2261,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_SAE */
 
 	if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
-		if (wpas_update_random_addr(wpa_s, rand_style) < 0)
+		if (wpas_update_random_addr(wpa_s, rand_style, ssid) < 0)
 			return;
 		wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
 	} else if (rand_style == 0 && wpa_s->mac_addr_changed) {
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index cbc955159..ee8049a4c 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1631,7 +1631,8 @@ int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
 void wpas_request_connection(struct wpa_supplicant *wpa_s);
 void wpas_request_disconnection(struct wpa_supplicant *wpa_s);
 int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen);
-int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style);
+int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style,
+			    struct wpa_ssid *ssid);
 int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
 void add_freq(int *freqs, int *num_freqs, int freq);
 
-- 
2.34.0.rc0.344.g81b53c2807-goog




More information about the Hostap mailing list