diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index 98527c6698..6324578486 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -116,6 +116,7 @@ typedef uint8_t tSirVersionString[SIR_VERSION_STRING_LEN]; (QOS_MAP_LEN_MIN + 2 * QOS_MAP_MAX_EX) #define NUM_CHAINS_MAX 2 +#define MAX_RSSI_AVOID_BSSID_LIST 10 /** * enum sir_conn_update_reason: Reason for conc connection update * @SIR_UPDATE_REASON_SET_OPER_CHAN: Set probable operating channel @@ -7426,4 +7427,21 @@ struct sir_peer_set_rx_blocksize { struct qdf_mac_addr peer_macaddr; uint32_t rx_block_ack_win_limit; }; + +/** + * struct sir_rssi_disallow_lst - Structure holding Rssi based avoid candidate + * list + * @node: Node pointer + * @bssid: BSSID of the AP + * @retry_delay: Retry delay received during last rejection in ms + * @ expected_rssi: RSSI at which STA can initate + * @time_during_rejection: Timestamp during last rejection in millisec + */ +struct sir_rssi_disallow_lst { + qdf_list_node_t node; + struct qdf_mac_addr bssid; + uint32_t retry_delay; + int8_t expected_rssi; + qdf_time_t time_during_rejection; +}; #endif /* __SIR_API_H */ diff --git a/core/mac/inc/sir_mac_prot_def.h b/core/mac/inc/sir_mac_prot_def.h index 60b8417702..b1a3c7d8c0 100644 --- a/core/mac/inc/sir_mac_prot_def.h +++ b/core/mac/inc/sir_mac_prot_def.h @@ -672,7 +672,11 @@ typedef enum eSirMacStatusCodes { eSIR_MAC_QOS_UNSPECIFIED_FAILURE_STATUS = 32, /* Unspecified, QoS-related failure */ eSIR_MAC_QAP_NO_BANDWIDTH_STATUS = 33, /* Association denied because QoS AP has insufficient bandwidth to handle another */ /* QoS STA */ - eSIR_MAC_XS_FRAME_LOSS_STATUS = 34, /* Association denied due to excessive frame loss rates and/or poor conditions on cur- */ + /* + * Association denied due to excessive frame loss rates + * and/or poor conditions/RSSI on cur channel + */ + eSIR_MAC_XS_FRAME_LOSS_POOR_CHANNEL_RSSI_STATUS = 34, /* rent operating channel */ eSIR_MAC_STA_QOS_NOT_SUPPORTED_STATUS = 35, /* Association (with QoS BSS) denied because the requesting STA does not support the */ /* QoS facility */ diff --git a/core/mac/src/include/parser_api.h b/core/mac/src/include/parser_api.h index 01f08419ed..6757b4474a 100644 --- a/core/mac/src/include/parser_api.h +++ b/core/mac/src/include/parser_api.h @@ -323,6 +323,7 @@ typedef struct sSirAssocRsp { #endif tDot11fIEvendor_vht_ie vendor_vht_ie; tDot11fIEOBSSScanParameters obss_scanparams; + tDot11fTLVrssi_assoc_rej rssi_assoc_rej; tSirQCNIE QCN_IE; tDot11fIEvendor_he_cap vendor_he_cap; tDot11fIEvendor_he_op vendor_he_op; diff --git a/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c b/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c index ba61c260a7..3da3236fd8 100644 --- a/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c +++ b/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c @@ -713,6 +713,13 @@ lim_process_assoc_rsp_frame(tpAniSirGlobal mac_ctx, else lim_stop_reassoc_retry_timer(mac_ctx); + if (eSIR_MAC_XS_FRAME_LOSS_POOR_CHANNEL_RSSI_STATUS == + assoc_rsp->statusCode && + assoc_rsp->rssi_assoc_rej.present) + lim_assoc_rej_add_to_rssi_based_reject_list(mac_ctx, + &assoc_rsp->rssi_assoc_rej, hdr->sa, + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info)); + if (assoc_rsp->statusCode != eSIR_MAC_SUCCESS_STATUS #ifdef WLAN_FEATURE_11W && (!session_entry->limRmfEnabled || diff --git a/core/mac/src/pe/lim/lim_utils.c b/core/mac/src/pe/lim/lim_utils.c index ee900a2d8a..e46fe3b367 100644 --- a/core/mac/src/pe/lim/lim_utils.c +++ b/core/mac/src/pe/lim/lim_utils.c @@ -7783,6 +7783,113 @@ error: } #endif +/** + * lim_assoc_rej_get_remaining_delta() - Get remaining time delta for + * the rssi based disallowed list entry + * @node: rssi based disallowed list entry + * + * Return: remaining delta, can be -ve if time has already expired. + */ +static inline int +lim_assoc_rej_get_remaining_delta(struct sir_rssi_disallow_lst *node) +{ + qdf_time_t cur_time; + uint32_t time_diff; + + cur_time = qdf_do_div(qdf_get_monotonic_boottime(), + QDF_MC_TIMER_TO_MS_UNIT); + time_diff = cur_time - node->time_during_rejection; + + return node->retry_delay - time_diff; +} + +/** + * lim_assoc_rej_rem_entry_with_lowest_delta() - Remove the entry + * with lowest time delta + * @list: rssi based rejected BSSID list + * + * Return: QDF_STATUS + */ +static QDF_STATUS +lim_assoc_rej_rem_entry_with_lowest_delta(qdf_list_t *list) +{ + struct sir_rssi_disallow_lst *oldest_node = NULL; + struct sir_rssi_disallow_lst *cur_node; + qdf_list_node_t *cur_list = NULL; + qdf_list_node_t *next_list = NULL; + + qdf_list_peek_front(list, &cur_list); + while (cur_list) { + cur_node = qdf_container_of(cur_list, + struct sir_rssi_disallow_lst, node); + if (!oldest_node || + (lim_assoc_rej_get_remaining_delta(oldest_node) > + lim_assoc_rej_get_remaining_delta(cur_node))) + oldest_node = cur_node; + + qdf_list_peek_next(list, cur_list, &next_list); + cur_list = next_list; + next_list = NULL; + } + + if (oldest_node) { + pe_debug("remove node %pM with lowest delta %d", + oldest_node->bssid.bytes, + lim_assoc_rej_get_remaining_delta(oldest_node)); + qdf_list_remove_node(list, &oldest_node->node); + qdf_mem_free(oldest_node); + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_E_INVAL; +} + +void lim_assoc_rej_add_to_rssi_based_reject_list(tpAniSirGlobal mac_ctx, + tDot11fTLVrssi_assoc_rej *rssi_assoc_rej, + tSirMacAddr bssid, int8_t rssi) +{ + struct sir_rssi_disallow_lst *entry; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + entry = qdf_mem_malloc(sizeof(*entry)); + if (!entry) { + pe_err("malloc failed for bssid entry"); + return; + } + + pe_debug("%pM: assoc resp rssi %d, delta rssi %d retry delay %d sec and list size %d", + bssid, rssi, rssi_assoc_rej->delta_rssi, + rssi_assoc_rej->retry_delay, + qdf_list_size(&mac_ctx->roam.rssi_disallow_bssid)); + + qdf_mem_copy(entry->bssid.bytes, + bssid, QDF_MAC_ADDR_SIZE); + entry->retry_delay = rssi_assoc_rej->retry_delay * + QDF_MC_TIMER_TO_MS_UNIT; + entry->expected_rssi = rssi + rssi_assoc_rej->delta_rssi; + entry->time_during_rejection = + qdf_do_div(qdf_get_monotonic_boottime(), + QDF_MC_TIMER_TO_MS_UNIT); + + if (qdf_list_size(&mac_ctx->roam.rssi_disallow_bssid) >= + MAX_RSSI_AVOID_BSSID_LIST) { + status = lim_assoc_rej_rem_entry_with_lowest_delta( + &mac_ctx->roam.rssi_disallow_bssid); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("Failed to remove entry with lowest delta"); + } + + if (QDF_IS_STATUS_SUCCESS(status)) + status = qdf_list_insert_back( + &mac_ctx->roam.rssi_disallow_bssid, + &entry->node); + + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to enqueue bssid entry"); + qdf_mem_free(entry); + } +} + void lim_decrement_pending_mgmt_count(tpAniSirGlobal mac_ctx) { qdf_spin_lock(&mac_ctx->sys.bbt_mgmt_lock); diff --git a/core/mac/src/pe/lim/lim_utils.h b/core/mac/src/pe/lim/lim_utils.h index 17c91878b8..29a3afe50c 100644 --- a/core/mac/src/pe/lim/lim_utils.h +++ b/core/mac/src/pe/lim/lim_utils.h @@ -1078,6 +1078,24 @@ static inline QDF_STATUS lim_populate_he_mcs_set(tpAniSirGlobal mac_ctx, #endif +/** + * lim_assoc_rej_add_to_rssi_based_reject_list() - Add BSSID to the rssi based + * rejection list + * @mac_ctx: mac ctx + * @rssi_assoc_rej: rssi assoc reject attribute + * @bssid : BSSID of the AP + * @rssi : RSSI of the assoc resp + * + * Add BSSID to the rssi based rejection list. Also if number + * of entries is greater than MAX_RSSI_AVOID_BSSID_LIST + * remove the entry with lowest time delta + * + * Return: void + */ +void lim_assoc_rej_add_to_rssi_based_reject_list(tpAniSirGlobal mac_ctx, + tDot11fTLVrssi_assoc_rej *rssi_assoc_rej, + tSirMacAddr bssid, int8_t rssi); + /** * lim_decrement_pending_mgmt_count: Decrement mgmt frame count * @mac_ctx: Pointer to global MAC structure diff --git a/core/mac/src/sys/legacy/src/utils/src/parser_api.c b/core/mac/src/sys/legacy/src/utils/src/parser_api.c index cb56e14efe..621fade679 100644 --- a/core/mac/src/sys/legacy/src/utils/src/parser_api.c +++ b/core/mac/src/sys/legacy/src/utils/src/parser_api.c @@ -2972,6 +2972,13 @@ sir_convert_assoc_resp_frame2_struct(tpAniSirGlobal pMac, sizeof(tDot11fIEvendor_he_op)); } + if (ar.MBO_IE.present && ar.MBO_IE.rssi_assoc_rej.present) { + qdf_mem_copy(&pAssocRsp->rssi_assoc_rej, + &ar.MBO_IE.rssi_assoc_rej, + sizeof(tDot11fTLVrssi_assoc_rej)); + pe_debug("Received Assoc Response with rssi based assoc rej"); + } + return eSIR_SUCCESS; } /* End sir_convert_assoc_resp_frame2_struct. */ diff --git a/core/sme/inc/csr_internal.h b/core/sme/inc/csr_internal.h index ef391b4816..7e116627c5 100644 --- a/core/sme/inc/csr_internal.h +++ b/core/sme/inc/csr_internal.h @@ -1009,6 +1009,7 @@ typedef struct tagCsrRoamStruct { uint8_t *pReassocResp; /* reassociation response from new AP */ uint16_t reassocRespLen; /* length of reassociation response */ qdf_mc_timer_t packetdump_timer; + qdf_list_t rssi_disallow_bssid; } tCsrRoamStruct; #define GET_NEXT_ROAM_ID(pRoamStruct) (((pRoamStruct)->nextRoamId + 1 == 0) ? \ diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 313f0f0c89..6bca5289c3 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -328,6 +328,8 @@ QDF_STATUS csr_open(tpAniSirGlobal pMac) (csr_ll_open(pMac->hHdd, &pMac->roam.peStatsReqList))) break; + qdf_list_create(&pMac->roam.rssi_disallow_bssid, + MAX_RSSI_AVOID_BSSID_LIST); } while (0); return status; @@ -379,12 +381,41 @@ QDF_STATUS csr_set_channels(tHalHandle hHal, tCsrConfigParam *pParam) return status; } +/** + * csr_assoc_rej_free_rssi_disallow_list() - Free the rssi diallowed + * BSSID entries and destroy the list + * @list: rssi based disallowed list entry + * + * Return: void + */ +static void csr_assoc_rej_free_rssi_disallow_list(qdf_list_t *list) +{ + QDF_STATUS status; + struct sir_rssi_disallow_lst *cur_node; + qdf_list_node_t *cur_lst = NULL, *next_lst = NULL; + + qdf_list_peek_front(list, &cur_lst); + while (cur_lst) { + qdf_list_peek_next(list, cur_lst, &next_lst); + cur_node = qdf_container_of(cur_lst, + struct sir_rssi_disallow_lst, node); + status = qdf_list_remove_node(list, cur_lst); + if (QDF_IS_STATUS_SUCCESS(status)) + qdf_mem_free(cur_node); + cur_lst = next_lst; + next_lst = NULL; + } + qdf_list_destroy(list); +} + QDF_STATUS csr_close(tpAniSirGlobal pMac) { QDF_STATUS status = QDF_STATUS_SUCCESS; tSmeCmd *saved_scan_cmd; csr_roam_close(pMac); + csr_assoc_rej_free_rssi_disallow_list( + &pMac->roam.rssi_disallow_bssid); csr_scan_close(pMac); csr_ll_close(&pMac->roam.statsClientReqList); csr_ll_close(&pMac->roam.peStatsReqList); diff --git a/core/sme/src/csr/csr_api_scan.c b/core/sme/src/csr/csr_api_scan.c index 07489434d2..1110d68b3a 100644 --- a/core/sme/src/csr/csr_api_scan.c +++ b/core/sme/src/csr/csr_api_scan.c @@ -5684,6 +5684,131 @@ static QDF_STATUS csr_parse_scan_list(tpAniSirGlobal mac_ctx, return status; } + +/** + * csr_remove_ap_due_to_rssi() - check if bss is present in + * list of BSSID which rejected Assoc due to RSSI + * @list: rssi based rejected BSS list + * @bss_descr: pointer to bss description + * + * Check if the time interval indicated in last Assoc reject + * has expired OR rssi has improved by margin indicated + * in last Assoc reject. If any of the condition match remove + * the AP from the avoid list, else do not try to conenct + * to the AP + * + * Return: true if connection cannot be tried with AP else false + */ +static bool csr_remove_ap_due_to_rssi(qdf_list_t *list, + tSirBssDescription *bss_descr) +{ + QDF_STATUS status; + struct sir_rssi_disallow_lst *cur_node = NULL; + qdf_list_node_t *cur_lst = NULL, *next_lst = NULL; + qdf_time_t cur_time; + uint32_t time_diff; + + if (!qdf_list_size(list)) + return false; + + cur_time = qdf_do_div(qdf_get_monotonic_boottime(), + QDF_MC_TIMER_TO_MS_UNIT); + + qdf_list_peek_front(list, &cur_lst); + while (cur_lst) { + cur_node = qdf_container_of(cur_lst, + struct sir_rssi_disallow_lst, node); + + qdf_list_peek_next(list, cur_lst, &next_lst); + + time_diff = cur_time - cur_node->time_during_rejection; + if ((time_diff > cur_node->retry_delay)) { + sme_debug("Remove %pM as time diff %d is greater retry delay %d", + cur_node->bssid.bytes, time_diff, + cur_node->retry_delay); + status = qdf_list_remove_node(list, cur_lst); + if (QDF_IS_STATUS_SUCCESS(status)) + qdf_mem_free(cur_node); + cur_lst = next_lst; + next_lst = NULL; + cur_node = NULL; + continue; + } + + if (!qdf_mem_cmp(cur_node->bssid.bytes, + bss_descr->bssId, QDF_MAC_ADDR_SIZE)) + break; + cur_lst = next_lst; + next_lst = NULL; + cur_node = NULL; + } + + if (cur_node) { + time_diff = cur_time - cur_node->time_during_rejection; + if (!(time_diff > cur_node->retry_delay || + bss_descr->rssi_raw >= cur_node->expected_rssi)) { + sme_err("Don't Attempt to connect %pM (time diff %d retry delay %d rssi %d expected rssi %d)", + cur_node->bssid.bytes, time_diff, + cur_node->retry_delay, bss_descr->rssi_raw, + cur_node->expected_rssi); + return true; + } + sme_debug("Remove %pM as time diff %d is greater retry delay %d or RSSI %d is greater than expected %d", + cur_node->bssid.bytes, time_diff, + cur_node->retry_delay, + bss_descr->rssi_raw, + cur_node->expected_rssi); + status = qdf_list_remove_node(list, cur_lst); + if (QDF_IS_STATUS_SUCCESS(status)) + qdf_mem_free(cur_node); + } + + return false; +} + +/** + * csr_filter_ap_due_to_rssi_reject() - filter the AP who has sent + * assoc reject due to RSSI if condition has not improved + * @mac_ctx: mac context + * @scan_list: candidate list for the connection + * + * Return: void + */ +static void csr_filter_ap_due_to_rssi_reject(tpAniSirGlobal mac_ctx, + tScanResultList *scan_list) +{ + tListElem *cur_entry; + tListElem *next_entry; + tCsrScanResult *scan_res; + bool remove; + + if (!scan_list || + !qdf_list_size(&mac_ctx->roam.rssi_disallow_bssid)) + return; + + csr_ll_lock(&scan_list->List); + + cur_entry = csr_ll_peek_head(&scan_list->List, LL_ACCESS_NOLOCK); + while (cur_entry) { + scan_res = GET_BASE_ADDR(cur_entry, tCsrScanResult, + Link); + next_entry = csr_ll_next(&scan_list->List, + cur_entry, LL_ACCESS_NOLOCK); + remove = csr_remove_ap_due_to_rssi( + &mac_ctx->roam.rssi_disallow_bssid, + &scan_res->Result.BssDescriptor); + if (remove) { + csr_ll_remove_entry(&scan_list->List, + cur_entry, LL_ACCESS_NOLOCK); + csr_free_scan_result_entry(mac_ctx, scan_res); + } + cur_entry = next_entry; + next_entry = NULL; + } + csr_ll_unlock(&scan_list->List); + +} + QDF_STATUS csr_scan_get_result(tpAniSirGlobal mac_ctx, tCsrScanResultFilter *pFilter, tScanResultHandle *results) @@ -5740,6 +5865,8 @@ QDF_STATUS csr_scan_get_result(tpAniSirGlobal mac_ctx, /* Fail or No one wants the result. */ csr_scan_result_purge(mac_ctx, (tScanResultHandle) ret_list); else { + if (pFilter) + csr_filter_ap_due_to_rssi_reject(mac_ctx, ret_list); if (!csr_ll_count(&ret_list->List)) { /* This mean that there is no match */ csr_ll_close(&ret_list->List);