Add support for using random local MAC address
This adds experimental support for wpa_supplicant to assign random local MAC addresses for both pre-association cases (scan, GAS/ANQP) and for connections. MAC address policy for each part can be controlled separately and the connection part can be set per network block. This requires support from the driver to allow local MAC address to be changed if random address policy is enabled. It should also be noted that number of drivers would not support concurrent operations (e.g., P2P and station association) with random addresses in use for one or both. This functionality can be controlled with the global configuration parameters mac_addr and preassoc_mac_addr which set the default MAC address policies for connections and pre-association operations (scan and GAS/ANQP while not connected). The global rand_addr_lifetime parameter can be used to set the lifetime of a random MAC address in seconds (default: 60 seconds). This is used to avoid unnecessarily frequent MAC address changes since those are likely to result in driver clearing most of its state. It should be noted that the random MAC address does not expire during an ESS connection, i.e., this lifetime is only for the case where the device is disconnected. The mac_addr parameter can also be set in the network blocks to define different behavior per network. For example, the global mac_addr=1 and preassoc_mac_addr=1 settings and mac_addr=0 in a home network profile would result in behavior where all scanning is performed using a random MAC address while connections to new networks (e.g., Interworking/Hotspot 2.0) would use random address and connections to the home network would use the permanent MAC address. Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
4d8fb63799
commit
c267753ba2
10 changed files with 178 additions and 0 deletions
|
@ -1754,6 +1754,7 @@ static const struct parse_data ssid_fields[] = {
|
||||||
#ifdef CONFIG_HS20
|
#ifdef CONFIG_HS20
|
||||||
{ INT(update_identifier) },
|
{ INT(update_identifier) },
|
||||||
#endif /* CONFIG_HS20 */
|
#endif /* CONFIG_HS20 */
|
||||||
|
{ INT_RANGE(mac_addr, 0, 1) },
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef OFFSET
|
#undef OFFSET
|
||||||
|
@ -2211,6 +2212,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
|
||||||
#ifdef CONFIG_IEEE80211W
|
#ifdef CONFIG_IEEE80211W
|
||||||
ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
|
ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
|
||||||
#endif /* CONFIG_IEEE80211W */
|
#endif /* CONFIG_IEEE80211W */
|
||||||
|
ssid->mac_addr = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3287,6 +3289,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
|
||||||
config->wmm_ac_params[2] = ac_vi;
|
config->wmm_ac_params[2] = ac_vi;
|
||||||
config->wmm_ac_params[3] = ac_vo;
|
config->wmm_ac_params[3] = ac_vo;
|
||||||
config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
|
config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
|
||||||
|
config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
|
||||||
|
|
||||||
if (ctrl_interface)
|
if (ctrl_interface)
|
||||||
config->ctrl_interface = os_strdup(ctrl_interface);
|
config->ctrl_interface = os_strdup(ctrl_interface);
|
||||||
|
@ -3909,6 +3912,9 @@ static const struct global_parse_data global_fields[] = {
|
||||||
{ STR(osu_dir), 0 },
|
{ STR(osu_dir), 0 },
|
||||||
{ STR(wowlan_triggers), 0 },
|
{ STR(wowlan_triggers), 0 },
|
||||||
{ INT(p2p_search_delay), 0},
|
{ INT(p2p_search_delay), 0},
|
||||||
|
{ INT(mac_addr), 0 },
|
||||||
|
{ INT(rand_addr_lifetime), 0 },
|
||||||
|
{ INT(preassoc_mac_addr), 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef FUNC
|
#undef FUNC
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#define DEFAULT_ACCESS_NETWORK_TYPE 15
|
#define DEFAULT_ACCESS_NETWORK_TYPE 15
|
||||||
#define DEFAULT_SCAN_CUR_FREQ 0
|
#define DEFAULT_SCAN_CUR_FREQ 0
|
||||||
#define DEFAULT_P2P_SEARCH_DELAY 500
|
#define DEFAULT_P2P_SEARCH_DELAY 500
|
||||||
|
#define DEFAULT_RAND_ADDR_LIFETIME 60
|
||||||
|
|
||||||
#include "config_ssid.h"
|
#include "config_ssid.h"
|
||||||
#include "wps/wps.h"
|
#include "wps/wps.h"
|
||||||
|
@ -1051,6 +1052,31 @@ struct wpa_config {
|
||||||
* resources.
|
* resources.
|
||||||
*/
|
*/
|
||||||
unsigned int p2p_search_delay;
|
unsigned int p2p_search_delay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mac_addr - MAC address policy default
|
||||||
|
*
|
||||||
|
* 0 = use permanent MAC address
|
||||||
|
* 1 = use random MAC address for each ESS connection
|
||||||
|
*
|
||||||
|
* By default, permanent MAC address is used unless policy is changed by
|
||||||
|
* the per-network mac_addr parameter. Global mac_addr=1 can be used to
|
||||||
|
* change this default behavior.
|
||||||
|
*/
|
||||||
|
int mac_addr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rand_addr_lifetime - Lifetime of random MAC address in seconds
|
||||||
|
*/
|
||||||
|
unsigned int rand_addr_lifetime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* preassoc_mac_addr - Pre-association MAC address policy
|
||||||
|
*
|
||||||
|
* 0 = use permanent MAC address
|
||||||
|
* 1 = use random MAC address
|
||||||
|
*/
|
||||||
|
int preassoc_mac_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -742,6 +742,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
|
||||||
#ifdef CONFIG_HS20
|
#ifdef CONFIG_HS20
|
||||||
INT(update_identifier);
|
INT(update_identifier);
|
||||||
#endif /* CONFIG_HS20 */
|
#endif /* CONFIG_HS20 */
|
||||||
|
write_int(f, "mac_addr", ssid->mac_addr, -1);
|
||||||
|
|
||||||
#undef STR
|
#undef STR
|
||||||
#undef INT
|
#undef INT
|
||||||
|
@ -1179,6 +1180,16 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
|
||||||
if (config->p2p_search_delay != DEFAULT_P2P_SEARCH_DELAY)
|
if (config->p2p_search_delay != DEFAULT_P2P_SEARCH_DELAY)
|
||||||
fprintf(f, "p2p_search_delay=%u\n",
|
fprintf(f, "p2p_search_delay=%u\n",
|
||||||
config->p2p_search_delay);
|
config->p2p_search_delay);
|
||||||
|
|
||||||
|
if (config->mac_addr)
|
||||||
|
fprintf(f, "mac_addr=%d\n", config->mac_addr);
|
||||||
|
|
||||||
|
if (config->rand_addr_lifetime != DEFAULT_RAND_ADDR_LIFETIME)
|
||||||
|
fprintf(f, "rand_addr_lifetime=%u\n",
|
||||||
|
config->rand_addr_lifetime);
|
||||||
|
|
||||||
|
if (config->preassoc_mac_addr)
|
||||||
|
fprintf(f, "preassoc_mac_addr=%d\n", config->preassoc_mac_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_NO_CONFIG_WRITE */
|
#endif /* CONFIG_NO_CONFIG_WRITE */
|
||||||
|
|
|
@ -653,6 +653,18 @@ struct wpa_ssid {
|
||||||
#endif /* CONFIG_HS20 */
|
#endif /* CONFIG_HS20 */
|
||||||
|
|
||||||
unsigned int wps_run;
|
unsigned int wps_run;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mac_addr - MAC address policy
|
||||||
|
*
|
||||||
|
* 0 = use permanent MAC address
|
||||||
|
* 1 = use random MAC address for each ESS connection
|
||||||
|
*
|
||||||
|
* Internally, special value -1 is used to indicate that the parameter
|
||||||
|
* was not specified in the configuration (i.e., default behavior is
|
||||||
|
* followed).
|
||||||
|
*/
|
||||||
|
int mac_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CONFIG_SSID_H */
|
#endif /* CONFIG_SSID_H */
|
||||||
|
|
|
@ -2480,6 +2480,8 @@ static int wpa_supplicant_ctrl_iface_remove_network(
|
||||||
struct wpa_ssid *remove_ssid = ssid;
|
struct wpa_ssid *remove_ssid = ssid;
|
||||||
id = ssid->id;
|
id = ssid->id;
|
||||||
ssid = ssid->next;
|
ssid = ssid->next;
|
||||||
|
if (wpa_s->last_ssid == remove_ssid)
|
||||||
|
wpa_s->last_ssid = NULL;
|
||||||
wpas_notify_network_removed(wpa_s, remove_ssid);
|
wpas_notify_network_removed(wpa_s, remove_ssid);
|
||||||
wpa_config_remove_network(wpa_s->conf, id);
|
wpa_config_remove_network(wpa_s->conf, id);
|
||||||
}
|
}
|
||||||
|
@ -2498,6 +2500,9 @@ static int wpa_supplicant_ctrl_iface_remove_network(
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wpa_s->last_ssid == ssid)
|
||||||
|
wpa_s->last_ssid = NULL;
|
||||||
|
|
||||||
if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
|
if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
|
||||||
#ifdef CONFIG_SME
|
#ifdef CONFIG_SME
|
||||||
wpa_s->sme.prev_bssid_set = 0;
|
wpa_s->sme.prev_bssid_set = 0;
|
||||||
|
|
|
@ -597,6 +597,7 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
|
||||||
{
|
{
|
||||||
struct gas_query_pending *query = work->ctx;
|
struct gas_query_pending *query = work->ctx;
|
||||||
struct gas_query *gas = query->gas;
|
struct gas_query *gas = query->gas;
|
||||||
|
struct wpa_supplicant *wpa_s = gas->wpa_s;
|
||||||
|
|
||||||
if (deinit) {
|
if (deinit) {
|
||||||
if (work->started) {
|
if (work->started) {
|
||||||
|
@ -609,6 +610,14 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
|
||||||
|
wpa_msg(wpa_s, MSG_INFO,
|
||||||
|
"Failed to assign random MAC address for GAS");
|
||||||
|
gas_query_free(query, 1);
|
||||||
|
radio_work_done(work);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
gas->work = work;
|
gas->work = work;
|
||||||
|
|
||||||
if (gas_query_tx(gas, query, query->req) < 0) {
|
if (gas_query_tx(gas, query, query->req) < 0) {
|
||||||
|
|
|
@ -158,6 +158,13 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
|
||||||
|
wpa_msg(wpa_s, MSG_INFO,
|
||||||
|
"Failed to assign random MAC address for a scan");
|
||||||
|
radio_work_done(work);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
wpa_supplicant_notify_scanning(wpa_s, 1);
|
wpa_supplicant_notify_scanning(wpa_s, 1);
|
||||||
|
|
||||||
if (wpa_s->clear_driver_scan_cache)
|
if (wpa_s->clear_driver_scan_cache)
|
||||||
|
|
|
@ -1380,6 +1380,55 @@ void wpas_connect_work_done(struct wpa_supplicant *wpa_s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wpas_update_random_addr(struct wpa_supplicant *wpa_s)
|
||||||
|
{
|
||||||
|
struct os_reltime now;
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
|
||||||
|
os_get_reltime(&now);
|
||||||
|
if (wpa_s->last_mac_addr_change.sec != 0 &&
|
||||||
|
!os_reltime_expired(&now, &wpa_s->last_mac_addr_change,
|
||||||
|
wpa_s->conf->rand_addr_lifetime)) {
|
||||||
|
wpa_msg(wpa_s, MSG_DEBUG,
|
||||||
|
"Previously selected random MAC address has not yet expired");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (random_mac_addr(addr) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (wpa_drv_set_mac_addr(wpa_s, addr) < 0) {
|
||||||
|
wpa_msg(wpa_s, MSG_INFO,
|
||||||
|
"Failed to set random MAC address");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_get_reltime(&wpa_s->last_mac_addr_change);
|
||||||
|
wpa_s->mac_addr_changed = 1;
|
||||||
|
|
||||||
|
if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
|
||||||
|
wpa_msg(wpa_s, MSG_INFO,
|
||||||
|
"Could not update MAC address information");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
|
||||||
|
MAC2STR(addr));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
|
||||||
|
{
|
||||||
|
if (wpa_s->wpa_state >= WPA_AUTHENTICATING ||
|
||||||
|
!wpa_s->conf->preassoc_mac_addr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return wpas_update_random_addr(wpa_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
|
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1395,6 +1444,29 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
|
||||||
{
|
{
|
||||||
struct wpa_connect_work *cwork;
|
struct wpa_connect_work *cwork;
|
||||||
|
|
||||||
|
if (wpa_s->last_ssid == ssid) {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
|
||||||
|
} else if (ssid->mac_addr == 1 ||
|
||||||
|
(ssid->mac_addr == -1 && wpa_s->conf->mac_addr == 1)) {
|
||||||
|
if (wpas_update_random_addr(wpa_s) < 0)
|
||||||
|
return;
|
||||||
|
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
|
||||||
|
} else if (wpa_s->mac_addr_changed) {
|
||||||
|
if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
|
||||||
|
wpa_msg(wpa_s, MSG_INFO,
|
||||||
|
"Could not restore permanent MAC address");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wpa_s->mac_addr_changed = 0;
|
||||||
|
if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
|
||||||
|
wpa_msg(wpa_s, MSG_INFO,
|
||||||
|
"Could not update MAC address information");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
|
||||||
|
}
|
||||||
|
wpa_s->last_ssid = ssid;
|
||||||
|
|
||||||
#ifdef CONFIG_IBSS_RSN
|
#ifdef CONFIG_IBSS_RSN
|
||||||
ibss_rsn_deinit(wpa_s->ibss_rsn);
|
ibss_rsn_deinit(wpa_s->ibss_rsn);
|
||||||
wpa_s->ibss_rsn = NULL;
|
wpa_s->ibss_rsn = NULL;
|
||||||
|
@ -2662,6 +2734,8 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -332,6 +332,23 @@ fast_reauth=1
|
||||||
# 1: Scan current operating frequency if another VIF on the same radio
|
# 1: Scan current operating frequency if another VIF on the same radio
|
||||||
# is already associated.
|
# is already associated.
|
||||||
|
|
||||||
|
# MAC address policy default
|
||||||
|
# 0 = use permanent MAC address
|
||||||
|
# 1 = use random MAC address for each ESS connection
|
||||||
|
#
|
||||||
|
# By default, permanent MAC address is used unless policy is changed by
|
||||||
|
# the per-network mac_addr parameter. Global mac_addr=1 can be used to
|
||||||
|
# change this default behavior.
|
||||||
|
#mac_addr=0
|
||||||
|
|
||||||
|
# Lifetime of random MAC address in seconds (default: 60)
|
||||||
|
#rand_addr_lifetime=60
|
||||||
|
|
||||||
|
# MAC address policy for pre-association operations (scanning, ANQP)
|
||||||
|
# 0 = use permanent MAC address
|
||||||
|
# 1 = use random MAC address
|
||||||
|
#preassoc_mac_addr=0
|
||||||
|
|
||||||
# Interworking (IEEE 802.11u)
|
# Interworking (IEEE 802.11u)
|
||||||
|
|
||||||
# Enable Interworking
|
# Enable Interworking
|
||||||
|
@ -962,6 +979,11 @@ fast_reauth=1
|
||||||
# Beacon interval (default: 100 TU)
|
# Beacon interval (default: 100 TU)
|
||||||
#beacon_int=100
|
#beacon_int=100
|
||||||
|
|
||||||
|
# MAC address policy
|
||||||
|
# 0 = use permanent MAC address
|
||||||
|
# 1 = use random MAC address for each ESS connection
|
||||||
|
#mac_addr=0
|
||||||
|
|
||||||
# disable_ht: Whether HT (802.11n) should be disabled.
|
# disable_ht: Whether HT (802.11n) should be disabled.
|
||||||
# 0 = HT enabled (if AP supports it)
|
# 0 = HT enabled (if AP supports it)
|
||||||
# 1 = HT disabled
|
# 1 = HT disabled
|
||||||
|
|
|
@ -421,6 +421,7 @@ struct wpa_supplicant {
|
||||||
int disconnected; /* all connections disabled; i.e., do no reassociate
|
int disconnected; /* all connections disabled; i.e., do no reassociate
|
||||||
* before this has been cleared */
|
* before this has been cleared */
|
||||||
struct wpa_ssid *current_ssid;
|
struct wpa_ssid *current_ssid;
|
||||||
|
struct wpa_ssid *last_ssid;
|
||||||
struct wpa_bss *current_bss;
|
struct wpa_bss *current_bss;
|
||||||
int ap_ies_from_associnfo;
|
int ap_ies_from_associnfo;
|
||||||
unsigned int assoc_freq;
|
unsigned int assoc_freq;
|
||||||
|
@ -609,6 +610,9 @@ struct wpa_supplicant {
|
||||||
unsigned int last_eapol_matches_bssid:1;
|
unsigned int last_eapol_matches_bssid:1;
|
||||||
unsigned int eap_expected_failure:1;
|
unsigned int eap_expected_failure:1;
|
||||||
unsigned int reattach:1; /* reassociation to the same BSS requested */
|
unsigned int reattach:1; /* reassociation to the same BSS requested */
|
||||||
|
unsigned int mac_addr_changed:1;
|
||||||
|
|
||||||
|
struct os_reltime last_mac_addr_change;
|
||||||
|
|
||||||
struct ibss_rsn *ibss_rsn;
|
struct ibss_rsn *ibss_rsn;
|
||||||
|
|
||||||
|
@ -958,6 +962,8 @@ int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
|
||||||
size_t ssid_len);
|
size_t ssid_len);
|
||||||
void wpas_request_connection(struct wpa_supplicant *wpa_s);
|
void wpas_request_connection(struct wpa_supplicant *wpa_s);
|
||||||
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen);
|
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 wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
|
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
|
||||||
|
|
Loading…
Reference in a new issue