P2P MAC Randomization

Randomize the MAC address of p2p-discovery and group interfaces

Bug:151203962
Test: Tested from Android -R UI and verified on sniffer.a

Signed-off-by: Mir Ali <mir-khizer.ali@broadcom.com>
Change-Id: I1428cbe81d7bbf6126aa7a3b2d9af823bc18b9ae
diff --git a/src/common/brcm_vendor.h b/src/common/brcm_vendor.h
index cb5b348..b1bf397 100644
--- a/src/common/brcm_vendor.h
+++ b/src/common/brcm_vendor.h
@@ -27,6 +27,7 @@
  */
 enum brcm_nl80211_vendor_subcmds {
 	BRCM_VENDOR_SUBCMD_UNSPEC		= 0,
+	BRCM_VENDOR_SUBCMD_SET_MAC		= 6,
 	BRCM_VENDOR_SCMD_ACS			= 9,
 	BRCM_VENDOR_SCMD_MAX			= 10
 };
@@ -61,5 +62,12 @@
 
 	BRCM_VENDOR_ATTR_ACS_LAST
 };
+
+enum brcm_wlan_vendor_attr {
+	BRCM_ATTR_DRIVER_CMD            = 0,
+	BRCM_ATTR_DRIVER_MAC_ADDR	= 3,
+	BRCM_ATTR_DRIVER_AFTER_LAST     = 5,
+	BRCM_ATTR_DRIVER_MAX            = BRCM_ATTR_DRIVER_AFTER_LAST - 1,
+};
 #endif /* BRCM_VENDOR_H */
 
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index ca74d35..4295f0c 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -7689,8 +7689,10 @@
 
 		drv->global->if_add_wdevid = p2pdev_info.wdev_id;
 		drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
-		if (!is_zero_ether_addr(p2pdev_info.macaddr))
+		if (!is_zero_ether_addr(p2pdev_info.macaddr)) {
 			os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
+			os_memcpy(drv->global->p2p_perm_addr, p2pdev_info.macaddr, ETH_ALEN);
+		}
 		wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
 			   ifname,
 			   (long long unsigned int) p2pdev_info.wdev_id);
@@ -10125,10 +10127,45 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int new_addr = addr != NULL;
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+	struct nl_msg *msg;
+	struct nlattr *params;
+	int ret;
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+	wpa_printf(MSG_DEBUG, "Enter: %s", __FUNCTION__);
 
 	if (TEST_FAIL())
 		return -1;
+	if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+		if (!addr ) {
+			addr = drv->global->p2p_perm_addr;
+		}
 
+		if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
+			nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
+			nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+				BRCM_VENDOR_SUBCMD_SET_MAC) ||
+			!(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+			nla_put(msg, BRCM_ATTR_DRIVER_MAC_ADDR, ETH_ALEN, addr)) {
+			wpa_printf(MSG_ERROR, "failed to put p2p randmac");
+			nl80211_nlmsg_clear(msg);
+			nlmsg_free(msg);
+			return -ENOBUFS;
+		}
+		nla_nest_end(msg, params);
+
+		ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
+		if (ret) {
+			wpa_printf(MSG_ERROR, "nl80211: p2p set macaddr failed: ret=%d (%s)",
+				ret, strerror(-ret));
+		}
+		memcpy(bss->addr, addr, ETH_ALEN);
+		return ret;
+#else
+		return -ENOTSUP;
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+	}
 	if (!addr)
 		addr = drv->perm_addr;
 
@@ -10138,27 +10175,26 @@
 	if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, addr) < 0)
 	{
 		wpa_printf(MSG_DEBUG,
-			   "nl80211: failed to set_mac_addr for %s to " MACSTR,
-			   bss->ifname, MAC2STR(addr));
+			"nl80211: failed to set_mac_addr for %s to " MACSTR,
+			bss->ifname, MAC2STR(addr));
 		if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
-					  1) < 0) {
+			1) < 0) {
 			wpa_printf(MSG_DEBUG,
-				   "nl80211: Could not restore interface UP after failed set_mac_addr");
+				"nl80211: Could not restore interface UP after failed set_mac_addr");
 		}
 		return -1;
 	}
 
 	wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR,
-		   bss->ifname, MAC2STR(addr));
+		bss->ifname, MAC2STR(addr));
 	drv->addr_changed = new_addr;
 	os_memcpy(bss->addr, addr, ETH_ALEN);
 
 	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0)
 	{
 		wpa_printf(MSG_DEBUG,
-			   "nl80211: Could not restore interface UP after set_mac_addr");
+			"nl80211: Could not restore interface UP after set_mac_addr");
 	}
-
 	return 0;
 }
 
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 017c025..0db7d55 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -33,8 +33,8 @@
 	struct nl_sock *nl;
 	int nl80211_id;
 	int ioctl_sock; /* socket for ioctl() use */
-
 	struct nl_sock *nl_event;
+	u8 p2p_perm_addr[ETH_ALEN];
 };
 
 struct nl80211_wiphy_data {
diff --git a/wpa_supplicant/hidl/1.4/p2p_iface.cpp b/wpa_supplicant/hidl/1.4/p2p_iface.cpp
index d3d374e..8e1e264 100644
--- a/wpa_supplicant/hidl/1.4/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/1.4/p2p_iface.cpp
@@ -1796,14 +1796,6 @@
 	bool currentEnabledState = !!wpa_s->conf->p2p_device_random_mac_addr;
 	u8 *addr = NULL;
 
-	// A dedicated p2p device is not managed by supplicant,
-	// supplicant could not change its MAC address.
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) {
-		wpa_printf(MSG_ERROR,
-			"Dedicated P2P device don't support MAC randomization");
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, "NotSupported"};
-	}
-
 	// The same state, no change is needed.
 	if (currentEnabledState == enable) {
 		wpa_printf(MSG_DEBUG, "The random MAC is %s already.",
diff --git a/wpa_supplicant/hidl/1.4/p2p_iface.h b/wpa_supplicant/hidl/1.4/p2p_iface.h
index 4d07051..4a0e60a 100644
--- a/wpa_supplicant/hidl/1.4/p2p_iface.h
+++ b/wpa_supplicant/hidl/1.4/p2p_iface.h
@@ -30,6 +30,8 @@
 #include "config.h"
 }
 
+#define P2P_MGMT_DEVICE_PREFIX       "p2p-dev-"
+
 namespace android {
 namespace hardware {
 namespace wifi {
diff --git a/wpa_supplicant/hidl/1.4/supplicant.cpp b/wpa_supplicant/hidl/1.4/supplicant.cpp
index 5fea68d..6f4cde6 100644
--- a/wpa_supplicant/hidl/1.4/supplicant.cpp
+++ b/wpa_supplicant/hidl/1.4/supplicant.cpp
@@ -10,6 +10,7 @@
 #include "hidl_manager.h"
 #include "hidl_return_util.h"
 #include "supplicant.h"
+#include "p2p_iface.h"
 
 #include <android-base/file.h>
 #include <fcntl.h>
@@ -254,6 +255,39 @@
 }
 
 std::pair<SupplicantStatus, sp<ISupplicantIface>>
+Supplicant::addP2pDevInterface(struct wpa_interface iface_params)
+{
+	char primary_ifname[IFNAMSIZ];
+	u32 primary_ifname_len =
+		strlen(iface_params.ifname) - strlen(P2P_MGMT_DEVICE_PREFIX);
+
+	if(primary_ifname_len > IFNAMSIZ) {
+		wpa_printf(MSG_DEBUG, "%s, Invalid primary iface name ", __FUNCTION__);
+		return {{SupplicantStatusCode::FAILURE_ARGS_INVALID, ""}, {}};
+	}
+
+	strncpy(primary_ifname, iface_params.ifname +
+		strlen(P2P_MGMT_DEVICE_PREFIX), primary_ifname_len);
+	wpa_printf(MSG_DEBUG, "%s, Initialize p2p-dev-wlan0 iface with"
+		"primary_iface = %s", __FUNCTION__, primary_ifname);
+	struct wpa_supplicant* wpa_s =
+		wpa_supplicant_get_iface(wpa_global_, primary_ifname);
+	if (!wpa_s) {
+		wpa_printf(MSG_DEBUG, "%s,NULL wpa_s for wlan0", __FUNCTION__);
+		return {{SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""},
+			nullptr};
+	}
+	if (wpas_p2p_add_p2pdev_interface(
+		wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
+		wpa_printf(MSG_INFO,
+			"Failed to enable P2P Device");
+		return {{SupplicantStatusCode::FAILURE_UNKNOWN,
+			"Enable P2P Device failed"}, {}};
+	}
+	return {{SupplicantStatusCode::SUCCESS,""}, {}};
+}
+
+std::pair<SupplicantStatus, sp<ISupplicantIface>>
 Supplicant::addInterfaceInternal(const IfaceInfo& iface_info)
 {
 	android::sp<ISupplicantIface> iface;
@@ -305,10 +339,19 @@
 		}
 	}
 	iface_params.ifname = iface_info.name.c_str();
-	struct wpa_supplicant* wpa_s =
-	    wpa_supplicant_add_iface(wpa_global_, &iface_params, NULL);
-	if (!wpa_s) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+	if (strncmp(iface_params.ifname, P2P_MGMT_DEVICE_PREFIX,
+		strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
+		std::tie(status, iface) = addP2pDevInterface(iface_params);
+		if (status.code != SupplicantStatusCode::SUCCESS) {
+			return {{status.code,
+				status.debugMessage.c_str()}, iface};
+		}
+	} else {
+		struct wpa_supplicant* wpa_s =
+			wpa_supplicant_add_iface(wpa_global_, &iface_params, NULL);
+		if (!wpa_s) {
+			return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+		}
 	}
 	// The supplicant core creates a corresponding hidl object via
 	// HidlManager when |wpa_supplicant_add_iface| is called.
diff --git a/wpa_supplicant/hidl/1.4/supplicant.h b/wpa_supplicant/hidl/1.4/supplicant.h
index 8fd2033..2944c50 100644
--- a/wpa_supplicant/hidl/1.4/supplicant.h
+++ b/wpa_supplicant/hidl/1.4/supplicant.h
@@ -81,6 +81,8 @@
 	SupplicantStatus setDebugParamsInternal(
 	    ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys);
 	SupplicantStatus setConcurrencyPriorityInternal(IfaceType type);
+	std::pair<SupplicantStatus, sp<ISupplicantIface>> addP2pDevInterface(
+	    struct wpa_interface iface_params);
 
 	// Raw pointer to the global structure maintained by the core.
 	struct wpa_global* wpa_global_;