From d4e87258284008b88397d13a58dcf94b39a667a6 Mon Sep 17 00:00:00 2001 From: Srinivas Dasari Date: Mon, 1 Jul 2019 15:35:52 +0530 Subject: [PATCH] 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 --- components/mlme/core/inc/wlan_mlme_main.h | 29 ++++++++ components/mlme/core/src/wlan_mlme_main.c | 73 +++++++++++++++++++ .../core/src/wlan_mlme_vdev_mgr_interface.c | 1 + core/hdd/src/wlan_hdd_assoc.c | 16 +++- core/hdd/src/wlan_hdd_cfg80211.c | 2 +- core/hdd/src/wlan_hdd_cfg80211.h | 26 ++++--- core/hdd/src/wlan_hdd_main.c | 3 +- core/mac/src/pe/lim/lim_assoc_utils.c | 25 +++++++ core/mac/src/pe/lim/lim_assoc_utils.h | 17 +++++ .../mac/src/pe/lim/lim_process_deauth_frame.c | 2 + .../src/pe/lim/lim_process_disassoc_frame.c | 2 + core/sme/inc/csr_api.h | 1 + core/sme/src/csr/csr_api_roam.c | 11 +++ 13 files changed, 193 insertions(+), 15 deletions(-) diff --git a/components/mlme/core/inc/wlan_mlme_main.h b/components/mlme/core/inc/wlan_mlme_main.h index 96f84f33c4f4..5327bf94ec19 100644 --- a/components/mlme/core/inc/wlan_mlme_main.h +++ b/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 diff --git a/components/mlme/core/src/wlan_mlme_main.c b/components/mlme/core/src/wlan_mlme_main.c index 69f76624eb4b..956bee7bdf8a 100644 --- a/components/mlme/core/src/wlan_mlme_main.c +++ b/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; +} diff --git a/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c b/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c index 248086dd0f7c..34b1cafe193e 100644 --- a/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c +++ b/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; diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index 8fbd4c604308..2a444756f044 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/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", diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 67d3db821cc9..369170fc827c 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/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; diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index 39321e79f730..63ae7ea20bb4 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/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 diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 9efe83e49bb3..0d2153d3a7db 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/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 diff --git a/core/mac/src/pe/lim/lim_assoc_utils.c b/core/mac/src/pe/lim/lim_assoc_utils.c index 70b499e6639d..4a3abae743e9 100644 --- a/core/mac/src/pe/lim/lim_assoc_utils.c +++ b/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); +} + diff --git a/core/mac/src/pe/lim/lim_assoc_utils.h b/core/mac/src/pe/lim/lim_assoc_utils.h index 1b77cb4f46d9..226306f8ec75 100644 --- a/core/mac/src/pe/lim/lim_assoc_utils.h +++ b/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 */ diff --git a/core/mac/src/pe/lim/lim_process_deauth_frame.c b/core/mac/src/pe/lim/lim_process_deauth_frame.c index 6da9fb758cf3..b35b65ba048b 100644 --- a/core/mac/src/pe/lim/lim_process_deauth_frame.c +++ b/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); diff --git a/core/mac/src/pe/lim/lim_process_disassoc_frame.c b/core/mac/src/pe/lim/lim_process_disassoc_frame.c index 5ecf2f9fb93e..6a190fe78cf9 100644 --- a/core/mac/src/pe/lim/lim_process_disassoc_frame.c +++ b/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); diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h index bc45f5de0081..9cc5ecd1136c 100644 --- a/core/sme/inc/csr_api.h +++ b/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 { diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index b84f7db36c84..8e7bc404db82 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/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))