qcacmn: Fix scan with random address failed since wdev is connected

Reproduce steps:
1.	Connect from OSIF success, wdev->connected = true;
2.	Disconnect from target if and reassoc from OSIF happens back to
	back.
3.	Disconnect event is not sent to kernel, wdev->connected keeps
	true, isn't cleared.
4.	Connect from OSIF failed too, wdev->connected keeps true,  isn't
	cleared.
5.	Scan with random address failed since wdev->connected is true.

To fix it, if connect req was a reassoc req and received in not connected
state for race between disconnect from target if and reassoc connect from
OSIF, set reassoc_in_non_connected to send disconnect instead of
connect rsp to kernel to cleanup kernel flags like: wdev->connected.

change-Id: Ibbe38da14e9339b49589216250453b76c7387b57
CRs-Fixed: 3290496
This commit is contained in:
Jianmin Zhu
2022-09-16 15:12:56 +08:00
کامیت شده توسط Madan Koyyalamudi
والد 1f49ac1d70
کامیت fb43cc12b8
8فایلهای تغییر یافته به همراه150 افزوده شده و 11 حذف شده

مشاهده پرونده

@@ -1080,13 +1080,14 @@ QDF_STATUS osif_connect_handler(struct wlan_objmgr_vdev *vdev,
struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev);
QDF_STATUS status;
osif_nofl_info("%s(vdevid-%d): " QDF_MAC_ADDR_FMT " Connect with " QDF_MAC_ADDR_FMT " SSID \"%.*s\" is %s cm_id 0x%x cm_reason %d status_code %d is_reassoc %d",
osif_nofl_info("%s(vdevid-%d): " QDF_MAC_ADDR_FMT " Connect with " QDF_MAC_ADDR_FMT " SSID \"%.*s\" is %s cm_id 0x%x cm_reason %d status_code %d is_reassoc %d send discon %d",
osif_priv->wdev->netdev->name, rsp->vdev_id,
QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)),
QDF_MAC_ADDR_REF(rsp->bssid.bytes),
rsp->ssid.length, rsp->ssid.ssid,
rsp->connect_status ? "FAILURE" : "SUCCESS", rsp->cm_id,
rsp->reason, rsp->status_code, rsp->is_reassoc);
rsp->reason, rsp->status_code, rsp->is_reassoc,
rsp->send_disconnect);
osif_check_and_unlink_bss(vdev, osif_priv, rsp);
@@ -1097,8 +1098,34 @@ QDF_STATUS osif_connect_handler(struct wlan_objmgr_vdev *vdev,
}
osif_cm_connect_comp_ind(vdev, rsp, OSIF_PRE_USERSPACE_UPDATE);
/*
* To fix issue that scan with random address failed since wdev keeps
* connected, rsp->send_disconnect is added.
* Reproduce steps:
* 1. Connect from OSIF success, wdev->connected = true;
* 2. Disconnect from target if and reassoc from OSIF happens back to
* back.
* 3. Disconnect event is not sent to kernel, wdev->connected keeps
* true, isn't cleared.
* 4. Connect from OSIF failed too, wdev->connected keeps true, isn't
* cleared.
* 5. Scan with random address failed since wdev->connected is true.
*
* To fix it, if connect req was a reassoc req and received in not
* connected state for race between disconnect from target if and
* reassoc connect from OSIF, set reassoc_in_non_connected to send
* disconnect instead of connect rsp to kernel to cleanup kernel flags
* like: wdev->connected.
*/
if (rsp->is_reassoc)
osif_indicate_reassoc_results(vdev, osif_priv, rsp);
else if (rsp->send_disconnect &&
QDF_IS_STATUS_ERROR(rsp->connect_status))
osif_cm_indicate_disconnect(vdev, osif_priv->wdev->netdev,
WLAN_REASON_UNSPECIFIED,
false, NULL, 0,
qdf_mem_malloc_flags());
else
osif_indcate_connect_results(vdev, osif_priv, rsp);
osif_cm_connect_comp_ind(vdev, rsp, OSIF_POST_USERSPACE_UPDATE);

مشاهده پرونده

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2012-2015, 2020-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -81,7 +82,7 @@ rel_lock:
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
#ifdef WLAN_FEATURE_11BE_MLO
#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
static void
void
osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
struct net_device *dev,
enum ieee80211_reasoncode reason,
@@ -98,7 +99,7 @@ osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
}
}
#else /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
static void
void
osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
struct net_device *dev,
enum ieee80211_reasoncode reason,
@@ -128,7 +129,7 @@ osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
}
#endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
#else /* WLAN_FEATURE_11BE_MLO */
static void
void
osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
struct net_device *dev,
enum ieee80211_reasoncode reason,
@@ -139,7 +140,7 @@ osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
}
#endif /* WLAN_FEATURE_11BE_MLO */
#else
static void
void
osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
struct net_device *dev,
enum ieee80211_reasoncode reason,

مشاهده پرونده

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2012-2015,2020-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -134,4 +135,25 @@ osif_indicate_reassoc_results(struct wlan_objmgr_vdev *vdev,
QDF_STATUS osif_failed_candidate_handler(struct wlan_objmgr_vdev *vdev,
struct wlan_cm_connect_resp *rsp);
/**
* osif_cm_indicate_disconnect - notify osif that connection was dropped
*
* @vdev: pointer to vdev
* @dev: network device
* @reason: reason code for the disconnection, set it to 0 if unknown
* @locally_generated: disconnection was requested locally
* @ie: information elements of the deauth/disassoc frame (may be %NULL)
* @ie_len: length of IEs
* @gfp: allocation flags
*
* After it calls this function, the driver should enter an idle state
* and not try to connect to any AP any more.
*/
void
osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
struct net_device *dev,
enum ieee80211_reasoncode reason,
bool locally_generated, const u8 *ie,
size_t ie_len, gfp_t gfp);
#endif /* __OSIF_CM_RSP_H */

مشاهده پرونده

@@ -1340,6 +1340,15 @@ cm_handle_connect_req_in_non_init_state(struct cnx_mgr *cm_ctx,
struct cm_connect_req *cm_req,
enum wlan_cm_sm_state cm_state_substate)
{
if (cm_state_substate != WLAN_CM_S_CONNECTED &&
cm_is_connect_req_reassoc(&cm_req->req)) {
cm_req->req.reassoc_in_non_connected = true;
mlme_debug(CM_PREFIX_FMT "Reassoc received in %d state",
CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
cm_req->cm_id),
cm_state_substate);
}
switch (cm_state_substate) {
case WLAN_CM_S_ROAMING:
/* for FW roam/LFR3 remove the req from the list */
@@ -2236,11 +2245,69 @@ cm_clear_vdev_mlo_cap(struct wlan_objmgr_vdev *vdev)
{ }
#endif /*WLAN_FEATURE_11BE_MLO*/
/**
* cm_is_connect_id_reassoc_in_non_connected()
* @cm_ctx: connection manager context
* @cm_id: cm id
*
* If connect req is a reassoc req and received in not connected state
*
* Return: bool
*/
static bool cm_is_connect_id_reassoc_in_non_connected(struct cnx_mgr *cm_ctx,
wlan_cm_id cm_id)
{
qdf_list_node_t *cur_node = NULL, *next_node = NULL;
struct cm_req *cm_req;
uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
bool is_reassoc = false;
if (prefix != CONNECT_REQ_PREFIX)
return is_reassoc;
cm_req_lock_acquire(cm_ctx);
qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
while (cur_node) {
qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
cm_req = qdf_container_of(cur_node, struct cm_req, node);
if (cm_req->cm_id == cm_id) {
if (cm_req->connect_req.req.reassoc_in_non_connected)
is_reassoc = true;
cm_req_lock_release(cm_ctx);
return is_reassoc;
}
cur_node = next_node;
next_node = NULL;
}
cm_req_lock_release(cm_ctx);
return is_reassoc;
}
QDF_STATUS cm_notify_connect_complete(struct cnx_mgr *cm_ctx,
struct wlan_cm_connect_resp *resp)
{
enum wlan_cm_sm_state sm_state;
sm_state = cm_get_state(cm_ctx);
mlme_cm_connect_complete_ind(cm_ctx->vdev, resp);
mlo_sta_link_connect_notify(cm_ctx->vdev, resp);
/*
* If connect req was a reassoc req and was received in not connected
* state send disconnect instead of connect resp to kernel to cleanup
* kernel flags
*/
if (QDF_IS_STATUS_ERROR(resp->connect_status) &&
sm_state == WLAN_CM_S_INIT &&
cm_is_connect_id_reassoc_in_non_connected(cm_ctx, resp->cm_id)) {
resp->send_disconnect = true;
mlme_debug(CM_PREFIX_FMT "Set send disconnect to true to indicate disconnect instaed of connect resp",
CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
resp->cm_id));
}
mlme_cm_osif_connect_complete(cm_ctx->vdev, resp);
cm_if_mgr_inform_connect_complete(cm_ctx->vdev,
resp->connect_status);

مشاهده پرونده

@@ -1193,4 +1193,12 @@ void cm_set_candidate_custom_sort_cb(
qdf_list_t *list));
#endif
/**
* cm_is_connect_req_reassoc() - Is connect req for reassoc
* @req: connect req
*
* Return: void
*/
bool cm_is_connect_req_reassoc(struct wlan_cm_connect_req *req);
#endif /* __WLAN_CM_MAIN_API_H__ */

مشاهده پرونده

@@ -72,9 +72,7 @@ QDF_STATUS cm_check_and_prepare_roam_req(struct cnx_mgr *cm_ctx,
* Reject re-assoc unless freq along with prev bssid and one
* of bssid or bssid hint is present.
*/
if (!freq || qdf_is_macaddr_zero(&req->prev_bssid) ||
(qdf_is_macaddr_zero(&req->bssid) &&
qdf_is_macaddr_zero(&req->bssid_hint)))
if (!cm_is_connect_req_reassoc(req))
return QDF_STATUS_E_FAILURE;
wlan_vdev_get_bss_peer_mac(cm_ctx->vdev, &bssid);

مشاهده پرونده

@@ -1256,6 +1256,17 @@ void cm_fill_ml_partner_info(struct wlan_cm_connect_req *req,
}
#endif
bool cm_is_connect_req_reassoc(struct wlan_cm_connect_req *req)
{
if (!qdf_is_macaddr_zero(&req->prev_bssid) &&
(!qdf_is_macaddr_zero(&req->bssid) ||
!qdf_is_macaddr_zero(&req->bssid_hint)) &&
(req->chan_freq || req->chan_freq_hint))
return true;
return false;
}
bool cm_get_active_connect_req(struct wlan_objmgr_vdev *vdev,
struct wlan_cm_vdev_connect_req *req)
{

مشاهده پرونده

@@ -188,6 +188,7 @@ enum wlan_cm_source {
* for production.
* @is_wps_connection: if its wps connection
* @is_osen_connection: if its osen connection
* @reassoc_in_non_connected: if reassoc received in non connected
* @dot11mode_filter: dot11mode filter used to restrict connection to
* 11n/11ac/11ax.
* @sae_pwe: SAE mechanism for PWE derivation
@@ -216,7 +217,8 @@ struct wlan_cm_connect_req {
struct element_info scan_ie;
uint8_t force_rsne_override:1,
is_wps_connection:1,
is_osen_connection:1;
is_osen_connection:1,
reassoc_in_non_connected:1;
enum dot11_mode_filter dot11mode_filter;
uint8_t sae_pwe;
uint16_t ht_caps;
@@ -483,6 +485,8 @@ struct wlan_roam_sync_info {
* @is_reassoc: if response is for reassoc/roam
* @is_ft: is FT reassoc
* @is_assoc: if response is for assoc
* @send_disconnect: if disconnect needed to sent to kernel, for reassoc
* received in non connected state, this is to cleanup kernel
* @cm_id: Connect manager id
* @bssid: BSSID of the ap
* @ssid: SSID of the connection
@@ -502,7 +506,8 @@ struct wlan_cm_connect_resp {
is_osen_connection:1,
is_reassoc:1,
is_ft:1,
is_assoc:1;
is_assoc:1,
send_disconnect:1;
wlan_cm_id cm_id;
struct qdf_mac_addr bssid;
struct wlan_ssid ssid;