From 9025def55cfdcdfa43cfb8712cd4befbf9fb4534 Mon Sep 17 00:00:00 2001 From: Andrzej Ostruszka Date: Wed, 10 Nov 2021 19:16:35 +0000 Subject: wpa_supplicant: Add support for pregenerated MAC 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 --- wpa_supplicant/config.c | 47 ++++++++++++++++++++++++++++++++- wpa_supplicant/config_ssid.h | 9 +++++++ wpa_supplicant/dbus/dbus_new_handlers.c | 22 ++++++++++++++- wpa_supplicant/wpa_supplicant.c | 18 ++++++++++--- wpa_supplicant/wpa_supplicant_i.h | 3 ++- 5 files changed, 93 insertions(+), 6 deletions(-) diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 2754ad833..a2e21431c 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2345,6 +2345,50 @@ 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) + 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 @@ -2643,7 +2687,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 c77ffa11a..7bf208237 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -974,6 +974,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 (see mac_value) * * Internally, special value -1 is used to indicate that the parameter * was not specified in the configuration (i.e., default behavior is @@ -981,6 +982,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 f99aafa4d..b45ab4022 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -152,7 +152,7 @@ static const char * const dont_quote[] = { #ifdef CONFIG_INTERWORKING "roaming_consortium", "required_roaming_consortium", #endif /* CONFIG_INTERWORKING */ - NULL + "mac_value", NULL }; static dbus_bool_t should_quote_opt(const char *key) @@ -206,6 +206,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; @@ -315,12 +317,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_INFO, "dbus: 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 2739e93df..e29fcc2c3 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -2222,13 +2222,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)) { @@ -2247,6 +2250,14 @@ 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_INFO, + "Invalid 'ssid' for address policy 3"); + return -1; + } + os_memcpy(addr, ssid->mac_value, ETH_ALEN); + break; default: return -1; } @@ -2280,7 +2291,8 @@ 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); } @@ -2417,7 +2429,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 330b80f4d..c1ed21dcc 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1640,7 +1640,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); -- cgit v1.2.3-18-g5258