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
Цей коміт міститься в:

зафіксовано
Madan Koyyalamudi

джерело
1f49ac1d70
коміт
fb43cc12b8
@@ -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;
|
||||
|
Посилання в новій задачі
Заблокувати користувача