Selaa lähdekoodia

qcacld-3.0: Release Interface MAC addresses gracefully

Currently if any interface comes up on any of the MAC address
from the driver's default MAC address list and if this MAC is
changed dynamically, now if this interface is deleted, it will
not be able to release this MAC address as this newly
configured MAC doesn't match with any of the MAC from the
driver's default MAC addresses and driver is not able to
release this MAC cosidering it as invalid MAC, because of
this corresponding MAC interface mask bit is also not getting
reset and will never get reset, indicating corresponding MAC
is not available for use. If MAC addresses are changed for all
the interfaces which initially comes up on driver's default
MAC address and later these interfaces are deleted, driver
will not be able to add any of new interfaces even there is
no active interface currently in the driver.

To resolve this issue add one more MAC address list for dynamic
addresses cache all the dynamic address changes in this list,
while releasing the MAC on interface delete, release the MAC
from this dynamic list and reset the corresponding interface
mask bit.

Change-Id: I9b6448dced2d3af75625a5c862d2913c33f9983c
CRs-Fixed: 2328304
Ashish Kumar Dhanotiya 6 vuotta sitten
vanhempi
sitoutus
6784b5042b

+ 17 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -1984,6 +1984,7 @@ struct hdd_context {
 	qdf_mutex_t cache_channel_lock;
 	qdf_mutex_t cache_channel_lock;
 #endif
 #endif
 	enum sar_version sar_version;
 	enum sar_version sar_version;
+	struct qdf_mac_addr dynamic_mac_list[QDF_MAX_CONCURRENCY_PERSONA];
 };
 };
 
 
 /**
 /**
@@ -3535,4 +3536,20 @@ struct hdd_context *hdd_handle_to_context(hdd_handle_t hdd_handle)
  */
  */
 void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx);
 void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx);
 
 
+/**
+ * hdd_update_dynamic_mac() - Updates the dynamic MAC list
+ * @hdd_ctx: Pointer to HDD context
+ * @curr_mac_addr: Current interface mac address
+ * @new_mac_addr: New mac address which needs to be updated
+ *
+ * This function updates newly configured MAC address to the
+ * dynamic MAC address list corresponding to the current
+ * adapter MAC address
+ *
+ * Return: None
+ */
+void hdd_update_dynamic_mac(struct hdd_context *hdd_ctx,
+			    struct qdf_mac_addr *curr_mac_addr,
+			    struct qdf_mac_addr *new_mac_addr);
+
 #endif /* end #if !defined(WLAN_HDD_MAIN_H) */
 #endif /* end #if !defined(WLAN_HDD_MAIN_H) */

+ 2 - 0
core/hdd/src/wlan_hdd_hostapd.c

@@ -693,6 +693,8 @@ static int __hdd_hostapd_set_mac_address(struct net_device *dev, void *addr)
 	hdd_info("Changing MAC to " MAC_ADDRESS_STR " of interface %s ",
 	hdd_info("Changing MAC to " MAC_ADDRESS_STR " of interface %s ",
 		 MAC_ADDR_ARRAY(mac_addr.bytes),
 		 MAC_ADDR_ARRAY(mac_addr.bytes),
 		 dev->name);
 		 dev->name);
+	hdd_update_dynamic_mac(hdd_ctx, &adapter->mac_addr, &mac_addr);
+	memcpy(&adapter->mac_addr, psta_mac_addr->sa_data, ETH_ALEN);
 	memcpy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN);
 	memcpy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN);
 	hdd_exit();
 	hdd_exit();
 	return 0;
 	return 0;

+ 44 - 1
core/hdd/src/wlan_hdd_main.c

@@ -3252,6 +3252,28 @@ static void hdd_close_cesium_nl_sock(void)
 	}
 	}
 }
 }
 
 
+void hdd_update_dynamic_mac(struct hdd_context *hdd_ctx,
+			    struct qdf_mac_addr *curr_mac_addr,
+			    struct qdf_mac_addr *new_mac_addr)
+{
+	uint8_t i;
+
+	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],
+				 sizeof(struct qdf_mac_addr))) {
+			qdf_mem_copy(&hdd_ctx->dynamic_mac_list[i],
+				     new_mac_addr->bytes,
+				     sizeof(struct qdf_mac_addr));
+			break;
+		}
+	}
+
+	hdd_exit();
+}
+
 /**
 /**
  * __hdd_set_mac_address() - set the user specified mac address
  * __hdd_set_mac_address() - set the user specified mac address
  * @dev:	Pointer to the net device.
  * @dev:	Pointer to the net device.
@@ -3302,6 +3324,7 @@ static int __hdd_set_mac_address(struct net_device *dev, void *addr)
 	hdd_info("Changing MAC to " MAC_ADDRESS_STR " of the interface %s ",
 	hdd_info("Changing MAC to " MAC_ADDRESS_STR " of the interface %s ",
 		 MAC_ADDR_ARRAY(mac_addr.bytes), dev->name);
 		 MAC_ADDR_ARRAY(mac_addr.bytes), dev->name);
 
 
+	hdd_update_dynamic_mac(hdd_ctx, &adapter->mac_addr, &mac_addr);
 	memcpy(&adapter->mac_addr, psta_mac_addr->sa_data, ETH_ALEN);
 	memcpy(&adapter->mac_addr, psta_mac_addr->sa_data, ETH_ALEN);
 	memcpy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN);
 	memcpy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN);
 
 
@@ -3341,6 +3364,9 @@ uint8_t *wlan_hdd_get_intf_addr(struct hdd_context *hdd_ctx)
 
 
 	hdd_ctx->config->intfAddrMask |= (1 << i);
 	hdd_ctx->config->intfAddrMask |= (1 << i);
 
 
+	qdf_mem_copy(&hdd_ctx->dynamic_mac_list[i].bytes,
+		     &hdd_ctx->config->intfMacAddr[i].bytes,
+		     sizeof(struct qdf_mac_addr));
 	return hdd_ctx->config->intfMacAddr[i].bytes;
 	return hdd_ctx->config->intfMacAddr[i].bytes;
 }
 }
 
 
@@ -3351,7 +3377,7 @@ void wlan_hdd_release_intf_addr(struct hdd_context *hdd_ctx,
 
 
 	for (i = 0; i < QDF_MAX_CONCURRENCY_PERSONA; i++) {
 	for (i = 0; i < QDF_MAX_CONCURRENCY_PERSONA; i++) {
 		if (!memcmp(releaseAddr,
 		if (!memcmp(releaseAddr,
-			    hdd_ctx->config->intfMacAddr[i].bytes,
+			    hdd_ctx->dynamic_mac_list[i].bytes,
 			    QDF_MAC_ADDR_SIZE)) {
 			    QDF_MAC_ADDR_SIZE)) {
 			hdd_ctx->config->intfAddrMask &= ~(1 << i);
 			hdd_ctx->config->intfAddrMask &= ~(1 << i);
 			break;
 			break;
@@ -4688,6 +4714,7 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio
 {
 {
 	struct hdd_adapter *adapter = NULL;
 	struct hdd_adapter *adapter = NULL;
 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	uint8_t i;
 
 
 	if (hdd_ctx->current_intf_count >= hdd_ctx->max_intf_count) {
 	if (hdd_ctx->current_intf_count >= hdd_ctx->max_intf_count) {
 		/*
 		/*
@@ -4716,6 +4743,22 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio
 
 
 	switch (session_type) {
 	switch (session_type) {
 	case QDF_STA_MODE:
 	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;
+			}
+		}
+
 		/* Reset locally administered bit if the device mode is STA */
 		/* Reset locally administered bit if the device mode is STA */
 		WLAN_HDD_RESET_LOCALLY_ADMINISTERED_BIT(macAddr);
 		WLAN_HDD_RESET_LOCALLY_ADMINISTERED_BIT(macAddr);
 		hdd_debug("locally administered bit reset in sta mode: "
 		hdd_debug("locally administered bit reset in sta mode: "