diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index bdaaa5430..58ecf19fd 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -3748,6 +3748,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->ctrl_interface = os_strdup(ctrl_interface); if (driver_param) config->driver_param = os_strdup(driver_param); + config->gas_rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME; return config; } @@ -4456,6 +4457,8 @@ static const struct global_parse_data global_fields[] = { { INT(gas_address3), 0 }, { INT_RANGE(ftm_responder, 0, 1), 0 }, { INT_RANGE(ftm_initiator, 0, 1), 0 }, + { INT(gas_rand_addr_lifetime), 0 }, + { INT_RANGE(gas_rand_mac_addr, 0, 2), 0 }, }; #undef FUNC diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 48e64be5d..2f2bb01c6 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -1328,6 +1328,21 @@ struct wpa_config { * wpa_supplicant. */ int ftm_initiator; + + /** + * gas_rand_addr_lifetime - Lifetime of random MAC address for ANQP in + * seconds + */ + unsigned int gas_rand_addr_lifetime; + + /** + * gas_rand_mac_addr - GAS MAC address policy + * + * 0 = use permanent MAC address + * 1 = use random MAC address + * 2 = like 1, but maintain OUI (with local admin bit set) + */ + int gas_rand_mac_addr; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 920bdc07f..84a1ee945 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1413,6 +1413,13 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) fprintf(f, "fst_priority=%d\n", config->fst_priority); if (config->fst_llt) fprintf(f, "fst_llt=%d\n", config->fst_llt); + + if (config->gas_rand_addr_lifetime != DEFAULT_RAND_ADDR_LIFETIME) + fprintf(f, "gas_rand_addr_lifetime=%u\n", + config->gas_rand_addr_lifetime); + if (config->gas_rand_mac_addr) + fprintf(f, "gas_rand_mac_addr=%d\n", config->gas_rand_mac_addr); + } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c index 1b57d8892..db481a591 100644 --- a/wpa_supplicant/gas_query.c +++ b/wpa_supplicant/gas_query.c @@ -53,6 +53,7 @@ struct gas_query_pending { const struct wpabuf *adv_proto, const struct wpabuf *resp, u16 status_code); void *ctx; + u8 sa[ETH_ALEN]; }; /** @@ -63,6 +64,9 @@ struct gas_query { struct dl_list pending; /* struct gas_query_pending */ struct gas_query_pending *current; struct wpa_radio_work *work; + struct os_reltime last_mac_addr_rand; + int last_rand_sa_type; + u8 rand_addr[ETH_ALEN]; }; @@ -278,8 +282,9 @@ static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, }; wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u " - "freq=%d prot=%d", MAC2STR(query->addr), - (unsigned int) wpabuf_len(req), query->freq, prot); + "freq=%d prot=%d using src addr " MACSTR, + MAC2STR(query->addr), (unsigned int) wpabuf_len(req), + query->freq, prot, MAC2STR(query->sa)); if (prot) { u8 *categ = wpabuf_mhead_u8(req); *categ = WLAN_ACTION_PROTECTED_DUAL; @@ -295,10 +300,12 @@ static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, bssid = query->addr; else bssid = wildcard_bssid; + res = offchannel_send_action(gas->wpa_s, query->freq, query->addr, - gas->wpa_s->own_addr, bssid, - wpabuf_head(req), wpabuf_len(req), - wait_time, gas_query_tx_status, 0); + query->sa, bssid, wpabuf_head(req), + wpabuf_len(req), wait_time, + gas_query_tx_status, 0); + if (res == 0) query->offchannel_tx_started = 1; return res; @@ -725,6 +732,58 @@ static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst) } +static int gas_query_set_sa(struct gas_query *gas, + struct gas_query_pending *query) +{ + struct wpa_supplicant *wpa_s = gas->wpa_s; + struct os_reltime now; + + if (!wpa_s->conf->gas_rand_mac_addr || + !(wpa_s->current_bss ? + (wpa_s->drv_flags & + WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED) : + (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA))) { + /* Use own MAC address as the transmitter address */ + os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN); + return 0; + } + + os_get_reltime(&now); + + if (wpa_s->conf->gas_rand_mac_addr == gas->last_rand_sa_type && + gas->last_mac_addr_rand.sec != 0 && + !os_reltime_expired(&now, &gas->last_mac_addr_rand, + wpa_s->conf->gas_rand_addr_lifetime)) { + wpa_printf(MSG_DEBUG, + "GAS: Use the previously selected random transmitter address " + MACSTR, MAC2STR(gas->rand_addr)); + os_memcpy(query->sa, gas->rand_addr, ETH_ALEN); + return 0; + } + + if (wpa_s->conf->gas_rand_mac_addr == 1 && + random_mac_addr(gas->rand_addr) < 0) { + wpa_printf(MSG_ERROR, "GAS: Failed to get random address"); + return -1; + } + + if (wpa_s->conf->gas_rand_mac_addr == 2 && + random_mac_addr_keep_oui(gas->rand_addr) < 0) { + wpa_printf(MSG_ERROR, + "GAS: Failed to get random address with same OUI"); + return -1; + } + + wpa_printf(MSG_DEBUG, "GAS: Use a new random transmitter address " + MACSTR, MAC2STR(gas->rand_addr)); + os_memcpy(query->sa, gas->rand_addr, ETH_ALEN); + os_get_reltime(&gas->last_mac_addr_rand); + gas->last_rand_sa_type = wpa_s->conf->gas_rand_mac_addr; + + return 0; +} + + /** * gas_query_req - Request a GAS query * @gas: GAS query data from gas_query_init() @@ -759,6 +818,10 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, return -1; query->gas = gas; + if (gas_query_set_sa(gas, query)) { + os_free(query); + return -1; + } os_memcpy(query->addr, dst, ETH_ALEN); query->dialog_token = dialog_token; query->freq = freq; diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index c90fa629a..6faa7af1f 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -422,6 +422,15 @@ fast_reauth=1 # 2 = like 1, but maintain OUI (with local admin bit set) #preassoc_mac_addr=0 +# MAC address policy for GAS operations +# 0 = use permanent MAC address +# 1 = use random MAC address +# 2 = like 1, but maintain OUI (with local admin bit set) +#gas_rand_mac_addr=0 + +# Lifetime of GAS random MAC address in seconds (default: 60) +#gas_rand_addr_lifetime=60 + # Interworking (IEEE 802.11u) # Enable Interworking