Parcourir la source

qcacld-3.0: Enable MAC provisioning from ini

Currently MAC addresses are generated by driver only.
MAC addresses are queried from platform driver or wlan_mac.bin.
If platform driver gives  mac addresses, driver uses it, else it
will use wlan_mac.bin to update MAC addresses. If wlan_mac.bin also
don't have MAC addresses then random MAC addresses are generated
using the HW address or using device serial number.

Add an ini support to enable MAC provisioning. If MAC provisioning
is enabled, ensure that platform driver provides atleast 2 provisioned
MAC addresses. Query the derived addresses also from platform driver.
Generate the remaining random MAC addresses.

Change-Id: Ib943f9de70a78ba5d5e87d81c76b20341893f8e9
CRs-Fixed: 2153836
Ashish Kumar Dhanotiya il y a 6 ans
Parent
commit
7a11e273df

+ 67 - 57
core/hdd/inc/hdd_config.h

@@ -547,86 +547,97 @@ enum hdd_wext_control {
 			"", \
 			"DBS Scan Selection")
 
-
 /*
- * <ini>
- * Intf0MacAddress - Interface address
- * @Default: 000AF58989FF
- *
- * Related: None
- *
- * Supported Feature: N/A
- *
- * Usage: External
- *
  * </ini>
- */
-#define __CFG_INTF0_MAC_ADDR_DEFAULT \
-	{.bytes = {0x00, 0x0a, 0xf5, 0x89, 0x89, 0xff} }
-#define CFG_INTF0_MAC_ADDR CFG_INI_MAC( \
-	"Intf0MacAddress", \
-	__CFG_INTF0_MAC_ADDR_DEFAULT, \
-	"Interface 0 MAC Address")
-
-/*
- * <ini>
- * Intf1MacAddress - Interface address
- * @Default: 000AF58989FE
+ * enable_mac_provision - Enable/disable MAC address provisioning feature
+ * @Min: 0
+ * @Max: 1
+ * @Default: 0
  *
- * Related: None
+ * This ini is used to enable/disable MAC address provisioning feature
  *
- * Supported Feature: N/A
+ * Supported Feature: STA/SAP/P2P
  *
  * Usage: External
  *
  * </ini>
  */
-#define __CFG_INTF1_MAC_ADDR_DEFAULT \
-	{.bytes = {0x00, 0x0a, 0xf5, 0x89, 0x89, 0xfe} }
-#define CFG_INTF1_MAC_ADDR CFG_INI_MAC( \
-	"Intf1MacAddress", \
-	__CFG_INTF1_MAC_ADDR_DEFAULT, \
-	"Interface 1 MAC Address")
+#define CFG_ENABLE_MAC_PROVISION CFG_INI_BOOL( \
+	"enable_mac_provision", \
+	0, \
+	"enable/disable MAC address provisioning feature")
 
 /*
  * <ini>
- * Intf2MacAddress - Interface address
- * @Default: 000AF58989FD
- *
- * Related: None
- *
- * Supported Feature: N/A
+ * provisioned_intf_pool - It is bit mask value of Interfaces
+ * @Min: 0
+ * @Max: 0xffffffff
+ * @Default: 0xffffffff
+ *
+ * This ini will contain the bitmask of all the interfaces
+ * which can use addresses from provisioned list. Using enum QDF_OPMODE
+ * for deciding the bit positions corresponding to each interface.
+ * Bit 0 : QDF_STA_MODE
+ * Bit 1 : QDF_SAP_MODE
+ * Bit 2 : QDF_P2P_CLIENT_MODE
+ * Bit 3 : QDF_P2P_GO_MODE
+ * Bit 4 : QDF_FTM_MODE
+ * Bit 5 : QDF_IBSS_MODE
+ * Bit 6 : QDF_MONITOR_MODE
+ * Bit 7 : QDF_P2P_DEVICE_MODE
+ * Bit 8 : QDF_OCB_MODE
+ * Bit 9 : QDF_EPPING_MODE
+ * Bit 10 : QDF_QVIT_MODE
+ * Bit 11 : QDF_NDI_MODE
+ * Bit 12 : QDF_MAX_NO_OF_MODE
+ * For example :
+ * If Bit 0 represents STA
+ * Bit 1 represents SAP
+ * Bit 2 represents P2PGO
+ * If only STA and SAP can use addresses from provisioned list then the value
+ * of ini should be 3 (00000011) as first and second bit should be set.
+ * If only STA and P2PGO can use addresses from provisioned list then the value
+ * of ini should be 5 (00000101) as first and third bit should be set.
+ * Similarly, for only SAP and P2PGO ini should be 6 (00000110)
+ *
+ * Supported Feature: STA/SAP/P2P
  *
  * Usage: External
  *
  * </ini>
  */
-#define __CFG_INTF2_MAC_ADDR_DEFAULT \
-	{.bytes = {0x00, 0x0a, 0xf5, 0x89, 0x89, 0xfd} }
-#define CFG_INTF2_MAC_ADDR CFG_INI_MAC( \
-	"Intf2MacAddress", \
-	__CFG_INTF2_MAC_ADDR_DEFAULT, \
-	"Interface 2 MAC Address")
+#define CFG_PROVISION_INTERFACE_POOL CFG_INI_UINT( \
+			"provisioned_intf_pool", \
+			0, \
+			0xffffffff, \
+			0xffffffff, \
+			CFG_VALUE_OR_DEFAULT, \
+			"It is bit mask value of Interfaces")
 
 /*
  * <ini>
- * Intf3MacAddress - Interface address
- * @Default: 000AF58989FC
+ * deriveded_intf_pool - It is bit mask value of Interfaces
+ * @Min: 0
+ * @Max: 0xffffffff
+ * @Default: 0xffffffff
  *
- * Related: None
+ * This ini will contain the bitmask of all the interfaces
+ * which can use addresses from derived list
  *
- * Supported Feature: N/A
+ *
+ * Supported Feature: STA/SAP/P2P
  *
  * Usage: External
  *
  * </ini>
  */
-#define __CFG_INTF3_MAC_ADDR_DEFAULT \
-	{.bytes = {0x00, 0x0a, 0xf5, 0x89, 0x89, 0xfc} }
-#define CFG_INTF3_MAC_ADDR CFG_INI_MAC( \
-	"Intf3MacAddress", \
-	__CFG_INTF3_MAC_ADDR_DEFAULT, \
-	"Interface 3 MAC Address")
+#define CFG_DERIVED_INTERFACE_POOL CFG_INI_UINT( \
+				"derived_intf_pool", \
+				0, \
+				0xffffffff, \
+				0xffffffff, \
+				CFG_VALUE_OR_DEFAULT, \
+				"It is bit mask value of Interfaces")
 
 /*
  * Start of action oui inis
@@ -1040,20 +1051,19 @@ enum hdd_wext_control {
 	CFG(CFG_ACTION_OUI_SWITCH_TO_11N_MODE) \
 	CFG(CFG_BUG_ON_REINIT_FAILURE) \
 	CFG(CFG_DBS_SCAN_SELECTION) \
+	CFG(CFG_DERIVED_INTERFACE_POOL) \
 	CFG(CFG_ENABLE_CONCURRENT_STA) \
 	CFG(CFG_ENABLE_ACTION_OUI) \
 	CFG(CFG_ENABLE_FW_LOG) \
 	CFG(CFG_ENABLE_FW_UART_PRINT) \
+	CFG(CFG_ENABLE_MAC_PROVISION) \
 	CFG(CFG_ENABLE_RAMDUMP_COLLECTION) \
 	CFG(CFG_INTERFACE_CHANGE_WAIT) \
 	CFG(CFG_INFORM_BSS_RSSI_RAW) \
-	CFG(CFG_INTF0_MAC_ADDR) \
-	CFG(CFG_INTF1_MAC_ADDR) \
-	CFG(CFG_INTF2_MAC_ADDR) \
-	CFG(CFG_INTF3_MAC_ADDR) \
 	CFG(CFG_MULTICAST_HOST_FW_MSGS) \
 	CFG(CFG_NUM_VDEV_ENABLE) \
 	CFG(CFG_OPERATING_CHANNEL) \
 	CFG(CFG_PRIVATE_WEXT_CONTROL) \
+	CFG(CFG_PROVISION_INTERFACE_POOL) \
 	CFG(CFG_TIMER_MULTIPLIER)
 #endif

+ 4 - 2
core/hdd/inc/wlan_hdd_cfg.h

@@ -3533,7 +3533,6 @@ struct hdd_config {
 	struct qdf_mac_addr IbssBssid;
 	uint32_t AdHocChannel5G;
 	uint32_t AdHocChannel24G;
-	uint8_t intfAddrMask;
 
 	bool apProtEnabled;
 	uint8_t nTxPowerCap;    /* In dBm */
@@ -3828,7 +3827,10 @@ struct hdd_config {
 	bool runtime_pm;
 #endif
 	uint8_t inform_bss_rssi_raw;
-	struct qdf_mac_addr intfMacAddr[QDF_MAX_CONCURRENCY_PERSONA];
+
+	bool mac_provision;
+	uint32_t provisioned_intf_pool;
+	uint32_t derived_intf_pool;
 };
 
 #define VAR_OFFSET(_Struct, _Var) (offsetof(_Struct, _Var))

+ 69 - 5
core/hdd/inc/wlan_hdd_main.h

@@ -1700,6 +1700,22 @@ struct hdd_psoc {
 	enum hdd_psoc_state state;
 };
 
+/**
+ * struct hdd_dynamic_mac - hdd structure to handle dynamic mac address changes
+ * @dynamic_mac: Dynamicaly configured mac, this contains the mac on which
+ * current interface is up
+ * @is_provisioned_mac: is this mac from provisioned list
+ * @bit_position: holds the bit mask position from where this mac is assigned,
+ * if mac is assigned from provisioned this field contains the position from
+ * provisioned_intf_addr_mask else contains the position from
+ * derived_intf_addr_mask
+ */
+struct hdd_dynamic_mac {
+	struct qdf_mac_addr dynamic_mac;
+	bool is_provisioned_mac;
+	uint8_t bit_position;
+};
+
 /**
  * struct hdd_context - hdd shared driver and psoc/device context
  * @hdd_psoc: hdd psoc context
@@ -1906,7 +1922,6 @@ struct hdd_context {
 	bool napi_enable;
 	bool stop_modules_in_progress;
 	bool start_modules_in_progress;
-	bool update_mac_addr_to_fw;
 	struct acs_dfs_policy acs_policy;
 	uint16_t wmi_max_len;
 	struct suspend_resume_stats suspend_resume_stats;
@@ -1977,9 +1992,16 @@ struct hdd_context {
 	qdf_mutex_t cache_channel_lock;
 #endif
 	enum sar_version sar_version;
-	struct qdf_mac_addr dynamic_mac_list[QDF_MAX_CONCURRENCY_PERSONA];
+	struct hdd_dynamic_mac dynamic_mac_list[QDF_MAX_CONCURRENCY_PERSONA];
 	bool dynamic_nss_chains_support;
 
+	struct qdf_mac_addr hw_macaddr;
+	struct qdf_mac_addr provisioned_mac_addr[QDF_MAX_CONCURRENCY_PERSONA];
+	struct qdf_mac_addr derived_mac_addr[QDF_MAX_CONCURRENCY_PERSONA];
+	uint32_t num_provisioned_addr;
+	uint32_t num_derived_addr;
+	unsigned long provisioned_intf_addr_mask;
+	unsigned long derived_intf_addr_mask;
 };
 
 /**
@@ -2198,7 +2220,20 @@ QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx,
 				enum hdd_adapter_stop_flag_t flag);
 
 void hdd_set_station_ops(struct net_device *dev);
-uint8_t *wlan_hdd_get_intf_addr(struct hdd_context *hdd_ctx);
+
+/**
+ * wlan_hdd_get_intf_addr() - Get address for the interface
+ * @hdd_ctx: Pointer to hdd context
+ * @interface_type: type of the interface for which address is queried
+ *
+ * This function is used to get mac address for every new interface
+ *
+ * Return: If addr is present then return pointer to MAC address
+ *         else NULL
+ */
+
+uint8_t *wlan_hdd_get_intf_addr(struct hdd_context *hdd_ctx,
+				enum QDF_OPMODE interface_type);
 void wlan_hdd_release_intf_addr(struct hdd_context *hdd_ctx,
 				uint8_t *releaseAddr);
 uint8_t hdd_get_operating_channel(struct hdd_context *hdd_ctx,
@@ -2614,8 +2649,37 @@ void hdd_ch_avoid_ind(struct hdd_context *hdd_ctxt,
 }
 #endif
 
-void hdd_update_macaddr(struct hdd_config *config,
-			struct qdf_mac_addr hw_macaddr);
+/**
+ * hdd_free_mac_address_lists() - Free both the MAC address lists
+ * @hdd_ctx: HDD context
+ *
+ * This API clears/memset provisioned address list and
+ * derived address list
+ *
+ */
+void hdd_free_mac_address_lists(struct hdd_context *hdd_ctx);
+
+/**
+ * hdd_update_macaddr() - update mac address
+ * @hdd_ctx:	hdd contxt
+ * @hw_macaddr:	mac address
+ * @generate_mac_auto: Indicates whether the first address is
+ * provisioned address or derived address.
+ *
+ * Mac address for multiple virtual interface is found as following
+ * i) The mac address of the first interface is just the actual hw mac address.
+ * ii) MSM 3 or 4 bits of byte5 of the actual mac address are used to
+ *     define the mac address for the remaining interfaces and locally
+ *     admistered bit is set. INTF_MACADDR_MASK is based on the number of
+ *     supported virtual interfaces, right now this is 0x07 (meaning 8
+ *     interface).
+ *     Byte[3] of second interface will be hw_macaddr[3](bit5..7) + 1,
+ *     for third interface it will be hw_macaddr[3](bit5..7) + 2, etc.
+ *
+ * Return: None
+ */
+void hdd_update_macaddr(struct hdd_context *hdd_ctx,
+			struct qdf_mac_addr hw_macaddr, bool generate_mac_auto);
 
 /**
  * wlan_hdd_disable_roaming() - disable roaming on all STAs except the input one

+ 12 - 5
core/hdd/src/wlan_hdd_cfg.c

@@ -1215,8 +1215,8 @@ static QDF_STATUS update_mac_from_string(struct hdd_context *hdd_ctx,
 				break;
 		}
 		if (res == 0 && !qdf_is_macaddr_zero(&macaddr[i])) {
-			qdf_mem_copy((uint8_t *) &hdd_ctx->config->
-				     intfMacAddr[i].bytes[0],
+			qdf_mem_copy((uint8_t *)&hdd_ctx->
+				     provisioned_mac_addr[i].bytes[0],
 				     (uint8_t *) &macaddr[i].bytes[0],
 				     QDF_MAC_ADDR_SIZE);
 		} else {
@@ -1802,13 +1802,20 @@ QDF_STATUS hdd_update_mac_config(struct hdd_context *hdd_ctx)
 		hdd_err("Invalid MAC addresses provided");
 		goto config_exit;
 	}
+	hdd_ctx->num_provisioned_addr = i;
 	hdd_debug("Populating remaining %d Mac addresses",
 		   max_mac_addr - i);
 	hdd_populate_random_mac_addr(hdd_ctx, max_mac_addr - i);
 
-	qdf_mem_copy(&customMacAddr,
-		     &hdd_ctx->config->intfMacAddr[0].bytes[0],
-		     sizeof(tSirMacAddr));
+	if (hdd_ctx->num_provisioned_addr)
+		qdf_mem_copy(&customMacAddr,
+			     &hdd_ctx->provisioned_mac_addr[0].bytes[0],
+			     sizeof(tSirMacAddr));
+	else
+		qdf_mem_copy(&customMacAddr,
+			     &hdd_ctx->derived_mac_addr[0].bytes[0],
+			     sizeof(tSirMacAddr));
+
 	sme_set_custom_mac_addr(customMacAddr);
 
 config_exit:

+ 339 - 142
core/hdd/src/wlan_hdd_main.c

@@ -1325,35 +1325,41 @@ static void hdd_runtime_suspend_context_deinit(struct hdd_context *hdd_ctx) {}
 
 #define INTF_MACADDR_MASK       0x7
 
-/**
- * hdd_update_macaddr() - update mac address
- * @config:	hdd configuration
- * @hw_macaddr:	mac address
- *
- * Mac address for multiple virtual interface is found as following
- * i) The mac address of the first interface is just the actual hw mac address.
- * ii) MSM 3 or 4 bits of byte5 of the actual mac address are used to
- *     define the mac address for the remaining interfaces and locally
- *     admistered bit is set. INTF_MACADDR_MASK is based on the number of
- *     supported virtual interfaces, right now this is 0x07 (meaning 8
- *     interface).
- *     Byte[3] of second interface will be hw_macaddr[3](bit5..7) + 1,
- *     for third interface it will be hw_macaddr[3](bit5..7) + 2, etc.
- *
- * Return: None
- */
-void hdd_update_macaddr(struct hdd_config *config,
-			struct qdf_mac_addr hw_macaddr)
+void hdd_update_macaddr(struct hdd_context *hdd_ctx,
+			struct qdf_mac_addr hw_macaddr, bool generate_mac_auto)
 {
 	int8_t i;
 	uint8_t macaddr_b3, tmp_br3;
 
-	qdf_mem_copy(config->intfMacAddr[0].bytes, hw_macaddr.bytes,
-		     QDF_MAC_ADDR_SIZE);
-	for (i = 1; i < QDF_MAX_CONCURRENCY_PERSONA; i++) {
-		qdf_mem_copy(config->intfMacAddr[i].bytes, hw_macaddr.bytes,
+	/*
+	 * If "generate_mac_auto" is true, it indicates that all the
+	 * addresses are derived addresses, else the first addresses
+	 * is not derived address (It is provided by fw).
+	 */
+	if (!generate_mac_auto) {
+		qdf_mem_copy(hdd_ctx->provisioned_mac_addr[0].bytes,
+			     hw_macaddr.bytes, QDF_MAC_ADDR_SIZE);
+		hdd_ctx->num_provisioned_addr++;
+		hdd_info("hdd_ctx->provisioned_mac_addr[0]: "
+			 MAC_ADDRESS_STR,
+			 MAC_ADDR_ARRAY(hdd_ctx->
+					provisioned_mac_addr[0].bytes));
+	} else {
+		qdf_mem_copy(hdd_ctx->derived_mac_addr[0].bytes,
+			     hw_macaddr.bytes,
+			     QDF_MAC_ADDR_SIZE);
+		hdd_ctx->num_derived_addr++;
+		hdd_info("hdd_ctx->derived_mac_addr[0]: "
+			 MAC_ADDRESS_STR,
+			 MAC_ADDR_ARRAY(hdd_ctx->derived_mac_addr[0].bytes));
+	}
+	for (i = hdd_ctx->num_derived_addr; i < (QDF_MAX_CONCURRENCY_PERSONA -
+						hdd_ctx->num_provisioned_addr);
+			i++) {
+		qdf_mem_copy(hdd_ctx->derived_mac_addr[i].bytes,
+			     hw_macaddr.bytes,
 			     QDF_MAC_ADDR_SIZE);
-		macaddr_b3 = config->intfMacAddr[i].bytes[3];
+		macaddr_b3 = hdd_ctx->derived_mac_addr[i].bytes[3];
 		tmp_br3 = ((macaddr_b3 >> 4 & INTF_MACADDR_MASK) + i) &
 			  INTF_MACADDR_MASK;
 		macaddr_b3 += tmp_br3;
@@ -1364,11 +1370,12 @@ void hdd_update_macaddr(struct hdd_config *config,
 		macaddr_b3 ^= (1 << 7);
 
 		/* Set locally administered bit */
-		config->intfMacAddr[i].bytes[0] |= 0x02;
-		config->intfMacAddr[i].bytes[3] = macaddr_b3;
-		hdd_debug("config->intfMacAddr[%d]: "
-		       MAC_ADDRESS_STR, i,
-		       MAC_ADDR_ARRAY(config->intfMacAddr[i].bytes));
+		hdd_ctx->derived_mac_addr[i].bytes[0] |= 0x02;
+		hdd_ctx->derived_mac_addr[i].bytes[3] = macaddr_b3;
+		hdd_info("hdd_ctx->derived_mac_addr[%d]: "
+			MAC_ADDRESS_STR, i,
+			MAC_ADDR_ARRAY(hdd_ctx->derived_mac_addr[i].bytes));
+		hdd_ctx->num_derived_addr++;
 	}
 }
 
@@ -1851,7 +1858,7 @@ static int hdd_generate_macaddr_auto(struct hdd_context *hdd_ctx)
 	mac_addr.bytes[4] = (serialno >> 8) & 0xff;
 	mac_addr.bytes[5] = serialno & 0xff;
 
-	hdd_update_macaddr(hdd_ctx->config, mac_addr);
+	hdd_update_macaddr(hdd_ctx, mac_addr, true);
 	return 0;
 }
 
@@ -2003,28 +2010,11 @@ void hdd_update_tgt_cfg(hdd_handle_t hdd_handle, struct wma_tgt_cfg *cfg)
 
 	/* This can be extended to other configurations like ht, vht cap... */
 
-	if (!qdf_is_macaddr_zero(&cfg->hw_macaddr)) {
-		hdd_update_macaddr(hdd_ctx->config, cfg->hw_macaddr);
-		hdd_ctx->update_mac_addr_to_fw = false;
-	} else {
-		static struct qdf_mac_addr default_mac_addr = {
-			{0x00, 0x0A, 0xF5, 0x89, 0x89, 0xFF}
-		};
-		if (qdf_is_macaddr_equal(&hdd_ctx->config->intfMacAddr[0],
-					 &default_mac_addr)) {
-			if (hdd_generate_macaddr_auto(hdd_ctx) != 0)
-				hdd_err("Fail to auto-generate MAC, using MAC from ini file "
-					MAC_ADDRESS_STR,
-					MAC_ADDR_ARRAY(hdd_ctx->config->
-						       intfMacAddr[0].bytes));
-		} else {
-			hdd_err("Invalid MAC passed from target, using MAC from ini file "
-				MAC_ADDRESS_STR,
-				MAC_ADDR_ARRAY(hdd_ctx->config->
-					       intfMacAddr[0].bytes));
-		}
-		hdd_ctx->update_mac_addr_to_fw = true;
-	}
+	if (!qdf_is_macaddr_zero(&cfg->hw_macaddr))
+		qdf_mem_copy(&hdd_ctx->hw_macaddr, &cfg->hw_macaddr,
+			     QDF_MAC_ADDR_SIZE);
+	else
+		hdd_info("hw_mac is zero");
 
 	hdd_ctx->target_fw_version = cfg->target_fw_version;
 	hdd_ctx->target_fw_vers_ext = cfg->target_fw_vers_ext;
@@ -3470,10 +3460,11 @@ void hdd_update_dynamic_mac(struct hdd_context *hdd_ctx,
 	hdd_enter();
 
 	for (i = 0; i < QDF_MAX_CONCURRENCY_PERSONA; i++) {
-		if (!qdf_mem_cmp(curr_mac_addr->bytes,
-				 &hdd_ctx->dynamic_mac_list[i].bytes[0],
+		if (!qdf_mem_cmp(
+			curr_mac_addr->bytes,
+			&hdd_ctx->dynamic_mac_list[i].dynamic_mac.bytes[0],
 				 sizeof(struct qdf_mac_addr))) {
-			qdf_mem_copy(&hdd_ctx->dynamic_mac_list[i],
+			qdf_mem_copy(&hdd_ctx->dynamic_mac_list[i].dynamic_mac,
 				     new_mac_addr->bytes,
 				     sizeof(struct qdf_mac_addr));
 			break;
@@ -3563,35 +3554,129 @@ static int hdd_set_mac_address(struct net_device *dev, void *addr)
 	return ret;
 }
 
-uint8_t *wlan_hdd_get_intf_addr(struct hdd_context *hdd_ctx)
+static uint8_t *wlan_hdd_get_derived_intf_addr(struct hdd_context *hdd_ctx)
 {
-	int i;
+	int i, j;
 
-	i = qdf_ffz(hdd_ctx->config->intfAddrMask);
-	if (i < 0 || i >= QDF_MAX_CONCURRENCY_PERSONA)
+	i = qdf_ffz(hdd_ctx->derived_intf_addr_mask);
+	if (i < 0 || i >= hdd_ctx->num_derived_addr)
+		return NULL;
+	qdf_atomic_set_bit(i, &hdd_ctx->derived_intf_addr_mask);
+	hdd_info("Assigning MAC from derived list" MAC_ADDRESS_STR,
+		 MAC_ADDR_ARRAY(hdd_ctx->derived_mac_addr[i].bytes));
+
+	/* Copy the mac in dynamic mac list at first free position */
+	for (j = 0; j < QDF_MAX_CONCURRENCY_PERSONA; j++) {
+		if (qdf_is_macaddr_zero(&hdd_ctx->
+					dynamic_mac_list[j].dynamic_mac))
+			break;
+	}
+	if (j == QDF_MAX_CONCURRENCY_PERSONA) {
+		hdd_err("Max interfaces are up");
 		return NULL;
+	}
+
+	qdf_mem_copy(&hdd_ctx->dynamic_mac_list[j].dynamic_mac.bytes,
+		     &hdd_ctx->derived_mac_addr[i].bytes,
+		     sizeof(struct qdf_mac_addr));
+	hdd_ctx->dynamic_mac_list[j].is_provisioned_mac = false;
+	hdd_ctx->dynamic_mac_list[j].bit_position = i;
+
+	return hdd_ctx->derived_mac_addr[i].bytes;
+}
+
+static uint8_t *wlan_hdd_get_provisioned_intf_addr(struct hdd_context *hdd_ctx)
+{
+	int i, j;
 
-	hdd_ctx->config->intfAddrMask |= (1 << i);
+	i = qdf_ffz(hdd_ctx->provisioned_intf_addr_mask);
+	if (i < 0 || i >= hdd_ctx->num_provisioned_addr)
+		return NULL;
+	qdf_atomic_set_bit(i, &hdd_ctx->provisioned_intf_addr_mask);
+	hdd_info("Assigning MAC from provisioned list" MAC_ADDRESS_STR,
+		 MAC_ADDR_ARRAY(hdd_ctx->provisioned_mac_addr[i].bytes));
+
+	/* Copy the mac in dynamic mac list at first free position */
+	for (j = 0; j < QDF_MAX_CONCURRENCY_PERSONA; j++) {
+		if (qdf_is_macaddr_zero(&hdd_ctx->
+					dynamic_mac_list[j].dynamic_mac))
+			break;
+	}
+	if (j == QDF_MAX_CONCURRENCY_PERSONA) {
+		hdd_err("Max interfaces are up");
+		return NULL;
+	}
 
-	qdf_mem_copy(&hdd_ctx->dynamic_mac_list[i].bytes,
-		     &hdd_ctx->config->intfMacAddr[i].bytes,
+	qdf_mem_copy(&hdd_ctx->dynamic_mac_list[j].dynamic_mac.bytes,
+		     &hdd_ctx->provisioned_mac_addr[i].bytes,
 		     sizeof(struct qdf_mac_addr));
-	return hdd_ctx->config->intfMacAddr[i].bytes;
+	hdd_ctx->dynamic_mac_list[j].is_provisioned_mac = true;
+	hdd_ctx->dynamic_mac_list[j].bit_position = i;
+	return hdd_ctx->provisioned_mac_addr[i].bytes;
+}
+
+uint8_t *wlan_hdd_get_intf_addr(struct hdd_context *hdd_ctx,
+				enum QDF_OPMODE interface_type)
+{
+	uint8_t *mac_addr = NULL;
+
+	if (qdf_atomic_test_bit(interface_type,
+				(unsigned long *)
+				(&hdd_ctx->config->provisioned_intf_pool)))
+		mac_addr = wlan_hdd_get_provisioned_intf_addr(hdd_ctx);
+
+	if ((!mac_addr) &&
+	    (qdf_atomic_test_bit(interface_type,
+				 (unsigned long *)
+				 (&hdd_ctx->config->derived_intf_pool))))
+		mac_addr = wlan_hdd_get_derived_intf_addr(hdd_ctx);
+
+	if (!mac_addr)
+		hdd_err("MAC is not available in both the lists");
+	return mac_addr;
 }
 
 void wlan_hdd_release_intf_addr(struct hdd_context *hdd_ctx,
 				uint8_t *releaseAddr)
 {
 	int i;
+	int mac_pos_in_mask;
 
 	for (i = 0; i < QDF_MAX_CONCURRENCY_PERSONA; i++) {
 		if (!memcmp(releaseAddr,
-			    hdd_ctx->dynamic_mac_list[i].bytes,
-			    QDF_MAC_ADDR_SIZE)) {
-			hdd_ctx->config->intfAddrMask &= ~(1 << i);
+		    hdd_ctx->dynamic_mac_list[i].dynamic_mac.bytes,
+		    QDF_MAC_ADDR_SIZE)) {
+			mac_pos_in_mask =
+				hdd_ctx->dynamic_mac_list[i].bit_position;
+			if (hdd_ctx->dynamic_mac_list[i].is_provisioned_mac) {
+				qdf_atomic_clear_bit(
+						mac_pos_in_mask,
+						&hdd_ctx->
+						   provisioned_intf_addr_mask);
+				hdd_info("Releasing MAC from provisioned list");
+				hdd_info(
+					MAC_ADDRESS_STR,
+					MAC_ADDR_ARRAY(releaseAddr));
+			} else {
+				qdf_atomic_clear_bit(
+						mac_pos_in_mask, &hdd_ctx->
+						derived_intf_addr_mask);
+				hdd_info("Releasing MAC from derived list");
+				hdd_info(MAC_ADDRESS_STR,
+					 MAC_ADDR_ARRAY(releaseAddr));
+			}
+			qdf_zero_macaddr(&hdd_ctx->
+					    dynamic_mac_list[i].dynamic_mac);
+			hdd_ctx->dynamic_mac_list[i].is_provisioned_mac =
+									false;
+			hdd_ctx->dynamic_mac_list[i].bit_position = 0;
 			break;
 		}
+
 	}
+	if (i == QDF_MAX_CONCURRENCY_PERSONA)
+		hdd_err("Releasing non existing MAC" MAC_ADDRESS_STR,
+			MAC_ADDR_ARRAY(releaseAddr));
 }
 
 /**
@@ -4984,6 +5069,36 @@ static void hdd_init_completion(struct hdd_adapter *adapter)
 	init_completion(&adapter->lfr_fw_status.disable_lfr_event);
 }
 
+static void hdd_reset_locally_admin_bit(struct hdd_context *hdd_ctx,
+					tSirMacAddr macAddr)
+{
+	int i;
+	/*
+	 * Reset locally administered bit for dynamic_mac_list
+	 * also as while releasing the MAC address for any
+	 * interface mac will be compared with dynamic mac list
+	 */
+	for (i = 0; i < QDF_MAX_CONCURRENCY_PERSONA; i++) {
+		if (!qdf_mem_cmp(
+			macAddr,
+			 &hdd_ctx->
+				dynamic_mac_list[i].dynamic_mac.bytes[0],
+				sizeof(struct qdf_mac_addr))) {
+			WLAN_HDD_RESET_LOCALLY_ADMINISTERED_BIT(
+				hdd_ctx->
+					dynamic_mac_list[i].dynamic_mac.bytes);
+			break;
+		}
+	}
+	/*
+	 * Reset locally administered bit if the device mode is
+	 * STA
+	 */
+	WLAN_HDD_RESET_LOCALLY_ADMINISTERED_BIT(macAddr);
+	hdd_debug("locally administered bit reset in sta mode: "
+		 MAC_ADDRESS_STR, MAC_ADDR_ARRAY(macAddr));
+}
+
 /**
  * hdd_open_adapter() - open and setup the hdd adatper
  * @hdd_ctx: global hdd context
@@ -5006,7 +5121,6 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio
 {
 	struct hdd_adapter *adapter = NULL;
 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
-	uint8_t i;
 
 	if (hdd_ctx->current_intf_count >= hdd_ctx->max_intf_count) {
 		/*
@@ -5035,26 +5149,9 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio
 
 	switch (session_type) {
 	case QDF_STA_MODE:
-		/*
-		 * Reset locally administered bit for dynamic_mac_list
-		 * also as while releasing the MAC address for any interface
-		 * mac will be compared with dynamic mac list
-		 */
-		for (i = 0; i < QDF_MAX_CONCURRENCY_PERSONA; i++) {
-			if (!qdf_mem_cmp(
-					macAddr,
-					&hdd_ctx->dynamic_mac_list[i].bytes[0],
-					sizeof(struct qdf_mac_addr))) {
-				WLAN_HDD_RESET_LOCALLY_ADMINISTERED_BIT(
-					hdd_ctx->dynamic_mac_list[i].bytes);
-				break;
-			}
-		}
+		if (!hdd_ctx->config->mac_provision)
+			hdd_reset_locally_admin_bit(hdd_ctx, macAddr);
 
-		/* Reset locally administered bit if the device mode is STA */
-		WLAN_HDD_RESET_LOCALLY_ADMINISTERED_BIT(macAddr);
-		hdd_debug("locally administered bit reset in sta mode: "
-			  MAC_ADDRESS_STR, MAC_ADDR_ARRAY(macAddr));
 	/* fall through */
 	case QDF_P2P_CLIENT_MODE:
 	case QDF_P2P_DEVICE_MODE:
@@ -9380,12 +9477,11 @@ static void hdd_cfg_params_init(struct hdd_context *hdd_ctx)
 		      cfg_get(psoc, CFG_DBS_SCAN_SELECTION),
 		      CFG_DBS_SCAN_PARAM_LENGTH);
 	config->inform_bss_rssi_raw = cfg_get(psoc, CFG_INFORM_BSS_RSSI_RAW);
-	config->intfMacAddr[0] = cfg_get(psoc, CFG_INTF0_MAC_ADDR);
-	config->intfMacAddr[1] = cfg_get(psoc, CFG_INTF1_MAC_ADDR);
-	config->intfMacAddr[2] = cfg_get(psoc, CFG_INTF2_MAC_ADDR);
-	config->intfMacAddr[3] = cfg_get(psoc, CFG_INTF3_MAC_ADDR);
+	config->mac_provision = cfg_get(psoc, CFG_ENABLE_MAC_PROVISION);
+	config->provisioned_intf_pool =
+				cfg_get(psoc, CFG_PROVISION_INTERFACE_POOL);
+	config->derived_intf_pool = cfg_get(psoc, CFG_DERIVED_INTERFACE_POOL);
 	config->action_oui_enable = cfg_get(psoc, CFG_ENABLE_ACTION_OUI);
-
 	qdf_str_lcopy(config->action_oui_str[0],
 		      cfg_get(psoc, CFG_ACTION_OUI_CONNECT_1X1),
 			      ACTION_OUI_MAX_STR_LEN);
@@ -9538,23 +9634,41 @@ static QDF_STATUS hdd_open_p2p_interface(struct hdd_context *hdd_ctx)
 {
 	struct hdd_adapter *adapter;
 	bool p2p_dev_addr_admin;
+	bool is_p2p_locally_administered = false;
 
 	cfg_p2p_get_device_addr_admin(hdd_ctx->psoc, &p2p_dev_addr_admin);
 
-	if (p2p_dev_addr_admin &&
-	    !(hdd_ctx->config->intfMacAddr[0].bytes[0] & 0x02)) {
-		hdd_ctx->p2p_device_address = hdd_ctx->config->intfMacAddr[0];
+	if (p2p_dev_addr_admin) {
+		if (hdd_ctx->num_provisioned_addr &&
+		    !(hdd_ctx->provisioned_mac_addr[0].bytes[0] & 0x02)) {
+			hdd_ctx->p2p_device_address =
+					hdd_ctx->provisioned_mac_addr[0];
 
-		/*
-		 * Generate the P2P Device Address. This consists of
-		 * the device's primary MAC address with the locally
-		 * administered bit set.
-		 */
-		hdd_ctx->p2p_device_address.bytes[0] |= 0x02;
-	} else {
+			/*
+			 * Generate the P2P Device Address.  This consists of
+			 * the device's primary MAC address with the locally
+			 * administered bit set.
+			 */
+
+			hdd_ctx->p2p_device_address.bytes[0] |= 0x02;
+			is_p2p_locally_administered = true;
+		} else if (!(hdd_ctx->derived_mac_addr[0].bytes[0] & 0x02)) {
+			hdd_ctx->p2p_device_address =
+						hdd_ctx->derived_mac_addr[0];
+			/*
+			 * Generate the P2P Device Address.  This consists of
+			 * the device's primary MAC address with the locally
+			 * administered bit set.
+			 */
+			hdd_ctx->p2p_device_address.bytes[0] |= 0x02;
+			is_p2p_locally_administered = true;
+		}
+	}
+	if (!is_p2p_locally_administered) {
 		uint8_t *p2p_dev_addr;
 
-		p2p_dev_addr = wlan_hdd_get_intf_addr(hdd_ctx);
+		p2p_dev_addr = wlan_hdd_get_intf_addr(hdd_ctx,
+						      QDF_P2P_DEVICE_MODE);
 		if (!p2p_dev_addr) {
 			hdd_err("Failed to get MAC address for new p2p device");
 			return QDF_STATUS_E_INVAL;
@@ -9586,7 +9700,8 @@ static QDF_STATUS hdd_open_ocb_interface(struct hdd_context *hdd_ctx)
 	struct hdd_adapter *adapter;
 
 	adapter = hdd_open_adapter(hdd_ctx, QDF_OCB_MODE, "wlanocb%d",
-				   wlan_hdd_get_intf_addr(hdd_ctx),
+				   wlan_hdd_get_intf_addr(hdd_ctx,
+							  QDF_OCB_MODE),
 				   NET_NAME_UNKNOWN, true);
 	if (!adapter) {
 		hdd_err("Failed to open 802.11p interface");
@@ -9605,7 +9720,8 @@ static QDF_STATUS hdd_open_concurrent_interface(struct hdd_context *hdd_ctx)
 
 	adapter = hdd_open_adapter(hdd_ctx, QDF_STA_MODE,
 				   hdd_ctx->config->enable_concurrent_sta,
-				   wlan_hdd_get_intf_addr(hdd_ctx),
+				   wlan_hdd_get_intf_addr(hdd_ctx,
+							  QDF_STA_MODE),
 				   NET_NAME_UNKNOWN, true);
 	if (!adapter) {
 		hdd_err("Failed to open concurrent station interface");
@@ -10166,6 +10282,19 @@ int hdd_pktlog_enable_disable(struct hdd_context *hdd_ctx, bool enable,
 }
 #endif /* REMOVE_PKT_LOG */
 
+void hdd_free_mac_address_lists(struct hdd_context *hdd_ctx)
+{
+	hdd_debug("Resetting MAC address lists");
+	qdf_mem_set(hdd_ctx->provisioned_mac_addr,
+		    sizeof(hdd_ctx->provisioned_mac_addr), 0);
+	qdf_mem_set(hdd_ctx->derived_mac_addr,
+		    sizeof(hdd_ctx->derived_mac_addr), 0);
+	hdd_ctx->num_provisioned_addr = 0;
+	hdd_ctx->num_derived_addr = 0;
+	hdd_ctx->provisioned_intf_addr_mask = 0;
+	hdd_ctx->derived_intf_addr_mask = 0;
+}
+
 /**
  * hdd_get_platform_wlan_mac_buff() - API to query platform driver
  *                                    for MAC address
@@ -10180,6 +10309,20 @@ static uint8_t *hdd_get_platform_wlan_mac_buff(struct device *dev,
 	return pld_get_wlan_mac_address(dev, num);
 }
 
+/**
+ * hdd_get_platform_wlan_derived_mac_buff() - API to query platform driver
+ *                                    for derived MAC address
+ * @dev: Device Pointer
+ * @num: Number of Valid Mac address
+ *
+ * Return: Pointer to MAC address buffer
+ */
+static uint8_t *hdd_get_platform_wlan_derived_mac_buff(struct device *dev,
+						       uint32_t *num)
+{
+	return pld_get_wlan_derived_mac_address(dev, num);
+}
+
 /**
  * hdd_populate_random_mac_addr() - API to populate random mac addresses
  * @hdd_ctx: HDD Context
@@ -10191,24 +10334,29 @@ static uint8_t *hdd_get_platform_wlan_mac_buff(struct device *dev,
  */
 void hdd_populate_random_mac_addr(struct hdd_context *hdd_ctx, uint32_t num)
 {
-	uint32_t start_idx = QDF_MAX_CONCURRENCY_PERSONA - num;
+	uint32_t idx = hdd_ctx->num_derived_addr;
 	uint32_t iter;
-	struct hdd_config *ini = hdd_ctx->config;
 	uint8_t *buf = NULL;
 	uint8_t macaddr_b3, tmp_br3;
-	uint8_t *src = ini->intfMacAddr[0].bytes;
+	/*
+	 * Consider first provisioned mac address as source address to derive
+	 * remaining addresses
+	 */
 
-	for (iter = start_idx; iter < QDF_MAX_CONCURRENCY_PERSONA; ++iter) {
-		buf = ini->intfMacAddr[iter].bytes;
+	uint8_t *src = hdd_ctx->provisioned_mac_addr[0].bytes;
+
+	for (iter = 0; iter < num; ++iter, ++idx) {
+		buf = hdd_ctx->derived_mac_addr[idx].bytes;
 		qdf_mem_copy(buf, src, QDF_MAC_ADDR_SIZE);
 		macaddr_b3 = buf[3];
-		tmp_br3 = ((macaddr_b3 >> 4 & INTF_MACADDR_MASK) + iter) &
+		tmp_br3 = ((macaddr_b3 >> 4 & INTF_MACADDR_MASK) + idx) &
 			INTF_MACADDR_MASK;
 		macaddr_b3 += tmp_br3;
 		macaddr_b3 ^= (1 << INTF_MACADDR_MASK);
 		buf[0] |= 0x02;
 		buf[3] = macaddr_b3;
 		hdd_debug(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(buf));
+		hdd_ctx->num_derived_addr++;
 	}
 }
 
@@ -10227,14 +10375,17 @@ static int hdd_platform_wlan_mac(struct hdd_context *hdd_ctx)
 	uint32_t mac_addr_size = QDF_MAC_ADDR_SIZE;
 	uint8_t *addr, *buf;
 	struct device *dev = hdd_ctx->parent_dev;
-	struct hdd_config *ini = hdd_ctx->config;
 	tSirMacAddr mac_addr;
 	QDF_STATUS status;
 
 	addr = hdd_get_platform_wlan_mac_buff(dev, &no_of_mac_addr);
 
-	if (no_of_mac_addr == 0 || !addr)
+	if (no_of_mac_addr == 0 || !addr) {
+		hdd_debug("No mac configured from platform driver");
 		return -EINVAL;
+	}
+
+	hdd_free_mac_address_lists(hdd_ctx);
 
 	if (no_of_mac_addr > max_mac_addr)
 		no_of_mac_addr = max_mac_addr;
@@ -10242,19 +10393,46 @@ static int hdd_platform_wlan_mac(struct hdd_context *hdd_ctx)
 	qdf_mem_copy(&mac_addr, addr, mac_addr_size);
 
 	for (iter = 0; iter < no_of_mac_addr; ++iter, addr += mac_addr_size) {
-		buf = ini->intfMacAddr[iter].bytes;
+		buf = hdd_ctx->provisioned_mac_addr[iter].bytes;
 		qdf_mem_copy(buf, addr, QDF_MAC_ADDR_SIZE);
-		hdd_debug(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(buf));
+		hdd_info("provisioned MAC Addr [%d]" MAC_ADDRESS_STR, iter,
+			 MAC_ADDR_ARRAY(buf));
 	}
 
-	status = sme_set_custom_mac_addr(mac_addr);
 
-	if (!QDF_IS_STATUS_SUCCESS(status))
-		return -EAGAIN;
+	hdd_ctx->num_provisioned_addr = no_of_mac_addr;
+
+	if (hdd_ctx->config->mac_provision) {
+		addr = hdd_get_platform_wlan_derived_mac_buff(dev,
+							      &no_of_mac_addr);
 
+		if (no_of_mac_addr == 0 || !addr)
+			hdd_warn("No derived address from platform driver");
+		else if (no_of_mac_addr >
+			 (max_mac_addr - hdd_ctx->num_provisioned_addr))
+			no_of_mac_addr = (max_mac_addr -
+					  hdd_ctx->num_provisioned_addr);
+
+		for (iter = 0; iter < no_of_mac_addr; ++iter,
+		     addr += mac_addr_size) {
+			buf = hdd_ctx->derived_mac_addr[iter].bytes;
+			qdf_mem_copy(buf, addr, QDF_MAC_ADDR_SIZE);
+			hdd_debug("derived MAC Addr [%d]" MAC_ADDRESS_STR, iter,
+				  MAC_ADDR_ARRAY(buf));
+		}
+		hdd_ctx->num_derived_addr = no_of_mac_addr;
+	}
+
+	no_of_mac_addr = hdd_ctx->num_provisioned_addr +
+					 hdd_ctx->num_derived_addr;
 	if (no_of_mac_addr < max_mac_addr)
 		hdd_populate_random_mac_addr(hdd_ctx, max_mac_addr -
 					     no_of_mac_addr);
+
+	status = sme_set_custom_mac_addr(mac_addr);
+	if (!QDF_IS_STATUS_SUCCESS(status))
+		return -EAGAIN;
+
 	return 0;
 }
 
@@ -10273,9 +10451,14 @@ static int hdd_update_mac_addr_to_fw(struct hdd_context *hdd_ctx)
 	tSirMacAddr customMacAddr;
 	QDF_STATUS status;
 
-	qdf_mem_copy(&customMacAddr,
-		     &hdd_ctx->config->intfMacAddr[0].bytes[0],
-		     sizeof(tSirMacAddr));
+	if (hdd_ctx->num_provisioned_addr)
+		qdf_mem_copy(&customMacAddr,
+			     &hdd_ctx->provisioned_mac_addr[0].bytes[0],
+			     sizeof(tSirMacAddr));
+	else
+		qdf_mem_copy(&customMacAddr,
+			     &hdd_ctx->derived_mac_addr[0].bytes[0],
+			     sizeof(tSirMacAddr));
 	status = sme_set_custom_mac_addr(customMacAddr);
 	if (!QDF_IS_STATUS_SUCCESS(status))
 		return -EAGAIN;
@@ -10292,30 +10475,50 @@ static int hdd_update_mac_addr_to_fw(struct hdd_context *hdd_ctx)
  *
  * Return: None
  */
-static void hdd_initialize_mac_address(struct hdd_context *hdd_ctx)
+static int hdd_initialize_mac_address(struct hdd_context *hdd_ctx)
 {
 	QDF_STATUS status;
 	int ret;
+	bool update_mac_addr_to_fw = true;
 
 	ret = hdd_platform_wlan_mac(hdd_ctx);
-	if (!ret) {
+	if (hdd_ctx->config->mac_provision || !ret) {
 		hdd_info("using MAC address from platform driver");
-		return;
+		return ret;
 	}
 
 	status = hdd_update_mac_config(hdd_ctx);
 	if (QDF_IS_STATUS_SUCCESS(status)) {
 		hdd_info("using MAC address from wlan_mac.bin");
-		return;
+		return 0;
 	}
 
 	hdd_info("using default MAC address");
 
-	if (hdd_ctx->update_mac_addr_to_fw) {
+	/* Use fw provided MAC */
+	if (!qdf_is_macaddr_zero(&hdd_ctx->hw_macaddr)) {
+		hdd_update_macaddr(hdd_ctx, hdd_ctx->hw_macaddr, false);
+		update_mac_addr_to_fw = false;
+		return 0;
+	} else if (hdd_generate_macaddr_auto(hdd_ctx) != 0) {
+		struct qdf_mac_addr mac_addr;
+
+		hdd_err("MAC failure from device serial no.");
+		cds_rand_get_bytes(0, (uint8_t *)(&mac_addr), sizeof(mac_addr));
+		/*
+		 * Reset multicast bit (bit-0) and set
+		 * locally-administered bit
+		 */
+		mac_addr.bytes[0] = 0x2;
+		hdd_update_macaddr(hdd_ctx, mac_addr, true);
+	}
+
+	if (update_mac_addr_to_fw) {
 		ret = hdd_update_mac_addr_to_fw(hdd_ctx);
 		if (ret)
 			hdd_err("MAC address out-of-sync, ret:%d", ret);
 	}
+	return ret;
 }
 
 static int hdd_set_smart_chainmask_enabled(struct hdd_context *hdd_ctx)
@@ -10477,19 +10680,6 @@ static int hdd_pre_enable_configure(struct hdd_context *hdd_ctx)
 		goto out;
 	}
 
-	/*
-	 * Set the MAC Address Currently this is used by HAL to add self sta.
-	 * Remove this once self sta is added as part of session open.
-	 */
-	status = sme_cfg_set_str(hdd_ctx->mac_handle, WNI_CFG_STA_ID,
-				 hdd_ctx->config->intfMacAddr[0].bytes,
-				 sizeof(hdd_ctx->config->intfMacAddr[0]));
-
-	if (QDF_IS_STATUS_ERROR(status)) {
-		hdd_err("Failed to set MAC Address, status %d", status);
-		ret = -EINVAL;
-		goto out;
-	}
 
 	hdd_init_channel_avoidance(hdd_ctx);
 
@@ -11590,7 +11780,8 @@ hdd_open_adapters_for_mission_mode(struct hdd_context *hdd_ctx)
 		return hdd_open_ocb_interface(hdd_ctx);
 
 	adapter = hdd_open_adapter(hdd_ctx, QDF_STA_MODE, "wlan%d",
-				   wlan_hdd_get_intf_addr(hdd_ctx),
+				   wlan_hdd_get_intf_addr(hdd_ctx,
+							  QDF_STA_MODE),
 				   NET_NAME_UNKNOWN, true);
 	if (!adapter)
 		return QDF_STATUS_E_INVAL;
@@ -11622,7 +11813,8 @@ static QDF_STATUS hdd_open_adapters_for_ftm_mode(struct hdd_context *hdd_ctx)
 	struct hdd_adapter *adapter;
 
 	adapter = hdd_open_adapter(hdd_ctx, QDF_FTM_MODE, "wlan%d",
-				   wlan_hdd_get_intf_addr(hdd_ctx),
+				   wlan_hdd_get_intf_addr(hdd_ctx,
+							  QDF_FTM_MODE),
 				   NET_NAME_UNKNOWN, true);
 
 	return adapter ? QDF_STATUS_SUCCESS : QDF_STATUS_E_INVAL;
@@ -11634,7 +11826,8 @@ hdd_open_adapters_for_monitor_mode(struct hdd_context *hdd_ctx)
 	struct hdd_adapter *adapter;
 
 	adapter = hdd_open_adapter(hdd_ctx, QDF_MONITOR_MODE, "wlan%d",
-				   wlan_hdd_get_intf_addr(hdd_ctx),
+				   wlan_hdd_get_intf_addr(hdd_ctx,
+							  QDF_MONITOR_MODE),
 				   NET_NAME_UNKNOWN, true);
 
 	return adapter ? QDF_STATUS_SUCCESS : QDF_STATUS_E_INVAL;
@@ -11742,7 +11935,11 @@ int hdd_wlan_startup(struct hdd_context *hdd_ctx)
 
 	hdd_dp_trace_init(hdd_ctx->config);
 
-	hdd_initialize_mac_address(hdd_ctx);
+	errno = hdd_initialize_mac_address(hdd_ctx);
+	if (errno) {
+		hdd_err("MAC initializtion failed: %d", errno);
+		goto unregister_wiphy;
+	}
 
 	errno = register_netdevice_notifier(&hdd_netdev_notifier);
 	if (errno) {

+ 24 - 5
core/hdd/src/wlan_hdd_nan_datapath.c

@@ -241,8 +241,10 @@ static int hdd_get_random_nan_mac_addr(struct hdd_context *hdd_ctx,
 	struct hdd_adapter *adapter;
 	uint8_t pos, bit_pos, byte_pos, mask;
 	uint8_t i, attempts, max_attempt = 16;
+	bool found;
 
 	for (attempts = 0; attempts < max_attempt; attempts++) {
+		found = false;
 		/* if NDI is present next addr is required to be 1 bit apart  */
 		adapter = hdd_get_adapter(hdd_ctx, QDF_NDI_MODE);
 		if (adapter) {
@@ -272,12 +274,29 @@ static int hdd_get_random_nan_mac_addr(struct hdd_context *hdd_ctx,
 			 */
 			mac_addr->bytes[5] &= 0xFE;
 		}
-		for (i = 0; i < QDF_MAX_CONCURRENCY_PERSONA; i++) {
-			if (!qdf_mem_cmp(hdd_ctx->config->intfMacAddr[i].bytes,
-					 mac_addr, sizeof(*mac_addr)))
-				continue;
+		for (i = 0; i < hdd_ctx->num_provisioned_addr; i++) {
+			if ((!qdf_mem_cmp(hdd_ctx->
+					  provisioned_mac_addr[i].bytes,
+			      mac_addr, sizeof(*mac_addr)))) {
+				found = true;
+				break;
+			}
 		}
 
+		if (found)
+			continue;
+
+		for (i = 0; i < hdd_ctx->num_derived_addr; i++) {
+			if ((!qdf_mem_cmp(hdd_ctx->
+					  derived_mac_addr[i].bytes,
+			      mac_addr, sizeof(*mac_addr)))) {
+				found = true;
+				break;
+			}
+		}
+		if (found)
+			continue;
+
 		adapter = hdd_get_adapter_by_macaddr(hdd_ctx, mac_addr->bytes);
 		if (!adapter)
 			return 0;
@@ -499,7 +518,7 @@ int hdd_ndi_open(char *iface_name)
 		}
 		ndi_mac_addr = &random_ndi_mac.bytes[0];
 	} else {
-		ndi_mac_addr = wlan_hdd_get_intf_addr(hdd_ctx);
+		ndi_mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_NDI_MODE);
 		if (!ndi_mac_addr) {
 			hdd_err("get intf address failed");
 			return -EFAULT;

+ 4 - 2
core/hdd/src/wlan_hdd_ocb.c

@@ -524,7 +524,8 @@ static int __iw_set_dot11p_channel_sched(struct net_device *dev,
 			qdf_copy_macaddr(&curr_chan->mac_address,
 				     &adapter->mac_addr);
 		} else {
-			mac_addr = wlan_hdd_get_intf_addr(hdd_ctx);
+			mac_addr = wlan_hdd_get_intf_addr(hdd_ctx,
+							  adapter->device_mode);
 			if (mac_addr == NULL) {
 				hdd_err("Cannot obtain mac address");
 				rc = -EINVAL;
@@ -869,7 +870,8 @@ static int __wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy,
 			qdf_copy_macaddr(&config->channels[i].mac_address,
 				&adapter->mac_addr);
 		} else {
-			mac_addr = wlan_hdd_get_intf_addr(hdd_ctx);
+			mac_addr = wlan_hdd_get_intf_addr(hdd_ctx,
+							  adapter->device_mode);
 			if (mac_addr == NULL) {
 				hdd_err("Cannot obtain mac address");
 				goto fail;

+ 2 - 1
core/hdd/src/wlan_hdd_p2p.c

@@ -687,7 +687,8 @@ struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy,
 					   name_assign_type, true);
 	} else {
 		adapter = hdd_open_adapter(hdd_ctx, mode, name,
-					   wlan_hdd_get_intf_addr(hdd_ctx),
+					   wlan_hdd_get_intf_addr(hdd_ctx,
+								  mode),
 					   name_assign_type, true);
 	}
 

+ 1 - 1
core/hdd/src/wlan_hdd_sap_cond_chan_switch.c

@@ -216,7 +216,7 @@ int wlan_hdd_request_pre_cac(uint8_t channel)
 		return -EINVAL;
 	}
 
-	mac_addr = wlan_hdd_get_intf_addr(hdd_ctx);
+	mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_SAP_MODE);
 	if (!mac_addr) {
 		hdd_err("can't add virtual intf: Not getting valid mac addr");
 		return -EINVAL;

+ 6 - 2
core/hdd/src/wlan_hdd_stats.c

@@ -4627,8 +4627,12 @@ static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
 	hdd_debug("%s: idx %d", __func__, idx);
 	if (idx != 0)
 		return -ENOENT;
-	qdf_mem_copy(mac, hdd_ctx->config->intfMacAddr[0].bytes,
-				QDF_MAC_ADDR_SIZE);
+	if (hdd_ctx->num_provisioned_addr)
+		qdf_mem_copy(mac, hdd_ctx->provisioned_mac_addr[0].bytes,
+			     QDF_MAC_ADDR_SIZE);
+	else
+		qdf_mem_copy(mac, hdd_ctx->derived_mac_addr[0].bytes,
+			     QDF_MAC_ADDR_SIZE);
 	return __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
 }
 

+ 26 - 0
core/pld/inc/pld_common.h

@@ -442,6 +442,24 @@ static inline uint8_t *pld_get_wlan_mac_address(struct device *dev,
 {
 	return cnss_utils_get_wlan_mac_address(dev, num);
 }
+
+/**
+ * pld_get_wlan_derived_mac_address() - API to query derived MAC address
+ * from platform Driver
+ * @dev: Device Structure
+ * @num: Pointer to number of MAC address supported
+ *
+ * Platform Driver can have MAC address stored. This API needs to be used
+ * to get those MAC address
+ *
+ * Return: Pointer to the list of MAC address
+ */
+static inline uint8_t *pld_get_wlan_derived_mac_address(struct device *dev,
+							uint32_t *num)
+{
+	return cnss_utils_get_wlan_derived_mac_address(dev, num);
+}
+
 /**
  * pld_increment_driver_load_cnt() - Maintain driver load count
  * @dev: device
@@ -496,6 +514,14 @@ static inline uint8_t *pld_get_wlan_mac_address(struct device *dev,
 	*num = 0;
 	return NULL;
 }
+
+static inline uint8_t *pld_get_wlan_derived_mac_address(struct device *dev,
+							uint32_t *num)
+{
+	*num = 0;
+	return NULL;
+}
+
 static inline void pld_increment_driver_load_cnt(struct device *dev) {}
 static inline int pld_get_driver_load_cnt(struct device *dev)
 {