From dac2e7867e8359ed3f775cb153e4fec67d44d61e Mon Sep 17 00:00:00 2001 From: Liangwei Dong Date: Tue, 16 Aug 2022 18:48:04 +0800 Subject: [PATCH] qcacld-3.0: Fix client disconnect from SAP in 2.4 GHz After SAP moved to 2.4 GHz HT 40 because of Radar detected in 5 GHz, the REF STA send SA Query to SAP. But the REF STA disabled HT 40 in 2.4 GHz(channelBondingMode24GHz=0), the REF STA switched to HT 20. The SA query OCI included op class 81 (20 MHz) from REF STA, the SAP check OCI failure (SAP op class 84, 40 MHz) by lim_check_oci_match and send deauth to REF STA. lim_check_oci_match only check the op_class equal or not with received OCI. If not equal, it will return false. According OCI doc, local transmit BW is not allowed greater than BW in OCI received from peer. Fix it by checking BW of local and peer instead of op class only. Change-Id: I62a477f8edabae31d07d6ec8ebb78ca76ca78792 CRs-Fixed: 3268105 --- .../mac/src/pe/lim/lim_process_action_frame.c | 22 ++++++++++--- .../src/pe/lim/lim_send_management_frames.c | 32 +++++++++++++++++-- core/mac/src/pe/lim/lim_utils.h | 4 ++- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/core/mac/src/pe/lim/lim_process_action_frame.c b/core/mac/src/pe/lim/lim_process_action_frame.c index 8a1211dfeb..3656f3a9cb 100644 --- a/core/mac/src/pe/lim/lim_process_action_frame.c +++ b/core/mac/src/pe/lim/lim_process_action_frame.c @@ -1214,6 +1214,9 @@ lim_check_oci_match(struct mac_context *mac, struct pe_session *pe_session, { const uint8_t *oci_ie; tDot11fIEoci self_oci, *peer_oci; + uint16_t peer_chan_width; + uint16_t local_peer_chan_width = 0; + uint8_t country_code[CDS_COUNTRY_CODE_LEN + 1]; if (!lim_is_self_and_peer_ocv_capable(mac, peer, pe_session)) return true; @@ -1233,18 +1236,29 @@ lim_check_oci_match(struct mac_context *mac, struct pe_session *pe_session, * Freq_seg_1_ch_num : 1 byte */ peer_oci = (tDot11fIEoci *)&oci_ie[2]; - lim_fill_oci_params(mac, pe_session, &self_oci); - if ((self_oci.op_class != peer_oci->op_class) || + wlan_reg_read_current_country(mac->psoc, country_code); + peer_chan_width = + wlan_reg_dmn_get_chanwidth_from_opclass_auto( + country_code, + peer_oci->prim_ch_num, + peer_oci->op_class); + + lim_fill_oci_params(mac, pe_session, &self_oci, peer, + &local_peer_chan_width); + if (((self_oci.op_class != peer_oci->op_class) && + (local_peer_chan_width > peer_chan_width)) || (self_oci.prim_ch_num != peer_oci->prim_ch_num) || (self_oci.freq_seg_1_ch_num != peer_oci->freq_seg_1_ch_num)) { - pe_err("OCI mismatch,self %d %d %d, peer %d %d %d", + pe_err("OCI mismatch,self %d %d %d %d, peer %d %d %d %d", self_oci.op_class, self_oci.prim_ch_num, self_oci.freq_seg_1_ch_num, + local_peer_chan_width, peer_oci->op_class, peer_oci->prim_ch_num, - peer_oci->freq_seg_1_ch_num); + peer_oci->freq_seg_1_ch_num, + peer_chan_width); return false; } diff --git a/core/mac/src/pe/lim/lim_send_management_frames.c b/core/mac/src/pe/lim/lim_send_management_frames.c index 79f9308e9f..42eda92f7f 100644 --- a/core/mac/src/pe/lim/lim_send_management_frames.c +++ b/core/mac/src/pe/lim/lim_send_management_frames.c @@ -5621,8 +5621,10 @@ lim_is_self_and_peer_ocv_capable(struct mac_context *mac, void lim_fill_oci_params(struct mac_context *mac, struct pe_session *session, - tDot11fIEoci *oci) + tDot11fIEoci *oci, uint8_t *peer, uint16_t *tx_chan_width) { + tpDphHashNode sta_ds; + uint16_t aid; uint8_t ch_offset; uint8_t prim_ch_num = wlan_reg_freq_to_chan(mac->pdev, session->curr_op_freq); @@ -5648,6 +5650,30 @@ lim_fill_oci_params(struct mac_context *mac, struct pe_session *session, oci->prim_ch_num = prim_ch_num; oci->freq_seg_1_ch_num = session->ch_center_freq_seg1; oci->present = 1; + if (tx_chan_width) + *tx_chan_width = ch_width_in_mhz(session->ch_width); + if (LIM_IS_STA_ROLE(session)) + return; + + if (!peer || !tx_chan_width) + return; + + sta_ds = dph_lookup_hash_entry(mac, peer, &aid, + &session->dph.dphHashTable); + if (!sta_ds) { + pe_nofl_debug("no find sta ds "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer)); + return; + } + if (WLAN_REG_IS_24GHZ_CH_FREQ(session->curr_op_freq)) { + if (*tx_chan_width > 20 && + !sta_ds->htSupportedChannelWidthSet) { + *tx_chan_width = 20; + pe_nofl_debug("peer no support ht40 in 2g, %d :"QDF_MAC_ADDR_FMT, + sta_ds->ch_width, + QDF_MAC_ADDR_REF(peer)); + } + } } /** @@ -5693,7 +5719,7 @@ QDF_STATUS lim_send_sa_query_request_frame(struct mac_context *mac, uint8_t *tra qdf_mem_copy(&frm.TransactionId.transId[0], &transId[0], 2); if (lim_is_self_and_peer_ocv_capable(mac, peer, pe_session)) - lim_fill_oci_params(mac, pe_session, &frm.oci); + lim_fill_oci_params(mac, pe_session, &frm.oci, NULL, NULL); nStatus = dot11f_get_packed_sa_query_req_size(mac, &frm, &nPayload); if (DOT11F_FAILED(nStatus)) { @@ -5825,7 +5851,7 @@ QDF_STATUS lim_send_sa_query_response_frame(struct mac_context *mac, SA query request transId */ qdf_mem_copy(&frm.TransactionId.transId[0], &transId[0], 2); if (lim_is_self_and_peer_ocv_capable(mac, peer, pe_session)) - lim_fill_oci_params(mac, pe_session, &frm.oci); + lim_fill_oci_params(mac, pe_session, &frm.oci, NULL, NULL); nStatus = dot11f_get_packed_sa_query_rsp_size(mac, &frm, &nPayload); if (DOT11F_FAILED(nStatus)) { diff --git a/core/mac/src/pe/lim/lim_utils.h b/core/mac/src/pe/lim/lim_utils.h index e7a71a7b62..086a1702bd 100644 --- a/core/mac/src/pe/lim/lim_utils.h +++ b/core/mac/src/pe/lim/lim_utils.h @@ -2907,12 +2907,14 @@ lim_is_self_and_peer_ocv_capable(struct mac_context *mac, * @mac: pointer to mac data * @session: pointer to pe session .* @oci: pointer of tDot11fIEoci + * @peer: peer mac address + * @tx_chan_width: tx channel width in MHz * * Return: void */ void lim_fill_oci_params(struct mac_context *mac, struct pe_session *session, - tDot11fIEoci *oci); + tDot11fIEoci *oci, uint8_t *peer, uint16_t *tx_chan_width); #ifdef WLAN_FEATURE_SAE /**