diff --git a/os_if/linux/scan/inc/wlan_cfg80211_scan.h b/os_if/linux/scan/inc/wlan_cfg80211_scan.h index 73a8c5a0e1..143adaa0f1 100644 --- a/os_if/linux/scan/inc/wlan_cfg80211_scan.h +++ b/os_if/linux/scan/inc/wlan_cfg80211_scan.h @@ -261,6 +261,34 @@ wlan_cfg80211_inform_bss_frame_data(struct wiphy *wiphy, void wlan_cfg80211_inform_bss_frame(struct wlan_objmgr_pdev *pdev, struct scan_cache_entry *scan_params); +/** + * wlan_cfg80211_get_bss() - Get the bss entry matching the chan, bssid and ssid + * @wiphy: wiphy + * @channel: channel of the BSS to find + * @bssid: bssid of the BSS to find + * @ssid: ssid of the BSS to find + * @ssid_len: ssid len of of the BSS to find + * + * The API is a wrapper to get bss from kernel matching the chan, + * bssid and ssid + * + * Return: bss structure if found else NULL + */ +struct cfg80211_bss *wlan_cfg80211_get_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + const u8 *ssid, size_t ssid_len); + +/* + * wlan_cfg80211_unlink_bss_list : flush bss from the kernel cache + * @pdev: Pointer to pdev + * @scan_entry: scan entry + * + * Return: bss which is unlinked from kernel cache + */ +void wlan_cfg80211_unlink_bss_list(struct wlan_objmgr_pdev *pdev, + struct scan_cache_entry *scan_entry); + /** * wlan_vendor_abort_scan() - API to vendor abort scan * @pdev: Pointer to pdev diff --git a/os_if/linux/scan/src/wlan_cfg80211_scan.c b/os_if/linux/scan/src/wlan_cfg80211_scan.c index 67c71581c0..011e1b6885 100644 --- a/os_if/linux/scan/src/wlan_cfg80211_scan.c +++ b/os_if/linux/scan/src/wlan_cfg80211_scan.c @@ -1936,6 +1936,57 @@ void wlan_cfg80211_inform_bss_frame(struct wlan_objmgr_pdev *pdev, qdf_mem_free(bss_data.mgmt); } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) && \ + !defined(WITH_BACKPORTS) && !defined(IEEE80211_PRIVACY) +struct cfg80211_bss *wlan_cfg80211_get_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, const u8 *ssid, + size_t ssid_len) +{ + return cfg80211_get_bss(wiphy, channel, bssid, + ssid, ssid_len, + WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); +} +#else +struct cfg80211_bss *wlan_cfg80211_get_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, const u8 *ssid, + size_t ssid_len) +{ + return cfg80211_get_bss(wiphy, channel, bssid, + ssid, ssid_len, + IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY_ANY); +} +#endif + +void wlan_cfg80211_unlink_bss_list(struct wlan_objmgr_pdev *pdev, + struct scan_cache_entry *scan_entry) +{ + struct cfg80211_bss *bss = NULL; + struct pdev_osif_priv *pdev_ospriv = wlan_pdev_get_ospriv(pdev); + struct wiphy *wiphy; + + if (!pdev_ospriv) { + cfg80211_err("os_priv is NULL"); + return; + } + + wiphy = pdev_ospriv->wiphy; + bss = wlan_cfg80211_get_bss(wiphy, NULL, scan_entry->bssid.bytes, + scan_entry->ssid.ssid, + scan_entry->ssid.length); + if (!bss) { + cfg80211_err("BSS %pM not found", scan_entry->bssid.bytes); + } else { + cfg80211_debug("cfg80211_unlink_bss called for BSSID %pM", + scan_entry->bssid.bytes); + cfg80211_unlink_bss(wiphy, bss); + wlan_cfg80211_put_bss(wiphy, bss); + } +} + #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) /* * wlan_scan_wiphy_set_max_sched_scans() - set maximum number of scheduled scans diff --git a/umac/scan/core/src/wlan_scan_cache_db.c b/umac/scan/core/src/wlan_scan_cache_db.c index 4278f95a4a..87a718297c 100644 --- a/umac/scan/core/src/wlan_scan_cache_db.c +++ b/umac/scan/core/src/wlan_scan_cache_db.c @@ -474,6 +474,8 @@ scm_update_mlme_info(struct scan_cache_entry *src, /** * scm_copy_info_from_dup_entry() - copy duplicate node info * to new scan entry + * @pdev: pdev ptr + * @scan_obj: scan obj ptr * @scan_db: scan database * @scan_params: new entry to be added * @scan_node: duplicate entry @@ -483,7 +485,9 @@ scm_update_mlme_info(struct scan_cache_entry *src, * Return: void */ static void -scm_copy_info_from_dup_entry(struct scan_dbs *scan_db, +scm_copy_info_from_dup_entry(struct wlan_objmgr_pdev *pdev, + struct wlan_scan_obj *scan_obj, + struct scan_dbs *scan_db, struct scan_cache_entry *scan_params, struct scan_cache_node *scan_node) { @@ -491,6 +495,29 @@ scm_copy_info_from_dup_entry(struct scan_dbs *scan_db, uint64_t time_gap; scan_entry = scan_node->entry; + + /* Update probe resp entry as well if AP is in hidden mode */ + if (scan_params->frm_subtype == MGMT_SUBTYPE_PROBE_RESP && + scan_entry->is_hidden_ssid) + scan_params->is_hidden_ssid = true; + + /* + * If AP changed its beacon from not having an SSID to showing it the + * kernel will drop the entry asumming that something is wrong with AP. + * This can result in connection failure while updating the bss during + * connection. So flush the hidden entry from kernel before indicating + * the new entry. + */ + if (scan_entry->is_hidden_ssid && + scan_params->frm_subtype == MGMT_SUBTYPE_BEACON && + !util_scan_is_null_ssid(&scan_params->ssid)) { + if (scan_obj->cb.unlink_bss) { + scm_debug("Hidden AP %pM switch to non-hidden SSID, So unlink the entry", + scan_entry->bssid.bytes); + scan_obj->cb.unlink_bss(pdev, scan_entry); + } + } + /* If old entry have the ssid but new entry does not */ if (util_scan_is_null_ssid(&scan_params->ssid) && scan_entry->ssid.length) { @@ -579,6 +606,8 @@ scm_copy_info_from_dup_entry(struct scan_dbs *scan_db, * scm_find_duplicate() - find duplicate entry, * if present, add input scan entry before it and delete * duplicate entry. otherwise add entry to tail + * @pdev: pdev ptr + * @scan_obj: scan obj ptr * @scan_db: scan db * @entry: input scan cache entry * @dup_node: node before which new entry to be added @@ -589,7 +618,9 @@ scm_copy_info_from_dup_entry(struct scan_dbs *scan_db, * Return: bool */ static bool -scm_find_duplicate(struct scan_dbs *scan_db, +scm_find_duplicate(struct wlan_objmgr_pdev *pdev, + struct wlan_scan_obj *scan_obj, + struct scan_dbs *scan_db, struct scan_cache_entry *entry, struct scan_cache_node **dup_node) { @@ -606,7 +637,8 @@ scm_find_duplicate(struct scan_dbs *scan_db, while (cur_node) { if (util_is_scan_entry_match(entry, cur_node->entry)) { - scm_copy_info_from_dup_entry(scan_db, entry, cur_node); + scm_copy_info_from_dup_entry(pdev, scan_obj, scan_db, + entry, cur_node); *dup_node = cur_node; return true; } @@ -661,7 +693,8 @@ static QDF_STATUS scm_add_update_entry(struct wlan_objmgr_psoc *psoc, scm_debug("CSA IE present for BSSID: %pM", scan_params->bssid.bytes); - is_dup_found = scm_find_duplicate(scan_db, scan_params, &dup_node); + is_dup_found = scm_find_duplicate(pdev, scan_obj, scan_db, scan_params, + &dup_node); if (scan_obj->cb.inform_beacon) scan_obj->cb.inform_beacon(pdev, scan_params); @@ -1328,6 +1361,9 @@ QDF_STATUS scm_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc, case SCAN_CB_TYPE_UPDATE_BCN: scan_obj->cb.update_beacon = cb; break; + case SCAN_CB_TYPE_UNLINK_BSS: + scan_obj->cb.unlink_bss = cb; + break; default: scm_err("invalid cb type %d", type); } diff --git a/umac/scan/core/src/wlan_scan_main.h b/umac/scan/core/src/wlan_scan_main.h index 88579ca4e3..852a00cb2f 100644 --- a/umac/scan/core/src/wlan_scan_main.h +++ b/umac/scan/core/src/wlan_scan_main.h @@ -462,10 +462,12 @@ struct scan_default_params { * struct scan_cb - nif/sif function callbacks * @inform_beacon: cb to indicate frame to OS * @update_beacon: cb to indicate frame to MLME + * @unlink_bss: cb to unlink bss from kernel cache */ struct scan_cb { update_beacon_cb inform_beacon; update_beacon_cb update_beacon; + update_beacon_cb unlink_bss; /* Define nif/sif function callbacks here */ }; diff --git a/umac/scan/dispatcher/inc/wlan_scan_public_structs.h b/umac/scan/dispatcher/inc/wlan_scan_public_structs.h index 83e2cba95c..057cefde2a 100644 --- a/umac/scan/dispatcher/inc/wlan_scan_public_structs.h +++ b/umac/scan/dispatcher/inc/wlan_scan_public_structs.h @@ -273,6 +273,7 @@ struct security_info { * @bssid: bssid * @mac_addr: mac address * @ssid: ssid + * @is_hidden_ssid: is AP having hidden ssid. * @seq_num: sequence number * @phy_mode: Phy mode of the AP * @avg_rssi: Average RSSI fof the AP @@ -309,6 +310,7 @@ struct scan_cache_entry { struct qdf_mac_addr bssid; struct qdf_mac_addr mac_addr; struct wlan_ssid ssid; + bool is_hidden_ssid; uint16_t seq_num; enum wlan_phymode phy_mode; int32_t avg_rssi; @@ -1139,12 +1141,14 @@ typedef void (*scan_event_handler) (struct wlan_objmgr_vdev *vdev, * enum scan_cb_type - update beacon cb type * @SCAN_CB_TYPE_INFORM_BCN: Calback to indicate beacon to OS * @SCAN_CB_TYPE_UPDATE_BCN: Calback to indicate beacon + * @SCAN_CB_TYPE_UNLINK_BSS: cb to unlink bss entry * to MLME and update MLME info * */ enum scan_cb_type { SCAN_CB_TYPE_INFORM_BCN, SCAN_CB_TYPE_UPDATE_BCN, + SCAN_CB_TYPE_UNLINK_BSS, }; /* Set PNO */ diff --git a/umac/scan/dispatcher/src/wlan_scan_utils_api.c b/umac/scan/dispatcher/src/wlan_scan_utils_api.c index 1836b43234..2bf43b8110 100644 --- a/umac/scan/dispatcher/src/wlan_scan_utils_api.c +++ b/umac/scan/dispatcher/src/wlan_scan_utils_api.c @@ -1097,6 +1097,7 @@ util_scan_gen_scan_entry(struct wlan_objmgr_pdev *pdev, if (util_scan_is_hidden_ssid(ssid)) { scan_entry->ie_list.ssid = NULL; + scan_entry->is_hidden_ssid = true; } else { qdf_mem_copy(scan_entry->ssid.ssid, ssid->ssid, ssid->ssid_len);