]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
wpa_supplicant: Add support for pregenerated MAC
authorAndrzej Ostruszka <amo@semihalf.com>
Wed, 10 Nov 2021 19:16:35 +0000 (19:16 +0000)
committerJouni Malinen <j@w1.fi>
Mon, 28 Nov 2022 17:05:26 +0000 (19:05 +0200)
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@semihalf.com>
wpa_supplicant/config.c
wpa_supplicant/config_ssid.h
wpa_supplicant/dbus/dbus_new_handlers.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index 2754ad8331ede5f0f4a9d73757638a8cb3ca9afe..a2e21431c2faea6ed940c1109ba8568c76d619ad 100644 (file)
@@ -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) },
index c77ffa11a92acf3286b8a0e6501ee8c6df91014d..7bf20823740d0d4ad6a08e562a125ad3742456cf 100644 (file)
@@ -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
         *
index f99aafa4d11ec61dd5687778512014011406e0e8..b45ab4022bb7edc70d118e2483930e9997387c31 100644 (file)
@@ -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:
index 2739e93df0a02a33bd3ea83be2d6b7e2f654f0fc..e29fcc2c32ffab791d644c7bc9a5dcaa1dd3c243 100644 (file)
@@ -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) {
index 330b80f4da82b97fa9bf9bdf5e2fdf908d547116..c1ed21dccc7e4d1f326c5e07bf06dd79b1a3ef66 100644 (file)
@@ -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);