Jelajahi Sumber

qcacld-3.0: Send disconnect IEs received in deauth/disassoc to kernel

AP may send IEs in deauth/disassoc frames as part of disconnection.
Extract the same and forward to kernel through
cfg80211_disconnected().

Change-Id: I4ef339dcd1ecff64d6bed1de35621ecce5d8030a
CRs-Fixed: 2481912
Srinivas Dasari 5 tahun lalu
induk
melakukan
d4e8725828

+ 29 - 0
components/mlme/core/inc/wlan_mlme_main.h

@@ -88,6 +88,8 @@ enum vdev_assoc_type {
  * @roam_invoke_params: Roam invoke params
  * @self_disconnect_ies: Disconnect IEs to be sent in deauth/disassoc frames
  *			 originated from driver
+ * @peer_disconnect_ies: Disconnect IEs received in deauth/disassoc frames
+ *			 from peer
  */
 struct mlme_legacy_priv {
 	bool chan_switch_in_progress;
@@ -101,6 +103,7 @@ struct mlme_legacy_priv {
 	uint8_t sta_dynamic_oce_value;
 	struct mlme_roam_after_data_stall roam_invoke_params;
 	struct wlan_ies self_disconnect_ies;
+	struct wlan_ies peer_disconnect_ies;
 };
 
 #ifndef CRYPTO_SET_KEY_CONVERGED
@@ -308,4 +311,30 @@ void mlme_free_self_disconnect_ies(struct wlan_objmgr_vdev *vdev);
  * Return: Returns a pointer to the self disconnect IEs present in vdev object
  */
 struct wlan_ies *mlme_get_self_disconnect_ies(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * mlme_set_peer_disconnect_ies() - Cache disconnect IEs received from peer
+ * @vdev: vdev pointer
+ * @ie: pointer for disconnect IEs
+ *
+ * Return: None
+ */
+void mlme_set_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev,
+				  struct wlan_ies *ie);
+
+/**
+ * mlme_free_peer_disconnect_ies() - Free the peer diconnect IEs
+ * @vdev: vdev pointer
+ *
+ * Return: None
+ */
+void mlme_free_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * mlme_get_peer_disconnect_ies() - Get diconnect IEs from vdev object
+ * @vdev: vdev pointer
+ *
+ * Return: Returns a pointer to the peer disconnect IEs present in vdev object
+ */
+struct wlan_ies *mlme_get_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev);
 #endif

+ 73 - 0
components/mlme/core/src/wlan_mlme_main.c

@@ -2435,3 +2435,76 @@ struct wlan_ies *mlme_get_self_disconnect_ies(struct wlan_objmgr_vdev *vdev)
 
 	return &mlme_priv->self_disconnect_ies;
 }
+
+void mlme_set_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev,
+				  struct wlan_ies *ie)
+{
+	struct vdev_mlme_obj *vdev_mlme;
+	struct mlme_legacy_priv *mlme_priv;
+
+	if (!ie || !ie->len || !ie->data) {
+		mlme_legacy_debug("disocnnect IEs are NULL");
+		return;
+	}
+
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme) {
+		mlme_legacy_err("vdev component object is NULL");
+		return;
+	}
+
+	mlme_priv = vdev_mlme->ext_vdev_ptr;
+
+	if (mlme_priv->peer_disconnect_ies.data) {
+		qdf_mem_free(mlme_priv->peer_disconnect_ies.data);
+		mlme_priv->peer_disconnect_ies.len = 0;
+	}
+
+	mlme_priv->peer_disconnect_ies.data = qdf_mem_malloc(ie->len);
+	if (!mlme_priv->peer_disconnect_ies.data)
+		return;
+
+	qdf_mem_copy(mlme_priv->peer_disconnect_ies.data, ie->data, ie->len);
+	mlme_priv->peer_disconnect_ies.len = ie->len;
+
+	mlme_legacy_debug("peer disconnect IEs");
+	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLME, QDF_TRACE_LEVEL_DEBUG,
+			   mlme_priv->peer_disconnect_ies.data,
+			   mlme_priv->peer_disconnect_ies.len);
+}
+
+void mlme_free_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev)
+{
+	struct vdev_mlme_obj *vdev_mlme;
+	struct mlme_legacy_priv *mlme_priv;
+
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme) {
+		mlme_legacy_err("vdev component object is NULL");
+		return;
+	}
+
+	mlme_priv = vdev_mlme->ext_vdev_ptr;
+
+	if (mlme_priv->peer_disconnect_ies.data) {
+		qdf_mem_free(mlme_priv->peer_disconnect_ies.data);
+		mlme_priv->peer_disconnect_ies.data = NULL;
+		mlme_priv->peer_disconnect_ies.len = 0;
+	}
+}
+
+struct wlan_ies *mlme_get_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev)
+{
+	struct vdev_mlme_obj *vdev_mlme;
+	struct mlme_legacy_priv *mlme_priv;
+
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme) {
+		mlme_legacy_err("vdev component object is NULL");
+		return NULL;
+	}
+
+	mlme_priv = vdev_mlme->ext_vdev_ptr;
+
+	return &mlme_priv->peer_disconnect_ies;
+}

+ 1 - 0
components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c

@@ -828,6 +828,7 @@ QDF_STATUS vdevmgr_mlme_ext_hdl_destroy(struct vdev_mlme_obj *vdev_mlme)
 		return QDF_STATUS_E_FAILURE;
 
 	mlme_free_self_disconnect_ies(vdev_mlme->vdev);
+	mlme_free_peer_disconnect_ies(vdev_mlme->vdev);
 	qdf_mem_free(vdev_mlme->ext_vdev_ptr);
 	vdev_mlme->ext_vdev_ptr = NULL;
 

+ 13 - 3
core/hdd/src/wlan_hdd_assoc.c

@@ -1709,6 +1709,7 @@ static QDF_STATUS hdd_dis_connect_handler(struct hdd_adapter *adapter,
 	uint8_t sta_id;
 	bool sendDisconInd = true;
 	mac_handle_t mac_handle;
+	struct wlan_ies disconnect_ies = {0};
 
 	if (!dev) {
 		hdd_err("net_dev is released return");
@@ -1771,6 +1772,12 @@ static QDF_STATUS hdd_dis_connect_handler(struct hdd_adapter *adapter,
 		 * by kernel
 		 */
 		if (sendDisconInd) {
+			if (roam_info && roam_info->disconnect_ies) {
+				disconnect_ies.data =
+					roam_info->disconnect_ies->data;
+				disconnect_ies.len =
+					roam_info->disconnect_ies->len;
+			}
 			/*
 			 * To avoid wpa_supplicant sending "HANGED" CMD
 			 * to ICS UI.
@@ -1782,12 +1789,15 @@ static QDF_STATUS hdd_dis_connect_handler(struct hdd_adapter *adapter,
 						roam_info->rxRssi);
 				wlan_hdd_cfg80211_indicate_disconnect(
 							dev, false,
-							roam_info->reasonCode);
+							roam_info->reasonCode,
+							disconnect_ies.data,
+							disconnect_ies.len);
 			} else {
 				wlan_hdd_cfg80211_indicate_disconnect(
 							dev, false,
-							WLAN_REASON_UNSPECIFIED
-							);
+							WLAN_REASON_UNSPECIFIED,
+							disconnect_ies.data,
+							disconnect_ies.len);
 			}
 
 			hdd_debug("sent disconnected event to nl80211, reason code %d",

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

@@ -18638,7 +18638,7 @@ disconnected:
 	 */
 	hdd_debug("Send disconnected event to userspace");
 	wlan_hdd_cfg80211_indicate_disconnect(adapter->dev, true,
-						WLAN_REASON_UNSPECIFIED);
+					      WLAN_REASON_UNSPECIFIED, NULL, 0);
 #endif
 
 	return result;

+ 16 - 10
core/hdd/src/wlan_hdd_cfg80211.h

@@ -445,20 +445,26 @@ int wlan_hdd_try_disconnect(struct hdd_adapter *adapter);
 
 #if defined(CFG80211_DISCONNECTED_V2) || \
 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
-static inline void wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev,
-							bool locally_generated,
-							int reason)
+static inline void
+wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev,
+				      bool locally_generated,
+				      int reason,
+				      uint8_t *disconnect_ies,
+				      uint16_t disconnect_ies_len)
 {
-	cfg80211_disconnected(dev, reason, NULL, 0,
-				locally_generated, GFP_KERNEL);
+	cfg80211_disconnected(dev, reason, disconnect_ies, disconnect_ies_len,
+			      locally_generated, GFP_KERNEL);
 }
 #else
-static inline void wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev,
-							bool locally_generated,
-							int reason)
+static inline void
+wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev,
+				      bool locally_generated,
+				      int reason,
+				      uint8_t *disconnect_ies,
+				      uint16_t disconnect_ies_len)
 {
-	cfg80211_disconnected(dev, reason, NULL, 0,
-				GFP_KERNEL);
+	cfg80211_disconnected(dev, reason, disconnect_ies, disconnect_ies_len,
+			      GFP_KERNEL);
 }
 #endif
 

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

@@ -6750,7 +6750,8 @@ QDF_STATUS hdd_start_all_adapters(struct hdd_context *hdd_ctx)
 				/* indicate disconnected event to nl80211 */
 				wlan_hdd_cfg80211_indicate_disconnect(
 						adapter->dev, false,
-						WLAN_REASON_UNSPECIFIED);
+						WLAN_REASON_UNSPECIFIED,
+						NULL, 0);
 			} else if (eConnectionState_Connecting == conn_state) {
 				/*
 				 * Indicate connect failure to supplicant if we

+ 25 - 0
core/mac/src/pe/lim/lim_assoc_utils.c

@@ -4827,3 +4827,28 @@ void lim_send_sme_tsm_ie_ind(struct mac_context *mac,
 	lim_sys_process_mmh_msg_api(mac, &msg);
 }
 #endif /* FEATURE_WLAN_ESE */
+
+void lim_extract_ies_from_deauth_disassoc(struct pe_session *session,
+					  uint8_t *deauth_disassoc_frame,
+					  uint16_t deauth_disassoc_frame_len)
+{
+	uint16_t reason_code, ie_offset;
+	struct wlan_ies ie;
+
+	if (!session) {
+		pe_err("NULL session");
+		return;
+	}
+
+	/* Get the offset of IEs */
+	ie_offset = sizeof(struct wlan_frame_hdr) + sizeof(reason_code);
+
+	if (!deauth_disassoc_frame || deauth_disassoc_frame_len <= ie_offset)
+		return;
+
+	ie.data = deauth_disassoc_frame + ie_offset;
+	ie.len = deauth_disassoc_frame_len - ie_offset;
+
+	mlme_set_peer_disconnect_ies(session->vdev, &ie);
+}
+

+ 17 - 0
core/mac/src/pe/lim/lim_assoc_utils.h

@@ -281,4 +281,21 @@ QDF_STATUS lim_populate_vht_mcs_set(struct mac_context *mac_ctx,
 				    struct pe_session *session_entry,
 				    uint8_t nss);
 
+/**
+ * lim_extract_ies_from_deauth_disassoc() - Extract IEs from deauth/disassoc
+ *
+ * @session: PE session entry
+ * @deauth_disassoc_frame: A pointer to the deauth/disconnect frame buffer
+ *			   received from WMA.
+ * @deauth_disassoc_frame_leni: Length of the deauth/disconnect frame.
+ *
+ * This function receives deauth/disassoc frame from header. It extracts
+ * the IEs(tagged params) from the frame and caches in vdev object.
+ *
+ * Return: None
+ */
+void
+lim_extract_ies_from_deauth_disassoc(struct pe_session *session,
+				     uint8_t *deauth_disassoc_frame,
+				     uint16_t deauth_disassoc_frame_len);
 #endif /* __LIM_ASSOC_UTILS_H */

+ 2 - 0
core/mac/src/pe/lim/lim_process_deauth_frame.c

@@ -314,6 +314,8 @@ lim_process_deauth_frame(struct mac_context *mac, uint8_t *pRxPacketInfo,
 		}
 	}
 
+	lim_extract_ies_from_deauth_disassoc(pe_session, (uint8_t *)pHdr,
+					WMA_GET_RX_MPDU_LEN(pRxPacketInfo));
 	lim_perform_deauth(mac, pe_session, reasonCode, pHdr->sa,
 			   frame_rssi);
 

+ 2 - 0
core/mac/src/pe/lim/lim_process_disassoc_frame.c

@@ -310,6 +310,8 @@ lim_process_disassoc_frame(struct mac_context *mac, uint8_t *pRxPacketInfo,
 
 	} /* if (sta->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) */
 
+	lim_extract_ies_from_deauth_disassoc(pe_session, (uint8_t *)pHdr,
+					WMA_GET_RX_MPDU_LEN(pRxPacketInfo));
 	lim_perform_disassoc(mac, frame_rssi, reasonCode,
 			     pe_session, pHdr->sa);
 

+ 1 - 0
core/sme/inc/csr_api.h

@@ -1179,6 +1179,7 @@ struct csr_roam_info {
 #endif
 	struct assoc_ind *owe_pending_assoc_ind;
 	uint16_t roam_reason;
+	struct wlan_ies *disconnect_ies;
 };
 
 typedef struct sSirSmeAssocIndToUpperLayerCnf {

+ 11 - 0
core/sme/src/csr/csr_api_roam.c

@@ -9733,6 +9733,7 @@ csr_roam_send_disconnect_done_indication(struct mac_context *mac_ctx,
 				(struct sir_sme_discon_done_ind *)(msg_ptr);
 	struct csr_roam_info *roam_info;
 	struct csr_roam_session *session;
+	struct wlan_objmgr_vdev *vdev;
 
 	roam_info = qdf_mem_malloc(sizeof(*roam_info));
 	if (!roam_info)
@@ -9751,10 +9752,20 @@ csr_roam_send_disconnect_done_indication(struct mac_context *mac_ctx,
 		roam_info->rx_rate = mac_ctx->peer_rxrate;
 		roam_info->disassoc_reason = discon_ind->reason_code;
 		roam_info->rx_mc_bc_cnt = mac_ctx->rx_mc_bc_cnt;
+		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc,
+							discon_ind->session_id,
+							WLAN_LEGACY_SME_ID);
+		if (vdev)
+			roam_info->disconnect_ies =
+				mlme_get_peer_disconnect_ies(vdev);
 
 		csr_roam_call_callback(mac_ctx, discon_ind->session_id,
 				       roam_info, 0, eCSR_ROAM_LOSTLINK,
 				       eCSR_ROAM_RESULT_DISASSOC_IND);
+		if (vdev) {
+			mlme_free_peer_disconnect_ies(vdev);
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID);
+		}
 		session = CSR_GET_SESSION(mac_ctx, discon_ind->session_id);
 		if (session &&
 		   !CSR_IS_INFRA_AP(&session->connectedProfile))