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