Просмотр исходного кода

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
Liangwei Dong 2 лет назад
Родитель
Сommit
dac2e7867e

+ 18 - 4
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;
 	}
 

+ 29 - 3
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)) {

+ 3 - 1
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
 /**