diff mbox series

[v3] Add MAC address randomization functionality

Message ID 1559239846-9329-1-git-send-email-ejcaruso@chromium.org
State Changes Requested
Headers show
Series [v3] Add MAC address randomization functionality | expand

Commit Message

Eric Caruso May 30, 2019, 6:10 p.m. UTC
Add D-Bus property:
* MACAddressRandomizationMask: a{say}

which configure random MAC address functionality in the Wi-Fi
driver via netlink. This also fixes weird pointer ownership
that was causing memory issues.

Signed-off-by: Eric Caruso <ejcaruso@chromium.org>
---
 doc/dbus.doxygen                        |   5 +
 wpa_supplicant/ctrl_iface.c             |  55 +--------
 wpa_supplicant/dbus/dbus_new.c          |   5 +
 wpa_supplicant/dbus/dbus_new_handlers.c | 153 ++++++++++++++++++++++++
 wpa_supplicant/dbus/dbus_new_handlers.h |   2 +
 wpa_supplicant/scan.c                   |  90 ++++++++------
 wpa_supplicant/scan.h                   |   2 +
 wpa_supplicant/wpa_supplicant.c         |  57 +++++++++
 wpa_supplicant/wpa_supplicant_i.h       |   5 +
 9 files changed, 288 insertions(+), 86 deletions(-)

Comments

Dan Williams May 30, 2019, 7:47 p.m. UTC | #1
On Thu, 2019-05-30 at 11:10 -0700, Eric Caruso wrote:
> Add D-Bus property:
> * MACAddressRandomizationMask: a{say}
> 
> which configure random MAC address functionality in the Wi-Fi
> driver via netlink. This also fixes weird pointer ownership
> that was causing memory issues.

All the dbus stuff LGTM.

Dan

> Signed-off-by: Eric Caruso <ejcaruso@chromium.org>
> ---
>  doc/dbus.doxygen                        |   5 +
>  wpa_supplicant/ctrl_iface.c             |  55 +--------
>  wpa_supplicant/dbus/dbus_new.c          |   5 +
>  wpa_supplicant/dbus/dbus_new_handlers.c | 153
> ++++++++++++++++++++++++
>  wpa_supplicant/dbus/dbus_new_handlers.h |   2 +
>  wpa_supplicant/scan.c                   |  90 ++++++++------
>  wpa_supplicant/scan.h                   |   2 +
>  wpa_supplicant/wpa_supplicant.c         |  57 +++++++++
>  wpa_supplicant/wpa_supplicant_i.h       |   5 +
>  9 files changed, 288 insertions(+), 86 deletions(-)
> 
> diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen
> index 072ed3486..9f6af52b1 100644
> --- a/doc/dbus.doxygen
> +++ b/doc/dbus.doxygen
> @@ -1043,6 +1043,11 @@ fi.w1.wpa_supplicant1.CreateInterface.
>  	<h3>WpsPriority - s - (read/write)</h3>
>  	<p>Priority for the networks added through WPS</p>
>        </li>
> +
> +      <li>
> +	<h3>MACAddressRandomizationMask - a{say} - (read/write)</h3>
> +	<p>Masks to show which bits not to randomize with MAC address
> randomization. Possible keys are "scan", "sched_scan", and "pno".
> Values must be an array of 6 bytes.</p>
> +      </li>
>      </ul>
>  
>  \subsection dbus_interface_signals Signals
> diff --git a/wpa_supplicant/ctrl_iface.c
> b/wpa_supplicant/ctrl_iface.c
> index 10f1908f8..8efc08d4d 100644
> --- a/wpa_supplicant/ctrl_iface.c
> +++ b/wpa_supplicant/ctrl_iface.c
> @@ -9626,59 +9626,10 @@ static int
> wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
>  		return -1;
>  	}
>  
> -	if (!enable) {
> -		wpas_mac_addr_rand_scan_clear(wpa_s, type);
> -		if (wpa_s->pno) {
> -			if (type & MAC_ADDR_RAND_PNO) {
> -				wpas_stop_pno(wpa_s);
> -				wpas_start_pno(wpa_s);
> -			}
> -		} else if (wpa_s->sched_scanning &&
> -			   (type & MAC_ADDR_RAND_SCHED_SCAN)) {
> -			wpas_scan_restart_sched_scan(wpa_s);
> -		}
> -		return 0;
> -	}
> +	if (!enable)
> +		return wpas_disable_mac_addr_randomization(wpa_s,
> type);
>  
> -	if ((addr && !mask) || (!addr && mask)) {
> -		wpa_printf(MSG_INFO,
> -			   "CTRL: MAC_RAND_SCAN invalid addr/mask
> combination");
> -		return -1;
> -	}
> -
> -	if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
> -		wpa_printf(MSG_INFO,
> -			   "CTRL: MAC_RAND_SCAN cannot allow multicast
> address");
> -		return -1;
> -	}
> -
> -	if (type & MAC_ADDR_RAND_SCAN) {
> -		if (wpas_mac_addr_rand_scan_set(wpa_s,
> MAC_ADDR_RAND_SCAN,
> -					    addr, mask))
> -			return -1;
> -	}
> -
> -	if (type & MAC_ADDR_RAND_SCHED_SCAN) {
> -		if (wpas_mac_addr_rand_scan_set(wpa_s,
> MAC_ADDR_RAND_SCHED_SCAN,
> -					    addr, mask))
> -			return -1;
> -
> -		if (wpa_s->sched_scanning && !wpa_s->pno)
> -			wpas_scan_restart_sched_scan(wpa_s);
> -	}
> -
> -	if (type & MAC_ADDR_RAND_PNO) {
> -		if (wpas_mac_addr_rand_scan_set(wpa_s,
> MAC_ADDR_RAND_PNO,
> -					    addr, mask))
> -			return -1;
> -
> -		if (wpa_s->pno) {
> -			wpas_stop_pno(wpa_s);
> -			wpas_start_pno(wpa_s);
> -		}
> -	}
> -
> -	return 0;
> +	return wpas_enable_mac_addr_randomization(wpa_s, type, addr,
> mask);
>  }
>  
>  
> diff --git a/wpa_supplicant/dbus/dbus_new.c
> b/wpa_supplicant/dbus/dbus_new.c
> index fc2fc2ef1..c5d3b8a02 100644
> --- a/wpa_supplicant/dbus/dbus_new.c
> +++ b/wpa_supplicant/dbus/dbus_new.c
> @@ -3803,6 +3803,11 @@ static const struct wpa_dbus_property_desc
> wpas_dbus_interface_properties[] = {
>  	  NULL,
>  	  NULL
>  	},
> +	{ "MACAddressRandomizationMask", WPAS_DBUS_NEW_IFACE_INTERFACE,
> "a{say}",
> +	  wpas_dbus_getter_mac_address_randomization_mask,
> +	  wpas_dbus_setter_mac_address_randomization_mask,
> +	  NULL
> +	},
>  	{ NULL, NULL, NULL, NULL, NULL, NULL }
>  };
>  
> diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c
> b/wpa_supplicant/dbus/dbus_new_handlers.c
> index 6c36d91a0..764675caa 100644
> --- a/wpa_supplicant/dbus/dbus_new_handlers.c
> +++ b/wpa_supplicant/dbus/dbus_new_handlers.c
> @@ -3989,6 +3989,159 @@ out:
>  }
>  
>  
> +/**
> + * wpas_dbus_setter_mac_address_randomization_mask - Set masks used
> for
> + * MAC address randomization
> + * @iter: Pointer to incoming dbus message iter
> + * @error: Location to store error on failure
> + * @user_data: Function specific data
> + * Returns: TRUE on success, FALSE on failure
> + *
> + * Setter for "MACAddressRandomizationMask" property.
> + */
> +dbus_bool_t wpas_dbus_setter_mac_address_randomization_mask(
> +	const struct wpa_dbus_property_desc *property_desc,
> +	DBusMessageIter *iter, DBusError *error, void *user_data)
> +{
> +	struct wpa_supplicant *wpa_s = user_data;
> +	DBusMessageIter variant_iter, dict_iter, entry_iter,
> array_iter;
> +	const char *key;
> +	unsigned int rand_type = 0;
> +	const u8 *mask;
> +	int mask_len;
> +	unsigned int rand_types_to_disable = MAC_ADDR_RAND_ALL;
> +
> +	dbus_message_iter_recurse(iter, &variant_iter);
> +	dbus_message_iter_recurse(&variant_iter, &dict_iter);
> +	while (dbus_message_iter_get_arg_type(&dict_iter) ==
> +	       DBUS_TYPE_DICT_ENTRY) {
> +		dbus_message_iter_recurse(&dict_iter, &entry_iter);
> +		if (dbus_message_iter_get_arg_type(&entry_iter) !=
> DBUS_TYPE_STRING) {
> +			dbus_set_error(error, DBUS_ERROR_FAILED,
> +				       "%s: key not a string",
> __func__);
> +			return FALSE;
> +		}
> +		dbus_message_iter_get_basic(&entry_iter, &key);
> +		dbus_message_iter_next(&entry_iter);
> +		if (dbus_message_iter_get_arg_type(&entry_iter) !=
> DBUS_TYPE_ARRAY ||
> +		    dbus_message_iter_get_element_type(&entry_iter) !=
> DBUS_TYPE_BYTE) {
> +			dbus_set_error(error, DBUS_ERROR_FAILED,
> +				       "%s: mask was not a byte array",
> __func__);
> +			return FALSE;
> +		}
> +		dbus_message_iter_recurse(&entry_iter, &array_iter);
> +		dbus_message_iter_get_fixed_array(&array_iter, &mask,
> &mask_len);
> +
> +		if (os_strcmp(key, "scan") == 0) {
> +			rand_type = MAC_ADDR_RAND_SCAN;
> +		} else if (os_strcmp(key, "sched_scan") == 0) {
> +			rand_type = MAC_ADDR_RAND_SCHED_SCAN;
> +		} else if (os_strcmp(key, "pno") == 0) {
> +			rand_type = MAC_ADDR_RAND_PNO;
> +		} else {
> +			dbus_set_error(error, DBUS_ERROR_FAILED,
> +				       "%s: bad scan type \"%s\"",
> __func__, key);
> +			return FALSE;
> +		}
> +
> +		if (mask_len != ETH_ALEN) {
> +			dbus_set_error(error, DBUS_ERROR_FAILED,
> +				       "%s: malformed MAC mask given",
> __func__);
> +			return FALSE;
> +		}
> +
> +		if (wpas_enable_mac_addr_randomization(
> +		    wpa_s, rand_type, wpa_s->perm_addr, mask)) {
> +			dbus_set_error(error, DBUS_ERROR_FAILED,
> +				       "%s: failed to set up MAC
> address randomization for %s",
> +				       __func__, key);
> +			return FALSE;
> +		}
> +
> +		wpa_printf(MSG_DEBUG, "%s: Enabled MAC address
> randomization for %s with mask: "
> +			MACSTR, wpa_s->ifname, key, MAC2STR(mask));
> +		rand_types_to_disable &= ~rand_type;
> +		dbus_message_iter_next(&dict_iter);
> +	}
> +
> +	if (rand_types_to_disable &&
> +	    wpas_disable_mac_addr_randomization(wpa_s,
> rand_types_to_disable)) {
> +		dbus_set_error(error, DBUS_ERROR_FAILED,
> +			       "%s: failed to disable MAC address
> randomization",
> +			       __func__);
> +		return FALSE;
> +	}
> +
> +	return TRUE;
> +}
> +
> +
> +dbus_bool_t wpas_dbus_getter_mac_address_randomization_mask(
> +	const struct wpa_dbus_property_desc *property_desc,
> +	DBusMessageIter *iter, DBusError *error, void *user_data)
> +{
> +	struct wpa_supplicant *wpa_s = user_data;
> +	DBusMessageIter variant_iter, dict_iter, entry_iter,
> array_iter;
> +	int i;
> +	u8 mask_buf[ETH_ALEN];
> +	/* Read docs on dbus_message_iter_append_fixed_array for why
> this
> +	 * is necessary... */
> +	u8* mask = mask_buf;
> +	static const struct {
> +		const char *key;
> +		unsigned int type;
> +	} types[] = {
> +		{ "scan", MAC_ADDR_RAND_SCAN },
> +		{ "sched_scan", MAC_ADDR_RAND_SCHED_SCAN },
> +		{ "pno", MAC_ADDR_RAND_PNO }
> +	};
> +
> +	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
> +					      "a{say}", &variant_iter)
> ||
> +	    !dbus_message_iter_open_container(&variant_iter,
> DBUS_TYPE_ARRAY,
> +					      "{say}", &dict_iter)) {
> +		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no
> memory");
> +		return FALSE;
> +	}
> +
> +	for (i = 0; i < sizeof(types)/sizeof(types[0]); i++) {
> +		if (wpas_mac_addr_rand_scan_get_mask(wpa_s,
> types[i].type, mask))
> +			continue;
> +
> +		if (!dbus_message_iter_open_container(&dict_iter,
> +						      DBUS_TYPE_DICT_EN
> TRY,
> +						      NULL,
> &entry_iter) ||
> +		    !dbus_message_iter_append_basic(&entry_iter,
> +						    DBUS_TYPE_STRING,
> +						    &types[i].key) ||
> +		    !dbus_message_iter_open_container(&entry_iter,
> +						      DBUS_TYPE_ARRAY,
> +						      DBUS_TYPE_BYTE_AS
> _STRING,
> +						      &array_iter) ||
> +		    !dbus_message_iter_append_fixed_array(&array_iter,
> +							  DBUS_TYPE_BYT
> E,
> +							  &mask,
> +							  ETH_ALEN) ||
> +		    !dbus_message_iter_close_container(&entry_iter,
> +						       &array_iter) ||
> +		    !dbus_message_iter_close_container(&dict_iter,
> +						       &entry_iter)) {
> +			dbus_set_error_const(error,
> DBUS_ERROR_NO_MEMORY,
> +					     "no memory");
> +			return FALSE;
> +		}
> +	}
> +
> +	if (!dbus_message_iter_close_container(&variant_iter,
> &dict_iter) ||
> +	    !dbus_message_iter_close_container(iter, &variant_iter)) {
> +		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no
> memory");
> +		return FALSE;
> +	}
> +
> +	return TRUE;
> +}
> +
> +
>  /**
>   * wpas_dbus_getter_sta_address - Return the address of a connected
> station
>   * @iter: Pointer to incoming dbus message iter
> diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h
> b/wpa_supplicant/dbus/dbus_new_handlers.h
> index d922ce1b4..afa26efed 100644
> --- a/wpa_supplicant/dbus/dbus_new_handlers.h
> +++ b/wpa_supplicant/dbus/dbus_new_handlers.h
> @@ -177,6 +177,8 @@
> DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_engine_path);
>  DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_module_path);
>  DECLARE_ACCESSOR(wpas_dbus_getter_blobs);
>  DECLARE_ACCESSOR(wpas_dbus_getter_stas);
> +DECLARE_ACCESSOR(wpas_dbus_getter_mac_address_randomization_mask);
> +DECLARE_ACCESSOR(wpas_dbus_setter_mac_address_randomization_mask);
>  DECLARE_ACCESSOR(wpas_dbus_getter_sta_address);
>  DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid);
>  DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps);
> diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
> index 7abb028dd..251e0642e 100644
> --- a/wpa_supplicant/scan.c
> +++ b/wpa_supplicant/scan.c
> @@ -79,6 +79,27 @@ static int wpas_wps_in_use(struct wpa_supplicant
> *wpa_s,
>  #endif /* CONFIG_WPS */
>  
>  
> +static int wpa_setup_mac_addr_rand_params(struct
> wpa_driver_scan_params *params,
> +					  const u8 *mac_addr)
> +{
> +	u8 *tmp;
> +
> +	if (!mac_addr)
> +		return 0;
> +
> +	params->mac_addr_rand = 1;
> +
> +	tmp = os_malloc(2 * ETH_ALEN);
> +	if (!tmp)
> +		return -1;
> +
> +	os_memcpy(tmp, mac_addr, 2 * ETH_ALEN);
> +	params->mac_addr = tmp;
> +	params->mac_addr_mask = tmp + ETH_ALEN;
> +	return 0;
> +}
> +
> +
>  /**
>   * wpa_supplicant_enabled_networks - Check whether there are enabled
> networks
>   * @wpa_s: Pointer to wpa_supplicant data
> @@ -169,7 +190,9 @@ static void wpas_trigger_scan_cb(struct
> wpa_radio_work *work, int deinit)
>  		return;
>  	}
>  
> -	if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
> +	if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN)
> +		wpa_setup_mac_addr_rand_params(params, wpa_s-
> >mac_addr_scan);
> +	else if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
>  		wpa_msg(wpa_s, MSG_INFO,
>  			"Failed to assign random MAC address for a
> scan");
>  		wpa_scan_free_params(params);
> @@ -1212,11 +1235,7 @@ ssid_list_set:
>  
>  	if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
>  	    wpa_s->wpa_state <= WPA_SCANNING) {
> -		params.mac_addr_rand = 1;
> -		if (wpa_s->mac_addr_scan) {
> -			params.mac_addr = wpa_s->mac_addr_scan;
> -			params.mac_addr_mask = wpa_s->mac_addr_scan +
> ETH_ALEN;
> -		}
> +		wpa_setup_mac_addr_rand_params(&params, wpa_s-
> >mac_addr_scan);
>  	}
>  
>  	if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
> @@ -1665,12 +1684,7 @@ scan:
>  
>  	if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) &&
>  	    wpa_s->wpa_state <= WPA_SCANNING) {
> -		params.mac_addr_rand = 1;
> -		if (wpa_s->mac_addr_sched_scan) {
> -			params.mac_addr = wpa_s->mac_addr_sched_scan;
> -			params.mac_addr_mask = wpa_s-
> >mac_addr_sched_scan +
> -				ETH_ALEN;
> -		}
> +		wpa_setup_mac_addr_rand_params(&params, wpa_s-
> >mac_addr_sched_scan);
>  	}
>  
>  	wpa_scan_set_relative_rssi_params(wpa_s, scan_params);
> @@ -2535,23 +2549,9 @@ wpa_scan_clone_params(const struct
> wpa_driver_scan_params *src)
>  		params->sched_scan_plans_num = src-
> >sched_scan_plans_num;
>  	}
>  
> -	if (src->mac_addr_rand) {
> -		params->mac_addr_rand = src->mac_addr_rand;
> -
> -		if (src->mac_addr && src->mac_addr_mask) {
> -			u8 *mac_addr;
> -
> -			mac_addr = os_malloc(2 * ETH_ALEN);
> -			if (!mac_addr)
> -				goto failed;
> -
> -			os_memcpy(mac_addr, src->mac_addr, ETH_ALEN);
> -			os_memcpy(mac_addr + ETH_ALEN, src-
> >mac_addr_mask,
> -				  ETH_ALEN);
> -			params->mac_addr = mac_addr;
> -			params->mac_addr_mask = mac_addr + ETH_ALEN;
> -		}
> -	}
> +	if (src->mac_addr_rand &&
> +	    wpa_setup_mac_addr_rand_params(params, (const u8 *)src-
> >mac_addr))
> +		goto failed;
>  
>  	if (src->bssid) {
>  		u8 *bssid;
> @@ -2739,11 +2739,7 @@ int wpas_start_pno(struct wpa_supplicant
> *wpa_s)
>  
>  	if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
>  	    wpa_s->wpa_state <= WPA_SCANNING) {
> -		params.mac_addr_rand = 1;
> -		if (wpa_s->mac_addr_pno) {
> -			params.mac_addr = wpa_s->mac_addr_pno;
> -			params.mac_addr_mask = wpa_s->mac_addr_pno +
> ETH_ALEN;
> -		}
> +		wpa_setup_mac_addr_rand_params(&params, wpa_s-
> >mac_addr_pno);
>  	}
>  
>  	wpa_scan_set_relative_rssi_params(wpa_s, &params);
> @@ -2843,6 +2839,32 @@ int wpas_mac_addr_rand_scan_set(struct
> wpa_supplicant *wpa_s,
>  }
>  
>  
> +int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
> +				     unsigned int type, u8 *mask)
> +{
> +	u8 *to_copy = NULL;
> +
> +	if ((wpa_s->mac_addr_rand_enable & type) != type)
> +		return -1;
> +
> +	if (type == MAC_ADDR_RAND_SCAN) {
> +		to_copy = wpa_s->mac_addr_scan;
> +	} else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
> +		to_copy = wpa_s->mac_addr_sched_scan;
> +	} else if (type == MAC_ADDR_RAND_PNO) {
> +		to_copy = wpa_s->mac_addr_pno;
> +	} else {
> +		wpa_printf(MSG_DEBUG,
> +			   "scan: Invalid MAC randomization type=0x%x",
> +			   type);
> +		return -1;
> +	}
> +
> +	os_memcpy(mask, to_copy + ETH_ALEN, ETH_ALEN);
> +	return 0;
> +}
> +
> +
>  int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
>  {
>  	struct wpa_radio_work *work;
> diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
> index 2aa0a8be0..58caa7818 100644
> --- a/wpa_supplicant/scan.h
> +++ b/wpa_supplicant/scan.h
> @@ -52,6 +52,8 @@ void wpas_mac_addr_rand_scan_clear(struct
> wpa_supplicant *wpa_s,
>  int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
>  				unsigned int type, const u8 *addr,
>  				const u8 *mask);
> +int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
> +				     unsigned int type, u8 *mask);
>  int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s);
>  void filter_scan_res(struct wpa_supplicant *wpa_s,
>  		     struct wpa_scan_results *res);
> diff --git a/wpa_supplicant/wpa_supplicant.c
> b/wpa_supplicant/wpa_supplicant.c
> index f82d18fe2..9d1e88bdd 100644
> --- a/wpa_supplicant/wpa_supplicant.c
> +++ b/wpa_supplicant/wpa_supplicant.c
> @@ -7477,3 +7477,60 @@ int wpa_is_bss_tmp_disallowed(struct
> wpa_supplicant *wpa_s,
>  
>  	return 1;
>  }
> +
> +int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
> +				       int type, const u8 *addr,
> +				       const u8 *mask)
> +{
> +	if ((addr && !mask) || (!addr && mask)) {
> +		wpa_printf(MSG_INFO,
> +			   "MAC_ADDR_RAND_SCAN invalid addr/mask
> combination");
> +		return -1;
> +	}
> +
> +	if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
> +		wpa_printf(MSG_INFO,
> +			   "MAC_ADDR_RAND_SCAN cannot allow multicast
> address");
> +		return -1;
> +	}
> +
> +	if (type & MAC_ADDR_RAND_SCAN) {
> +		wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
> +					    addr, mask);
> +	}
> +
> +	if (type & MAC_ADDR_RAND_SCHED_SCAN) {
> +		wpas_mac_addr_rand_scan_set(wpa_s,
> MAC_ADDR_RAND_SCHED_SCAN,
> +					    addr, mask);
> +
> +		if (wpa_s->sched_scanning && !wpa_s->pno)
> +			wpas_scan_restart_sched_scan(wpa_s);
> +	}
> +
> +	if (type & MAC_ADDR_RAND_PNO) {
> +		wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
> +					    addr, mask);
> +		if (wpa_s->pno) {
> +			wpas_stop_pno(wpa_s);
> +			wpas_start_pno(wpa_s);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +
> +int wpas_disable_mac_addr_randomization(struct wpa_supplicant
> *wpa_s, int type)
> +{
> +	wpas_mac_addr_rand_scan_clear(wpa_s, type);
> +	if (wpa_s->pno) {
> +		if (type & MAC_ADDR_RAND_PNO) {
> +			wpas_stop_pno(wpa_s);
> +			wpas_start_pno(wpa_s);
> +		}
> +	} else if (wpa_s->sched_scanning && (type &
> MAC_ADDR_RAND_SCHED_SCAN)) {
> +		wpas_scan_restart_sched_scan(wpa_s);
> +	}
> +
> +	return 0;
> +}
> diff --git a/wpa_supplicant/wpa_supplicant_i.h
> b/wpa_supplicant/wpa_supplicant_i.h
> index b51390ba3..796d83475 100644
> --- a/wpa_supplicant/wpa_supplicant_i.h
> +++ b/wpa_supplicant/wpa_supplicant_i.h
> @@ -1417,6 +1417,11 @@ size_t wpas_supp_op_class_ie(struct
> wpa_supplicant *wpa_s,
>  			     struct wpa_ssid *ssid,
>  			     int freq, u8 *pos, size_t len);
>  
> +int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
> +				       int type, const u8 *addr,
> +				       const u8 *mask);
> +int wpas_disable_mac_addr_randomization(struct wpa_supplicant
> *wpa_s, int type);
> +
>  /**
>   * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control
> response
>   * @wpa_s: Pointer to wpa_supplicant data
Eric Caruso June 19, 2019, 5:43 p.m. UTC | #2
On Thu, May 30, 2019 at 12:47 PM Dan Williams <dcbw@redhat.com> wrote:
>
> On Thu, 2019-05-30 at 11:10 -0700, Eric Caruso wrote:
> > Add D-Bus property:
> > * MACAddressRandomizationMask: a{say}
> >
> > which configure random MAC address functionality in the Wi-Fi
> > driver via netlink. This also fixes weird pointer ownership
> > that was causing memory issues.
>
> All the dbus stuff LGTM.
>
> Dan

Any other comments about this? It hasn't seen any discussion in a few weeks.

>
> > Signed-off-by: Eric Caruso <ejcaruso@chromium.org>
> > ---
> >  doc/dbus.doxygen                        |   5 +
> >  wpa_supplicant/ctrl_iface.c             |  55 +--------
> >  wpa_supplicant/dbus/dbus_new.c          |   5 +
> >  wpa_supplicant/dbus/dbus_new_handlers.c | 153
> > ++++++++++++++++++++++++
> >  wpa_supplicant/dbus/dbus_new_handlers.h |   2 +
> >  wpa_supplicant/scan.c                   |  90 ++++++++------
> >  wpa_supplicant/scan.h                   |   2 +
> >  wpa_supplicant/wpa_supplicant.c         |  57 +++++++++
> >  wpa_supplicant/wpa_supplicant_i.h       |   5 +
> >  9 files changed, 288 insertions(+), 86 deletions(-)
> >
> > diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen
> > index 072ed3486..9f6af52b1 100644
> > --- a/doc/dbus.doxygen
> > +++ b/doc/dbus.doxygen
> > @@ -1043,6 +1043,11 @@ fi.w1.wpa_supplicant1.CreateInterface.
> >       <h3>WpsPriority - s - (read/write)</h3>
> >       <p>Priority for the networks added through WPS</p>
> >        </li>
> > +
> > +      <li>
> > +     <h3>MACAddressRandomizationMask - a{say} - (read/write)</h3>
> > +     <p>Masks to show which bits not to randomize with MAC address
> > randomization. Possible keys are "scan", "sched_scan", and "pno".
> > Values must be an array of 6 bytes.</p>
> > +      </li>
> >      </ul>
> >
> >  \subsection dbus_interface_signals Signals
> > diff --git a/wpa_supplicant/ctrl_iface.c
> > b/wpa_supplicant/ctrl_iface.c
> > index 10f1908f8..8efc08d4d 100644
> > --- a/wpa_supplicant/ctrl_iface.c
> > +++ b/wpa_supplicant/ctrl_iface.c
> > @@ -9626,59 +9626,10 @@ static int
> > wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
> >               return -1;
> >       }
> >
> > -     if (!enable) {
> > -             wpas_mac_addr_rand_scan_clear(wpa_s, type);
> > -             if (wpa_s->pno) {
> > -                     if (type & MAC_ADDR_RAND_PNO) {
> > -                             wpas_stop_pno(wpa_s);
> > -                             wpas_start_pno(wpa_s);
> > -                     }
> > -             } else if (wpa_s->sched_scanning &&
> > -                        (type & MAC_ADDR_RAND_SCHED_SCAN)) {
> > -                     wpas_scan_restart_sched_scan(wpa_s);
> > -             }
> > -             return 0;
> > -     }
> > +     if (!enable)
> > +             return wpas_disable_mac_addr_randomization(wpa_s,
> > type);
> >
> > -     if ((addr && !mask) || (!addr && mask)) {
> > -             wpa_printf(MSG_INFO,
> > -                        "CTRL: MAC_RAND_SCAN invalid addr/mask
> > combination");
> > -             return -1;
> > -     }
> > -
> > -     if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
> > -             wpa_printf(MSG_INFO,
> > -                        "CTRL: MAC_RAND_SCAN cannot allow multicast
> > address");
> > -             return -1;
> > -     }
> > -
> > -     if (type & MAC_ADDR_RAND_SCAN) {
> > -             if (wpas_mac_addr_rand_scan_set(wpa_s,
> > MAC_ADDR_RAND_SCAN,
> > -                                         addr, mask))
> > -                     return -1;
> > -     }
> > -
> > -     if (type & MAC_ADDR_RAND_SCHED_SCAN) {
> > -             if (wpas_mac_addr_rand_scan_set(wpa_s,
> > MAC_ADDR_RAND_SCHED_SCAN,
> > -                                         addr, mask))
> > -                     return -1;
> > -
> > -             if (wpa_s->sched_scanning && !wpa_s->pno)
> > -                     wpas_scan_restart_sched_scan(wpa_s);
> > -     }
> > -
> > -     if (type & MAC_ADDR_RAND_PNO) {
> > -             if (wpas_mac_addr_rand_scan_set(wpa_s,
> > MAC_ADDR_RAND_PNO,
> > -                                         addr, mask))
> > -                     return -1;
> > -
> > -             if (wpa_s->pno) {
> > -                     wpas_stop_pno(wpa_s);
> > -                     wpas_start_pno(wpa_s);
> > -             }
> > -     }
> > -
> > -     return 0;
> > +     return wpas_enable_mac_addr_randomization(wpa_s, type, addr,
> > mask);
> >  }
> >
> >
> > diff --git a/wpa_supplicant/dbus/dbus_new.c
> > b/wpa_supplicant/dbus/dbus_new.c
> > index fc2fc2ef1..c5d3b8a02 100644
> > --- a/wpa_supplicant/dbus/dbus_new.c
> > +++ b/wpa_supplicant/dbus/dbus_new.c
> > @@ -3803,6 +3803,11 @@ static const struct wpa_dbus_property_desc
> > wpas_dbus_interface_properties[] = {
> >         NULL,
> >         NULL
> >       },
> > +     { "MACAddressRandomizationMask", WPAS_DBUS_NEW_IFACE_INTERFACE,
> > "a{say}",
> > +       wpas_dbus_getter_mac_address_randomization_mask,
> > +       wpas_dbus_setter_mac_address_randomization_mask,
> > +       NULL
> > +     },
> >       { NULL, NULL, NULL, NULL, NULL, NULL }
> >  };
> >
> > diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c
> > b/wpa_supplicant/dbus/dbus_new_handlers.c
> > index 6c36d91a0..764675caa 100644
> > --- a/wpa_supplicant/dbus/dbus_new_handlers.c
> > +++ b/wpa_supplicant/dbus/dbus_new_handlers.c
> > @@ -3989,6 +3989,159 @@ out:
> >  }
> >
> >
> > +/**
> > + * wpas_dbus_setter_mac_address_randomization_mask - Set masks used
> > for
> > + * MAC address randomization
> > + * @iter: Pointer to incoming dbus message iter
> > + * @error: Location to store error on failure
> > + * @user_data: Function specific data
> > + * Returns: TRUE on success, FALSE on failure
> > + *
> > + * Setter for "MACAddressRandomizationMask" property.
> > + */
> > +dbus_bool_t wpas_dbus_setter_mac_address_randomization_mask(
> > +     const struct wpa_dbus_property_desc *property_desc,
> > +     DBusMessageIter *iter, DBusError *error, void *user_data)
> > +{
> > +     struct wpa_supplicant *wpa_s = user_data;
> > +     DBusMessageIter variant_iter, dict_iter, entry_iter,
> > array_iter;
> > +     const char *key;
> > +     unsigned int rand_type = 0;
> > +     const u8 *mask;
> > +     int mask_len;
> > +     unsigned int rand_types_to_disable = MAC_ADDR_RAND_ALL;
> > +
> > +     dbus_message_iter_recurse(iter, &variant_iter);
> > +     dbus_message_iter_recurse(&variant_iter, &dict_iter);
> > +     while (dbus_message_iter_get_arg_type(&dict_iter) ==
> > +            DBUS_TYPE_DICT_ENTRY) {
> > +             dbus_message_iter_recurse(&dict_iter, &entry_iter);
> > +             if (dbus_message_iter_get_arg_type(&entry_iter) !=
> > DBUS_TYPE_STRING) {
> > +                     dbus_set_error(error, DBUS_ERROR_FAILED,
> > +                                    "%s: key not a string",
> > __func__);
> > +                     return FALSE;
> > +             }
> > +             dbus_message_iter_get_basic(&entry_iter, &key);
> > +             dbus_message_iter_next(&entry_iter);
> > +             if (dbus_message_iter_get_arg_type(&entry_iter) !=
> > DBUS_TYPE_ARRAY ||
> > +                 dbus_message_iter_get_element_type(&entry_iter) !=
> > DBUS_TYPE_BYTE) {
> > +                     dbus_set_error(error, DBUS_ERROR_FAILED,
> > +                                    "%s: mask was not a byte array",
> > __func__);
> > +                     return FALSE;
> > +             }
> > +             dbus_message_iter_recurse(&entry_iter, &array_iter);
> > +             dbus_message_iter_get_fixed_array(&array_iter, &mask,
> > &mask_len);
> > +
> > +             if (os_strcmp(key, "scan") == 0) {
> > +                     rand_type = MAC_ADDR_RAND_SCAN;
> > +             } else if (os_strcmp(key, "sched_scan") == 0) {
> > +                     rand_type = MAC_ADDR_RAND_SCHED_SCAN;
> > +             } else if (os_strcmp(key, "pno") == 0) {
> > +                     rand_type = MAC_ADDR_RAND_PNO;
> > +             } else {
> > +                     dbus_set_error(error, DBUS_ERROR_FAILED,
> > +                                    "%s: bad scan type \"%s\"",
> > __func__, key);
> > +                     return FALSE;
> > +             }
> > +
> > +             if (mask_len != ETH_ALEN) {
> > +                     dbus_set_error(error, DBUS_ERROR_FAILED,
> > +                                    "%s: malformed MAC mask given",
> > __func__);
> > +                     return FALSE;
> > +             }
> > +
> > +             if (wpas_enable_mac_addr_randomization(
> > +                 wpa_s, rand_type, wpa_s->perm_addr, mask)) {
> > +                     dbus_set_error(error, DBUS_ERROR_FAILED,
> > +                                    "%s: failed to set up MAC
> > address randomization for %s",
> > +                                    __func__, key);
> > +                     return FALSE;
> > +             }
> > +
> > +             wpa_printf(MSG_DEBUG, "%s: Enabled MAC address
> > randomization for %s with mask: "
> > +                     MACSTR, wpa_s->ifname, key, MAC2STR(mask));
> > +             rand_types_to_disable &= ~rand_type;
> > +             dbus_message_iter_next(&dict_iter);
> > +     }
> > +
> > +     if (rand_types_to_disable &&
> > +         wpas_disable_mac_addr_randomization(wpa_s,
> > rand_types_to_disable)) {
> > +             dbus_set_error(error, DBUS_ERROR_FAILED,
> > +                            "%s: failed to disable MAC address
> > randomization",
> > +                            __func__);
> > +             return FALSE;
> > +     }
> > +
> > +     return TRUE;
> > +}
> > +
> > +
> > +dbus_bool_t wpas_dbus_getter_mac_address_randomization_mask(
> > +     const struct wpa_dbus_property_desc *property_desc,
> > +     DBusMessageIter *iter, DBusError *error, void *user_data)
> > +{
> > +     struct wpa_supplicant *wpa_s = user_data;
> > +     DBusMessageIter variant_iter, dict_iter, entry_iter,
> > array_iter;
> > +     int i;
> > +     u8 mask_buf[ETH_ALEN];
> > +     /* Read docs on dbus_message_iter_append_fixed_array for why
> > this
> > +      * is necessary... */
> > +     u8* mask = mask_buf;
> > +     static const struct {
> > +             const char *key;
> > +             unsigned int type;
> > +     } types[] = {
> > +             { "scan", MAC_ADDR_RAND_SCAN },
> > +             { "sched_scan", MAC_ADDR_RAND_SCHED_SCAN },
> > +             { "pno", MAC_ADDR_RAND_PNO }
> > +     };
> > +
> > +     if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
> > +                                           "a{say}", &variant_iter)
> > ||
> > +         !dbus_message_iter_open_container(&variant_iter,
> > DBUS_TYPE_ARRAY,
> > +                                           "{say}", &dict_iter)) {
> > +             dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no
> > memory");
> > +             return FALSE;
> > +     }
> > +
> > +     for (i = 0; i < sizeof(types)/sizeof(types[0]); i++) {
> > +             if (wpas_mac_addr_rand_scan_get_mask(wpa_s,
> > types[i].type, mask))
> > +                     continue;
> > +
> > +             if (!dbus_message_iter_open_container(&dict_iter,
> > +                                                   DBUS_TYPE_DICT_EN
> > TRY,
> > +                                                   NULL,
> > &entry_iter) ||
> > +                 !dbus_message_iter_append_basic(&entry_iter,
> > +                                                 DBUS_TYPE_STRING,
> > +                                                 &types[i].key) ||
> > +                 !dbus_message_iter_open_container(&entry_iter,
> > +                                                   DBUS_TYPE_ARRAY,
> > +                                                   DBUS_TYPE_BYTE_AS
> > _STRING,
> > +                                                   &array_iter) ||
> > +                 !dbus_message_iter_append_fixed_array(&array_iter,
> > +                                                       DBUS_TYPE_BYT
> > E,
> > +                                                       &mask,
> > +                                                       ETH_ALEN) ||
> > +                 !dbus_message_iter_close_container(&entry_iter,
> > +                                                    &array_iter) ||
> > +                 !dbus_message_iter_close_container(&dict_iter,
> > +                                                    &entry_iter)) {
> > +                     dbus_set_error_const(error,
> > DBUS_ERROR_NO_MEMORY,
> > +                                          "no memory");
> > +                     return FALSE;
> > +             }
> > +     }
> > +
> > +     if (!dbus_message_iter_close_container(&variant_iter,
> > &dict_iter) ||
> > +         !dbus_message_iter_close_container(iter, &variant_iter)) {
> > +             dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no
> > memory");
> > +             return FALSE;
> > +     }
> > +
> > +     return TRUE;
> > +}
> > +
> > +
> >  /**
> >   * wpas_dbus_getter_sta_address - Return the address of a connected
> > station
> >   * @iter: Pointer to incoming dbus message iter
> > diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h
> > b/wpa_supplicant/dbus/dbus_new_handlers.h
> > index d922ce1b4..afa26efed 100644
> > --- a/wpa_supplicant/dbus/dbus_new_handlers.h
> > +++ b/wpa_supplicant/dbus/dbus_new_handlers.h
> > @@ -177,6 +177,8 @@
> > DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_engine_path);
> >  DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_module_path);
> >  DECLARE_ACCESSOR(wpas_dbus_getter_blobs);
> >  DECLARE_ACCESSOR(wpas_dbus_getter_stas);
> > +DECLARE_ACCESSOR(wpas_dbus_getter_mac_address_randomization_mask);
> > +DECLARE_ACCESSOR(wpas_dbus_setter_mac_address_randomization_mask);
> >  DECLARE_ACCESSOR(wpas_dbus_getter_sta_address);
> >  DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid);
> >  DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps);
> > diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
> > index 7abb028dd..251e0642e 100644
> > --- a/wpa_supplicant/scan.c
> > +++ b/wpa_supplicant/scan.c
> > @@ -79,6 +79,27 @@ static int wpas_wps_in_use(struct wpa_supplicant
> > *wpa_s,
> >  #endif /* CONFIG_WPS */
> >
> >
> > +static int wpa_setup_mac_addr_rand_params(struct
> > wpa_driver_scan_params *params,
> > +                                       const u8 *mac_addr)
> > +{
> > +     u8 *tmp;
> > +
> > +     if (!mac_addr)
> > +             return 0;
> > +
> > +     params->mac_addr_rand = 1;
> > +
> > +     tmp = os_malloc(2 * ETH_ALEN);
> > +     if (!tmp)
> > +             return -1;
> > +
> > +     os_memcpy(tmp, mac_addr, 2 * ETH_ALEN);
> > +     params->mac_addr = tmp;
> > +     params->mac_addr_mask = tmp + ETH_ALEN;
> > +     return 0;
> > +}
> > +
> > +
> >  /**
> >   * wpa_supplicant_enabled_networks - Check whether there are enabled
> > networks
> >   * @wpa_s: Pointer to wpa_supplicant data
> > @@ -169,7 +190,9 @@ static void wpas_trigger_scan_cb(struct
> > wpa_radio_work *work, int deinit)
> >               return;
> >       }
> >
> > -     if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
> > +     if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN)
> > +             wpa_setup_mac_addr_rand_params(params, wpa_s-
> > >mac_addr_scan);
> > +     else if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
> >               wpa_msg(wpa_s, MSG_INFO,
> >                       "Failed to assign random MAC address for a
> > scan");
> >               wpa_scan_free_params(params);
> > @@ -1212,11 +1235,7 @@ ssid_list_set:
> >
> >       if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
> >           wpa_s->wpa_state <= WPA_SCANNING) {
> > -             params.mac_addr_rand = 1;
> > -             if (wpa_s->mac_addr_scan) {
> > -                     params.mac_addr = wpa_s->mac_addr_scan;
> > -                     params.mac_addr_mask = wpa_s->mac_addr_scan +
> > ETH_ALEN;
> > -             }
> > +             wpa_setup_mac_addr_rand_params(&params, wpa_s-
> > >mac_addr_scan);
> >       }
> >
> >       if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
> > @@ -1665,12 +1684,7 @@ scan:
> >
> >       if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) &&
> >           wpa_s->wpa_state <= WPA_SCANNING) {
> > -             params.mac_addr_rand = 1;
> > -             if (wpa_s->mac_addr_sched_scan) {
> > -                     params.mac_addr = wpa_s->mac_addr_sched_scan;
> > -                     params.mac_addr_mask = wpa_s-
> > >mac_addr_sched_scan +
> > -                             ETH_ALEN;
> > -             }
> > +             wpa_setup_mac_addr_rand_params(&params, wpa_s-
> > >mac_addr_sched_scan);
> >       }
> >
> >       wpa_scan_set_relative_rssi_params(wpa_s, scan_params);
> > @@ -2535,23 +2549,9 @@ wpa_scan_clone_params(const struct
> > wpa_driver_scan_params *src)
> >               params->sched_scan_plans_num = src-
> > >sched_scan_plans_num;
> >       }
> >
> > -     if (src->mac_addr_rand) {
> > -             params->mac_addr_rand = src->mac_addr_rand;
> > -
> > -             if (src->mac_addr && src->mac_addr_mask) {
> > -                     u8 *mac_addr;
> > -
> > -                     mac_addr = os_malloc(2 * ETH_ALEN);
> > -                     if (!mac_addr)
> > -                             goto failed;
> > -
> > -                     os_memcpy(mac_addr, src->mac_addr, ETH_ALEN);
> > -                     os_memcpy(mac_addr + ETH_ALEN, src-
> > >mac_addr_mask,
> > -                               ETH_ALEN);
> > -                     params->mac_addr = mac_addr;
> > -                     params->mac_addr_mask = mac_addr + ETH_ALEN;
> > -             }
> > -     }
> > +     if (src->mac_addr_rand &&
> > +         wpa_setup_mac_addr_rand_params(params, (const u8 *)src-
> > >mac_addr))
> > +             goto failed;
> >
> >       if (src->bssid) {
> >               u8 *bssid;
> > @@ -2739,11 +2739,7 @@ int wpas_start_pno(struct wpa_supplicant
> > *wpa_s)
> >
> >       if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
> >           wpa_s->wpa_state <= WPA_SCANNING) {
> > -             params.mac_addr_rand = 1;
> > -             if (wpa_s->mac_addr_pno) {
> > -                     params.mac_addr = wpa_s->mac_addr_pno;
> > -                     params.mac_addr_mask = wpa_s->mac_addr_pno +
> > ETH_ALEN;
> > -             }
> > +             wpa_setup_mac_addr_rand_params(&params, wpa_s-
> > >mac_addr_pno);
> >       }
> >
> >       wpa_scan_set_relative_rssi_params(wpa_s, &params);
> > @@ -2843,6 +2839,32 @@ int wpas_mac_addr_rand_scan_set(struct
> > wpa_supplicant *wpa_s,
> >  }
> >
> >
> > +int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
> > +                                  unsigned int type, u8 *mask)
> > +{
> > +     u8 *to_copy = NULL;
> > +
> > +     if ((wpa_s->mac_addr_rand_enable & type) != type)
> > +             return -1;
> > +
> > +     if (type == MAC_ADDR_RAND_SCAN) {
> > +             to_copy = wpa_s->mac_addr_scan;
> > +     } else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
> > +             to_copy = wpa_s->mac_addr_sched_scan;
> > +     } else if (type == MAC_ADDR_RAND_PNO) {
> > +             to_copy = wpa_s->mac_addr_pno;
> > +     } else {
> > +             wpa_printf(MSG_DEBUG,
> > +                        "scan: Invalid MAC randomization type=0x%x",
> > +                        type);
> > +             return -1;
> > +     }
> > +
> > +     os_memcpy(mask, to_copy + ETH_ALEN, ETH_ALEN);
> > +     return 0;
> > +}
> > +
> > +
> >  int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
> >  {
> >       struct wpa_radio_work *work;
> > diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
> > index 2aa0a8be0..58caa7818 100644
> > --- a/wpa_supplicant/scan.h
> > +++ b/wpa_supplicant/scan.h
> > @@ -52,6 +52,8 @@ void wpas_mac_addr_rand_scan_clear(struct
> > wpa_supplicant *wpa_s,
> >  int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
> >                               unsigned int type, const u8 *addr,
> >                               const u8 *mask);
> > +int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
> > +                                  unsigned int type, u8 *mask);
> >  int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s);
> >  void filter_scan_res(struct wpa_supplicant *wpa_s,
> >                    struct wpa_scan_results *res);
> > diff --git a/wpa_supplicant/wpa_supplicant.c
> > b/wpa_supplicant/wpa_supplicant.c
> > index f82d18fe2..9d1e88bdd 100644
> > --- a/wpa_supplicant/wpa_supplicant.c
> > +++ b/wpa_supplicant/wpa_supplicant.c
> > @@ -7477,3 +7477,60 @@ int wpa_is_bss_tmp_disallowed(struct
> > wpa_supplicant *wpa_s,
> >
> >       return 1;
> >  }
> > +
> > +int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
> > +                                    int type, const u8 *addr,
> > +                                    const u8 *mask)
> > +{
> > +     if ((addr && !mask) || (!addr && mask)) {
> > +             wpa_printf(MSG_INFO,
> > +                        "MAC_ADDR_RAND_SCAN invalid addr/mask
> > combination");
> > +             return -1;
> > +     }
> > +
> > +     if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
> > +             wpa_printf(MSG_INFO,
> > +                        "MAC_ADDR_RAND_SCAN cannot allow multicast
> > address");
> > +             return -1;
> > +     }
> > +
> > +     if (type & MAC_ADDR_RAND_SCAN) {
> > +             wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
> > +                                         addr, mask);
> > +     }
> > +
> > +     if (type & MAC_ADDR_RAND_SCHED_SCAN) {
> > +             wpas_mac_addr_rand_scan_set(wpa_s,
> > MAC_ADDR_RAND_SCHED_SCAN,
> > +                                         addr, mask);
> > +
> > +             if (wpa_s->sched_scanning && !wpa_s->pno)
> > +                     wpas_scan_restart_sched_scan(wpa_s);
> > +     }
> > +
> > +     if (type & MAC_ADDR_RAND_PNO) {
> > +             wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
> > +                                         addr, mask);
> > +             if (wpa_s->pno) {
> > +                     wpas_stop_pno(wpa_s);
> > +                     wpas_start_pno(wpa_s);
> > +             }
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +
> > +int wpas_disable_mac_addr_randomization(struct wpa_supplicant
> > *wpa_s, int type)
> > +{
> > +     wpas_mac_addr_rand_scan_clear(wpa_s, type);
> > +     if (wpa_s->pno) {
> > +             if (type & MAC_ADDR_RAND_PNO) {
> > +                     wpas_stop_pno(wpa_s);
> > +                     wpas_start_pno(wpa_s);
> > +             }
> > +     } else if (wpa_s->sched_scanning && (type &
> > MAC_ADDR_RAND_SCHED_SCAN)) {
> > +             wpas_scan_restart_sched_scan(wpa_s);
> > +     }
> > +
> > +     return 0;
> > +}
> > diff --git a/wpa_supplicant/wpa_supplicant_i.h
> > b/wpa_supplicant/wpa_supplicant_i.h
> > index b51390ba3..796d83475 100644
> > --- a/wpa_supplicant/wpa_supplicant_i.h
> > +++ b/wpa_supplicant/wpa_supplicant_i.h
> > @@ -1417,6 +1417,11 @@ size_t wpas_supp_op_class_ie(struct
> > wpa_supplicant *wpa_s,
> >                            struct wpa_ssid *ssid,
> >                            int freq, u8 *pos, size_t len);
> >
> > +int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
> > +                                    int type, const u8 *addr,
> > +                                    const u8 *mask);
> > +int wpas_disable_mac_addr_randomization(struct wpa_supplicant
> > *wpa_s, int type);
> > +
> >  /**
> >   * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control
> > response
> >   * @wpa_s: Pointer to wpa_supplicant data
>
Dan Williams June 19, 2019, 6:43 p.m. UTC | #3
On Wed, 2019-06-19 at 10:43 -0700, Eric Caruso wrote:
> On Thu, May 30, 2019 at 12:47 PM Dan Williams <dcbw@redhat.com>
> wrote:
> > On Thu, 2019-05-30 at 11:10 -0700, Eric Caruso wrote:
> > > Add D-Bus property:
> > > * MACAddressRandomizationMask: a{say}
> > > 
> > > which configure random MAC address functionality in the Wi-Fi
> > > driver via netlink. This also fixes weird pointer ownership
> > > that was causing memory issues.
> > 
> > All the dbus stuff LGTM.
> > 
> > Dan
> 
> Any other comments about this? It hasn't seen any discussion in a few
> weeks.

I don't have any; I was waiting for Jouni to weigh in on the scan
infrastructure bits.

Dan

> > > Signed-off-by: Eric Caruso <ejcaruso@chromium.org>
> > > ---
> > >  doc/dbus.doxygen                        |   5 +
> > >  wpa_supplicant/ctrl_iface.c             |  55 +--------
> > >  wpa_supplicant/dbus/dbus_new.c          |   5 +
> > >  wpa_supplicant/dbus/dbus_new_handlers.c | 153
> > > ++++++++++++++++++++++++
> > >  wpa_supplicant/dbus/dbus_new_handlers.h |   2 +
> > >  wpa_supplicant/scan.c                   |  90 ++++++++------
> > >  wpa_supplicant/scan.h                   |   2 +
> > >  wpa_supplicant/wpa_supplicant.c         |  57 +++++++++
> > >  wpa_supplicant/wpa_supplicant_i.h       |   5 +
> > >  9 files changed, 288 insertions(+), 86 deletions(-)
> > > 
> > > diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen
> > > index 072ed3486..9f6af52b1 100644
> > > --- a/doc/dbus.doxygen
> > > +++ b/doc/dbus.doxygen
> > > @@ -1043,6 +1043,11 @@ fi.w1.wpa_supplicant1.CreateInterface.
> > >       <h3>WpsPriority - s - (read/write)</h3>
> > >       <p>Priority for the networks added through WPS</p>
> > >        </li>
> > > +
> > > +      <li>
> > > +     <h3>MACAddressRandomizationMask - a{say} -
> > > (read/write)</h3>
> > > +     <p>Masks to show which bits not to randomize with MAC
> > > address
> > > randomization. Possible keys are "scan", "sched_scan", and "pno".
> > > Values must be an array of 6 bytes.</p>
> > > +      </li>
> > >      </ul>
> > > 
> > >  \subsection dbus_interface_signals Signals
> > > diff --git a/wpa_supplicant/ctrl_iface.c
> > > b/wpa_supplicant/ctrl_iface.c
> > > index 10f1908f8..8efc08d4d 100644
> > > --- a/wpa_supplicant/ctrl_iface.c
> > > +++ b/wpa_supplicant/ctrl_iface.c
> > > @@ -9626,59 +9626,10 @@ static int
> > > wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
> > >               return -1;
> > >       }
> > > 
> > > -     if (!enable) {
> > > -             wpas_mac_addr_rand_scan_clear(wpa_s, type);
> > > -             if (wpa_s->pno) {
> > > -                     if (type & MAC_ADDR_RAND_PNO) {
> > > -                             wpas_stop_pno(wpa_s);
> > > -                             wpas_start_pno(wpa_s);
> > > -                     }
> > > -             } else if (wpa_s->sched_scanning &&
> > > -                        (type & MAC_ADDR_RAND_SCHED_SCAN)) {
> > > -                     wpas_scan_restart_sched_scan(wpa_s);
> > > -             }
> > > -             return 0;
> > > -     }
> > > +     if (!enable)
> > > +             return wpas_disable_mac_addr_randomization(wpa_s,
> > > type);
> > > 
> > > -     if ((addr && !mask) || (!addr && mask)) {
> > > -             wpa_printf(MSG_INFO,
> > > -                        "CTRL: MAC_RAND_SCAN invalid addr/mask
> > > combination");
> > > -             return -1;
> > > -     }
> > > -
> > > -     if (addr && mask && (!(mask[0] & 0x01) || (addr[0] &
> > > 0x01))) {
> > > -             wpa_printf(MSG_INFO,
> > > -                        "CTRL: MAC_RAND_SCAN cannot allow
> > > multicast
> > > address");
> > > -             return -1;
> > > -     }
> > > -
> > > -     if (type & MAC_ADDR_RAND_SCAN) {
> > > -             if (wpas_mac_addr_rand_scan_set(wpa_s,
> > > MAC_ADDR_RAND_SCAN,
> > > -                                         addr, mask))
> > > -                     return -1;
> > > -     }
> > > -
> > > -     if (type & MAC_ADDR_RAND_SCHED_SCAN) {
> > > -             if (wpas_mac_addr_rand_scan_set(wpa_s,
> > > MAC_ADDR_RAND_SCHED_SCAN,
> > > -                                         addr, mask))
> > > -                     return -1;
> > > -
> > > -             if (wpa_s->sched_scanning && !wpa_s->pno)
> > > -                     wpas_scan_restart_sched_scan(wpa_s);
> > > -     }
> > > -
> > > -     if (type & MAC_ADDR_RAND_PNO) {
> > > -             if (wpas_mac_addr_rand_scan_set(wpa_s,
> > > MAC_ADDR_RAND_PNO,
> > > -                                         addr, mask))
> > > -                     return -1;
> > > -
> > > -             if (wpa_s->pno) {
> > > -                     wpas_stop_pno(wpa_s);
> > > -                     wpas_start_pno(wpa_s);
> > > -             }
> > > -     }
> > > -
> > > -     return 0;
> > > +     return wpas_enable_mac_addr_randomization(wpa_s, type,
> > > addr,
> > > mask);
> > >  }
> > > 
> > > 
> > > diff --git a/wpa_supplicant/dbus/dbus_new.c
> > > b/wpa_supplicant/dbus/dbus_new.c
> > > index fc2fc2ef1..c5d3b8a02 100644
> > > --- a/wpa_supplicant/dbus/dbus_new.c
> > > +++ b/wpa_supplicant/dbus/dbus_new.c
> > > @@ -3803,6 +3803,11 @@ static const struct wpa_dbus_property_desc
> > > wpas_dbus_interface_properties[] = {
> > >         NULL,
> > >         NULL
> > >       },
> > > +     { "MACAddressRandomizationMask",
> > > WPAS_DBUS_NEW_IFACE_INTERFACE,
> > > "a{say}",
> > > +       wpas_dbus_getter_mac_address_randomization_mask,
> > > +       wpas_dbus_setter_mac_address_randomization_mask,
> > > +       NULL
> > > +     },
> > >       { NULL, NULL, NULL, NULL, NULL, NULL }
> > >  };
> > > 
> > > diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c
> > > b/wpa_supplicant/dbus/dbus_new_handlers.c
> > > index 6c36d91a0..764675caa 100644
> > > --- a/wpa_supplicant/dbus/dbus_new_handlers.c
> > > +++ b/wpa_supplicant/dbus/dbus_new_handlers.c
> > > @@ -3989,6 +3989,159 @@ out:
> > >  }
> > > 
> > > 
> > > +/**
> > > + * wpas_dbus_setter_mac_address_randomization_mask - Set masks
> > > used
> > > for
> > > + * MAC address randomization
> > > + * @iter: Pointer to incoming dbus message iter
> > > + * @error: Location to store error on failure
> > > + * @user_data: Function specific data
> > > + * Returns: TRUE on success, FALSE on failure
> > > + *
> > > + * Setter for "MACAddressRandomizationMask" property.
> > > + */
> > > +dbus_bool_t wpas_dbus_setter_mac_address_randomization_mask(
> > > +     const struct wpa_dbus_property_desc *property_desc,
> > > +     DBusMessageIter *iter, DBusError *error, void *user_data)
> > > +{
> > > +     struct wpa_supplicant *wpa_s = user_data;
> > > +     DBusMessageIter variant_iter, dict_iter, entry_iter,
> > > array_iter;
> > > +     const char *key;
> > > +     unsigned int rand_type = 0;
> > > +     const u8 *mask;
> > > +     int mask_len;
> > > +     unsigned int rand_types_to_disable = MAC_ADDR_RAND_ALL;
> > > +
> > > +     dbus_message_iter_recurse(iter, &variant_iter);
> > > +     dbus_message_iter_recurse(&variant_iter, &dict_iter);
> > > +     while (dbus_message_iter_get_arg_type(&dict_iter) ==
> > > +            DBUS_TYPE_DICT_ENTRY) {
> > > +             dbus_message_iter_recurse(&dict_iter, &entry_iter);
> > > +             if (dbus_message_iter_get_arg_type(&entry_iter) !=
> > > DBUS_TYPE_STRING) {
> > > +                     dbus_set_error(error, DBUS_ERROR_FAILED,
> > > +                                    "%s: key not a string",
> > > __func__);
> > > +                     return FALSE;
> > > +             }
> > > +             dbus_message_iter_get_basic(&entry_iter, &key);
> > > +             dbus_message_iter_next(&entry_iter);
> > > +             if (dbus_message_iter_get_arg_type(&entry_iter) !=
> > > DBUS_TYPE_ARRAY ||
> > > +                 dbus_message_iter_get_element_type(&entry_iter)
> > > !=
> > > DBUS_TYPE_BYTE) {
> > > +                     dbus_set_error(error, DBUS_ERROR_FAILED,
> > > +                                    "%s: mask was not a byte
> > > array",
> > > __func__);
> > > +                     return FALSE;
> > > +             }
> > > +             dbus_message_iter_recurse(&entry_iter,
> > > &array_iter);
> > > +             dbus_message_iter_get_fixed_array(&array_iter,
> > > &mask,
> > > &mask_len);
> > > +
> > > +             if (os_strcmp(key, "scan") == 0) {
> > > +                     rand_type = MAC_ADDR_RAND_SCAN;
> > > +             } else if (os_strcmp(key, "sched_scan") == 0) {
> > > +                     rand_type = MAC_ADDR_RAND_SCHED_SCAN;
> > > +             } else if (os_strcmp(key, "pno") == 0) {
> > > +                     rand_type = MAC_ADDR_RAND_PNO;
> > > +             } else {
> > > +                     dbus_set_error(error, DBUS_ERROR_FAILED,
> > > +                                    "%s: bad scan type \"%s\"",
> > > __func__, key);
> > > +                     return FALSE;
> > > +             }
> > > +
> > > +             if (mask_len != ETH_ALEN) {
> > > +                     dbus_set_error(error, DBUS_ERROR_FAILED,
> > > +                                    "%s: malformed MAC mask
> > > given",
> > > __func__);
> > > +                     return FALSE;
> > > +             }
> > > +
> > > +             if (wpas_enable_mac_addr_randomization(
> > > +                 wpa_s, rand_type, wpa_s->perm_addr, mask)) {
> > > +                     dbus_set_error(error, DBUS_ERROR_FAILED,
> > > +                                    "%s: failed to set up MAC
> > > address randomization for %s",
> > > +                                    __func__, key);
> > > +                     return FALSE;
> > > +             }
> > > +
> > > +             wpa_printf(MSG_DEBUG, "%s: Enabled MAC address
> > > randomization for %s with mask: "
> > > +                     MACSTR, wpa_s->ifname, key, MAC2STR(mask));
> > > +             rand_types_to_disable &= ~rand_type;
> > > +             dbus_message_iter_next(&dict_iter);
> > > +     }
> > > +
> > > +     if (rand_types_to_disable &&
> > > +         wpas_disable_mac_addr_randomization(wpa_s,
> > > rand_types_to_disable)) {
> > > +             dbus_set_error(error, DBUS_ERROR_FAILED,
> > > +                            "%s: failed to disable MAC address
> > > randomization",
> > > +                            __func__);
> > > +             return FALSE;
> > > +     }
> > > +
> > > +     return TRUE;
> > > +}
> > > +
> > > +
> > > +dbus_bool_t wpas_dbus_getter_mac_address_randomization_mask(
> > > +     const struct wpa_dbus_property_desc *property_desc,
> > > +     DBusMessageIter *iter, DBusError *error, void *user_data)
> > > +{
> > > +     struct wpa_supplicant *wpa_s = user_data;
> > > +     DBusMessageIter variant_iter, dict_iter, entry_iter,
> > > array_iter;
> > > +     int i;
> > > +     u8 mask_buf[ETH_ALEN];
> > > +     /* Read docs on dbus_message_iter_append_fixed_array for
> > > why
> > > this
> > > +      * is necessary... */
> > > +     u8* mask = mask_buf;
> > > +     static const struct {
> > > +             const char *key;
> > > +             unsigned int type;
> > > +     } types[] = {
> > > +             { "scan", MAC_ADDR_RAND_SCAN },
> > > +             { "sched_scan", MAC_ADDR_RAND_SCHED_SCAN },
> > > +             { "pno", MAC_ADDR_RAND_PNO }
> > > +     };
> > > +
> > > +     if (!dbus_message_iter_open_container(iter,
> > > DBUS_TYPE_VARIANT,
> > > +                                           "a{say}",
> > > &variant_iter)
> > > +         !dbus_message_iter_open_container(&variant_iter,
> > > DBUS_TYPE_ARRAY,
> > > +                                           "{say}", &dict_iter))
> > > {
> > > +             dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
> > > "no
> > > memory");
> > > +             return FALSE;
> > > +     }
> > > +
> > > +     for (i = 0; i < sizeof(types)/sizeof(types[0]); i++) {
> > > +             if (wpas_mac_addr_rand_scan_get_mask(wpa_s,
> > > types[i].type, mask))
> > > +                     continue;
> > > +
> > > +             if (!dbus_message_iter_open_container(&dict_iter,
> > > +                                                   DBUS_TYPE_DIC
> > > T_EN
> > > TRY,
> > > +                                                   NULL,
> > > &entry_iter) ||
> > > +                 !dbus_message_iter_append_basic(&entry_iter,
> > > +                                                 DBUS_TYPE_STRIN
> > > G,
> > > +                                                 &types[i].key)
> > > ||
> > > +                 !dbus_message_iter_open_container(&entry_iter,
> > > +                                                   DBUS_TYPE_ARR
> > > AY,
> > > +                                                   DBUS_TYPE_BYT
> > > E_AS
> > > _STRING,
> > > +                                                   &array_iter)
> > > ||
> > > +                 !dbus_message_iter_append_fixed_array(&array_it
> > > er,
> > > +                                                       DBUS_TYPE
> > > _BYT
> > > E,
> > > +                                                       &mask,
> > > +                                                       ETH_ALEN)
> > > ||
> > > +                 !dbus_message_iter_close_container(&entry_iter,
> > > +                                                    &array_iter)
> > > ||
> > > +                 !dbus_message_iter_close_container(&dict_iter,
> > > +                                                    &entry_iter)
> > > ) {
> > > +                     dbus_set_error_const(error,
> > > DBUS_ERROR_NO_MEMORY,
> > > +                                          "no memory");
> > > +                     return FALSE;
> > > +             }
> > > +     }
> > > +
> > > +     if (!dbus_message_iter_close_container(&variant_iter,
> > > &dict_iter) ||
> > > +         !dbus_message_iter_close_container(iter,
> > > &variant_iter)) {
> > > +             dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
> > > "no
> > > memory");
> > > +             return FALSE;
> > > +     }
> > > +
> > > +     return TRUE;
> > > +}
> > > +
> > > +
> > >  /**
> > >   * wpas_dbus_getter_sta_address - Return the address of a
> > > connected
> > > station
> > >   * @iter: Pointer to incoming dbus message iter
> > > diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h
> > > b/wpa_supplicant/dbus/dbus_new_handlers.h
> > > index d922ce1b4..afa26efed 100644
> > > --- a/wpa_supplicant/dbus/dbus_new_handlers.h
> > > +++ b/wpa_supplicant/dbus/dbus_new_handlers.h
> > > @@ -177,6 +177,8 @@
> > > DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_engine_path);
> > >  DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_module_path);
> > >  DECLARE_ACCESSOR(wpas_dbus_getter_blobs);
> > >  DECLARE_ACCESSOR(wpas_dbus_getter_stas);
> > > +DECLARE_ACCESSOR(wpas_dbus_getter_mac_address_randomization_mask
> > > );
> > > +DECLARE_ACCESSOR(wpas_dbus_setter_mac_address_randomization_mask
> > > );
> > >  DECLARE_ACCESSOR(wpas_dbus_getter_sta_address);
> > >  DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid);
> > >  DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps);
> > > diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
> > > index 7abb028dd..251e0642e 100644
> > > --- a/wpa_supplicant/scan.c
> > > +++ b/wpa_supplicant/scan.c
> > > @@ -79,6 +79,27 @@ static int wpas_wps_in_use(struct
> > > wpa_supplicant
> > > *wpa_s,
> > >  #endif /* CONFIG_WPS */
> > > 
> > > 
> > > +static int wpa_setup_mac_addr_rand_params(struct
> > > wpa_driver_scan_params *params,
> > > +                                       const u8 *mac_addr)
> > > +{
> > > +     u8 *tmp;
> > > +
> > > +     if (!mac_addr)
> > > +             return 0;
> > > +
> > > +     params->mac_addr_rand = 1;
> > > +
> > > +     tmp = os_malloc(2 * ETH_ALEN);
> > > +     if (!tmp)
> > > +             return -1;
> > > +
> > > +     os_memcpy(tmp, mac_addr, 2 * ETH_ALEN);
> > > +     params->mac_addr = tmp;
> > > +     params->mac_addr_mask = tmp + ETH_ALEN;
> > > +     return 0;
> > > +}
> > > +
> > > +
> > >  /**
> > >   * wpa_supplicant_enabled_networks - Check whether there are
> > > enabled
> > > networks
> > >   * @wpa_s: Pointer to wpa_supplicant data
> > > @@ -169,7 +190,9 @@ static void wpas_trigger_scan_cb(struct
> > > wpa_radio_work *work, int deinit)
> > >               return;
> > >       }
> > > 
> > > -     if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
> > > +     if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN)
> > > +             wpa_setup_mac_addr_rand_params(params, wpa_s-
> > > > mac_addr_scan);
> > > +     else if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
> > >               wpa_msg(wpa_s, MSG_INFO,
> > >                       "Failed to assign random MAC address for a
> > > scan");
> > >               wpa_scan_free_params(params);
> > > @@ -1212,11 +1235,7 @@ ssid_list_set:
> > > 
> > >       if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
> > >           wpa_s->wpa_state <= WPA_SCANNING) {
> > > -             params.mac_addr_rand = 1;
> > > -             if (wpa_s->mac_addr_scan) {
> > > -                     params.mac_addr = wpa_s->mac_addr_scan;
> > > -                     params.mac_addr_mask = wpa_s->mac_addr_scan 
> > > +
> > > ETH_ALEN;
> > > -             }
> > > +             wpa_setup_mac_addr_rand_params(&params, wpa_s-
> > > > mac_addr_scan);
> > >       }
> > > 
> > >       if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
> > > @@ -1665,12 +1684,7 @@ scan:
> > > 
> > >       if ((wpa_s->mac_addr_rand_enable &
> > > MAC_ADDR_RAND_SCHED_SCAN) &&
> > >           wpa_s->wpa_state <= WPA_SCANNING) {
> > > -             params.mac_addr_rand = 1;
> > > -             if (wpa_s->mac_addr_sched_scan) {
> > > -                     params.mac_addr = wpa_s-
> > > >mac_addr_sched_scan;
> > > -                     params.mac_addr_mask = wpa_s-
> > > > mac_addr_sched_scan +
> > > -                             ETH_ALEN;
> > > -             }
> > > +             wpa_setup_mac_addr_rand_params(&params, wpa_s-
> > > > mac_addr_sched_scan);
> > >       }
> > > 
> > >       wpa_scan_set_relative_rssi_params(wpa_s, scan_params);
> > > @@ -2535,23 +2549,9 @@ wpa_scan_clone_params(const struct
> > > wpa_driver_scan_params *src)
> > >               params->sched_scan_plans_num = src-
> > > > sched_scan_plans_num;
> > >       }
> > > 
> > > -     if (src->mac_addr_rand) {
> > > -             params->mac_addr_rand = src->mac_addr_rand;
> > > -
> > > -             if (src->mac_addr && src->mac_addr_mask) {
> > > -                     u8 *mac_addr;
> > > -
> > > -                     mac_addr = os_malloc(2 * ETH_ALEN);
> > > -                     if (!mac_addr)
> > > -                             goto failed;
> > > -
> > > -                     os_memcpy(mac_addr, src->mac_addr,
> > > ETH_ALEN);
> > > -                     os_memcpy(mac_addr + ETH_ALEN, src-
> > > > mac_addr_mask,
> > > -                               ETH_ALEN);
> > > -                     params->mac_addr = mac_addr;
> > > -                     params->mac_addr_mask = mac_addr +
> > > ETH_ALEN;
> > > -             }
> > > -     }
> > > +     if (src->mac_addr_rand &&
> > > +         wpa_setup_mac_addr_rand_params(params, (const u8 *)src-
> > > > mac_addr))
> > > +             goto failed;
> > > 
> > >       if (src->bssid) {
> > >               u8 *bssid;
> > > @@ -2739,11 +2739,7 @@ int wpas_start_pno(struct wpa_supplicant
> > > *wpa_s)
> > > 
> > >       if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
> > >           wpa_s->wpa_state <= WPA_SCANNING) {
> > > -             params.mac_addr_rand = 1;
> > > -             if (wpa_s->mac_addr_pno) {
> > > -                     params.mac_addr = wpa_s->mac_addr_pno;
> > > -                     params.mac_addr_mask = wpa_s->mac_addr_pno
> > > +
> > > ETH_ALEN;
> > > -             }
> > > +             wpa_setup_mac_addr_rand_params(&params, wpa_s-
> > > > mac_addr_pno);
> > >       }
> > > 
> > >       wpa_scan_set_relative_rssi_params(wpa_s, &params);
> > > @@ -2843,6 +2839,32 @@ int wpas_mac_addr_rand_scan_set(struct
> > > wpa_supplicant *wpa_s,
> > >  }
> > > 
> > > 
> > > +int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant
> > > *wpa_s,
> > > +                                  unsigned int type, u8 *mask)
> > > +{
> > > +     u8 *to_copy = NULL;
> > > +
> > > +     if ((wpa_s->mac_addr_rand_enable & type) != type)
> > > +             return -1;
> > > +
> > > +     if (type == MAC_ADDR_RAND_SCAN) {
> > > +             to_copy = wpa_s->mac_addr_scan;
> > > +     } else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
> > > +             to_copy = wpa_s->mac_addr_sched_scan;
> > > +     } else if (type == MAC_ADDR_RAND_PNO) {
> > > +             to_copy = wpa_s->mac_addr_pno;
> > > +     } else {
> > > +             wpa_printf(MSG_DEBUG,
> > > +                        "scan: Invalid MAC randomization
> > > type=0x%x",
> > > +                        type);
> > > +             return -1;
> > > +     }
> > > +
> > > +     os_memcpy(mask, to_copy + ETH_ALEN, ETH_ALEN);
> > > +     return 0;
> > > +}
> > > +
> > > +
> > >  int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
> > >  {
> > >       struct wpa_radio_work *work;
> > > diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
> > > index 2aa0a8be0..58caa7818 100644
> > > --- a/wpa_supplicant/scan.h
> > > +++ b/wpa_supplicant/scan.h
> > > @@ -52,6 +52,8 @@ void wpas_mac_addr_rand_scan_clear(struct
> > > wpa_supplicant *wpa_s,
> > >  int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
> > >                               unsigned int type, const u8 *addr,
> > >                               const u8 *mask);
> > > +int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant
> > > *wpa_s,
> > > +                                  unsigned int type, u8 *mask);
> > >  int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s);
> > >  void filter_scan_res(struct wpa_supplicant *wpa_s,
> > >                    struct wpa_scan_results *res);
> > > diff --git a/wpa_supplicant/wpa_supplicant.c
> > > b/wpa_supplicant/wpa_supplicant.c
> > > index f82d18fe2..9d1e88bdd 100644
> > > --- a/wpa_supplicant/wpa_supplicant.c
> > > +++ b/wpa_supplicant/wpa_supplicant.c
> > > @@ -7477,3 +7477,60 @@ int wpa_is_bss_tmp_disallowed(struct
> > > wpa_supplicant *wpa_s,
> > > 
> > >       return 1;
> > >  }
> > > +
> > > +int wpas_enable_mac_addr_randomization(struct wpa_supplicant
> > > *wpa_s,
> > > +                                    int type, const u8 *addr,
> > > +                                    const u8 *mask)
> > > +{
> > > +     if ((addr && !mask) || (!addr && mask)) {
> > > +             wpa_printf(MSG_INFO,
> > > +                        "MAC_ADDR_RAND_SCAN invalid addr/mask
> > > combination");
> > > +             return -1;
> > > +     }
> > > +
> > > +     if (addr && mask && (!(mask[0] & 0x01) || (addr[0] &
> > > 0x01))) {
> > > +             wpa_printf(MSG_INFO,
> > > +                        "MAC_ADDR_RAND_SCAN cannot allow
> > > multicast
> > > address");
> > > +             return -1;
> > > +     }
> > > +
> > > +     if (type & MAC_ADDR_RAND_SCAN) {
> > > +             wpas_mac_addr_rand_scan_set(wpa_s,
> > > MAC_ADDR_RAND_SCAN,
> > > +                                         addr, mask);
> > > +     }
> > > +
> > > +     if (type & MAC_ADDR_RAND_SCHED_SCAN) {
> > > +             wpas_mac_addr_rand_scan_set(wpa_s,
> > > MAC_ADDR_RAND_SCHED_SCAN,
> > > +                                         addr, mask);
> > > +
> > > +             if (wpa_s->sched_scanning && !wpa_s->pno)
> > > +                     wpas_scan_restart_sched_scan(wpa_s);
> > > +     }
> > > +
> > > +     if (type & MAC_ADDR_RAND_PNO) {
> > > +             wpas_mac_addr_rand_scan_set(wpa_s,
> > > MAC_ADDR_RAND_PNO,
> > > +                                         addr, mask);
> > > +             if (wpa_s->pno) {
> > > +                     wpas_stop_pno(wpa_s);
> > > +                     wpas_start_pno(wpa_s);
> > > +             }
> > > +     }
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +
> > > +int wpas_disable_mac_addr_randomization(struct wpa_supplicant
> > > *wpa_s, int type)
> > > +{
> > > +     wpas_mac_addr_rand_scan_clear(wpa_s, type);
> > > +     if (wpa_s->pno) {
> > > +             if (type & MAC_ADDR_RAND_PNO) {
> > > +                     wpas_stop_pno(wpa_s);
> > > +                     wpas_start_pno(wpa_s);
> > > +             }
> > > +     } else if (wpa_s->sched_scanning && (type &
> > > MAC_ADDR_RAND_SCHED_SCAN)) {
> > > +             wpas_scan_restart_sched_scan(wpa_s);
> > > +     }
> > > +
> > > +     return 0;
> > > +}
> > > diff --git a/wpa_supplicant/wpa_supplicant_i.h
> > > b/wpa_supplicant/wpa_supplicant_i.h
> > > index b51390ba3..796d83475 100644
> > > --- a/wpa_supplicant/wpa_supplicant_i.h
> > > +++ b/wpa_supplicant/wpa_supplicant_i.h
> > > @@ -1417,6 +1417,11 @@ size_t wpas_supp_op_class_ie(struct
> > > wpa_supplicant *wpa_s,
> > >                            struct wpa_ssid *ssid,
> > >                            int freq, u8 *pos, size_t len);
> > > 
> > > +int wpas_enable_mac_addr_randomization(struct wpa_supplicant
> > > *wpa_s,
> > > +                                    int type, const u8 *addr,
> > > +                                    const u8 *mask);
> > > +int wpas_disable_mac_addr_randomization(struct wpa_supplicant
> > > *wpa_s, int type);
> > > +
> > >  /**
> > >   * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control
> > > response
> > >   * @wpa_s: Pointer to wpa_supplicant data
Jouni Malinen June 26, 2019, 7:08 p.m. UTC | #4
On Thu, May 30, 2019 at 11:10:46AM -0700, Eric Caruso wrote:
> Add D-Bus property:
> * MACAddressRandomizationMask: a{say}
> 
> which configure random MAC address functionality in the Wi-Fi
> driver via netlink. This also fixes weird pointer ownership
> that was causing memory issues.

It would be nice to get bit more detailed description of that pointer
ownership issue and ideally, have it separated into its own patch if it
is indeed fixing something that already exists and not something that
is only exposed with the changes here.

> diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
> @@ -9626,59 +9626,10 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,

> -	if (!enable) {
> -		wpas_mac_addr_rand_scan_clear(wpa_s, type);
> -		if (wpa_s->pno) {
> -			if (type & MAC_ADDR_RAND_PNO) {
> -				wpas_stop_pno(wpa_s);
> -				wpas_start_pno(wpa_s);
> -			}
> -		} else if (wpa_s->sched_scanning &&
> -			   (type & MAC_ADDR_RAND_SCHED_SCAN)) {
> -			wpas_scan_restart_sched_scan(wpa_s);
> -		}
> -		return 0;
> -	}
> +	if (!enable)
> +		return wpas_disable_mac_addr_randomization(wpa_s, type);
..

This part about moving this functionality into a helper function sounds
reasonable, but should be done without functional changes and in its own
patch. I applied this now with the changed behavior removed in this
commit:
https://w1.fi/cgit/hostap/commit/?id=91b6eba7732354ed3dfe0aa9715dc4c0746e3336

> -	if (type & MAC_ADDR_RAND_SCHED_SCAN) {
> -		if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
> -					    addr, mask))
> -			return -1;

The changes were to reintroduce some of the return -1 statements that
had been removed in your patch without any clear explanation of why they
were removed. If such changes are needed, please provide a separate
patch with those changes and a commit log that explains the need.

> diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c

> +static int wpa_setup_mac_addr_rand_params(struct wpa_driver_scan_params *params,
> +					  const u8 *mac_addr)
> +{
> +	u8 *tmp;
> +
> +	if (!mac_addr)
> +		return 0;
> +
> +	params->mac_addr_rand = 1;
> +
> +	tmp = os_malloc(2 * ETH_ALEN);
> +	if (!tmp)
> +		return -1;
> +
> +	os_memcpy(tmp, mac_addr, 2 * ETH_ALEN);
> +	params->mac_addr = tmp;
> +	params->mac_addr_mask = tmp + ETH_ALEN;
> +	return 0;
> +}

This would result in memory leaks since that allocated heap memory is
not freed anywhere. I'd assume this part is related to that "weird
pointer ownership". It should really be handled in a separate patch and
with clear explanation of why it is needed and changes to clearly
describe how this new allocated buffer can be safely freed.

I'm attaching the patch for the remaining changes that I did not yet
apply due to that memory leak and hope of getting it split into two
patches. This has some coding style cleanup compared to the version you
sent to get rid of a compiler warnings and to be a bit more consistent
with the coding style used in hostap.git.
Eric Caruso June 27, 2019, 6:38 p.m. UTC | #5
> > -     if (type & MAC_ADDR_RAND_SCHED_SCAN) {
> > -             if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
> > -                                         addr, mask))
> > -                     return -1;
>
> The changes were to reintroduce some of the return -1 statements that
> had been removed in your patch without any clear explanation of why they
> were removed. If such changes are needed, please provide a separate
> patch with those changes and a commit log that explains the need.

Thanks for catching this. I think it was just something I missed while
rebasing these patches from a much older version of wpa_supplicant.

> This would result in memory leaks since that allocated heap memory is
> not freed anywhere. I'd assume this part is related to that "weird
> pointer ownership". It should really be handled in a separate patch and
> with clear explanation of why it is needed and changes to clearly
> describe how this new allocated buffer can be safely freed.
>
> I'm attaching the patch for the remaining changes that I did not yet
> apply due to that memory leak and hope of getting it split into two
> patches. This has some coding style cleanup compared to the version you
> sent to get rid of a compiler warnings and to be a bit more consistent
> with the coding style used in hostap.git.

The weird pointer ownership comes from the fact that the MAC address
randomization byte arrays could be simultaneously referenced by the
scan params and the wpa_supplicant struct itself, leading to
situations where we might free it in one place and leave it dangling
in the other struct. For example, a wpa_scan_free_params invalidates
the pointer held in the relevant wpa_supplicant struct. I chose to
allocate a new array and copy to avoid this because I think I was
seeing crashes at the time I originally wrote this code for that
reason.

Either way, the fix for this is pretty simple. Thanks for the review.
diff mbox series

Patch

diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen
index 072ed3486..9f6af52b1 100644
--- a/doc/dbus.doxygen
+++ b/doc/dbus.doxygen
@@ -1043,6 +1043,11 @@  fi.w1.wpa_supplicant1.CreateInterface.
 	<h3>WpsPriority - s - (read/write)</h3>
 	<p>Priority for the networks added through WPS</p>
       </li>
+
+      <li>
+	<h3>MACAddressRandomizationMask - a{say} - (read/write)</h3>
+	<p>Masks to show which bits not to randomize with MAC address randomization. Possible keys are "scan", "sched_scan", and "pno". Values must be an array of 6 bytes.</p>
+      </li>
     </ul>
 
 \subsection dbus_interface_signals Signals
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 10f1908f8..8efc08d4d 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -9626,59 +9626,10 @@  static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
 		return -1;
 	}
 
-	if (!enable) {
-		wpas_mac_addr_rand_scan_clear(wpa_s, type);
-		if (wpa_s->pno) {
-			if (type & MAC_ADDR_RAND_PNO) {
-				wpas_stop_pno(wpa_s);
-				wpas_start_pno(wpa_s);
-			}
-		} else if (wpa_s->sched_scanning &&
-			   (type & MAC_ADDR_RAND_SCHED_SCAN)) {
-			wpas_scan_restart_sched_scan(wpa_s);
-		}
-		return 0;
-	}
+	if (!enable)
+		return wpas_disable_mac_addr_randomization(wpa_s, type);
 
-	if ((addr && !mask) || (!addr && mask)) {
-		wpa_printf(MSG_INFO,
-			   "CTRL: MAC_RAND_SCAN invalid addr/mask combination");
-		return -1;
-	}
-
-	if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
-		wpa_printf(MSG_INFO,
-			   "CTRL: MAC_RAND_SCAN cannot allow multicast address");
-		return -1;
-	}
-
-	if (type & MAC_ADDR_RAND_SCAN) {
-		if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
-					    addr, mask))
-			return -1;
-	}
-
-	if (type & MAC_ADDR_RAND_SCHED_SCAN) {
-		if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
-					    addr, mask))
-			return -1;
-
-		if (wpa_s->sched_scanning && !wpa_s->pno)
-			wpas_scan_restart_sched_scan(wpa_s);
-	}
-
-	if (type & MAC_ADDR_RAND_PNO) {
-		if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
-					    addr, mask))
-			return -1;
-
-		if (wpa_s->pno) {
-			wpas_stop_pno(wpa_s);
-			wpas_start_pno(wpa_s);
-		}
-	}
-
-	return 0;
+	return wpas_enable_mac_addr_randomization(wpa_s, type, addr, mask);
 }
 
 
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index fc2fc2ef1..c5d3b8a02 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -3803,6 +3803,11 @@  static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
 	  NULL,
 	  NULL
 	},
+	{ "MACAddressRandomizationMask", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}",
+	  wpas_dbus_getter_mac_address_randomization_mask,
+	  wpas_dbus_setter_mac_address_randomization_mask,
+	  NULL
+	},
 	{ NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 6c36d91a0..764675caa 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -3989,6 +3989,159 @@  out:
 }
 
 
+/**
+ * wpas_dbus_setter_mac_address_randomization_mask - Set masks used for
+ * MAC address randomization
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "MACAddressRandomizationMask" property.
+ */
+dbus_bool_t wpas_dbus_setter_mac_address_randomization_mask(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
+	const char *key;
+	unsigned int rand_type = 0;
+	const u8 *mask;
+	int mask_len;
+	unsigned int rand_types_to_disable = MAC_ADDR_RAND_ALL;
+
+	dbus_message_iter_recurse(iter, &variant_iter);
+	dbus_message_iter_recurse(&variant_iter, &dict_iter);
+	while (dbus_message_iter_get_arg_type(&dict_iter) ==
+	       DBUS_TYPE_DICT_ENTRY) {
+		dbus_message_iter_recurse(&dict_iter, &entry_iter);
+		if (dbus_message_iter_get_arg_type(&entry_iter) != DBUS_TYPE_STRING) {
+			dbus_set_error(error, DBUS_ERROR_FAILED,
+				       "%s: key not a string", __func__);
+			return FALSE;
+		}
+		dbus_message_iter_get_basic(&entry_iter, &key);
+		dbus_message_iter_next(&entry_iter);
+		if (dbus_message_iter_get_arg_type(&entry_iter) != DBUS_TYPE_ARRAY ||
+		    dbus_message_iter_get_element_type(&entry_iter) != DBUS_TYPE_BYTE) {
+			dbus_set_error(error, DBUS_ERROR_FAILED,
+				       "%s: mask was not a byte array", __func__);
+			return FALSE;
+		}
+		dbus_message_iter_recurse(&entry_iter, &array_iter);
+		dbus_message_iter_get_fixed_array(&array_iter, &mask, &mask_len);
+
+		if (os_strcmp(key, "scan") == 0) {
+			rand_type = MAC_ADDR_RAND_SCAN;
+		} else if (os_strcmp(key, "sched_scan") == 0) {
+			rand_type = MAC_ADDR_RAND_SCHED_SCAN;
+		} else if (os_strcmp(key, "pno") == 0) {
+			rand_type = MAC_ADDR_RAND_PNO;
+		} else {
+			dbus_set_error(error, DBUS_ERROR_FAILED,
+				       "%s: bad scan type \"%s\"", __func__, key);
+			return FALSE;
+		}
+
+		if (mask_len != ETH_ALEN) {
+			dbus_set_error(error, DBUS_ERROR_FAILED,
+				       "%s: malformed MAC mask given", __func__);
+			return FALSE;
+		}
+
+		if (wpas_enable_mac_addr_randomization(
+		    wpa_s, rand_type, wpa_s->perm_addr, mask)) {
+			dbus_set_error(error, DBUS_ERROR_FAILED,
+				       "%s: failed to set up MAC address randomization for %s",
+				       __func__, key);
+			return FALSE;
+		}
+
+		wpa_printf(MSG_DEBUG, "%s: Enabled MAC address randomization for %s with mask: "
+			MACSTR, wpa_s->ifname, key, MAC2STR(mask));
+		rand_types_to_disable &= ~rand_type;
+		dbus_message_iter_next(&dict_iter);
+	}
+
+	if (rand_types_to_disable &&
+	    wpas_disable_mac_addr_randomization(wpa_s, rand_types_to_disable)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "%s: failed to disable MAC address randomization",
+			       __func__);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_mac_address_randomization_mask(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
+	int i;
+	u8 mask_buf[ETH_ALEN];
+	/* Read docs on dbus_message_iter_append_fixed_array for why this
+	 * is necessary... */
+	u8* mask = mask_buf;
+	static const struct {
+		const char *key;
+		unsigned int type;
+	} types[] = {
+		{ "scan", MAC_ADDR_RAND_SCAN },
+		{ "sched_scan", MAC_ADDR_RAND_SCHED_SCAN },
+		{ "pno", MAC_ADDR_RAND_PNO }
+	};
+
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+					      "a{say}", &variant_iter) ||
+	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+					      "{say}", &dict_iter)) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	for (i = 0; i < sizeof(types)/sizeof(types[0]); i++) {
+		if (wpas_mac_addr_rand_scan_get_mask(wpa_s, types[i].type, mask))
+			continue;
+
+		if (!dbus_message_iter_open_container(&dict_iter,
+						      DBUS_TYPE_DICT_ENTRY,
+						      NULL, &entry_iter) ||
+		    !dbus_message_iter_append_basic(&entry_iter,
+						    DBUS_TYPE_STRING,
+						    &types[i].key) ||
+		    !dbus_message_iter_open_container(&entry_iter,
+						      DBUS_TYPE_ARRAY,
+						      DBUS_TYPE_BYTE_AS_STRING,
+						      &array_iter) ||
+		    !dbus_message_iter_append_fixed_array(&array_iter,
+							  DBUS_TYPE_BYTE,
+							  &mask,
+							  ETH_ALEN) ||
+		    !dbus_message_iter_close_container(&entry_iter,
+						       &array_iter) ||
+		    !dbus_message_iter_close_container(&dict_iter,
+						       &entry_iter)) {
+			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+					     "no memory");
+			return FALSE;
+		}
+	}
+
+	if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter)) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
 /**
  * wpas_dbus_getter_sta_address - Return the address of a connected station
  * @iter: Pointer to incoming dbus message iter
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index d922ce1b4..afa26efed 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -177,6 +177,8 @@  DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_engine_path);
 DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_module_path);
 DECLARE_ACCESSOR(wpas_dbus_getter_blobs);
 DECLARE_ACCESSOR(wpas_dbus_getter_stas);
+DECLARE_ACCESSOR(wpas_dbus_getter_mac_address_randomization_mask);
+DECLARE_ACCESSOR(wpas_dbus_setter_mac_address_randomization_mask);
 DECLARE_ACCESSOR(wpas_dbus_getter_sta_address);
 DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid);
 DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 7abb028dd..251e0642e 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -79,6 +79,27 @@  static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_WPS */
 
 
+static int wpa_setup_mac_addr_rand_params(struct wpa_driver_scan_params *params,
+					  const u8 *mac_addr)
+{
+	u8 *tmp;
+
+	if (!mac_addr)
+		return 0;
+
+	params->mac_addr_rand = 1;
+
+	tmp = os_malloc(2 * ETH_ALEN);
+	if (!tmp)
+		return -1;
+
+	os_memcpy(tmp, mac_addr, 2 * ETH_ALEN);
+	params->mac_addr = tmp;
+	params->mac_addr_mask = tmp + ETH_ALEN;
+	return 0;
+}
+
+
 /**
  * wpa_supplicant_enabled_networks - Check whether there are enabled networks
  * @wpa_s: Pointer to wpa_supplicant data
@@ -169,7 +190,9 @@  static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
 		return;
 	}
 
-	if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
+	if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN)
+		wpa_setup_mac_addr_rand_params(params, wpa_s->mac_addr_scan);
+	else if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
 		wpa_msg(wpa_s, MSG_INFO,
 			"Failed to assign random MAC address for a scan");
 		wpa_scan_free_params(params);
@@ -1212,11 +1235,7 @@  ssid_list_set:
 
 	if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
 	    wpa_s->wpa_state <= WPA_SCANNING) {
-		params.mac_addr_rand = 1;
-		if (wpa_s->mac_addr_scan) {
-			params.mac_addr = wpa_s->mac_addr_scan;
-			params.mac_addr_mask = wpa_s->mac_addr_scan + ETH_ALEN;
-		}
+		wpa_setup_mac_addr_rand_params(&params, wpa_s->mac_addr_scan);
 	}
 
 	if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
@@ -1665,12 +1684,7 @@  scan:
 
 	if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) &&
 	    wpa_s->wpa_state <= WPA_SCANNING) {
-		params.mac_addr_rand = 1;
-		if (wpa_s->mac_addr_sched_scan) {
-			params.mac_addr = wpa_s->mac_addr_sched_scan;
-			params.mac_addr_mask = wpa_s->mac_addr_sched_scan +
-				ETH_ALEN;
-		}
+		wpa_setup_mac_addr_rand_params(&params, wpa_s->mac_addr_sched_scan);
 	}
 
 	wpa_scan_set_relative_rssi_params(wpa_s, scan_params);
@@ -2535,23 +2549,9 @@  wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
 		params->sched_scan_plans_num = src->sched_scan_plans_num;
 	}
 
-	if (src->mac_addr_rand) {
-		params->mac_addr_rand = src->mac_addr_rand;
-
-		if (src->mac_addr && src->mac_addr_mask) {
-			u8 *mac_addr;
-
-			mac_addr = os_malloc(2 * ETH_ALEN);
-			if (!mac_addr)
-				goto failed;
-
-			os_memcpy(mac_addr, src->mac_addr, ETH_ALEN);
-			os_memcpy(mac_addr + ETH_ALEN, src->mac_addr_mask,
-				  ETH_ALEN);
-			params->mac_addr = mac_addr;
-			params->mac_addr_mask = mac_addr + ETH_ALEN;
-		}
-	}
+	if (src->mac_addr_rand &&
+	    wpa_setup_mac_addr_rand_params(params, (const u8 *)src->mac_addr))
+		goto failed;
 
 	if (src->bssid) {
 		u8 *bssid;
@@ -2739,11 +2739,7 @@  int wpas_start_pno(struct wpa_supplicant *wpa_s)
 
 	if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
 	    wpa_s->wpa_state <= WPA_SCANNING) {
-		params.mac_addr_rand = 1;
-		if (wpa_s->mac_addr_pno) {
-			params.mac_addr = wpa_s->mac_addr_pno;
-			params.mac_addr_mask = wpa_s->mac_addr_pno + ETH_ALEN;
-		}
+		wpa_setup_mac_addr_rand_params(&params, wpa_s->mac_addr_pno);
 	}
 
 	wpa_scan_set_relative_rssi_params(wpa_s, &params);
@@ -2843,6 +2839,32 @@  int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
 }
 
 
+int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
+				     unsigned int type, u8 *mask)
+{
+	u8 *to_copy = NULL;
+
+	if ((wpa_s->mac_addr_rand_enable & type) != type)
+		return -1;
+
+	if (type == MAC_ADDR_RAND_SCAN) {
+		to_copy = wpa_s->mac_addr_scan;
+	} else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
+		to_copy = wpa_s->mac_addr_sched_scan;
+	} else if (type == MAC_ADDR_RAND_PNO) {
+		to_copy = wpa_s->mac_addr_pno;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "scan: Invalid MAC randomization type=0x%x",
+			   type);
+		return -1;
+	}
+
+	os_memcpy(mask, to_copy + ETH_ALEN, ETH_ALEN);
+	return 0;
+}
+
+
 int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
 {
 	struct wpa_radio_work *work;
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 2aa0a8be0..58caa7818 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -52,6 +52,8 @@  void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
 int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
 				unsigned int type, const u8 *addr,
 				const u8 *mask);
+int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
+				     unsigned int type, u8 *mask);
 int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s);
 void filter_scan_res(struct wpa_supplicant *wpa_s,
 		     struct wpa_scan_results *res);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index f82d18fe2..9d1e88bdd 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -7477,3 +7477,60 @@  int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
 
 	return 1;
 }
+
+int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
+				       int type, const u8 *addr,
+				       const u8 *mask)
+{
+	if ((addr && !mask) || (!addr && mask)) {
+		wpa_printf(MSG_INFO,
+			   "MAC_ADDR_RAND_SCAN invalid addr/mask combination");
+		return -1;
+	}
+
+	if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
+		wpa_printf(MSG_INFO,
+			   "MAC_ADDR_RAND_SCAN cannot allow multicast address");
+		return -1;
+	}
+
+	if (type & MAC_ADDR_RAND_SCAN) {
+		wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
+					    addr, mask);
+	}
+
+	if (type & MAC_ADDR_RAND_SCHED_SCAN) {
+		wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
+					    addr, mask);
+
+		if (wpa_s->sched_scanning && !wpa_s->pno)
+			wpas_scan_restart_sched_scan(wpa_s);
+	}
+
+	if (type & MAC_ADDR_RAND_PNO) {
+		wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
+					    addr, mask);
+		if (wpa_s->pno) {
+			wpas_stop_pno(wpa_s);
+			wpas_start_pno(wpa_s);
+		}
+	}
+
+	return 0;
+}
+
+
+int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s, int type)
+{
+	wpas_mac_addr_rand_scan_clear(wpa_s, type);
+	if (wpa_s->pno) {
+		if (type & MAC_ADDR_RAND_PNO) {
+			wpas_stop_pno(wpa_s);
+			wpas_start_pno(wpa_s);
+		}
+	} else if (wpa_s->sched_scanning && (type & MAC_ADDR_RAND_SCHED_SCAN)) {
+		wpas_scan_restart_sched_scan(wpa_s);
+	}
+
+	return 0;
+}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index b51390ba3..796d83475 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1417,6 +1417,11 @@  size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
 			     struct wpa_ssid *ssid,
 			     int freq, u8 *pos, size_t len);
 
+int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
+				       int type, const u8 *addr,
+				       const u8 *mask);
+int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s, int type);
+
 /**
  * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
  * @wpa_s: Pointer to wpa_supplicant data