From 3a759ca4311de0e68b485abd1c0db01d956c46bf Mon Sep 17 00:00:00 2001 From: Liangwei Dong Date: Thu, 16 Mar 2023 17:00:25 +0800 Subject: [PATCH] qcacmn: Update candidate list before try next Some IOT APs only allow to connect if last 3 bytes of BSSID and self MAC is same. They create a new bssid on receiving unicast probe/auth req from STA and allow STA to connect to this matching BSSID only. So boost the matching BSSID to try to connect to this BSSID. And add logic to refresh the candidate list before next candidate try when the last candidate connect fail. Change-Id: I482e122c8c9febbab42f64013fbb78c266f49655 CRs-Fixed: 3432618 --- qdf/inc/qdf_util.h | 11 ++ .../core/src/wlan_cm_bss_scoring.c | 49 +++++- .../connection_mgr/core/src/wlan_cm_connect.c | 143 ++++++++++++++++-- .../connection_mgr/core/src/wlan_cm_main.h | 2 +- .../core/src/wlan_cm_main_api.h | 12 ++ .../connection_mgr/core/src/wlan_cm_util.c | 47 +++++- .../dispatcher/inc/wlan_cm_bss_score_param.h | 4 +- 7 files changed, 251 insertions(+), 17 deletions(-) diff --git a/qdf/inc/qdf_util.h b/qdf/inc/qdf_util.h index d24136b3dc..791b816b07 100644 --- a/qdf/inc/qdf_util.h +++ b/qdf/inc/qdf_util.h @@ -127,6 +127,17 @@ typedef __qdf_wait_queue_head_t qdf_wait_queue_head_t; (_a)[4] == 0xff && \ (_a)[5] == 0xff) +/** + * QDF_IS_LAST_3_BYTES_OF_MAC_SAME - check the last 3 bytes + * same or not for two mac addresses + * @mac1: mac address 1 + * @mac2: mac address 2 + */ +#define QDF_IS_LAST_3_BYTES_OF_MAC_SAME(mac1, mac2) \ + ((mac1)->bytes[3] == (mac2)->bytes[3] && \ + (mac1)->bytes[4] == (mac2)->bytes[4] && \ + (mac1)->bytes[5] == (mac2)->bytes[5]) + /* Get number of bits from the index bit */ #define QDF_GET_BITS(_val, _index, _num_bits) \ (((_val) >> (_index)) & ((1 << (_num_bits)) - 1)) diff --git a/umac/mlme/connection_mgr/core/src/wlan_cm_bss_scoring.c b/umac/mlme/connection_mgr/core/src/wlan_cm_bss_scoring.c index f7b4fc6286..8d5ebe1947 100644 --- a/umac/mlme/connection_mgr/core/src/wlan_cm_bss_scoring.c +++ b/umac/mlme/connection_mgr/core/src/wlan_cm_bss_scoring.c @@ -2299,6 +2299,40 @@ bool cm_is_bad_rssi_entry(struct scan_cache_entry *scan_entry, return false; } + +/** + * cm_update_bss_score_for_mac_addr_matching() - boost score based on mac + * address matching + * @scan_entry: pointer to scan cache entry + * @self_mac: pointer to bssid to be matched + * + * Some IOT APs only allow to connect if last 3 bytes of BSSID + * and self MAC is same. They create a new bssid on receiving + * unicast probe/auth req from STA and allow STA to connect to + * this matching BSSID only. So boost the matching BSSID to try + * to connect to this BSSID. + * + * Return: void + */ +static void +cm_update_bss_score_for_mac_addr_matching(struct scan_cache_node *scan_entry, + struct qdf_mac_addr *self_mac) +{ + struct qdf_mac_addr *scan_entry_bssid; + + if (!self_mac) + return; + scan_entry_bssid = &scan_entry->entry->bssid; + if (QDF_IS_LAST_3_BYTES_OF_MAC_SAME( + self_mac, scan_entry_bssid)) { + mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): boost bss score due to same last 3 byte match", + QDF_MAC_ADDR_REF( + scan_entry_bssid->bytes), + scan_entry->entry->channel.chan_freq); + scan_entry->entry->bss_score = + CM_BEST_CANDIDATE_MAX_BSS_SCORE; + } +} #else static inline bool cm_is_bad_rssi_entry(struct scan_cache_entry *scan_entry, @@ -2308,12 +2342,19 @@ bool cm_is_bad_rssi_entry(struct scan_cache_entry *scan_entry, { return false; } + +static void +cm_update_bss_score_for_mac_addr_matching(struct scan_cache_node *scan_entry, + struct qdf_mac_addr *self_mac) +{ +} #endif void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev, struct pcl_freq_weight_list *pcl_lst, qdf_list_t *scan_list, - struct qdf_mac_addr *bssid_hint) + struct qdf_mac_addr *bssid_hint, + struct qdf_mac_addr *self_mac) { struct scan_cache_node *scan_entry; qdf_list_node_t *cur_node = NULL, *next_node = NULL; @@ -2410,8 +2451,14 @@ void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev, scan_entry->entry->channel.chan_freq, scan_entry->entry->rssi_raw, scan_entry->entry->bss_score); + } else { + mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): denylist_action %d", + QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes), + scan_entry->entry->channel.chan_freq, + denylist_action); } + cm_update_bss_score_for_mac_addr_matching(scan_entry, self_mac); /* * The below logic is added to select the best candidate * amongst the denylisted candidates. This is done to diff --git a/umac/mlme/connection_mgr/core/src/wlan_cm_connect.c b/umac/mlme/connection_mgr/core/src/wlan_cm_connect.c index 9442d65f0d..1a4f1fa83b 100644 --- a/umac/mlme/connection_mgr/core/src/wlan_cm_connect.c +++ b/umac/mlme/connection_mgr/core/src/wlan_cm_connect.c @@ -1319,9 +1319,12 @@ static QDF_STATUS cm_update_mlo_filter(struct wlan_objmgr_pdev *pdev, } #endif -static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev, - struct cnx_mgr *cm_ctx, - struct cm_connect_req *cm_req) +static QDF_STATUS +cm_connect_fetch_candidates(struct wlan_objmgr_pdev *pdev, + struct cnx_mgr *cm_ctx, + struct cm_connect_req *cm_req, + qdf_list_t **fetched_candidate_list, + uint32_t *num_bss_found) { struct scan_filter *filter; uint32_t num_bss = 0; @@ -1331,10 +1334,6 @@ static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev, bool security_valid_for_6ghz; const uint8_t *rsnxe; - filter = qdf_mem_malloc(sizeof(*filter)); - if (!filter) - return QDF_STATUS_E_NOMEM; - rsnxe = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RSNXE, cm_req->req.assoc_ie.ptr, cm_req->req.assoc_ie.len); @@ -1356,6 +1355,10 @@ static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev, cm_req->req.chan_freq); return QDF_STATUS_E_INVAL; } + filter = qdf_mem_malloc(sizeof(*filter)); + if (!filter) + return QDF_STATUS_E_NOMEM; + cm_connect_prepare_scan_filter(pdev, cm_ctx, cm_req, filter, security_valid_for_6ghz); @@ -1367,7 +1370,7 @@ static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev, mlme_debug(CM_PREFIX_FMT "num_entries found %d", CM_PREFIX_REF(vdev_id, cm_req->cm_id), num_bss); } - + *num_bss_found = num_bss; op_mode = wlan_vdev_mlme_get_opmode(cm_ctx->vdev); if (num_bss && op_mode == QDF_STA_MODE && !cm_req->req.is_non_assoc_link) @@ -1375,8 +1378,27 @@ static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev, qdf_mem_free(filter); if (!candidate_list || !qdf_list_size(candidate_list)) { - QDF_STATUS status; + if (candidate_list) + wlan_scan_purge_results(candidate_list); + return QDF_STATUS_E_EMPTY; + } + *fetched_candidate_list = candidate_list; + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev, + struct cnx_mgr *cm_ctx, + struct cm_connect_req *cm_req) +{ + uint32_t num_bss = 0; + qdf_list_t *candidate_list = NULL; + uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev); + QDF_STATUS status; + + status = cm_connect_fetch_candidates(pdev, cm_ctx, cm_req, + &candidate_list, &num_bss); + if (QDF_IS_STATUS_ERROR(status)) { if (candidate_list) wlan_scan_purge_results(candidate_list); mlme_info(CM_PREFIX_FMT "no valid candidate found, num_bss %d scan_id %d", @@ -1406,9 +1428,100 @@ static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev, } cm_req->candidate_list = candidate_list; - return QDF_STATUS_SUCCESS; + return status; } +#ifdef CONN_MGR_ADV_FEATURE +static void cm_update_candidate_list(struct cnx_mgr *cm_ctx, + struct cm_connect_req *cm_req, + struct scan_cache_node *prev_candidate) +{ + struct wlan_objmgr_pdev *pdev; + uint32_t num_bss = 0; + qdf_list_t *candidate_list = NULL; + uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev); + QDF_STATUS status; + struct scan_cache_node *scan_entry; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + struct qdf_mac_addr *bssid; + bool found; + + pdev = wlan_vdev_get_pdev(cm_ctx->vdev); + if (!pdev) { + mlme_err(CM_PREFIX_FMT "Failed to find pdev", + CM_PREFIX_REF(vdev_id, cm_req->cm_id)); + return; + } + + status = cm_connect_fetch_candidates(pdev, cm_ctx, cm_req, + &candidate_list, &num_bss); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_debug(CM_PREFIX_FMT "failed to fetch bss: %d", + CM_PREFIX_REF(vdev_id, cm_req->cm_id), num_bss); + goto free_list; + } + + if (qdf_list_peek_front(candidate_list, &cur_node) != + QDF_STATUS_SUCCESS) { + mlme_err(CM_PREFIX_FMT"failed to peer front of candidate_list", + CM_PREFIX_REF(vdev_id, cm_req->cm_id)); + goto free_list; + } + + while (cur_node) { + qdf_list_peek_next(candidate_list, cur_node, &next_node); + + scan_entry = qdf_container_of(cur_node, struct scan_cache_node, + node); + bssid = &scan_entry->entry->bssid; + if (qdf_is_macaddr_zero(bssid) || + qdf_is_macaddr_broadcast(bssid)) + goto next; + found = cm_find_bss_from_candidate_list(cm_req->candidate_list, + bssid, NULL); + if (found) + goto next; + status = qdf_list_remove_node(candidate_list, cur_node); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT"failed to remove node for BSS "QDF_MAC_ADDR_FMT" from candidate list", + CM_PREFIX_REF(vdev_id, cm_req->cm_id), + QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes)); + goto free_list; + } + + status = qdf_list_insert_after(cm_req->candidate_list, + &scan_entry->node, + &prev_candidate->node); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT"failed to insert node for BSS "QDF_MAC_ADDR_FMT" from candidate list", + CM_PREFIX_REF(vdev_id, cm_req->cm_id), + QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes)); + util_scan_free_cache_entry(scan_entry->entry); + qdf_mem_free(scan_entry); + goto free_list; + } + prev_candidate = scan_entry; + mlme_debug(CM_PREFIX_FMT"insert new node BSS "QDF_MAC_ADDR_FMT" to existing candidate list", + CM_PREFIX_REF(vdev_id, cm_req->cm_id), + QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes)); +next: + cur_node = next_node; + next_node = NULL; + } + +free_list: + if (candidate_list) + wlan_scan_purge_results(candidate_list); +} +#else +static inline void +cm_update_candidate_list(struct cnx_mgr *cm_ctx, + struct cm_connect_req *cm_req, + struct scan_cache_node *prev_candidate) +{ +} +#endif + QDF_STATUS cm_if_mgr_inform_connect_complete(struct wlan_objmgr_vdev *vdev, QDF_STATUS connect_status) { @@ -1683,12 +1796,18 @@ static QDF_STATUS cm_get_valid_candidate(struct cnx_mgr *cm_ctx, * Get next candidate if prev_candidate is not NULL, else get * the first candidate */ - if (prev_candidate) + if (prev_candidate) { + /* Fetch new candidate list and append new entries to the + * current candidate list. + */ + cm_update_candidate_list(cm_ctx, &cm_req->connect_req, + prev_candidate); qdf_list_peek_next(cm_req->connect_req.candidate_list, &prev_candidate->node, &cur_node); - else + } else { qdf_list_peek_front(cm_req->connect_req.candidate_list, &cur_node); + } while (cur_node) { qdf_list_peek_next(cm_req->connect_req.candidate_list, diff --git a/umac/mlme/connection_mgr/core/src/wlan_cm_main.h b/umac/mlme/connection_mgr/core/src/wlan_cm_main.h index 1b24d752a1..96a40aa4ca 100644 --- a/umac/mlme/connection_mgr/core/src/wlan_cm_main.h +++ b/umac/mlme/connection_mgr/core/src/wlan_cm_main.h @@ -29,7 +29,7 @@ #include /* Max candidate/attempts to be tried to connect */ -#define CM_MAX_CONNECT_ATTEMPTS 5 +#define CM_MAX_CONNECT_ATTEMPTS 10 /* * Default connect timeout to consider 3 sec join timeout + 5 sec auth timeout + * 2 sec assoc timeout + 5 sec buffer for vdev related timeouts. diff --git a/umac/mlme/connection_mgr/core/src/wlan_cm_main_api.h b/umac/mlme/connection_mgr/core/src/wlan_cm_main_api.h index b3ef403c7e..a37f3093d7 100644 --- a/umac/mlme/connection_mgr/core/src/wlan_cm_main_api.h +++ b/umac/mlme/connection_mgr/core/src/wlan_cm_main_api.h @@ -305,6 +305,18 @@ cm_send_connect_start_fail(struct cnx_mgr *cm_ctx, struct cm_connect_req *req, enum wlan_cm_connect_fail_reason reason); +/** + * cm_find_bss_from_candidate_list() - get bss entry by bssid value + * @candidate_list: candidate list + * @bssid: bssid to find + * @entry_found: found bss entry + * + * Return: true if find bss entry with bssid + */ +bool cm_find_bss_from_candidate_list(qdf_list_t *candidate_list, + struct qdf_mac_addr *bssid, + struct scan_cache_node **entry_found); + #ifdef WLAN_POLICY_MGR_ENABLE /** * cm_hw_mode_change_resp() - HW mode change response diff --git a/umac/mlme/connection_mgr/core/src/wlan_cm_util.c b/umac/mlme/connection_mgr/core/src/wlan_cm_util.c index 649dd8c09d..46ba051f24 100644 --- a/umac/mlme/connection_mgr/core/src/wlan_cm_util.c +++ b/umac/mlme/connection_mgr/core/src/wlan_cm_util.c @@ -1373,6 +1373,46 @@ void cm_fill_ml_partner_info(struct wlan_cm_connect_req *req, } #endif +bool cm_find_bss_from_candidate_list(qdf_list_t *candidate_list, + struct qdf_mac_addr *bssid, + struct scan_cache_node **entry_found) +{ + struct scan_cache_node *scan_entry; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + struct qdf_mac_addr *bssid2; + + if (qdf_is_macaddr_zero(bssid) || + qdf_is_macaddr_broadcast(bssid)) + return false; + + if (qdf_list_peek_front(candidate_list, &cur_node) != + QDF_STATUS_SUCCESS) { + mlme_err("failed to peer front of candidate_list"); + return false; + } + + while (cur_node) { + qdf_list_peek_next(candidate_list, cur_node, &next_node); + + scan_entry = qdf_container_of(cur_node, struct scan_cache_node, + node); + bssid2 = &scan_entry->entry->bssid; + if (qdf_is_macaddr_zero(bssid2)) + goto next; + + if (qdf_is_macaddr_equal(bssid, bssid2)) { + if (entry_found) + *entry_found = scan_entry; + return true; + } +next: + cur_node = next_node; + next_node = NULL; + } + + return false; +} + bool cm_is_connect_req_reassoc(struct wlan_cm_connect_req *req) { if (!qdf_is_macaddr_zero(&req->prev_bssid) && @@ -1566,7 +1606,9 @@ void cm_calculate_scores(struct cnx_mgr *cm_ctx, pcl_lst = NULL; } } - wlan_cm_calculate_bss_score(pdev, pcl_lst, list, &filter->bssid_hint); + wlan_cm_calculate_bss_score(pdev, pcl_lst, list, &filter->bssid_hint, + (struct qdf_mac_addr *) + wlan_vdev_mlme_get_macaddr(cm_ctx->vdev)); if (pcl_lst) qdf_mem_free(pcl_lst); } @@ -1576,7 +1618,8 @@ void cm_calculate_scores(struct cnx_mgr *cm_ctx, struct wlan_objmgr_pdev *pdev, struct scan_filter *filter, qdf_list_t *list) { - wlan_cm_calculate_bss_score(pdev, NULL, list, &filter->bssid_hint); + wlan_cm_calculate_bss_score(pdev, NULL, list, &filter->bssid_hint, + NULL); /* * Custom sorting if enabled diff --git a/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_bss_score_param.h b/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_bss_score_param.h index 81bd9ebe59..0473870ff1 100644 --- a/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_bss_score_param.h +++ b/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_bss_score_param.h @@ -329,13 +329,15 @@ wlan_denylist_action_on_bssid(struct wlan_objmgr_pdev *pdev, * @scan_list: scan list, contains the input list and after the * func it will have sorted list * @bssid_hint: bssid hint + * @self_mac: connecting vdev self mac address * * Return: void */ void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev, struct pcl_freq_weight_list *pcl_lst, qdf_list_t *scan_list, - struct qdf_mac_addr *bssid_hint); + struct qdf_mac_addr *bssid_hint, + struct qdf_mac_addr *self_mac); /** * wlan_cm_init_score_config() - Init score INI and config