1 /*
2  * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*
21  *
22  * This file lim_process_probe_rsp_frame.cc contains the code
23  * for processing Probe Response Frame.
24  * Author:        Chandra Modumudi
25  * Date:          03/01/02
26  * History:-
27  * Date           Modified by    Modification Information
28  * --------------------------------------------------------------------
29  *
30  */
31 
32 #include "wni_api.h"
33 #include "wni_cfg.h"
34 #include "ani_global.h"
35 #include "sch_api.h"
36 #include "utils_api.h"
37 #include "lim_api.h"
38 #include "lim_types.h"
39 #include "lim_utils.h"
40 #include "lim_assoc_utils.h"
41 #include "lim_prop_exts_utils.h"
42 #include "lim_ser_des_utils.h"
43 #include "lim_send_messages.h"
44 #include "lim_mlo.h"
45 #include "wlan_mlo_mgr_sta.h"
46 #include "parser_api.h"
47 
48 /**
49  * lim_validate_ie_information_in_probe_rsp_frame () - validates ie
50  * information in probe response.
51  * @mac_ctx: mac context
52  * @pRxPacketInfo: Rx packet info
53  *
54  * Return: 0 on success, one on failure
55  */
56 static QDF_STATUS
lim_validate_ie_information_in_probe_rsp_frame(struct mac_context * mac_ctx,uint8_t * pRxPacketInfo)57 lim_validate_ie_information_in_probe_rsp_frame(struct mac_context *mac_ctx,
58 				uint8_t *pRxPacketInfo)
59 {
60 	QDF_STATUS status = QDF_STATUS_SUCCESS;
61 	uint8_t *pframe;
62 	uint32_t nframe;
63 	uint32_t missing_rsn_bytes;
64 
65 	/*
66 	 * Validate a Probe response frame for malformed frame.
67 	 * If the frame is malformed then do not consider as it
68 	 * may cause problem fetching wrong IE values
69 	 */
70 
71 	if (WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo) <
72 		(SIR_MAC_B_PR_SSID_OFFSET + SIR_MAC_MIN_IE_LEN))
73 		return QDF_STATUS_E_FAILURE;
74 
75 	pframe = WMA_GET_RX_MPDU_DATA(pRxPacketInfo);
76 	nframe = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
77 	missing_rsn_bytes = 0;
78 
79 	status = sir_validate_and_rectify_ies(mac_ctx,
80 			pframe, nframe, &missing_rsn_bytes);
81 
82 	if (status == QDF_STATUS_SUCCESS)
83 		WMA_GET_RX_MPDU_LEN(pRxPacketInfo) += missing_rsn_bytes;
84 
85 	return status;
86 }
87 
88 /**
89  * lim_process_updated_ies_in_probe_rsp() -  process IEs of probe rsp frame
90  * @mac_ctx: pointer to global mac context
91  * @session_entry: pointer to pe session
92  * @probe_rsp: pointer to structure tSirProbeRespBeacon
93  *
94  * Return: void
95  */
96 static void
lim_process_updated_ies_in_probe_rsp(struct mac_context * mac_ctx,struct pe_session * session_entry,tSirProbeRespBeacon * probe_rsp)97 lim_process_updated_ies_in_probe_rsp(struct mac_context *mac_ctx,
98 				     struct pe_session *session_entry,
99 				     tSirProbeRespBeacon *probe_rsp)
100 {
101 	bool qos_enabled;
102 	bool wme_enabled;
103 	tpDphHashNode sta_ds;
104 	QDF_STATUS status;
105 
106 	if (session_entry->limMlmState == eLIM_MLM_LINK_ESTABLISHED_STATE) {
107 		/*
108 		 * Now Process EDCA Parameters, if EDCAParamSet
109 		 * count is different.
110 		 * -- While processing beacons in link established
111 		 * state if it is determined that
112 		 * QoS Info IE has a different count for EDCA Params,
113 		 * and EDCA IE is not present in beacon,
114 		 * then probe req is sent out to get the EDCA params.
115 		 */
116 		sta_ds = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER,
117 					    &session_entry->dph.dphHashTable);
118 
119 		limGetQosMode(session_entry, &qos_enabled);
120 		limGetWmeMode(session_entry, &wme_enabled);
121 		pe_debug("wmeEdcaPresent: %d wme_enabled: %d edcaPresent: %d, qos_enabled: %d edcaParams.qosInfo.count: %d schObject.gLimEdcaParamSetCount: %d",
122 			 probe_rsp->wmeEdcaPresent, wme_enabled,
123 			 probe_rsp->edcaPresent, qos_enabled,
124 			 probe_rsp->edcaParams.qosInfo.count,
125 			 session_entry->gLimEdcaParamSetCount);
126 
127 		if (((probe_rsp->wmeEdcaPresent && wme_enabled) ||
128 		     (probe_rsp->edcaPresent && qos_enabled)) &&
129 		    (probe_rsp->edcaParams.qosInfo.count !=
130 		     session_entry->gLimEdcaParamSetCount)) {
131 			status = sch_beacon_edca_process(mac_ctx,
132 						    &probe_rsp->edcaParams,
133 						    session_entry);
134 			if (QDF_IS_STATUS_ERROR(status)) {
135 				pe_err("EDCA param process error");
136 			} else if (sta_ds) {
137 				qdf_mem_copy(&sta_ds->qos.peer_edca_params,
138 					     &probe_rsp->edcaParams,
139 					     sizeof(probe_rsp->edcaParams));
140 				/*
141 				 * If needed, downgrade the
142 				 * EDCA parameters
143 				 */
144 				lim_set_active_edca_params(mac_ctx,
145 						session_entry->gLimEdcaParams,
146 						session_entry);
147 				lim_send_edca_params(mac_ctx,
148 					session_entry->gLimEdcaParamsActive,
149 					session_entry->vdev_id, false);
150 				sch_qos_concurrency_update();
151 			} else {
152 				pe_err("SelfEntry missing in Hash");
153 			}
154 		}
155 		if (session_entry->fWaitForProbeRsp) {
156 			pe_warn("Check probe resp for caps change");
157 			lim_detect_change_in_ap_capabilities(mac_ctx, probe_rsp,
158 							     session_entry,
159 							     false);
160 		}
161 	}
162 }
163 
lim_process_gen_probe_rsp_frame(struct mac_context * mac_ctx,struct pe_session * session_entry,uint8_t * bcn_probe,uint32_t len)164 void lim_process_gen_probe_rsp_frame(struct mac_context *mac_ctx,
165 				     struct pe_session *session_entry,
166 				     uint8_t *bcn_probe, uint32_t len)
167 {
168 	tSirProbeRespBeacon *probe_rsp;
169 	struct wlan_frame_hdr *header;
170 	QDF_STATUS status;
171 
172 	if (!bcn_probe || !len) {
173 		pe_err("bcn_probe is null or invalid len %d", len);
174 		return;
175 	}
176 
177 	if (!session_entry) {
178 		pe_err("session_entry is NULL");
179 		return;
180 	}
181 
182 	probe_rsp = qdf_mem_malloc(sizeof(tSirProbeRespBeacon));
183 	if (!probe_rsp) {
184 		pe_err("Unable to allocate memory");
185 		return;
186 	}
187 
188 	header = (struct wlan_frame_hdr *)(bcn_probe);
189 	pe_debug("Generate Probe Resp for cu (len %d): " QDF_MAC_ADDR_FMT,
190 		 len, QDF_MAC_ADDR_REF(header->i_addr3));
191 
192 	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
193 			   bcn_probe, len);
194 
195 	bcn_probe = (uint8_t *)(bcn_probe + sizeof(*header));
196 	len -= sizeof(*header);
197 
198 	status = sir_convert_probe_frame2_struct(mac_ctx,
199 						 bcn_probe, len, probe_rsp);
200 	if (QDF_IS_STATUS_ERROR(status) || !probe_rsp->ssidPresent) {
201 		pe_err("Parse error ProbeResponse, length=%d", len);
202 		qdf_mem_free(probe_rsp);
203 		return;
204 	}
205 
206 	lim_process_updated_ies_in_probe_rsp(mac_ctx, session_entry, probe_rsp);
207 	qdf_mem_free(probe_rsp);
208 }
209 
210 #ifdef WLAN_FEATURE_11BE_MLO
211 static
lim_update_mlo_mgr_prb_info(struct mac_context * mac_ctx,struct pe_session * session_entry,struct qdf_mac_addr * mac_addr,tpSirProbeRespBeacon probe_rsp)212 void lim_update_mlo_mgr_prb_info(struct mac_context *mac_ctx,
213 				 struct pe_session *session_entry,
214 				 struct qdf_mac_addr *mac_addr,
215 				 tpSirProbeRespBeacon probe_rsp)
216 {
217 	if (!(session_entry->lim_join_req &&
218 	      session_entry->lim_join_req->is_ml_probe_req_sent &&
219 	      probe_rsp->mlo_ie.mlo_ie_present))
220 		return;
221 
222 	lim_update_mlo_mgr_info(mac_ctx, session_entry->vdev, mac_addr,
223 				session_entry->lim_join_req->assoc_link_id,
224 				probe_rsp->chan_freq);
225 }
226 #else
227 static inline
lim_update_mlo_mgr_prb_info(struct mac_context * mac_ctx,struct pe_session * session_entry,struct qdf_mac_addr * mac_addr,tpSirProbeRespBeacon probe_rsp)228 void lim_update_mlo_mgr_prb_info(struct mac_context *mac_ctx,
229 				 struct pe_session *session_entry,
230 				 struct qdf_mac_addr *mac_addr,
231 				 tpSirProbeRespBeacon probe_rsp)
232 {
233 }
234 #endif
235 
236 #ifdef WLAN_FEATURE_11BE_MLO
237 static bool
lim_validate_probe_rsp_mld_addr(struct pe_session * session,tpSirProbeRespBeacon probe_rsp)238 lim_validate_probe_rsp_mld_addr(struct pe_session *session,
239 				tpSirProbeRespBeacon probe_rsp)
240 {
241 	QDF_STATUS status;
242 	struct wlan_mlo_ie *mlo_ie;
243 	struct qdf_mac_addr curr_bss_mld;
244 	struct qdf_mac_addr *probe_rsp_mld;
245 
246 	/* If ML-IE is not present or if the VDEV is not MLO return success */
247 	if (!probe_rsp->mlo_ie.mlo_ie_present ||
248 	    !wlan_vdev_mlme_is_mlo_vdev(session->vdev))
249 		return true;
250 
251 	status = wlan_vdev_get_bss_peer_mld_mac(session->vdev, &curr_bss_mld);
252 	if (QDF_IS_STATUS_ERROR(status)) {
253 		pe_err("Failed to fetch MLD address for ML VDEV");
254 		return false;
255 	}
256 
257 	mlo_ie = &probe_rsp->mlo_ie.mlo_ie;
258 	probe_rsp_mld =	(struct qdf_mac_addr *)mlo_ie->mld_mac_addr;
259 	if (qdf_is_macaddr_zero(probe_rsp_mld) ||
260 	    !qdf_is_macaddr_equal(probe_rsp_mld, &curr_bss_mld)) {
261 		pe_err("prb rsp MLD " QDF_MAC_ADDR_FMT ", bss peer MLD " QDF_MAC_ADDR_FMT,
262 		       QDF_MAC_ADDR_REF(probe_rsp_mld->bytes),
263 		       QDF_MAC_ADDR_REF(curr_bss_mld.bytes));
264 		return false;
265 	}
266 
267 	return true;
268 }
269 #else
270 static inline bool
lim_validate_probe_rsp_mld_addr(struct pe_session * session,tpSirProbeRespBeacon probe_rsp)271 lim_validate_probe_rsp_mld_addr(struct pe_session *session,
272 				tpSirProbeRespBeacon probe_rsp)
273 {
274 	return true;
275 }
276 #endif
277 /**
278  * lim_process_probe_rsp_frame() - processes received Probe Response frame
279  * @mac_ctx: Pointer to Global MAC structure
280  * @rx_Packet_info: A pointer to Buffer descriptor + associated PDUs
281  * @session_entry: Handle to the session.
282  *
283  * This function processes received Probe Response frame.
284  * Frames with out-of-order IEs are dropped.
285  * In case of IBSS, join 'success' makes MLM state machine
286  * transition into 'BSS started' state. This may have to change
287  * depending on supporting what kinda Authentication in IBSS.
288  *
289  * Return: None
290  */
291 void
lim_process_probe_rsp_frame(struct mac_context * mac_ctx,uint8_t * rx_Packet_info,struct pe_session * session_entry)292 lim_process_probe_rsp_frame(struct mac_context *mac_ctx, uint8_t *rx_Packet_info,
293 			    struct pe_session *session_entry)
294 {
295 	uint8_t *body;
296 	uint32_t frame_len = 0;
297 	tSirMacAddr current_bssid;
298 	tpSirMacMgmtHdr header;
299 	tSirProbeRespBeacon *probe_rsp;
300 	uint32_t chan_freq = 0;
301 	uint8_t bpcc;
302 	bool cu_flag = true;
303 	QDF_STATUS status;
304 
305 	if (!session_entry) {
306 		pe_err("session_entry is NULL");
307 		return;
308 	}
309 
310 	probe_rsp = qdf_mem_malloc(sizeof(tSirProbeRespBeacon));
311 	if (!probe_rsp) {
312 		pe_err("Unable to allocate memory");
313 		return;
314 	}
315 
316 	probe_rsp->ssId.length = 0;
317 	probe_rsp->wpa.length = 0;
318 
319 	header = WMA_GET_RX_MAC_HEADER(rx_Packet_info);
320 
321 	mac_ctx->lim.bss_rssi = (int8_t)
322 				WMA_GET_RX_RSSI_NORMALIZED(rx_Packet_info);
323 
324 	/* Validate IE information before processing Probe Response Frame */
325 	if (lim_validate_ie_information_in_probe_rsp_frame(mac_ctx,
326 				rx_Packet_info) !=
327 		QDF_STATUS_SUCCESS) {
328 		pe_err("Parse error ProbeResponse, length=%d", frame_len);
329 		goto mem_free;
330 	}
331 
332 	frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_Packet_info);
333 	/* Get pointer to Probe Response frame body */
334 	body = WMA_GET_RX_MPDU_DATA(rx_Packet_info);
335 		/* Enforce Mandatory IEs */
336 	if ((sir_convert_probe_frame2_struct(mac_ctx,
337 		body, frame_len, probe_rsp) == QDF_STATUS_E_FAILURE) ||
338 		!probe_rsp->ssidPresent) {
339 		pe_err("Parse error ProbeResponse, length=%d", frame_len);
340 		goto mem_free;
341 	}
342 
343 	if (!lim_validate_probe_rsp_mld_addr(session_entry, probe_rsp))
344 		goto mem_free;
345 
346 	lim_update_mlo_mgr_prb_info(mac_ctx, session_entry,
347 				    (struct qdf_mac_addr *)header->bssId,
348 				    probe_rsp);
349 
350 	lim_process_bcn_prb_rsp_t2lm(mac_ctx, session_entry, probe_rsp);
351 	lim_gen_link_specific_probe_rsp(mac_ctx, session_entry,
352 					probe_rsp,
353 					body,
354 					frame_len,
355 					mac_ctx->lim.bss_rssi);
356 
357 	if (mlo_is_mld_sta(session_entry->vdev)) {
358 		cu_flag = false;
359 		status = lim_get_bpcc_from_mlo_ie(probe_rsp, &bpcc);
360 		if (QDF_IS_STATUS_SUCCESS(status))
361 			cu_flag = lim_check_cu_happens(session_entry->vdev,
362 						       bpcc);
363 		lim_process_cu_for_probe_rsp(mac_ctx, session_entry,
364 					     body, frame_len);
365 	}
366 
367 	if (session_entry->limMlmState ==
368 			eLIM_MLM_WT_JOIN_BEACON_STATE) {
369 		/*
370 		 * Either Beacon/probe response is required.
371 		 * Hence store it in same buffer.
372 		 */
373 		if (session_entry->beacon) {
374 			qdf_mem_free(session_entry->beacon);
375 			session_entry->beacon = NULL;
376 			session_entry->bcnLen = 0;
377 		}
378 		session_entry->bcnLen =
379 			WMA_GET_RX_MPDU_LEN(rx_Packet_info);
380 		session_entry->beacon =
381 			qdf_mem_malloc(session_entry->bcnLen);
382 		if (!session_entry->beacon) {
383 			pe_err("No Memory to store beacon");
384 		} else {
385 			/*
386 			 * Store the whole ProbeRsp frame.
387 			 * This is sent to csr/hdd in join cnf response.
388 			 */
389 			qdf_mem_copy(session_entry->beacon,
390 				     WMA_GET_RX_MAC_HEADER
391 					     (rx_Packet_info),
392 				     session_entry->bcnLen);
393 		}
394 		/* STA in WT_JOIN_BEACON_STATE */
395 		mgmt_txrx_frame_hex_dump((uint8_t *)header,
396 					 WMA_GET_RX_MPDU_LEN(rx_Packet_info),
397 					 false);
398 		lim_check_and_announce_join_success(mac_ctx, probe_rsp,
399 						header,
400 						session_entry);
401 
402 	} else if (session_entry->limMlmState ==
403 		   eLIM_MLM_LINK_ESTABLISHED_STATE) {
404 		/*
405 		 * Check if this Probe Response is for
406 		 * our Probe Request sent upon reaching
407 		 * heart beat threshold
408 		 */
409 		sir_copy_mac_addr(current_bssid, session_entry->bssId);
410 		if (qdf_mem_cmp(current_bssid, header->bssId,
411 				sizeof(tSirMacAddr))) {
412 			goto mem_free;
413 		}
414 		if (!LIM_IS_CONNECTION_ACTIVE(session_entry)) {
415 			pe_warn("Recved Probe Resp from AP,AP-alive");
416 			if (probe_rsp->HTInfo.present) {
417 				chan_freq =
418 				    wlan_reg_legacy_chan_to_freq(mac_ctx->pdev,
419 								 probe_rsp->HTInfo.primaryChannel);
420 				lim_received_hb_handler(mac_ctx, chan_freq,
421 							session_entry);
422 			} else
423 				lim_received_hb_handler(mac_ctx,
424 							probe_rsp->chan_freq,
425 							session_entry);
426 		}
427 
428 		if (!cu_flag)
429 			goto mem_free;
430 
431 		lim_process_updated_ies_in_probe_rsp(mac_ctx, session_entry,
432 						     probe_rsp);
433 	}
434 
435 mem_free:
436 	qdf_mem_free(probe_rsp);
437 
438 	/* Ignore Probe Response frame in all other states */
439 	return;
440 }
441