Browse Source

qcacld-3.0: Move to single netdev model

Enable the central logic to manage multiple VDEVs from a
single adapter and keep the code under the feature flag.

Enable WLAN_HDD_MULTI_VDEV_SINGLE_NDEV flag in build to
create single adapter which manages multiple VDEVs.
Keep the existing code which manages link adapters under
WLAN_HDD_MULTI_VDEV_SINGLE_NDEV flag undefined condition.

New number of active links field:
    -Introduce new member in adapter which stores number of links
     to create as part of VDEV create, this value to stay same
     throughout the lifetime of adapter which will be used to
     restore the number of links on adapter mode change.

     On mode change this value is used to set number of active
     links bitmap in adapter restrict access of link_info elements
     based on adapter type and mode.

     Currently only one STA adapter will have the value of two
     representing two VDEVs to be created for the purpose of
     two-link ML connection, remaining all adapters will have
     only one link enabled.

New MAC address field:
    -Introduce link_addr field in per link data structure which
     holds link address incase of ML adapter and remove mld_addr
     member in adapter structure, the mac_addr member in adapter
     will now hold the netdev address, incase of ML adapter that
     will be the MLD address.

     To get adapter from MAC address, also search each active
     link's link_addr member, the link address is filled in
     link_addr member during start adapter and as part of
     stop adapter, remove the derived link MAC address in
     each active link info to avoid conflict of new MAC address
     set on different adapter.

Change-Id: If78f75b78a6e42df9df18509aea7fe18e2aa77ff
CRs-Fixed: 3524362
Vinod Kumar Pirla 2 years ago
parent
commit
1e000aa4c4

+ 62 - 37
core/hdd/inc/wlan_hdd_main.h

@@ -1016,6 +1016,7 @@ enum udp_qos_upgrade {
  *                      sap_ctx would be freed.  During the SSR if the
  *                      same sap context is used it would result in
  *                      null pointer de-reference.
+ * @link_addr: Link MAC address
  * @session: union of @ap and @station specific structs
  * @session.station: station mode information
  * @session.ap: ap mode specific information
@@ -1039,6 +1040,9 @@ struct wlan_hdd_link_info {
 	qdf_spinlock_t vdev_lock;
 	struct wlan_objmgr_vdev *vdev;
 	struct completion vdev_destroy_event;
+#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
+	struct qdf_mac_addr link_addr;
+#endif
 
 	union {
 		struct hdd_station_ctx station;
@@ -1104,6 +1108,7 @@ struct wlan_hdd_tx_power {
  * @mld_addr: MLD address for adapter
  * @event_flags: a bitmap of hdd_adapter_flags
  * @active_links: a bitmap of active links in @link_info array
+ * @num_links_on_create: No of active links set on initial hdd_open_adapter().
  * @is_ll_stats_req_pending: atomic variable to check active stats req
  * @sta_stats_cached_timestamp: last updated stats timestamp
  * @qdf_monitor_mode_vdev_up_event: QDF event for monitor mode vdev up
@@ -1226,9 +1231,12 @@ struct hdd_adapter {
 	uint32_t ctw;
 
 	struct qdf_mac_addr mac_addr;
+#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
 	struct qdf_mac_addr mld_addr;
+#endif
 	unsigned long event_flags;
 	unsigned long active_links;
+	uint8_t num_links_on_create;
 
 	qdf_atomic_t is_ll_stats_req_pending;
 
@@ -3900,6 +3908,49 @@ QDF_STATUS hdd_sme_close_session_callback(uint8_t vdev_id);
 int hdd_register_cb(struct hdd_context *hdd_ctx);
 void hdd_deregister_cb(struct hdd_context *hdd_ctx);
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \
+	defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
+/**
+ * hdd_adapter_fill_link_address() - Fill derived
+ * link address in adapter
+ * @adapter: HDD adapter
+ *
+ * The API takes MLD address of @adapter and calls link address
+ * derive API and fills the derived link address in each link.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hdd_adapter_fill_link_address(struct hdd_adapter *adapter);
+#else
+static inline
+QDF_STATUS hdd_adapter_fill_link_address(struct hdd_adapter *adapter)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * hdd_adapter_get_mac_address() - Returns the appropriate MAC address pointer
+ * in adapter.
+ * @link_info: Link info in HDD adapter.
+ *
+ * If WLAN_HDD_MULTI_VDEV_SINGLE_NDEV flag is enabled, then MAC address pointer
+ * returned is based on following conditions:
+ *      -if adapter of link info is non-ml:
+ *              Return pointer of mac_addr in adapter.
+ *      -else if link_addr in @link_info is NULL:
+ *              Return pointer of mac_addr in adapter.
+ *      -else
+ *              Return pointer of link_addr in @link_info.
+ *
+ * If WLAN_HDD_MULTI_VDEV_SINGLE_NDEV flag is not enabled, then return pointer
+ * of mac_addr in adapter.
+ *
+ * Return: MAC address pointer based on adapter type.
+ */
+struct qdf_mac_addr *
+hdd_adapter_get_mac_address(struct wlan_hdd_link_info *link_info);
+
 /**
  * hdd_adapter_check_duplicate_session() - Check for duplicate
  * session on start adapter.
@@ -4505,7 +4556,8 @@ int wlan_hdd_set_mon_chan(struct hdd_adapter *adapter, qdf_freq_t freq,
 }
 #endif
 
-#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \
+	!defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
 /**
  *  hdd_set_mld_address() - Set the MLD address of the adapter
  *  @adapter: Handle to adapter
@@ -4883,35 +4935,6 @@ hdd_monitor_mode_qdf_create_event(struct hdd_adapter *adapter,
 }
 #endif
 
-static inline bool hdd_is_mac_addr_same(uint8_t *addr1, uint8_t *addr2)
-{
-	return !qdf_mem_cmp(addr1, addr2, QDF_MAC_ADDR_SIZE);
-}
-
-#ifdef WLAN_FEATURE_11BE_MLO
-static inline bool hdd_nbuf_dst_addr_is_mld_addr(struct hdd_adapter *adapter,
-						 struct sk_buff *nbuf)
-{
-	return hdd_is_mac_addr_same(adapter->mld_addr.bytes,
-				    qdf_nbuf_data(nbuf) +
-				    QDF_NBUF_DEST_MAC_OFFSET);
-}
-#else
-static inline bool hdd_nbuf_dst_addr_is_mld_addr(struct hdd_adapter *adapter,
-						 struct sk_buff *nbuf)
-{
-	return false;
-}
-#endif
-
-static inline bool hdd_nbuf_dst_addr_is_self_addr(struct hdd_adapter *adapter,
-						  struct sk_buff *nbuf)
-{
-	return hdd_is_mac_addr_same(adapter->mac_addr.bytes,
-				    qdf_nbuf_data(nbuf) +
-				    QDF_NBUF_DEST_MAC_OFFSET);
-}
-
 /**
  * hdd_cleanup_conn_info() - Cleanup connectin info
  * @link_info: pointer to link_info struct in adapter
@@ -5102,7 +5125,7 @@ void hdd_check_for_net_dev_ref_leak(struct hdd_adapter *adapter);
 /**
  * hdd_dynamic_mac_address_set(): API to set MAC address, when interface
  *                                is up.
- * @adapter: Pointer to hdd_adapter
+ * @link_info: Link info pointer in HDD adapter
  * @mac_addr: MAC address to set
  * @mld_addr: MLD address to set
  * @update_self_peer: Set to true to update self peer's address
@@ -5111,7 +5134,7 @@ void hdd_check_for_net_dev_ref_leak(struct hdd_adapter *adapter);
  *
  * Return: 0 for success. non zero valure for failure.
  */
-int hdd_dynamic_mac_address_set(struct hdd_adapter *adapter,
+int hdd_dynamic_mac_address_set(struct wlan_hdd_link_info *link_info,
 				struct qdf_mac_addr mac_addr,
 				struct qdf_mac_addr mld_addr,
 				bool update_self_peer);
@@ -5143,7 +5166,8 @@ static inline int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
 {
 	struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT;
 
-	return hdd_dynamic_mac_address_set(adapter, mac_addr, mld_addr, true);
+	return hdd_dynamic_mac_address_set(adapter->deflink, mac_addr,
+					   mld_addr, true);
 }
 #endif /* WLAN_FEATURE_11BE_MLO */
 #else
@@ -5153,10 +5177,11 @@ static inline int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
 	return 0;
 }
 
-static inline int hdd_dynamic_mac_address_set(struct hdd_adapter *adapter,
-					      struct qdf_mac_addr mac_addr,
-					      struct qdf_mac_addr mld_addr,
-					      bool update_self_peer)
+static inline int
+hdd_dynamic_mac_address_set(struct wlan_hdd_link_info *link_info,
+			    struct qdf_mac_addr mac_addr,
+			    struct qdf_mac_addr mld_addr,
+			    bool update_self_peer)
 {
 	return 0;
 }

+ 88 - 65
core/hdd/inc/wlan_hdd_mlo.h

@@ -34,6 +34,7 @@
  * @is_ml_adapter: is a ml adapter with associated netdev
  * @is_add_virtual_iface: is netdev create request from add virtual interface
  * @is_single_link: Is the adapter single link ML
+ * @num_sessions: No of session to create on start adapter
  * @unused: Reserved spare bits
  */
 struct hdd_adapter_create_param {
@@ -42,7 +43,8 @@ struct hdd_adapter_create_param {
 		 is_ml_adapter:1,
 		 is_add_virtual_iface:1,
 		 is_single_link:1,
-		 unused:27;
+		 num_sessions:4,
+		 unused:23;
 };
 
 #ifdef WLAN_FEATURE_11BE_MLO
@@ -51,14 +53,8 @@ struct hdd_adapter_create_param {
 #endif
 
 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
-#define hdd_adapter_is_link_adapter(x) ((x)->mlo_adapter_info.is_link_adapter)
 #define hdd_adapter_is_ml_adapter(x)   ((x)->mlo_adapter_info.is_ml_adapter)
-#define hdd_adapter_is_sl_ml_adapter(x) \
-			   ((x)->mlo_adapter_info.is_single_link_ml)
-#define hdd_adapter_is_associated_with_ml_adapter(x) \
-			   ((x)->mlo_adapter_info.associate_with_ml_adapter)
-#define hdd_adapter_get_mlo_adapter_from_link(x) \
-			   ((x)->mlo_adapter_info.ml_adapter)
+
 /* MLO_STATE_COMMANDS */
 #define FEATURE_ML_LINK_STATE_COMMANDS					\
 	{								\
@@ -71,16 +67,32 @@ struct hdd_adapter_create_param {
 		vendor_command_policy(ml_link_state_request_policy,	\
 				QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX)	\
 	},
+
+#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
+#define hdd_adapter_is_link_adapter(x) ((x)->mlo_adapter_info.is_link_adapter)
+#define hdd_adapter_is_sl_ml_adapter(x) \
+			   ((x)->mlo_adapter_info.is_single_link_ml)
+#define hdd_adapter_is_associated_with_ml_adapter(x) \
+			   ((x)->mlo_adapter_info.associate_with_ml_adapter)
+#define hdd_adapter_get_mlo_adapter_from_link(x) \
+			   ((x)->mlo_adapter_info.ml_adapter)
+
+#else
+#define hdd_adapter_is_link_adapter(x) (0)
+#define hdd_adapter_is_sl_ml_adapter(x) (0)
+#define hdd_adapter_is_associated_with_ml_adapter(x) (0)
+#define hdd_adapter_get_mlo_adapter_from_link(x) (NULL)
+#endif /* WLAN_HDD_MULTI_VDEV_SINGLE_NDEV */
 #else
 #define hdd_adapter_is_link_adapter(x) (0)
 #define hdd_adapter_is_ml_adapter(x)   (0)
 #define hdd_adapter_is_sl_ml_adapter(x) (0)
 #define hdd_adapter_is_associated_with_ml_adapter(x) (0)
 #define hdd_adapter_get_mlo_adapter_from_link(x) (NULL)
-#endif
+#endif /* WLAN_FEATURE_11BE_MLO && CFG80211_11BE_BASIC */
 
 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
-
+#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
 /**
  * struct hdd_mlo_adapter_info - Mlo specific adapter information
  * @is_ml_adapter: Whether this is the main ml adaper attached to netdev
@@ -103,7 +115,16 @@ struct hdd_mlo_adapter_info {
 	struct hdd_adapter *ml_adapter;
 	struct hdd_adapter *link_adapter[WLAN_MAX_MLD];
 };
+#else
+struct hdd_mlo_adapter_info {
+	uint32_t is_ml_adapter:1,
+		 unused:31;
+};
+#endif
+#endif
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \
+	!defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
 /**
  * hdd_register_wdev() - Function to register only wdev
  * @sta_adapter : Station adapter linked with netdevice
@@ -127,7 +148,6 @@ void hdd_register_wdev(struct hdd_adapter *sta_adapter,
  */
 QDF_STATUS hdd_wlan_unregister_mlo_interfaces(struct hdd_adapter *adapter,
 					      bool rtnl_held);
-
 /**
  * hdd_wlan_register_mlo_interfaces() - Function to register mlo wdev interfaces
  * @hdd_ctx: hdd context
@@ -138,13 +158,16 @@ QDF_STATUS hdd_wlan_unregister_mlo_interfaces(struct hdd_adapter *adapter,
 void hdd_wlan_register_mlo_interfaces(struct hdd_context *hdd_ctx);
 
 /**
- * hdd_adapter_set_ml_adapter() - set adapter as ml adapter
- * @adapter: HDD adapter
+ * hdd_get_assoc_link_adapter() - get assoc link adapter
+ * @ml_adapter: ML adapter
  *
- * This function sets adapter as ml adapter
- * Return: None
+ * This function returns assoc link adapter.
+ * For single link ML adapter, function returns
+ * same adapter pointer.
+ *
+ * Return: adapter or NULL
  */
-void hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter);
+struct hdd_adapter *hdd_get_assoc_link_adapter(struct hdd_adapter *ml_adapter);
 
 /**
  * hdd_adapter_set_sl_ml_adapter() - Set adapter as sl ml adapter
@@ -173,17 +196,58 @@ void hdd_adapter_clear_sl_ml_adapter(struct hdd_adapter *adapter);
  */
 struct hdd_adapter *hdd_get_ml_adapter(struct hdd_context *hdd_ctx);
 
+#else
+static inline
+QDF_STATUS hdd_wlan_unregister_mlo_interfaces(struct hdd_adapter *adapter,
+					      bool rtnl_held)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline
+void hdd_wlan_register_mlo_interfaces(struct hdd_context *hdd_ctx)
+{
+}
+
+static inline
+void hdd_register_wdev(struct hdd_adapter *sta_adapter,
+		       struct hdd_adapter *link_adapter,
+		       struct hdd_adapter_create_param *adapter_params)
+{
+}
+
+static inline
+struct hdd_adapter *hdd_get_assoc_link_adapter(struct hdd_adapter *ml_adapter)
+{
+	return NULL;
+}
+
+static inline void
+hdd_adapter_set_sl_ml_adapter(struct hdd_adapter *adapter)
+{
+}
+
+static inline void
+hdd_adapter_clear_sl_ml_adapter(struct hdd_adapter *adapter)
+{
+}
+
+static inline
+struct hdd_adapter *hdd_get_ml_adapter(struct hdd_context *hdd_ctx)
+{
+	return NULL;
+}
+#endif
+
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
 /**
- * hdd_get_assoc_link_adapter() - get assoc link adapter
- * @ml_adapter: ML adapter
- *
- * This function returns assoc link adapter.
- * For single link ML adapter, function returns
- * same adapter pointer.
+ * hdd_adapter_set_ml_adapter() - set adapter as ml adapter
+ * @adapter: HDD adapter
  *
- * Return: adapter or NULL
+ * This function sets adapter as ml adapter
+ * Return: None
  */
-struct hdd_adapter *hdd_get_assoc_link_adapter(struct hdd_adapter *ml_adapter);
+void hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter);
 
 /**
  * hdd_mlo_t2lm_register_callback() - Register T2LM callback
@@ -264,52 +328,11 @@ QDF_STATUS hdd_derive_link_address_from_mld(struct qdf_mac_addr *mld_addr,
 					    struct qdf_mac_addr *link_addr_list,
 					    uint8_t max_idx);
 #else
-static inline
-QDF_STATUS hdd_wlan_unregister_mlo_interfaces(struct hdd_adapter *adapter,
-					      bool rtnl_held)
-{
-	return QDF_STATUS_SUCCESS;
-}
-
-static inline
-void hdd_register_wdev(struct hdd_adapter *sta_adapter,
-		       struct hdd_adapter *link_adapter,
-		       struct hdd_adapter_create_param *adapter_params)
-{
-}
-
-static inline
-void hdd_wlan_register_mlo_interfaces(struct hdd_context *hdd_ctx)
-{
-}
-
 static inline void
 hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter)
 {
 }
 
-static inline void
-hdd_adapter_set_sl_ml_adapter(struct hdd_adapter *adapter)
-{
-}
-
-static inline void
-hdd_adapter_clear_sl_ml_adapter(struct hdd_adapter *adapter)
-{
-}
-
-static inline
-struct hdd_adapter *hdd_get_ml_adapter(struct hdd_context *hdd_ctx)
-{
-	return NULL;
-}
-
-static inline
-struct hdd_adapter *hdd_get_assoc_link_adapter(struct hdd_adapter *ml_adapter)
-{
-	return NULL;
-}
-
 static inline
 void hdd_mlo_t2lm_register_callback(struct wlan_objmgr_vdev *vdev)
 {

+ 2 - 2
core/hdd/inc/wlan_hdd_power.h

@@ -524,13 +524,13 @@ void hdd_wlan_suspend_resume_event(uint8_t state) {}
 
 /**
  * wlan_hdd_set_powersave() - Set powersave mode
- * @adapter: adapter upon which the request was received
+ * @link_info: Link inof pointer in HDD adapter
  * @allow_power_save: is wlan allowed to go into power save mode
  * @timeout: timeout period in ms
  *
  * Return: 0 on success, non-zero on any error
  */
-int wlan_hdd_set_powersave(struct hdd_adapter *adapter,
+int wlan_hdd_set_powersave(struct wlan_hdd_link_info *link_info,
 			   bool allow_power_save, uint32_t timeout);
 
 /**

+ 1 - 9
core/hdd/src/wlan_hdd_assoc.c

@@ -1426,15 +1426,7 @@ QDF_STATUS hdd_roam_register_sta(struct wlan_hdd_link_info *link_info,
 	if (!vdev)
 		return QDF_STATUS_E_INVAL;
 
-	/* TODO, right now only one interface is registered with DP
-	 * so for second vdev not doing the register ops as it will
-	 * point to the same again.
-	 */
-	if (ucfg_dp_get_intf_id(vdev) == wlan_vdev_get_id(vdev))
-		qdf_status = ucfg_dp_sta_register_txrx_ops(vdev);
-	else
-		qdf_status = QDF_STATUS_SUCCESS;
-
+	qdf_status = ucfg_dp_sta_register_txrx_ops(vdev);
 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
 		hdd_err("DP tx/rx ops register failed Status: %d", qdf_status);

+ 6 - 1
core/hdd/src/wlan_hdd_cfg80211.c

@@ -21376,7 +21376,8 @@ static bool hdd_is_ap_mode(enum QDF_OPMODE mode)
 	}
 }
 
-#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \
+	!defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
 static QDF_STATUS
 hdd_adapter_update_mac_on_mode_change(struct hdd_adapter *adapter)
 {
@@ -21577,6 +21578,7 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy,
 		switch (adapter->device_mode) {
 		case QDF_SAP_MODE:
 			hdd_adapter_set_sl_ml_adapter(adapter);
+			adapter->active_links = 0x1;
 			break;
 		case QDF_STA_MODE:
 			hdd_adapter_clear_sl_ml_adapter(adapter);
@@ -21585,9 +21587,12 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy,
 			if (QDF_IS_STATUS_ERROR(status))
 				goto err;
 
+			adapter->active_links =
+					(1 << adapter->num_links_on_create) - 1;
 			break;
 		default:
 			hdd_adapter_clear_sl_ml_adapter(adapter);
+			adapter->active_links = 0x1;
 			break;
 		}
 	}

+ 18 - 3
core/hdd/src/wlan_hdd_cm_connect.c

@@ -1203,8 +1203,7 @@ static void hdd_cm_save_connect_info(struct wlan_hdd_link_info *link_info,
 	qdf_copy_macaddr(&sta_ctx->conn_info.bssid, &rsp->bssid);
 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID);
 	if (vdev) {
-		if (ucfg_dp_get_intf_id(vdev) == rsp->vdev_id)
-			ucfg_dp_conn_info_set_bssid(vdev, &rsp->bssid);
+		ucfg_dp_conn_info_set_bssid(vdev, &rsp->bssid);
 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
 	}
 
@@ -1333,6 +1332,7 @@ static bool hdd_cm_is_roam_auth_required(struct hdd_station_ctx *sta_ctx,
 #endif
 
 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
+#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
 struct hdd_adapter *hdd_get_assoc_link_adapter(struct hdd_adapter *ml_adapter)
 {
 	int i;
@@ -1355,7 +1355,22 @@ struct hdd_adapter *hdd_get_assoc_link_adapter(struct hdd_adapter *ml_adapter)
 
 	return NULL;
 }
+#endif
+
+#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
+static void hdd_set_immediate_power_save(struct hdd_adapter *adapter,
+					 bool is_immediate_powersave)
+{
+	struct hdd_station_ctx *sta_ctx;
+	struct wlan_hdd_link_info *link_info;
 
+	hdd_adapter_for_each_active_link_info(adapter, link_info) {
+		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
+		sta_ctx->ap_supports_immediate_power_save =
+						is_immediate_powersave;
+	}
+}
+#else
 static void hdd_set_immediate_power_save(struct hdd_adapter *adapter,
 					 bool is_immediate_powersave)
 {
@@ -1382,7 +1397,7 @@ update_non_ml:
 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
 	sta_ctx->ap_supports_immediate_power_save = is_immediate_powersave;
 }
-
+#endif
 #else
 static void hdd_set_immediate_power_save(struct hdd_adapter *adapter,
 					 bool is_immediate_powersave)

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

@@ -796,8 +796,8 @@ static int __hdd_hostapd_set_mac_address(struct net_device *dev, void *addr)
 		else
 			qdf_zero_macaddr(&mld_addr);
 
-		ret = hdd_dynamic_mac_address_set(adapter, mac_addr, mld_addr,
-						  false);
+		ret = hdd_dynamic_mac_address_set(adapter->deflink, mac_addr,
+						  mld_addr, false);
 		if (ret)
 			return ret;
 	}

+ 275 - 39
core/hdd/src/wlan_hdd_main.c

@@ -2599,7 +2599,7 @@ static void hdd_lpc_enable_powersave(struct hdd_context *hdd_ctx)
 	}
 
 	if (sta_adapter->deflink->vdev_id < WLAN_UMAC_VDEV_ID_MAX)
-		wlan_hdd_set_powersave(sta_adapter, true, 0);
+		wlan_hdd_set_powersave(sta_adapter->deflink, true, 0);
 }
 
 static void hdd_lpc_disable_powersave(struct hdd_context *hdd_ctx)
@@ -2616,7 +2616,7 @@ static void hdd_lpc_disable_powersave(struct hdd_context *hdd_ctx)
 		hdd_err("STA adapter does not exist");
 		return;
 	}
-	wlan_hdd_set_powersave(sta_adapter, false, 0);
+	wlan_hdd_set_powersave(sta_adapter->deflink, false, 0);
 }
 #else
 static inline void hdd_lpc_enable_powersave(struct hdd_context *hdd_ctx)
@@ -3446,7 +3446,8 @@ static bool hdd_max_sta_interface_up_count_reached(struct hdd_adapter *adapter)
 
 #if (defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)) && \
 (defined(CFG80211_IFTYPE_MLO_LINK_SUPPORT) || \
-defined(CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT))
+defined(CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT)) && \
+!defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
 static int hdd_start_link_adapter(struct hdd_adapter *sta_adapter)
 {
 	int i, ret = 0;
@@ -5516,10 +5517,10 @@ void hdd_update_dynamic_mac(struct hdd_context *hdd_ctx,
 	hdd_exit();
 }
 
-#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
-void
-hdd_set_mld_address(struct hdd_adapter *adapter,
-		    const struct qdf_mac_addr *mac_addr)
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \
+	!defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
+void hdd_set_mld_address(struct hdd_adapter *adapter,
+			 const struct qdf_mac_addr *mac_addr)
 {
 	int i;
 	bool eht_capab;
@@ -5600,7 +5601,8 @@ hdd_get_netdev_by_vdev_mac(struct qdf_mac_addr *mac_addr)
 #endif
 
 #ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE
-#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \
+	!defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
 static void hdd_update_set_mac_addr_req_ctx(struct hdd_adapter *adapter,
 					    void *req_ctx)
 {
@@ -5666,7 +5668,7 @@ bool hdd_is_dynamic_set_mac_addr_allowed(struct hdd_adapter *adapter)
 	}
 }
 
-int hdd_dynamic_mac_address_set(struct hdd_adapter *adapter,
+int hdd_dynamic_mac_address_set(struct wlan_hdd_link_info *link_info,
 				struct qdf_mac_addr mac_addr,
 				struct qdf_mac_addr mld_addr,
 				bool update_self_peer)
@@ -5678,13 +5680,14 @@ int hdd_dynamic_mac_address_set(struct hdd_adapter *adapter,
 	QDF_STATUS status;
 	struct osif_request *request;
 	struct wlan_objmgr_vdev *vdev;
+	struct hdd_adapter *adapter = link_info->adapter;
 	struct hdd_context *hdd_ctx = adapter->hdd_ctx;
 	static const struct osif_request_params params = {
 		.priv_size = sizeof(*fw_resp_status),
 		.timeout_ms = WLAN_SET_MAC_ADDR_TIMEOUT
 	};
 
-	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID);
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
 	if (!vdev)
 		return -EINVAL;
 
@@ -7161,11 +7164,33 @@ hdd_vdev_configure_opmode_params(struct hdd_context *hdd_ctx,
 	hdd_store_nss_chains_cfg_in_vdev(hdd_ctx, vdev);
 }
 
-#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \
+	defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
+static void
+hdd_populate_vdev_create_params(struct wlan_hdd_link_info *link_info,
+				struct wlan_vdev_create_params *vdev_params)
+{
+	struct hdd_adapter *adapter = link_info->adapter;
+
+	vdev_params->opmode = adapter->device_mode;
+	vdev_params->size_vdev_priv = sizeof(struct vdev_osif_priv);
+
+	if (hdd_adapter_is_ml_adapter(adapter)) {
+		qdf_ether_addr_copy(vdev_params->mldaddr,
+				    adapter->mac_addr.bytes);
+		qdf_ether_addr_copy(vdev_params->macaddr,
+				    link_info->link_addr.bytes);
+	} else {
+		qdf_ether_addr_copy(vdev_params->macaddr,
+				    adapter->mac_addr.bytes);
+	}
+}
+#elif defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
 static void
-hdd_populate_vdev_create_params(struct hdd_adapter *adapter,
+hdd_populate_vdev_create_params(struct wlan_hdd_link_info *link_info,
 				struct wlan_vdev_create_params *vdev_params)
 {
+	struct hdd_adapter *adapter = link_info->adapter;
 	struct hdd_mlo_adapter_info *mlo_adapter_info;
 	struct hdd_adapter *link_adapter;
 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
@@ -7179,20 +7204,19 @@ hdd_populate_vdev_create_params(struct hdd_adapter *adapter,
 	    adapter->device_mode == QDF_STA_MODE) {
 		link_adapter = hdd_get_assoc_link_adapter(adapter);
 		if (link_adapter) {
-			qdf_mem_copy(vdev_params->macaddr,
-				     link_adapter->mac_addr.bytes,
-				     QDF_MAC_ADDR_SIZE);
+			qdf_ether_addr_copy(vdev_params->macaddr,
+					    link_adapter->mac_addr.bytes);
 		}
 	} else {
-		qdf_mem_copy(vdev_params->macaddr, adapter->mac_addr.bytes,
-			     QDF_MAC_ADDR_SIZE);
+		qdf_ether_addr_copy(vdev_params->macaddr,
+				    adapter->mac_addr.bytes);
 	}
 
 	vdev_params->opmode = adapter->device_mode;
 
 	if (eht_capab) {
-		qdf_mem_copy(vdev_params->mldaddr, adapter->mld_addr.bytes,
-			     QDF_MAC_ADDR_SIZE);
+		qdf_ether_addr_copy(vdev_params->mldaddr,
+				    adapter->mld_addr.bytes);
 	}
 
 	vdev_params->size_vdev_priv = sizeof(struct vdev_osif_priv);
@@ -7200,13 +7224,13 @@ hdd_populate_vdev_create_params(struct hdd_adapter *adapter,
 }
 #else
 static void
-hdd_populate_vdev_create_params(struct hdd_adapter *adapter,
+hdd_populate_vdev_create_params(struct wlan_hdd_link_info *link_info,
 				struct wlan_vdev_create_params *vdev_params)
 {
+	struct hdd_adapter *adapter = link_info->adapter;
+
 	vdev_params->opmode = adapter->device_mode;
-	qdf_mem_copy(vdev_params->macaddr,
-		     adapter->mac_addr.bytes,
-		     QDF_NET_MAC_ADDR_MAX_LEN);
+	qdf_ether_addr_copy(vdev_params->macaddr, adapter->mac_addr.bytes);
 	vdev_params->size_vdev_priv = sizeof(struct vdev_osif_priv);
 }
 #endif
@@ -7225,7 +7249,7 @@ int hdd_vdev_create(struct wlan_hdd_link_info *link_info)
 	/* do vdev create via objmgr */
 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 
-	hdd_populate_vdev_create_params(adapter, &vdev_params);
+	hdd_populate_vdev_create_params(link_info, &vdev_params);
 
 	vdev = sme_vdev_create(hdd_ctx->mac_handle, &vdev_params);
 	if (!vdev) {
@@ -8146,7 +8170,8 @@ static void wlan_hdd_cfg80211_scan_block_cb(struct work_struct *work)
 	osif_vdev_sync_op_stop(vdev_sync);
 }
 
-#ifdef WLAN_FEATURE_11BE_MLO
+#if defined(WLAN_FEATURE_11BE_MLO) && \
+	defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
 static inline void
 wlan_hdd_set_ml_cap_for_sap_intf(struct hdd_adapter_create_param *create_params,
 				 enum QDF_OPMODE mode)
@@ -8154,17 +8179,64 @@ wlan_hdd_set_ml_cap_for_sap_intf(struct hdd_adapter_create_param *create_params,
 	if (mode != QDF_SAP_MODE)
 		return;
 
-	create_params->is_single_link = true;
 	create_params->is_ml_adapter = true;
 }
+#elif defined(WLAN_FEATURE_11BE_MLO)
+static inline void
+wlan_hdd_set_ml_cap_for_sap_intf(struct hdd_adapter_create_param *create_params,
+				 enum QDF_OPMODE mode)
+{
+	if (mode != QDF_SAP_MODE)
+		return;
+
+	create_params->is_ml_adapter = true;
+	create_params->is_single_link = true;
+}
 #else
 static inline void
 wlan_hdd_set_ml_cap_for_sap_intf(struct hdd_adapter_create_param *create_params,
 				 enum QDF_OPMODE mode)
+{
+	create_params->is_ml_adapter = false;
+}
+#endif /* WLAN_FEATURE_11BE_MLO */
+
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \
+	defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
+static void hdd_adapter_disable_all_links(struct hdd_adapter *adapter)
+{
+	struct wlan_hdd_link_info *link_info;
+
+	hdd_adapter_for_each_link_info(adapter, link_info)
+		qdf_zero_macaddr(&link_info->link_addr);
+}
+#else
+static inline void
+hdd_adapter_disable_all_links(struct hdd_adapter *adapter)
 {
 }
 #endif
 
+static void hdd_adapter_enable_links(struct hdd_adapter *adapter,
+				     struct hdd_adapter_create_param *params)
+{
+	uint8_t num, link_idx;
+
+	/* Default link is already set on adapter allocation, only
+	 * enable other links if requested links is greater than 1
+	 */
+	if (params->num_sessions <= 1) {
+		adapter->num_links_on_create = 1;
+		return;
+	}
+
+	num = QDF_MIN(params->num_sessions, WLAN_MAX_MLD);
+	for (link_idx = WLAN_HDD_DEFLINK_IDX; link_idx < num; link_idx++)
+		qdf_atomic_set_bit(link_idx, &adapter->active_links);
+
+	adapter->num_links_on_create = num;
+}
+
 static void hdd_adapter_init_link_info(struct hdd_adapter *adapter)
 {
 	struct wlan_hdd_link_info *link_info;
@@ -8366,7 +8438,6 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx,
 			  hdd_ipv6_notifier_work_queue);
 #endif
 		wlan_hdd_set_ml_cap_for_sap_intf(params, session_type);
-
 		break;
 	case QDF_FTM_MODE:
 		adapter = hdd_alloc_station_adapter(hdd_ctx, mac_addr,
@@ -8406,9 +8477,11 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx,
 	hdd_adapter_init_link_info(adapter);
 
 	ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab);
+	if (eht_capab)
+		hdd_adapter_enable_links(adapter, params);
+
 	if (params->is_ml_adapter && eht_capab) {
 		hdd_adapter_set_ml_adapter(adapter);
-		qdf_copy_macaddr(&adapter->mld_addr, &adapter->mac_addr);
 		if (params->is_single_link)
 			hdd_adapter_set_sl_ml_adapter(adapter);
 	}
@@ -9172,6 +9245,11 @@ QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx,
 	/* Moved from vdev destroy as it is per adapter */
 	wlan_cfg80211_cleanup_scan_queue(hdd_ctx->pdev, adapter->dev);
 
+	/* Disable all links (expect default index) in adapter.
+	 * Set link address to NULL
+	 */
+	hdd_adapter_disable_all_links(adapter);
+
 	/* This function should be invoked at the end of this api*/
 	hdd_dump_func_call_map();
 	hdd_exit();
@@ -10054,29 +10132,73 @@ struct hdd_adapter *hdd_get_adapter_by_rand_macaddr(
 	struct hdd_context *hdd_ctx, tSirMacAddr mac_addr)
 {
 	struct hdd_adapter *adapter, *next_adapter = NULL;
-	wlan_net_dev_ref_dbgid dbgid =
-				NET_DEV_HOLD_GET_ADAPTER_BY_RAND_MACADDR;
+	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_RAND_MACADDR;
+	struct wlan_hdd_link_info *link_info;
+
+	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
+					   dbgid) {
+		if (adapter->device_mode != QDF_STA_MODE &&
+		    adapter->device_mode != QDF_P2P_CLIENT_MODE &&
+		    adapter->device_mode != QDF_P2P_DEVICE_MODE) {
+			hdd_adapter_dev_put_debug(adapter, dbgid);
+			continue;
+		}
+
+		hdd_adapter_for_each_active_link_info(adapter, link_info) {
+			if (ucfg_p2p_check_random_mac(hdd_ctx->psoc,
+						      link_info->vdev_id,
+						      mac_addr)) {
+				hdd_adapter_dev_put_debug(adapter, dbgid);
+				if (next_adapter)
+					hdd_adapter_dev_put_debug(next_adapter,
+								  dbgid);
+				return adapter;
+			}
+		}
+		hdd_adapter_dev_put_debug(adapter, dbgid);
+	}
+
+	return NULL;
+}
+
+#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
+struct hdd_adapter *hdd_get_adapter_by_macaddr(struct hdd_context *hdd_ctx,
+					       tSirMacAddr mac_addr)
+{
+	struct hdd_adapter *adapter, *next_adapter = NULL;
+	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_MACADDR;
+	struct qdf_mac_addr zero_mac_addr = QDF_MAC_ADDR_ZERO_INIT;
+	struct wlan_hdd_link_info *link_info;
+
+	if (!qdf_mem_cmp(mac_addr, zero_mac_addr.bytes, sizeof(tSirMacAddr)))
+		return NULL;
 
 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
 					   dbgid) {
-		if ((adapter->device_mode == QDF_STA_MODE ||
-		     adapter->device_mode == QDF_P2P_CLIENT_MODE ||
-		     adapter->device_mode == QDF_P2P_DEVICE_MODE) &&
-		    ucfg_p2p_check_random_mac(hdd_ctx->psoc,
-					      adapter->deflink->vdev_id,
-					      mac_addr)) {
+		if (!qdf_mem_cmp(adapter->mac_addr.bytes,
+				 mac_addr, sizeof(tSirMacAddr))) {
 			hdd_adapter_dev_put_debug(adapter, dbgid);
 			if (next_adapter)
 				hdd_adapter_dev_put_debug(next_adapter,
 							  dbgid);
 			return adapter;
 		}
+		hdd_adapter_for_each_active_link_info(adapter, link_info) {
+			if (!qdf_mem_cmp(link_info->link_addr.bytes,
+					 mac_addr, sizeof(tSirMacAddr))) {
+				hdd_adapter_dev_put_debug(adapter, dbgid);
+				if (next_adapter)
+					hdd_adapter_dev_put_debug(next_adapter,
+								  dbgid);
+				return adapter;
+			}
+		}
 		hdd_adapter_dev_put_debug(adapter, dbgid);
 	}
 
 	return NULL;
 }
-
+#else
 struct hdd_adapter *hdd_get_adapter_by_macaddr(struct hdd_context *hdd_ctx,
 					       tSirMacAddr mac_addr)
 {
@@ -10107,6 +10229,7 @@ struct hdd_adapter *hdd_get_adapter_by_macaddr(struct hdd_context *hdd_ctx,
 
 	return NULL;
 }
+#endif
 
 struct wlan_hdd_link_info *
 hdd_get_link_info_by_vdev(struct hdd_context *hdd_ctx, uint32_t vdev_id)
@@ -13950,7 +14073,88 @@ out:
 	hdd_debug("wlm initial mode %u", adapter->latency_level);
 }
 
-#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
+#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
+struct qdf_mac_addr *
+hdd_adapter_get_mac_address(struct wlan_hdd_link_info *link_info)
+{
+	struct hdd_adapter *adapter;
+
+	if (!link_info)
+		return NULL;
+
+	adapter = link_info->adapter;
+	if (!hdd_adapter_is_ml_adapter(adapter) ||
+	    qdf_is_macaddr_zero(&link_info->link_addr))
+		return &adapter->mac_addr;
+
+	return &link_info->link_addr;
+}
+#else
+struct qdf_mac_addr *
+hdd_adapter_get_mac_address(struct wlan_hdd_link_info *link_info)
+{
+	if (!link_info)
+		return NULL;
+
+	return &link_info->adapter->mac_addr;
+}
+#endif
+
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \
+	defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
+QDF_STATUS hdd_adapter_check_duplicate_session(struct hdd_adapter *adapter)
+{
+	int i = 0;
+	QDF_STATUS status;
+	uint8_t *addr_list[WLAN_MAX_MLD + 2] = {0};
+	struct wlan_hdd_link_info *link_info;
+
+	if (!hdd_adapter_is_ml_adapter(adapter) ||
+	    adapter->device_mode == QDF_SAP_MODE)
+		goto netdev_addr;
+
+	hdd_adapter_for_each_active_link_info(adapter, link_info)
+		addr_list[i++] = &link_info->link_addr.bytes[0];
+
+netdev_addr:
+	addr_list[i] = &adapter->mac_addr.bytes[0];
+	status = sme_check_for_duplicate_session(adapter->hdd_ctx->mac_handle,
+						 &addr_list[0]);
+	return status;
+}
+
+QDF_STATUS hdd_adapter_fill_link_address(struct hdd_adapter *adapter)
+{
+	int i = 0;
+	QDF_STATUS status;
+	enum QDF_OPMODE opmode = adapter->device_mode;
+	struct qdf_mac_addr link_addrs[WLAN_MAX_MLD] = {0};
+	struct wlan_hdd_link_info *link_info;
+
+	if (opmode != QDF_STA_MODE && opmode != QDF_SAP_MODE)
+		return QDF_STATUS_SUCCESS;
+
+	if (opmode == QDF_SAP_MODE) {
+		link_info = adapter->deflink;
+		qdf_copy_macaddr(&link_info->link_addr, &adapter->mac_addr);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	if (!hdd_adapter_is_ml_adapter(adapter))
+		return QDF_STATUS_SUCCESS;
+
+	status = hdd_derive_link_address_from_mld(&adapter->mac_addr,
+						  &link_addrs[0],
+						  WLAN_MAX_MLD);
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
+
+	hdd_adapter_for_each_active_link_info(adapter, link_info)
+		qdf_copy_macaddr(&link_info->link_addr, &link_addrs[i++]);
+
+	return status;
+}
+#elif defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
 QDF_STATUS hdd_adapter_check_duplicate_session(struct hdd_adapter *adapter)
 {
 	int i;
@@ -14011,6 +14215,12 @@ int hdd_start_station_adapter(struct hdd_adapter *adapter)
 	    (adapter->device_mode == QDF_NAN_DISC_MODE))
 		wlan_hdd_lpc_del_monitor_interface(adapter->hdd_ctx);
 
+	status = hdd_adapter_fill_link_address(adapter);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_debug("Link address derive failed");
+		return qdf_status_to_os_return(status);
+	}
+
 	status = hdd_adapter_check_duplicate_session(adapter);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err("Duplicate session is existing with same mac address");
@@ -14079,6 +14289,12 @@ int hdd_start_ap_adapter(struct hdd_adapter *adapter)
 
 	wlan_hdd_lpc_del_monitor_interface(hdd_ctx);
 
+	status = hdd_adapter_fill_link_address(adapter);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_debug("Link address derive failed");
+		return qdf_status_to_os_return(status);
+	}
+
 	status = hdd_adapter_check_duplicate_session(adapter);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err("Duplicate session is existing with same mac address");
@@ -16321,6 +16537,23 @@ static QDF_STATUS hdd_open_concurrent_interface(struct hdd_context *hdd_ctx)
 	return status;
 }
 
+#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
+static inline void
+hdd_adapter_open_set_max_active_links(struct hdd_adapter_create_param *params)
+{
+	if (params->is_add_virtual_iface || !params->is_ml_adapter)
+		params->num_sessions = 1;
+	else
+		params->num_sessions = 2;
+}
+#else
+static inline void
+hdd_adapter_open_set_max_active_links(struct hdd_adapter_create_param *params)
+{
+	params->num_sessions = 1;
+}
+#endif
+
 static QDF_STATUS
 hdd_open_adapters_for_mission_mode(struct hdd_context *hdd_ctx)
 {
@@ -16341,8 +16574,11 @@ hdd_open_adapters_for_mission_mode(struct hdd_context *hdd_ctx)
 	if (!mac_addr)
 		return QDF_STATUS_E_INVAL;
 
-	if (eht_capab)
+	if (eht_capab) {
 		params.is_ml_adapter = true;
+		hdd_adapter_open_set_max_active_links(&params);
+	}
+
 	status = hdd_open_adapter_no_trans(hdd_ctx, QDF_STA_MODE,
 					   "wlan%d", mac_addr,
 					   &params);

+ 75 - 24
core/hdd/src/wlan_hdd_mlo.c

@@ -35,6 +35,7 @@
 #define WLAN_WAIT_TIME_LINK_STATE 800
 
 #if defined(CFG80211_11BE_BASIC)
+#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
 #ifdef CFG80211_IFTYPE_MLO_LINK_SUPPORT
 
 static
@@ -196,27 +197,6 @@ void hdd_wlan_register_mlo_interfaces(struct hdd_context *hdd_ctx)
 		hdd_err("Failed to register link adapter:%d", status);
 }
 
-#ifdef CFG80211_MLD_MAC_IN_WDEV
-static inline
-void wlan_hdd_populate_mld_address(struct hdd_adapter *adapter,
-				   uint8_t *mld_addr)
-{
-	qdf_mem_copy(adapter->wdev.mld_address, mld_addr,
-		     QDF_NET_MAC_ADDR_MAX_LEN);
-}
-#else
-static inline
-void wlan_hdd_populate_mld_address(struct hdd_adapter *adapter,
-				   uint8_t *mld_addr)
-{
-}
-#endif
-void
-hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter)
-{
-	adapter->mlo_adapter_info.is_ml_adapter = true;
-}
-
 void
 hdd_adapter_set_sl_ml_adapter(struct hdd_adapter *adapter)
 {
@@ -248,6 +228,20 @@ struct hdd_adapter *hdd_get_ml_adapter(struct hdd_context *hdd_ctx)
 
 	return NULL;
 }
+#endif
+
+#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
+void hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter)
+{
+	adapter->mlo_adapter_info.is_ml_adapter = true;
+	qdf_copy_macaddr(&adapter->mld_addr, &adapter->mac_addr);
+}
+#else
+void hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter)
+{
+	adapter->mlo_adapter_info.is_ml_adapter = true;
+}
+#endif
 
 void hdd_mlo_t2lm_register_callback(struct wlan_objmgr_vdev *vdev)
 {
@@ -305,6 +299,61 @@ QDF_STATUS hdd_derive_link_address_from_mld(struct qdf_mac_addr *mld_addr,
 }
 
 #ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE
+#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
+int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
+				struct qdf_mac_addr mac_addr)
+{
+	int i = 0, ret = 0;
+	bool eht_capab, update_self_peer;
+	QDF_STATUS status;
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	struct wlan_hdd_link_info *link_info;
+	uint8_t *addr_list[WLAN_MAX_MLD + 2] = {0};
+	struct qdf_mac_addr link_addrs[WLAN_MAX_MLD] = {0};
+
+	/* This API is only called with is ml adapter set for STA mode adapter.
+	 * For SAP mode, hdd_hostapd_set_mac_address() is the entry point for
+	 * MAC address update.
+	 */
+	ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab);
+	if (!(eht_capab && hdd_adapter_is_ml_adapter(adapter))) {
+		struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT;
+
+		ret = hdd_dynamic_mac_address_set(adapter->deflink, mac_addr,
+						  mld_addr, true);
+		return ret;
+	}
+
+	status = hdd_derive_link_address_from_mld(&mac_addr, &link_addrs[0],
+						  WLAN_MAX_MLD);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		return qdf_status_to_os_return(status);
+
+	hdd_adapter_for_each_active_link_info(adapter, link_info) {
+		addr_list[i] = &link_addrs[i].bytes[0];
+		i++;
+	}
+
+	status = sme_check_for_duplicate_session(hdd_ctx->mac_handle,
+						 &addr_list[0]);
+	if (QDF_IS_STATUS_ERROR(status))
+		return qdf_status_to_os_return(status);
+
+	i = 0;
+	hdd_adapter_for_each_active_link_info(adapter, link_info) {
+		update_self_peer =
+			(link_info == adapter->deflink) ? true : false;
+		ret = hdd_dynamic_mac_address_set(link_info, link_addrs[i],
+						  mac_addr, update_self_peer);
+		if (ret)
+			return ret;
+
+		qdf_copy_macaddr(&link_info->link_addr, &link_addrs[i++]);
+	}
+	return ret;
+}
+#else
 int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
 				struct qdf_mac_addr mac_addr)
 {
@@ -325,7 +374,7 @@ int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
 	if (!(eht_capab && hdd_adapter_is_ml_adapter(adapter))) {
 		struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT;
 
-		ret = hdd_dynamic_mac_address_set(adapter, mac_addr,
+		ret = hdd_dynamic_mac_address_set(adapter->deflink, mac_addr,
 						  mld_addr, true);
 		return ret;
 	}
@@ -355,8 +404,9 @@ int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
 		else
 			update_self_peer = false;
 
-		ret = hdd_dynamic_mac_address_set(link_adapter, link_addrs[i],
-						  mac_addr, update_self_peer);
+		ret = hdd_dynamic_mac_address_set(link_adapter->deflink,
+						  link_addrs[i], mac_addr,
+						  update_self_peer);
 		if (ret)
 			return ret;
 
@@ -370,6 +420,7 @@ int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
 	return ret;
 }
 #endif
+#endif /* WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE */
 
 const struct nla_policy
 ml_link_state_config_policy [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX + 1] = {

+ 6 - 0
core/hdd/src/wlan_hdd_nan_datapath.c

@@ -579,6 +579,12 @@ int hdd_init_nan_data_mode(struct hdd_adapter *adapter)
 	struct wlan_objmgr_vdev *vdev;
 	uint16_t rts_profile = 0;
 
+	status = hdd_adapter_fill_link_address(adapter);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_debug("Link address derive failed");
+		return qdf_status_to_os_return(status);
+	}
+
 	status = hdd_adapter_check_duplicate_session(adapter);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err("Duplicate session is existing with same mac address");

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

@@ -870,7 +870,8 @@ struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy,
 }
 #endif
 
-#if defined(WLAN_FEATURE_11BE_MLO)
+#if defined(WLAN_FEATURE_11BE_MLO) && \
+	!defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
 /**
  * hdd_deinit_mlo_interfaces() - De-initialize link adapters
  * @hdd_ctx: Pointer to hdd context

+ 79 - 85
core/hdd/src/wlan_hdd_power.c

@@ -624,25 +624,34 @@ out:
 }
 
 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
-static void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter,
-				  struct hdd_context *hdd_ctx)
+#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
+static void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter)
 {
+	struct wlan_hdd_link_info *link_info;
+	mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter);
+
+	hdd_adapter_for_each_active_link_info(adapter, link_info)
+		sme_ps_update(mac_handle, link_info->vdev_id);
+}
+#else
+static void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter)
+{
+	int i;
 	struct hdd_adapter *link_adapter;
 	struct hdd_mlo_adapter_info *mlo_adapter_info;
-	int i;
+	mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter);
 
 	mlo_adapter_info = &adapter->mlo_adapter_info;
 	for (i = 0; i < WLAN_MAX_MLD; i++) {
 		link_adapter = mlo_adapter_info->link_adapter[i];
 		if (!link_adapter)
 			continue;
-		sme_ps_update(hdd_ctx->mac_handle,
-			      link_adapter->deflink->vdev_id);
+		sme_ps_update(mac_handle, link_adapter->deflink->vdev_id);
 	}
 }
+#endif
 #else
-static void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter,
-				  struct hdd_context *hdd_ctx)
+static inline void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter)
 {}
 #endif
 
@@ -672,7 +681,7 @@ static void hdd_send_ps_config_to_fw(struct hdd_adapter *adapter)
 		return;
 	}
 
-	hdd_send_mlo_ps_to_fw(adapter, hdd_ctx);
+	hdd_send_mlo_ps_to_fw(adapter);
 }
 
 /**
@@ -2169,17 +2178,13 @@ err_ctx_null:
 	return -EPERM;
 }
 
-int wlan_hdd_set_powersave(struct hdd_adapter *adapter,
+int wlan_hdd_set_powersave(struct wlan_hdd_link_info *link_info,
 			   bool allow_power_save, uint32_t timeout)
 {
+	struct hdd_adapter *adapter = link_info->adapter;
 	struct hdd_context *hdd_ctx;
 	QDF_STATUS status;
-	struct hdd_station_ctx *hdd_sta_ctx = NULL;
-
-	if (!adapter) {
-		hdd_err("Adapter NULL");
-		return -ENODEV;
-	}
+	struct hdd_station_ctx *sta_ctx;
 
 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 	if (!hdd_ctx) {
@@ -2187,21 +2192,17 @@ int wlan_hdd_set_powersave(struct hdd_adapter *adapter,
 		return -EINVAL;
 	}
 
-	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
-	if (!hdd_sta_ctx) {
-		hdd_err("hdd_sta_context is NULL");
-		return -EINVAL;
-	}
+	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
 
 	status = sme_ps_set_powersave(
-		hdd_ctx->mac_handle, adapter->deflink->vdev_id,
-		allow_power_save, timeout,
-		hdd_sta_ctx->ap_supports_immediate_power_save);
+				hdd_ctx->mac_handle, link_info->vdev_id,
+				allow_power_save, timeout,
+				sta_ctx->ap_supports_immediate_power_save);
 	if (!allow_power_save) {
 		if (adapter->device_mode == QDF_STA_MODE)
 			hdd_twt_del_dialog_in_ps_disable(hdd_ctx,
-						&hdd_sta_ctx->conn_info.bssid,
-						adapter->deflink->vdev_id);
+						&sta_ctx->conn_info.bssid,
+						link_info->vdev_id);
 	}
 
 	return qdf_status_to_os_return(status);
@@ -2774,36 +2775,41 @@ int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
 
 /**
  * hdd_stop_dhcp_ind() - API to stop DHCP sequence
- * @adapter: Adapter on which DHCP needs to be stopped
+ * @link_info: Link  info pointer in HDD adapter
+ * @mac: mac address
  *
  * Release the wakelock held for DHCP process and allow
  * the runtime pm to continue
  *
  * Return: None
  */
-static void hdd_stop_dhcp_ind(struct hdd_adapter *adapter)
+static void hdd_stop_dhcp_ind(struct wlan_hdd_link_info *link_info,
+			      uint8_t *mac)
 {
+	struct hdd_adapter *adapter = link_info->adapter;
 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 
 	hdd_debug("DHCP stop indicated through power save");
 	sme_dhcp_stop_ind(hdd_ctx->mac_handle, adapter->device_mode,
-			  adapter->mac_addr.bytes,
-			  adapter->deflink->vdev_id);
+			  mac, link_info->vdev_id);
 	hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP);
 	qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.connect);
 }
 
 /**
  * hdd_start_dhcp_ind() - API to start DHCP sequence
- * @adapter: Adapter on which DHCP needs to be stopped
+ * @link_info: Link info pointer in HDD adapter
+ * @mac: mac address
  *
  * Prevent APPS suspend and the runtime suspend during
  * DHCP sequence
  *
  * Return: None
  */
-static void hdd_start_dhcp_ind(struct hdd_adapter *adapter)
+static void
+hdd_start_dhcp_ind(struct wlan_hdd_link_info *link_info, uint8_t *mac)
 {
+	struct hdd_adapter *adapter = link_info->adapter;
 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 
 	hdd_debug("DHCP start indicated through power save");
@@ -2811,35 +2817,51 @@ static void hdd_start_dhcp_ind(struct hdd_adapter *adapter)
 	hdd_prevent_suspend_timeout(HDD_WAKELOCK_TIMEOUT_CONNECT,
 				    WIFI_POWER_EVENT_WAKELOCK_DHCP);
 	sme_dhcp_start_ind(hdd_ctx->mac_handle, adapter->device_mode,
-			   adapter->mac_addr.bytes,
-			   adapter->deflink->vdev_id);
+			   mac, link_info->vdev_id);
 }
 
-static int wlan_hdd_set_ps(struct wlan_objmgr_psoc *psoc,
-			   struct hdd_adapter *adapter,
-			   bool allow_power_save, int timeout)
+static int wlan_hdd_set_ps(struct wlan_hdd_link_info *link_info,
+			   uint8_t *mac, bool allow_power_save, int timeout)
 {
 	int status;
+	struct hdd_adapter *adapter = link_info->adapter;
 
-	status = wlan_hdd_set_powersave(adapter, allow_power_save, timeout);
+	status = wlan_hdd_set_powersave(link_info, allow_power_save, timeout);
 
-	if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
+	if (!hdd_cm_is_vdev_associated(link_info)) {
 		hdd_debug("vdev[%d] mode %d disconnected ignore dhcp protection",
-			  adapter->deflink->vdev_id, adapter->device_mode);
+			  link_info->vdev_id, adapter->device_mode);
 		return status;
 	}
 
 	hdd_debug("vdev[%d] mode %d enable dhcp protection",
-		  adapter->deflink->vdev_id, adapter->device_mode);
-	allow_power_save ? hdd_stop_dhcp_ind(adapter) :
-			   hdd_start_dhcp_ind(adapter);
+		  link_info->vdev_id, adapter->device_mode);
+	allow_power_save ? hdd_stop_dhcp_ind(link_info, mac) :
+			   hdd_start_dhcp_ind(link_info, mac);
 
 	return status;
 }
 
 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
-static int wlan_hdd_set_mlo_ps(struct wlan_objmgr_psoc *psoc,
-			       struct hdd_adapter *adapter,
+#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
+static int wlan_hdd_set_mlo_ps(struct hdd_adapter *adapter,
+			       bool allow_power_save, int timeout)
+{
+	struct wlan_hdd_link_info *link_info;
+	int status = -EINVAL;
+
+	hdd_adapter_for_each_active_link_info(adapter, link_info) {
+		status = wlan_hdd_set_ps(link_info,
+					 link_info->link_addr.bytes,
+					 allow_power_save, timeout);
+		if (status)
+			break;
+	}
+
+	return status;
+}
+#else
+static int wlan_hdd_set_mlo_ps(struct hdd_adapter *adapter,
 			       bool allow_power_save, int timeout)
 {
 	struct hdd_adapter *link_adapter;
@@ -2851,38 +2873,22 @@ static int wlan_hdd_set_mlo_ps(struct wlan_objmgr_psoc *psoc,
 		link_adapter = mlo_adapter_info->link_adapter[i];
 		if (!link_adapter)
 			continue;
-
-		status = wlan_hdd_set_ps(psoc, link_adapter, allow_power_save,
-					 timeout);
+		status = wlan_hdd_set_ps(link_adapter->deflink,
+					 link_adapter->mac_addr.bytes,
+					 allow_power_save, timeout);
 		if (status)
-			return status;
+			break;
 	}
 
 	return status;
 }
-
-static bool wlan_hdd_is_ml_adapter(struct hdd_adapter *adapter)
-{
-	struct hdd_mlo_adapter_info *mlo_adapter_info;
-	bool is_ml_adapter = false;
-
-	mlo_adapter_info = &adapter->mlo_adapter_info;
-	is_ml_adapter = mlo_adapter_info->is_ml_adapter ? 1 : 0;
-
-	return is_ml_adapter;
-}
+#endif
 #else
-static int wlan_hdd_set_mlo_ps(struct wlan_objmgr_psoc *psoc,
-			       struct hdd_adapter *adapter,
+static int wlan_hdd_set_mlo_ps(struct hdd_adapter *adapter,
 			       bool allow_power_save, int timeout)
 {
 	return 0;
 }
-
-static bool wlan_hdd_is_ml_adapter(struct hdd_adapter *adapter)
-{
-	return false;
-}
 #endif
 
 /**
@@ -2902,8 +2908,7 @@ static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
 	struct hdd_context *hdd_ctx;
 	int status;
-	struct wlan_objmgr_vdev *vdev;
-	bool is_ml_adapter;
+	struct wlan_hdd_link_info *link_info = adapter->deflink;
 
 	hdd_enter();
 
@@ -2918,12 +2923,12 @@ static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
 		return -EINVAL;
 	}
 
-	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
+	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
 		return -EINVAL;
 
 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
 		   TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT,
-		   adapter->deflink->vdev_id, timeout);
+		   link_info->vdev_id, timeout);
 
 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 	status = wlan_hdd_validate_context(hdd_ctx);
@@ -2936,17 +2941,6 @@ static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
 		return 0;
 	}
 
-	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
-					   WLAN_OSIF_POWER_ID);
-	if (!vdev) {
-		hdd_info("vdev is NULL");
-		return -EINVAL;
-	}
-
-	is_ml_adapter = wlan_hdd_is_ml_adapter(adapter);
-
-	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
-
 	/* Flush any scheduled inet change notifier work
 	 * This is to make sure set power save request
 	 * sent to FW are serialized to avoid race condition
@@ -2954,13 +2948,13 @@ static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
 	flush_work(&adapter->ipv4_notifier_work);
 	hdd_adapter_flush_ipv6_notifier_work(adapter);
 
-	if (is_ml_adapter) {
-		status = wlan_hdd_set_mlo_ps(hdd_ctx->psoc, adapter,
-					     allow_power_save, timeout);
+	if (hdd_adapter_is_ml_adapter(adapter)) {
+		status = wlan_hdd_set_mlo_ps(adapter, allow_power_save,
+					     timeout);
 		goto exit;
 	}
 
-	status = wlan_hdd_set_ps(hdd_ctx->psoc, adapter,
+	status = wlan_hdd_set_ps(link_info, adapter->mac_addr.bytes,
 				 allow_power_save, timeout);
 
 exit:

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

@@ -878,11 +878,18 @@ bool hdd_get_interface_info(struct wlan_hdd_link_info *link_info,
 {
 	struct hdd_station_ctx *sta_ctx;
 	struct sap_config *config;
+	struct qdf_mac_addr *mac;
 	struct hdd_adapter *adapter = link_info->adapter;
 
 	info->mode = hdd_map_device_to_ll_iface_mode(adapter->device_mode);
 
-	qdf_copy_macaddr(&info->macAddr, &adapter->mac_addr);
+	mac = hdd_adapter_get_mac_address(link_info);
+	if (!mac) {
+		hdd_debug("Invalid HDD link info");
+		return false;
+	}
+
+	qdf_copy_macaddr(&info->macAddr, mac);
 
 	if (((QDF_STA_MODE == adapter->device_mode) ||
 	     (QDF_P2P_CLIENT_MODE == adapter->device_mode) ||
@@ -900,7 +907,7 @@ bool hdd_get_interface_info(struct wlan_hdd_link_info *link_info,
 		    !sta_ctx->conn_info.is_authenticated) {
 			hdd_err("client " QDF_MAC_ADDR_FMT
 				" is in the middle of WPS/EAPOL exchange.",
-				QDF_MAC_ADDR_REF(adapter->mac_addr.bytes));
+				QDF_MAC_ADDR_REF(mac->bytes));
 			info->state = WIFI_AUTHENTICATING;
 		}
 		if (hdd_cm_is_vdev_associated(link_info)) {