GAS: Add support to randomize transmitter address

Add support to send GAS requests with a randomized transmitter address
if supported by the driver. The following control interface commands
(and matching configuration file parameters) can be used to configure
different types of randomization:

"SET gas_rand_mac_addr 0" to disable randomizing TX MAC address,
"SET gas_rand_mac_addr 1" to randomize the complete TX MAC address,
"SET gas_rand_mac_addr 2" to randomize the TX MAC address except for OUI.

A new random MAC address will be generated for every
gas_rand_addr_lifetime seconds and this can be configured with
"SET gas_rand_addr_lifetime <timeout>".

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Vamsi Krishna 2016-12-08 21:51:25 +05:30 committed by Jouni Malinen
parent 8331c9b316
commit 1d9d21f376
5 changed files with 102 additions and 5 deletions

View file

@ -3748,6 +3748,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->ctrl_interface = os_strdup(ctrl_interface); config->ctrl_interface = os_strdup(ctrl_interface);
if (driver_param) if (driver_param)
config->driver_param = os_strdup(driver_param); config->driver_param = os_strdup(driver_param);
config->gas_rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
return config; return config;
} }
@ -4456,6 +4457,8 @@ static const struct global_parse_data global_fields[] = {
{ INT(gas_address3), 0 }, { INT(gas_address3), 0 },
{ INT_RANGE(ftm_responder, 0, 1), 0 }, { INT_RANGE(ftm_responder, 0, 1), 0 },
{ INT_RANGE(ftm_initiator, 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 #undef FUNC

View file

@ -1328,6 +1328,21 @@ struct wpa_config {
* wpa_supplicant. * wpa_supplicant.
*/ */
int ftm_initiator; 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;
}; };

View file

@ -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); fprintf(f, "fst_priority=%d\n", config->fst_priority);
if (config->fst_llt) if (config->fst_llt)
fprintf(f, "fst_llt=%d\n", 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 */ #endif /* CONFIG_NO_CONFIG_WRITE */

View file

@ -53,6 +53,7 @@ struct gas_query_pending {
const struct wpabuf *adv_proto, const struct wpabuf *adv_proto,
const struct wpabuf *resp, u16 status_code); const struct wpabuf *resp, u16 status_code);
void *ctx; void *ctx;
u8 sa[ETH_ALEN];
}; };
/** /**
@ -63,6 +64,9 @@ struct gas_query {
struct dl_list pending; /* struct gas_query_pending */ struct dl_list pending; /* struct gas_query_pending */
struct gas_query_pending *current; struct gas_query_pending *current;
struct wpa_radio_work *work; 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 " wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
"freq=%d prot=%d", MAC2STR(query->addr), "freq=%d prot=%d using src addr " MACSTR,
(unsigned int) wpabuf_len(req), query->freq, prot); MAC2STR(query->addr), (unsigned int) wpabuf_len(req),
query->freq, prot, MAC2STR(query->sa));
if (prot) { if (prot) {
u8 *categ = wpabuf_mhead_u8(req); u8 *categ = wpabuf_mhead_u8(req);
*categ = WLAN_ACTION_PROTECTED_DUAL; *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; bssid = query->addr;
else else
bssid = wildcard_bssid; bssid = wildcard_bssid;
res = offchannel_send_action(gas->wpa_s, query->freq, query->addr, res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
gas->wpa_s->own_addr, bssid, query->sa, bssid, wpabuf_head(req),
wpabuf_head(req), wpabuf_len(req), wpabuf_len(req), wait_time,
wait_time, gas_query_tx_status, 0); gas_query_tx_status, 0);
if (res == 0) if (res == 0)
query->offchannel_tx_started = 1; query->offchannel_tx_started = 1;
return res; 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_query_req - Request a GAS query
* @gas: GAS query data from gas_query_init() * @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; return -1;
query->gas = gas; query->gas = gas;
if (gas_query_set_sa(gas, query)) {
os_free(query);
return -1;
}
os_memcpy(query->addr, dst, ETH_ALEN); os_memcpy(query->addr, dst, ETH_ALEN);
query->dialog_token = dialog_token; query->dialog_token = dialog_token;
query->freq = freq; query->freq = freq;

View file

@ -422,6 +422,15 @@ fast_reauth=1
# 2 = like 1, but maintain OUI (with local admin bit set) # 2 = like 1, but maintain OUI (with local admin bit set)
#preassoc_mac_addr=0 #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) # Interworking (IEEE 802.11u)
# Enable Interworking # Enable Interworking