1 /*
2  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-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  * DOC: lim_send_frames_host_roam.c
22  *
23  * Send management frames for host based roaming
24  */
25 #include "sir_api.h"
26 #include "ani_global.h"
27 #include "sir_mac_prot_def.h"
28 #include "utils_api.h"
29 #include "lim_types.h"
30 #include "lim_utils.h"
31 #include "lim_security_utils.h"
32 #include "lim_prop_exts_utils.h"
33 #include "dot11f.h"
34 #include "sch_api.h"
35 #include "lim_send_messages.h"
36 #include "lim_assoc_utils.h"
37 #include "lim_ft.h"
38 #include "wni_cfg.h"
39 
40 #include "lim_ft_defs.h"
41 #include "lim_session.h"
42 #include "qdf_types.h"
43 #include "qdf_trace.h"
44 #include "cds_utils.h"
45 #include "sme_trace.h"
46 #include "rrm_api.h"
47 
48 #include "wma_types.h"
49 #include "wlan_utility.h"
50 
51 /**
52  * lim_send_reassoc_req_with_ft_ies_mgmt_frame() - Send Reassoc Req with FTIEs.
53  *
54  * @mac_ctx: Handle to mac context
55  * @mlm_reassoc_req: Original reassoc request
56  * @pe_session: PE session information
57  *
58  * It builds a reassoc request with FT IEs and sends it to AP through WMA.
59  * Then it creates assoc request and stores it for sending after join
60  * confirmation.
61  *
62  * Return: None
63  */
lim_send_reassoc_req_with_ft_ies_mgmt_frame(struct mac_context * mac_ctx,tLimMlmReassocReq * mlm_reassoc_req,struct pe_session * pe_session)64 void lim_send_reassoc_req_with_ft_ies_mgmt_frame(struct mac_context *mac_ctx,
65 	tLimMlmReassocReq *mlm_reassoc_req,
66 	struct pe_session *pe_session)
67 {
68 	tDot11fReAssocRequest *frm;
69 	uint16_t caps;
70 	uint8_t *frame;
71 	uint32_t bytes, payload, status;
72 	uint8_t qos_enabled, wme_enabled, wsm_enabled;
73 	void *packet;
74 	QDF_STATUS qdf_status;
75 	uint8_t power_caps_populated = false;
76 	uint16_t ft_ies_length = 0;
77 	uint8_t *body;
78 	uint16_t add_ie_len;
79 	uint8_t *add_ie;
80 	const uint8_t *wps_ie = NULL;
81 	uint8_t tx_flag = 0;
82 	uint8_t vdev_id = 0;
83 	bool vht_enabled = false;
84 	tpSirMacMgmtHdr mac_hdr;
85 	struct mlme_legacy_priv *mlme_priv;
86 	int ret;
87 	tDot11fIEExtCap extr_ext_cap;
88 	QDF_STATUS sir_status;
89 	bool extr_ext_flag = true;
90 	uint32_t ie_offset = 0;
91 	tDot11fIEExtCap bcn_ext_cap;
92 	uint8_t *bcn_ie = NULL;
93 	uint32_t bcn_ie_len = 0;
94 	uint8_t *p_ext_cap = NULL;
95 
96 	if (!pe_session)
97 		return;
98 
99 	mlme_priv = wlan_vdev_mlme_get_ext_hdl(pe_session->vdev);
100 	if (!mlme_priv)
101 		return;
102 
103 	vdev_id = pe_session->vdev_id;
104 
105 	/* check this early to avoid unnecessary operation */
106 	if (!pe_session->pLimReAssocReq)
107 		return;
108 
109 	frm = qdf_mem_malloc(sizeof(*frm));
110 	if (!frm)
111 		goto err;
112 
113 	add_ie_len = pe_session->pLimReAssocReq->addIEAssoc.length;
114 	add_ie = pe_session->pLimReAssocReq->addIEAssoc.addIEdata;
115 	pe_debug("called in state: %d", pe_session->limMlmState);
116 
117 	qdf_mem_zero((uint8_t *) frm, sizeof(*frm));
118 
119 	if (add_ie_len && pe_session->is_ext_caps_present) {
120 		qdf_mem_zero((uint8_t *)&extr_ext_cap,
121 			     sizeof(tDot11fIEExtCap));
122 		sir_status = lim_strip_extcap_update_struct(
123 				mac_ctx, add_ie, &add_ie_len, &extr_ext_cap);
124 		if (QDF_STATUS_SUCCESS != sir_status) {
125 			extr_ext_flag = false;
126 			pe_debug("Unable to Stripoff ExtCap IE from Assoc Req");
127 		} else {
128 			struct s_ext_cap *p_ext_cap = (struct s_ext_cap *)
129 							extr_ext_cap.bytes;
130 
131 			if (p_ext_cap->interworking_service)
132 				p_ext_cap->qos_map = 1;
133 			extr_ext_cap.num_bytes =
134 				lim_compute_ext_cap_ie_length(&extr_ext_cap);
135 			extr_ext_flag = (extr_ext_cap.num_bytes > 0);
136 		}
137 	} else {
138 		pe_debug("No addn IE or peer doesn't support addnIE for Assoc Req");
139 		extr_ext_flag = false;
140 	}
141 	caps = mlm_reassoc_req->capabilityInfo;
142 #if defined(FEATURE_WLAN_WAPI)
143 	/*
144 	 * According to WAPI standard:
145 	 * 7.3.1.4 Capability Information field
146 	 * In WAPI, non-AP STAs within an ESS set the Privacy subfield
147 	 * to 0 in transmitted Association or Reassociation management
148 	 * frames. APs ignore the Privacy subfield within received
149 	 * Association and Reassociation management frames.
150 	 */
151 	if (pe_session->encryptType == eSIR_ED_WPI)
152 		((tSirMacCapabilityInfo *) &caps)->privacy = 0;
153 #endif
154 	swap_bit_field16(caps, (uint16_t *) &frm->Capabilities);
155 
156 	frm->ListenInterval.interval = mlm_reassoc_req->listenInterval;
157 
158 	/*
159 	 * Get the old bssid of the older AP.
160 	 * The previous ap bssid is stored in the FT Session
161 	 * while creating the PE FT Session for reassociation.
162 	 */
163 	qdf_mem_copy((uint8_t *)frm->CurrentAPAddress.mac,
164 			pe_session->prev_ap_bssid, sizeof(tSirMacAddr));
165 
166 	populate_dot11f_ssid2(pe_session, &frm->SSID);
167 	populate_dot11f_supp_rates(mac_ctx, POPULATE_DOT11F_RATES_OPERATIONAL,
168 		&frm->SuppRates, pe_session);
169 
170 	qos_enabled = (pe_session->limQosEnabled) &&
171 		      SIR_MAC_GET_QOS(pe_session->limReassocBssCaps);
172 
173 	wme_enabled = (pe_session->limWmeEnabled) &&
174 		      LIM_BSS_CAPS_GET(WME, pe_session->limReassocBssQosCaps);
175 
176 	wsm_enabled = (pe_session->limWsmEnabled) && wme_enabled &&
177 		      LIM_BSS_CAPS_GET(WSM, pe_session->limReassocBssQosCaps);
178 
179 	if (pe_session->lim11hEnable &&
180 	    pe_session->spectrumMgtEnabled) {
181 		power_caps_populated = true;
182 
183 		populate_dot11f_power_caps(mac_ctx, &frm->PowerCaps,
184 					   LIM_REASSOC, pe_session);
185 		populate_dot11f_supp_channels(mac_ctx, &frm->SuppChannels,
186 			LIM_REASSOC, pe_session);
187 	}
188 	if (mac_ctx->rrm.rrmPEContext.rrmEnable &&
189 	    SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) {
190 		if (power_caps_populated == false) {
191 			power_caps_populated = true;
192 			populate_dot11f_power_caps(mac_ctx, &frm->PowerCaps,
193 				LIM_REASSOC, pe_session);
194 		}
195 	}
196 
197 	if (qos_enabled)
198 		populate_dot11f_qos_caps_station(mac_ctx, pe_session,
199 						&frm->QOSCapsStation);
200 
201 	populate_dot11f_ext_supp_rates(mac_ctx,
202 		POPULATE_DOT11F_RATES_OPERATIONAL, &frm->ExtSuppRates,
203 		pe_session);
204 
205 	if (mac_ctx->rrm.rrmPEContext.rrmEnable &&
206 	    SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps))
207 		populate_dot11f_rrm_ie(mac_ctx, &frm->RRMEnabledCap, pe_session);
208 
209 	/*
210 	 * Ideally this should be enabled for 11r also. But 11r does
211 	 * not follow the usual norm of using the Opaque object
212 	 * for rsnie and fties. Instead we just add the rsnie and fties
213 	 * at the end of the pack routine for 11r.
214 	 * This should ideally! be fixed.
215 	 */
216 	/*
217 	 * The join request *should* contain zero or one of the WPA and RSN
218 	 * IEs.  The payload send along with the request is a
219 	 * 'struct join_req'; the IE portion is held inside a 'tSirRSNie':
220 	 *
221 	 *     typedef struct sSirRSNie
222 	 *     {
223 	 *         uint16_t       length;
224 	 *         uint8_t        rsnIEdata[WLAN_MAX_IE_LEN+2];
225 	 *     } tSirRSNie, *tpSirRSNie;
226 	 *
227 	 * So, we should be able to make the following two calls harmlessly,
228 	 * since they do nothing if they don't find the given IE in the
229 	 * bytestream with which they're provided.
230 	 *
231 	 * The net effect of this will be to faithfully transmit whatever
232 	 * security IE is in the join request.
233 
234 	 * However, if we're associating for the purpose of WPS
235 	 * enrollment, and we've been configured to indicate that by
236 	 * eliding the WPA or RSN IE, we just skip this:
237 	 */
238 	if (!pe_session->is11Rconnection) {
239 		if (add_ie_len && add_ie)
240 			wps_ie = limGetWscIEPtr(mac_ctx, add_ie, add_ie_len);
241 		if (!wps_ie) {
242 			populate_dot11f_rsn_opaque(mac_ctx,
243 				&(pe_session->pLimReAssocReq->rsnIE),
244 				&frm->RSNOpaque);
245 			populate_dot11f_wpa_opaque(mac_ctx,
246 				&(pe_session->pLimReAssocReq->rsnIE),
247 				&frm->WPAOpaque);
248 		}
249 #ifdef FEATURE_WLAN_ESE
250 		if (mlme_priv->connect_info.cckm_ie_len) {
251 			populate_dot11f_ese_cckm_opaque(mac_ctx,
252 				&mlme_priv->connect_info,
253 				&frm->ESECckmOpaque);
254 		}
255 #endif
256 	}
257 #ifdef FEATURE_WLAN_ESE
258 	/*
259 	 * ESE Version IE will be included in re-association request
260 	 * when ESE is enabled on DUT through ini and it is also
261 	 * advertised by the peer AP to which we are trying to
262 	 * associate to.
263 	 */
264 	if (pe_session->is_ese_version_ie_present &&
265 		mac_ctx->mlme_cfg->lfr.ese_enabled)
266 		populate_dot11f_ese_version(&frm->ESEVersion);
267 	/* For ESE Associations fill the ESE IEs */
268 	if (wlan_cm_get_ese_assoc(mac_ctx->pdev, vdev_id)) {
269 #ifndef FEATURE_DISABLE_RM
270 		populate_dot11f_ese_rad_mgmt_cap(&frm->ESERadMgmtCap);
271 #endif
272 	}
273 #endif /* FEATURE_WLAN_ESE */
274 
275 	/* include WME EDCA IE as well */
276 	if (wme_enabled) {
277 		populate_dot11f_wmm_info_station_per_session(mac_ctx,
278 			pe_session, &frm->WMMInfoStation);
279 		if (wsm_enabled)
280 			populate_dot11f_wmm_caps(&frm->WMMCaps);
281 #ifdef FEATURE_WLAN_ESE
282 		if (wlan_cm_get_ese_assoc(mac_ctx->pdev, vdev_id)) {
283 			uint32_t phymode;
284 			uint8_t rate;
285 
286 			populate_dot11f_re_assoc_tspec(mac_ctx, frm,
287 				pe_session);
288 
289 			/*
290 			 * Populate the TSRS IE if TSPEC is included in
291 			 * the reassoc request
292 			 */
293 			lim_get_phy_mode(mac_ctx, &phymode, pe_session);
294 			if (phymode == WNI_CFG_PHY_MODE_11G ||
295 			    phymode == WNI_CFG_PHY_MODE_11A)
296 				rate = TSRS_11AG_RATE_6MBPS;
297 			else
298 				rate = TSRS_11B_RATE_5_5MBPS;
299 
300 			if (mlme_priv->connect_info.ese_tspec_info.numTspecs)
301 			{
302 				struct ese_tsrs_ie tsrs_ie;
303 
304 				tsrs_ie.tsid = 0;
305 				tsrs_ie.rates[0] = rate;
306 				populate_dot11_tsrsie(mac_ctx, &tsrs_ie,
307 					&frm->ESETrafStrmRateSet,
308 					sizeof(uint8_t));
309 			}
310 		}
311 #endif
312 	}
313 
314 	if (pe_session->htCapability &&
315 	    mac_ctx->lim.htCapabilityPresentInBeacon) {
316 		populate_dot11f_ht_caps(mac_ctx, pe_session, &frm->HTCaps);
317 	}
318 	if (pe_session->pLimReAssocReq->bssDescription.mdiePresent &&
319 	    (mlme_priv->connect_info.ft_info.add_mdie)
320 #if defined FEATURE_WLAN_ESE
321 	    && !wlan_cm_get_ese_assoc(mac_ctx->pdev, vdev_id)
322 #endif
323 	    ) {
324 		populate_mdie(mac_ctx, &frm->MobilityDomain,
325 			pe_session->pLimReAssocReq->bssDescription.mdie);
326 	}
327 	if (pe_session->vhtCapability &&
328 	    pe_session->vhtCapabilityPresentInBeacon) {
329 		pe_debug("Populate VHT IEs in Re-Assoc Request");
330 		populate_dot11f_vht_caps(mac_ctx, pe_session, &frm->VHTCaps);
331 		vht_enabled = true;
332 		populate_dot11f_ext_cap(mac_ctx, vht_enabled, &frm->ExtCap,
333 			pe_session);
334 	}
335 	if (!vht_enabled &&
336 			pe_session->is_vendor_specific_vhtcaps) {
337 		pe_debug("Populate Vendor VHT IEs in Re-Assoc Request");
338 		frm->vendor_vht_ie.present = 1;
339 		frm->vendor_vht_ie.sub_type =
340 			pe_session->vendor_specific_vht_ie_sub_type;
341 		frm->vendor_vht_ie.VHTCaps.present = 1;
342 		populate_dot11f_vht_caps(mac_ctx, pe_session,
343 				&frm->vendor_vht_ie.VHTCaps);
344 		vht_enabled = true;
345 	}
346 
347 	if (lim_is_session_he_capable(pe_session)) {
348 		pe_debug("Populate HE IEs");
349 		populate_dot11f_he_caps(mac_ctx, pe_session,
350 					&frm->he_cap);
351 		populate_dot11f_he_6ghz_cap(mac_ctx, pe_session,
352 					    &frm->he_6ghz_band_cap);
353 	}
354 	/*
355 	 * Extcap IE now support variable length, merge Extcap IE from addn_ie
356 	 * may change the frame size. Therefore, MUST merge ExtCap IE before
357 	 * dot11f get packed payload size.
358 	 */
359 	if (extr_ext_flag)
360 		lim_merge_extcap_struct(&frm->ExtCap, &extr_ext_cap, true);
361 
362 	/* Clear the bits in EXTCAP IE if AP not advertise it in beacon */
363 	if (frm->ExtCap.present && pe_session->is_ext_caps_present) {
364 		ie_offset = DOT11F_FF_TIMESTAMP_LEN +
365 				DOT11F_FF_BEACONINTERVAL_LEN +
366 				DOT11F_FF_CAPABILITIES_LEN;
367 
368 		qdf_mem_zero((uint8_t *)&bcn_ext_cap, sizeof(tDot11fIEExtCap));
369 		if (pe_session->beacon && (pe_session->bcnLen >
370 		    (ie_offset + sizeof(struct wlan_frame_hdr)))) {
371 			bcn_ie = pe_session->beacon + ie_offset +
372 						sizeof(struct wlan_frame_hdr);
373 			bcn_ie_len = pe_session->bcnLen - ie_offset -
374 						sizeof(struct wlan_frame_hdr);
375 			p_ext_cap = (uint8_t *)wlan_get_ie_ptr_from_eid(
376 							DOT11F_EID_EXTCAP,
377 							bcn_ie, bcn_ie_len);
378 			lim_update_extcap_struct(mac_ctx, p_ext_cap,
379 						 &bcn_ext_cap);
380 			lim_merge_extcap_struct(&frm->ExtCap, &bcn_ext_cap,
381 						false);
382 		}
383 		/*
384 		 * TWT extended capabilities should be populated after the
385 		 * intersection of beacon caps and self caps is done because
386 		 * the bits for TWT are unique to STA and AP and cannot be
387 		 * intersected.
388 		 */
389 		populate_dot11f_twt_extended_caps(mac_ctx, pe_session,
390 						  &frm->ExtCap);
391 	}
392 
393 	/*
394 	 * Do unpack to populate the add_ie buffer to frm structure
395 	 * before packing the frm structure. In this way, the IE ordering
396 	 * which the latest 802.11 spec mandates is maintained.
397 	 */
398 	if (add_ie_len) {
399 		ret = dot11f_unpack_re_assoc_request(mac_ctx, add_ie,
400 						     add_ie_len,
401 						     frm, true);
402 		if (DOT11F_FAILED(ret)) {
403 			pe_err("unpack failed, ret: 0x%x", ret);
404 			goto end;
405 		}
406 	}
407 
408 	if (lim_is_session_eht_capable(pe_session)) {
409 		pe_debug("Populate EHT IEs");
410 		populate_dot11f_eht_caps(mac_ctx, pe_session, &frm->eht_cap);
411 	}
412 
413 	status = dot11f_get_packed_re_assoc_request_size(mac_ctx, frm,
414 			&payload);
415 	if (DOT11F_FAILED(status)) {
416 		pe_err("Failure in size calculation (0x%08x)", status);
417 		/* We'll fall back on the worst case scenario: */
418 		payload = sizeof(tDot11fReAssocRequest);
419 	} else if (DOT11F_WARNED(status)) {
420 		pe_warn("Warnings in size calculation (0x%08x)", status);
421 	}
422 
423 	bytes = payload + sizeof(tSirMacMgmtHdr);
424 
425 	pe_debug("FT IE Reassoc Req %d",
426 		 mlme_priv->connect_info.ft_info.reassoc_ie_len);
427 
428 	if (pe_session->is11Rconnection)
429 		ft_ies_length = mlme_priv->connect_info.ft_info.reassoc_ie_len;
430 
431 	qdf_status = cds_packet_alloc((uint16_t) bytes + ft_ies_length,
432 				 (void **)&frame, (void **)&packet);
433 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
434 		pe_session->limMlmState = pe_session->limPrevMlmState;
435 		MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_MLM_STATE,
436 				 pe_session->peSessionId,
437 				 pe_session->limMlmState));
438 		pe_err("Failed to alloc memory %d", bytes);
439 		goto end;
440 	}
441 	/* Paranoia: */
442 	qdf_mem_zero(frame, bytes + ft_ies_length);
443 
444 	pe_debug("BSSID: "QDF_MAC_ADDR_FMT,
445 		 QDF_MAC_ADDR_REF(pe_session->limReAssocbssId));
446 	/* Next, we fill out the buffer descriptor: */
447 	lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME,
448 		SIR_MAC_MGMT_REASSOC_REQ, pe_session->limReAssocbssId,
449 		pe_session->self_mac_addr);
450 	mac_hdr = (tpSirMacMgmtHdr) frame;
451 	/* That done, pack the ReAssoc Request: */
452 	status = dot11f_pack_re_assoc_request(mac_ctx, frm, frame +
453 					       sizeof(tSirMacMgmtHdr),
454 					       payload, &payload);
455 	if (DOT11F_FAILED(status)) {
456 		pe_err("Failure in pack (0x%08x)", status);
457 		cds_packet_free((void *)packet);
458 		goto end;
459 	} else if (DOT11F_WARNED(status)) {
460 		pe_warn("Warnings in pack (0x%08x)", status);
461 	}
462 
463 	pe_debug("*** Sending Re-Assoc Request length: %d %d to",
464 		       bytes, payload);
465 
466 	if (pe_session->is11Rconnection &&
467 	    mlme_priv->connect_info.ft_info.reassoc_ie_len) {
468 		int i = 0;
469 
470 		body = frame + bytes;
471 		for (i = 0; i < ft_ies_length; i++) {
472 			*body =
473 			   mlme_priv->connect_info.ft_info.reassoc_ft_ie[i];
474 			body++;
475 		}
476 		payload += ft_ies_length;
477 	}
478 	pe_debug("Re-assoc Req Frame is:");
479 	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
480 			   (uint8_t *) frame, (bytes + ft_ies_length));
481 
482 	if ((pe_session->ftPEContext.pFTPreAuthReq) &&
483 	    (!wlan_reg_is_24ghz_ch_freq(
484 	     pe_session->ftPEContext.pFTPreAuthReq->pre_auth_channel_freq)))
485 		tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME;
486 	else if (wlan_reg_is_5ghz_ch_freq(pe_session->curr_op_freq) ||
487 		 pe_session->opmode == QDF_P2P_CLIENT_MODE ||
488 		 pe_session->opmode == QDF_P2P_GO_MODE)
489 		tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME;
490 
491 	if (pe_session->assoc_req) {
492 		qdf_mem_free(pe_session->assoc_req);
493 		pe_session->assoc_req = NULL;
494 		pe_session->assocReqLen = 0;
495 	}
496 
497 	pe_session->assoc_req = qdf_mem_malloc(payload);
498 	if (pe_session->assoc_req) {
499 		/*
500 		 * Store the Assoc request. This is sent to csr/hdd in
501 		 * join cnf response.
502 		 */
503 		qdf_mem_copy(pe_session->assoc_req,
504 			     frame + sizeof(tSirMacMgmtHdr), payload);
505 		pe_session->assocReqLen = payload;
506 	}
507 
508 	MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT,
509 			 pe_session->peSessionId, mac_hdr->fc.subType));
510 	lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_REASSOC_START_EVENT,
511 			      pe_session, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS);
512 	lim_diag_mgmt_tx_event_report(mac_ctx, mac_hdr,
513 				      pe_session, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS);
514 	qdf_status = wma_tx_frame(mac_ctx, packet,
515 				(uint16_t) (bytes + ft_ies_length),
516 				TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7,
517 				lim_tx_complete, frame, tx_flag, vdev_id,
518 				0, RATEID_DEFAULT, 0);
519 	MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE,
520 		       pe_session->peSessionId, qdf_status));
521 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
522 		pe_err("Failed to send Re-Assoc Request: %X!", qdf_status);
523 	}
524 
525 end:
526 	qdf_mem_free(frm);
527 err:
528 	/* Free up buffer allocated for mlmAssocReq */
529 	qdf_mem_free(mlm_reassoc_req);
530 	pe_session->pLimMlmReassocReq = NULL;
531 
532 }
533 
534 /**
535  * lim_send_retry_reassoc_req_frame() - Retry for reassociation
536  * @mac: Global MAC Context
537  * @pMlmReassocReq: Request buffer to be sent
538  * @pe_session: PE Session
539  *
540  * Return: None
541  */
lim_send_retry_reassoc_req_frame(struct mac_context * mac,tLimMlmReassocReq * pMlmReassocReq,struct pe_session * pe_session)542 void lim_send_retry_reassoc_req_frame(struct mac_context *mac,
543 				      tLimMlmReassocReq *pMlmReassocReq,
544 				      struct pe_session *pe_session)
545 {
546 	tLimMlmReassocCnf mlmReassocCnf;        /* keep sme */
547 	tLimMlmReassocReq *pTmpMlmReassocReq = NULL;
548 
549 	if (!pTmpMlmReassocReq) {
550 		pTmpMlmReassocReq = qdf_mem_malloc(sizeof(tLimMlmReassocReq));
551 		if (!pTmpMlmReassocReq)
552 			goto end;
553 		qdf_mem_copy(pTmpMlmReassocReq, pMlmReassocReq,
554 			     sizeof(tLimMlmReassocReq));
555 	}
556 	/* Prepare and send Reassociation request frame */
557 	/* start reassoc timer. */
558 	mac->lim.lim_timers.gLimReassocFailureTimer.sessionId =
559 		pe_session->peSessionId;
560 	/* Start reassociation failure timer */
561 	MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TIMER_ACTIVATE,
562 			 pe_session->peSessionId, eLIM_REASSOC_FAIL_TIMER));
563 	if (tx_timer_activate(&mac->lim.lim_timers.gLimReassocFailureTimer)
564 	    != TX_SUCCESS) {
565 		/* Could not start reassoc failure timer. */
566 		/* Log error */
567 		pe_err("could not start Reassociation failure timer");
568 		/* Return Reassoc confirm with */
569 		/* Resources Unavailable */
570 		mlmReassocCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE;
571 		mlmReassocCnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE;
572 		goto end;
573 	}
574 
575 	lim_send_reassoc_req_with_ft_ies_mgmt_frame(mac, pTmpMlmReassocReq,
576 						    pe_session);
577 	return;
578 
579 end:
580 	/* Free up buffer allocated for reassocReq */
581 	if (pMlmReassocReq) {
582 		qdf_mem_free(pMlmReassocReq);
583 		pMlmReassocReq = NULL;
584 	}
585 	if (pTmpMlmReassocReq) {
586 		qdf_mem_free(pTmpMlmReassocReq);
587 		pTmpMlmReassocReq = NULL;
588 	}
589 	mlmReassocCnf.resultCode = eSIR_SME_FT_REASSOC_FAILURE;
590 	mlmReassocCnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE;
591 	/* Update PE session Id */
592 	mlmReassocCnf.sessionId = pe_session->peSessionId;
593 
594 	lim_post_sme_message(mac, LIM_MLM_REASSOC_CNF,
595 			     (uint32_t *) &mlmReassocCnf);
596 }
597 
598 /**
599  * lim_send_reassoc_req_mgmt_frame() - Send the reassociation frame
600  * @mac: Global MAC Context
601  * @pMlmReassocReq: Reassociation request buffer to be sent
602  * @pe_session: PE Session
603  *
604  * Return: None
605  */
lim_send_reassoc_req_mgmt_frame(struct mac_context * mac,tLimMlmReassocReq * pMlmReassocReq,struct pe_session * pe_session)606 void lim_send_reassoc_req_mgmt_frame(struct mac_context *mac,
607 				tLimMlmReassocReq *pMlmReassocReq,
608 				struct pe_session *pe_session)
609 {
610 	tDot11fReAssocRequest *frm;
611 	uint16_t caps;
612 	uint8_t *pFrame;
613 	uint32_t nBytes, nPayload, nStatus;
614 	uint8_t fQosEnabled, fWmeEnabled, fWsmEnabled;
615 	void *pPacket;
616 	QDF_STATUS qdf_status;
617 	uint16_t nAddIELen;
618 	uint8_t *pAddIE;
619 	const uint8_t *wpsIe = NULL;
620 	uint8_t txFlag = 0;
621 	uint8_t PowerCapsPopulated = false;
622 	uint8_t smeSessionId = 0;
623 	bool isVHTEnabled = false;
624 	tpSirMacMgmtHdr pMacHdr;
625 	int ret;
626 	tDot11fIEExtCap extr_ext_cap;
627 	QDF_STATUS sir_status;
628 	bool extr_ext_flag = true;
629 	uint32_t ie_offset = 0;
630 	tDot11fIEExtCap bcn_ext_cap;
631 	uint8_t *bcn_ie = NULL;
632 	uint32_t bcn_ie_len = 0;
633 	uint8_t *p_ext_cap = NULL;
634 	enum rateid min_rid = RATEID_DEFAULT;
635 
636 	if (!pe_session)
637 		return;
638 
639 	smeSessionId = pe_session->smeSessionId;
640 	if (!pe_session->pLimReAssocReq)
641 		return;
642 
643 	frm = qdf_mem_malloc(sizeof(*frm));
644 	if (!frm)
645 		goto err;
646 	nAddIELen = pe_session->pLimReAssocReq->addIEAssoc.length;
647 	pAddIE = pe_session->pLimReAssocReq->addIEAssoc.addIEdata;
648 
649 	qdf_mem_zero((uint8_t *) frm, sizeof(*frm));
650 
651 	if (nAddIELen && pe_session->is_ext_caps_present) {
652 		qdf_mem_zero((uint8_t *)&extr_ext_cap,
653 			     sizeof(tDot11fIEExtCap));
654 		sir_status = lim_strip_extcap_update_struct(
655 					mac, pAddIE, &nAddIELen, &extr_ext_cap);
656 		if (QDF_STATUS_SUCCESS != sir_status) {
657 			extr_ext_flag = false;
658 			pe_debug("Unable to Stripoff ExtCap IE from Assoc Req");
659 		} else {
660 			struct s_ext_cap *p_ext_cap = (struct s_ext_cap *)
661 							extr_ext_cap.bytes;
662 
663 			if (p_ext_cap->interworking_service)
664 				p_ext_cap->qos_map = 1;
665 			extr_ext_cap.num_bytes =
666 				lim_compute_ext_cap_ie_length(&extr_ext_cap);
667 			extr_ext_flag = (extr_ext_cap.num_bytes > 0);
668 		}
669 	} else {
670 		pe_debug("No addn IE or peer doesn't support addnIE for Assoc Req");
671 		extr_ext_flag = false;
672 	}
673 
674 	caps = pMlmReassocReq->capabilityInfo;
675 #if defined(FEATURE_WLAN_WAPI)
676 	/*
677 	 * CR: 262463 :
678 	 * According to WAPI standard:
679 	 * 7.3.1.4 Capability Information field
680 	 * In WAPI, non-AP STAs within an ESS set the Privacy subfield to 0 in
681 	 * transmitted. Association or Reassociation management frames. APs
682 	 * ignore the Privacy subfield within received Association and
683 	 * Reassociation management frames.
684 	 */
685 	if (pe_session->encryptType == eSIR_ED_WPI)
686 		((tSirMacCapabilityInfo *) &caps)->privacy = 0;
687 #endif
688 	swap_bit_field16(caps, (uint16_t *) &frm->Capabilities);
689 
690 	frm->ListenInterval.interval = pMlmReassocReq->listenInterval;
691 
692 	qdf_mem_copy((uint8_t *) frm->CurrentAPAddress.mac,
693 		     (uint8_t *) pe_session->bssId, 6);
694 
695 	populate_dot11f_ssid2(pe_session, &frm->SSID);
696 	populate_dot11f_supp_rates(mac, POPULATE_DOT11F_RATES_OPERATIONAL,
697 				   &frm->SuppRates, pe_session);
698 
699 	fQosEnabled = (pe_session->limQosEnabled) &&
700 		      SIR_MAC_GET_QOS(pe_session->limReassocBssCaps);
701 
702 	fWmeEnabled = (pe_session->limWmeEnabled) &&
703 		     LIM_BSS_CAPS_GET(WME, pe_session->limReassocBssQosCaps);
704 
705 	fWsmEnabled = (pe_session->limWsmEnabled) && fWmeEnabled &&
706 		     LIM_BSS_CAPS_GET(WSM, pe_session->limReassocBssQosCaps);
707 
708 	if (pe_session->lim11hEnable &&
709 	    pe_session->spectrumMgtEnabled) {
710 		PowerCapsPopulated = true;
711 		populate_dot11f_power_caps(mac, &frm->PowerCaps, LIM_REASSOC,
712 					   pe_session);
713 		populate_dot11f_supp_channels(mac, &frm->SuppChannels,
714 				LIM_REASSOC, pe_session);
715 	}
716 	if (mac->rrm.rrmPEContext.rrmEnable &&
717 	    SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) {
718 		if (PowerCapsPopulated == false) {
719 			PowerCapsPopulated = true;
720 			populate_dot11f_power_caps(mac, &frm->PowerCaps,
721 						   LIM_REASSOC, pe_session);
722 		}
723 	}
724 
725 	if (fQosEnabled)
726 		populate_dot11f_qos_caps_station(mac, pe_session,
727 						&frm->QOSCapsStation);
728 
729 	populate_dot11f_ext_supp_rates(mac, POPULATE_DOT11F_RATES_OPERATIONAL,
730 				       &frm->ExtSuppRates, pe_session);
731 
732 	if (mac->rrm.rrmPEContext.rrmEnable &&
733 	    SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps))
734 		populate_dot11f_rrm_ie(mac, &frm->RRMEnabledCap, pe_session);
735 	/* The join request *should* contain zero or one of the WPA and RSN */
736 	/* IEs.  The payload send along with the request is a */
737 	/* 'struct join_req'; the IE portion is held inside a 'tSirRSNie': */
738 
739 	/*     typedef struct sSirRSNie */
740 	/*     { */
741 	/*         uint16_t       length; */
742 	/*         uint8_t        rsnIEdata[WLAN_MAX_IE_LEN+2]; */
743 	/*     } tSirRSNie, *tpSirRSNie; */
744 
745 	/* So, we should be able to make the following two calls harmlessly, */
746 	/* since they do nothing if they don't find the given IE in the */
747 	/* bytestream with which they're provided. */
748 
749 	/* The net effect of this will be to faithfully transmit whatever */
750 	/* security IE is in the join request. */
751 
752 	/**However*, if we're associating for the purpose of WPS */
753 	/* enrollment, and we've been configured to indicate that by */
754 	/* eliding the WPA or RSN IE, we just skip this: */
755 	if (nAddIELen && pAddIE)
756 		wpsIe = limGetWscIEPtr(mac, pAddIE, nAddIELen);
757 	if (!wpsIe) {
758 		populate_dot11f_rsn_opaque(mac,
759 				&(pe_session->pLimReAssocReq->rsnIE),
760 				&frm->RSNOpaque);
761 		populate_dot11f_wpa_opaque(mac,
762 				&(pe_session->pLimReAssocReq->rsnIE),
763 				&frm->WPAOpaque);
764 #if defined(FEATURE_WLAN_WAPI)
765 		populate_dot11f_wapi_opaque(mac,
766 					    &(pe_session->pLimReAssocReq->
767 					      rsnIE), &frm->WAPIOpaque);
768 #endif /* defined(FEATURE_WLAN_WAPI) */
769 	}
770 	/* include WME EDCA IE as well */
771 	if (fWmeEnabled) {
772 		populate_dot11f_wmm_info_station_per_session(mac,
773 				pe_session, &frm->WMMInfoStation);
774 
775 		if (fWsmEnabled)
776 			populate_dot11f_wmm_caps(&frm->WMMCaps);
777 	}
778 
779 	if (pe_session->htCapability &&
780 	    mac->lim.htCapabilityPresentInBeacon) {
781 		populate_dot11f_ht_caps(mac, pe_session, &frm->HTCaps);
782 	}
783 	if (pe_session->vhtCapability &&
784 	    pe_session->vhtCapabilityPresentInBeacon) {
785 		pe_warn("Populate VHT IEs in Re-Assoc Request");
786 		populate_dot11f_vht_caps(mac, pe_session, &frm->VHTCaps);
787 		isVHTEnabled = true;
788 	}
789 	populate_dot11f_ext_cap(mac, isVHTEnabled, &frm->ExtCap, pe_session);
790 
791 	if (lim_is_session_he_capable(pe_session)) {
792 		pe_debug("Populate HE IEs");
793 		populate_dot11f_he_caps(mac, pe_session,
794 					&frm->he_cap);
795 		populate_dot11f_he_6ghz_cap(mac, pe_session,
796 					    &frm->he_6ghz_band_cap);
797 	}
798 
799 	if (lim_is_session_eht_capable(pe_session)) {
800 		pe_debug("Populate EHT IEs");
801 		populate_dot11f_eht_caps(mac, pe_session, &frm->eht_cap);
802 	}
803 	/*
804 	 * Extcap IE now support variable length, merge Extcap IE from addn_ie
805 	 * may change the frame size. Therefore, MUST merge ExtCap IE before
806 	 * dot11f get packed payload size.
807 	 */
808 	if (extr_ext_flag)
809 		lim_merge_extcap_struct(&frm->ExtCap, &extr_ext_cap, true);
810 
811 	/* Clear the bits in EXTCAP IE if AP not advertise it in beacon */
812 	if (frm->ExtCap.present && pe_session->is_ext_caps_present) {
813 		ie_offset = DOT11F_FF_TIMESTAMP_LEN +
814 				DOT11F_FF_BEACONINTERVAL_LEN +
815 				DOT11F_FF_CAPABILITIES_LEN;
816 
817 		qdf_mem_zero((uint8_t *)&bcn_ext_cap, sizeof(tDot11fIEExtCap));
818 		if (pe_session->beacon && (pe_session->bcnLen >
819 		    (ie_offset + sizeof(struct wlan_frame_hdr)))) {
820 			bcn_ie = pe_session->beacon + ie_offset +
821 						sizeof(struct wlan_frame_hdr);
822 			bcn_ie_len = pe_session->bcnLen - ie_offset -
823 						sizeof(struct wlan_frame_hdr);
824 			p_ext_cap = (uint8_t *)wlan_get_ie_ptr_from_eid(
825 							DOT11F_EID_EXTCAP,
826 							bcn_ie, bcn_ie_len);
827 			lim_update_extcap_struct(mac, p_ext_cap,
828 						 &bcn_ext_cap);
829 			lim_merge_extcap_struct(&frm->ExtCap, &bcn_ext_cap,
830 						false);
831 		}
832 		/*
833 		 * TWT extended capabilities should be populated after the
834 		 * intersection of beacon caps and self caps is done because
835 		 * the bits for TWT are unique to STA and AP and cannot be
836 		 * intersected.
837 		 */
838 		populate_dot11f_twt_extended_caps(mac, pe_session,
839 						  &frm->ExtCap);
840 	}
841 
842 	/*
843 	 * Do unpack to populate the add_ie buffer to frm structure
844 	 * before packing the frm structure. In this way, the IE ordering
845 	 * which the latest 802.11 spec mandates is maintained.
846 	 */
847 	if (nAddIELen) {
848 		ret = dot11f_unpack_re_assoc_request(mac, pAddIE, nAddIELen,
849 						     frm, true);
850 		if (DOT11F_FAILED(ret)) {
851 			pe_err("unpack failed, ret: 0x%x", ret);
852 			goto end;
853 		}
854 	}
855 
856 	nStatus =
857 		dot11f_get_packed_re_assoc_request_size(mac, frm, &nPayload);
858 	if (DOT11F_FAILED(nStatus)) {
859 		pe_err("Fail to get size:ReassocReq: (0x%08x)", nStatus);
860 		/* We'll fall back on the worst case scenario: */
861 		nPayload = sizeof(tDot11fReAssocRequest);
862 	} else if (DOT11F_WARNED(nStatus)) {
863 		pe_err("warning for size:ReAssoc Req: (0x%08x)", nStatus);
864 	}
865 
866 	nBytes = nPayload + sizeof(tSirMacMgmtHdr);
867 
868 	qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame,
869 				      (void **)&pPacket);
870 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
871 		pe_session->limMlmState = pe_session->limPrevMlmState;
872 		MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_MLM_STATE,
873 				 pe_session->peSessionId,
874 				 pe_session->limMlmState));
875 		pe_err("Failed to alloc %d bytes for a ReAssociation Req",
876 			nBytes);
877 		goto end;
878 	}
879 	/* Paranoia: */
880 	qdf_mem_zero(pFrame, nBytes);
881 
882 	/* Next, we fill out the buffer descriptor: */
883 	lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME,
884 		SIR_MAC_MGMT_REASSOC_REQ, pe_session->limReAssocbssId,
885 		pe_session->self_mac_addr);
886 	pMacHdr = (tpSirMacMgmtHdr) pFrame;
887 
888 	/* That done, pack the Probe Request: */
889 	nStatus = dot11f_pack_re_assoc_request(mac, frm, pFrame +
890 					       sizeof(tSirMacMgmtHdr),
891 					       nPayload, &nPayload);
892 	if (DOT11F_FAILED(nStatus)) {
893 		pe_err("Fail to pack a Re-Assoc Req: (0x%08x)", nStatus);
894 		cds_packet_free((void *)pPacket);
895 		goto end;
896 	} else if (DOT11F_WARNED(nStatus)) {
897 		pe_warn("warning packing a Re-AssocReq: (0x%08x)", nStatus);
898 	}
899 
900 	lim_cp_stats_cstats_log_assoc_req_evt(pe_session, CSTATS_DIR_TX,
901 					      pMacHdr->bssId, pMacHdr->sa,
902 					      frm->SSID.num_ssid,
903 					      frm->SSID.ssid,
904 					      frm->HTCaps.present,
905 					      frm->VHTCaps.present,
906 					      frm->he_cap.present,
907 					      frm->eht_cap.present, true);
908 
909 	pe_debug("*** Sending Re-Association Request length: %d" "to", nBytes);
910 
911 	if (pe_session->assoc_req) {
912 		qdf_mem_free(pe_session->assoc_req);
913 		pe_session->assoc_req = NULL;
914 		pe_session->assocReqLen = 0;
915 	}
916 
917 	pe_session->assoc_req = qdf_mem_malloc(nPayload);
918 	if (pe_session->assoc_req) {
919 		/* Store the Assocrequest. It is sent to csr in joincnfrsp */
920 		qdf_mem_copy(pe_session->assoc_req,
921 			     pFrame + sizeof(tSirMacMgmtHdr), nPayload);
922 		pe_session->assocReqLen = nPayload;
923 	}
924 
925 	if (wlan_reg_is_5ghz_ch_freq(pe_session->curr_op_freq) ||
926 	    pe_session->opmode == QDF_P2P_CLIENT_MODE ||
927 	    pe_session->opmode == QDF_P2P_GO_MODE)
928 		txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME;
929 
930 	if (pe_session->opmode == QDF_P2P_CLIENT_MODE ||
931 	    pe_session->opmode == QDF_STA_MODE)
932 		txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK;
933 
934 	MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT,
935 			 pe_session->peSessionId, pMacHdr->fc.subType));
936 	lim_diag_event_report(mac, WLAN_PE_DIAG_REASSOC_START_EVENT,
937 			      pe_session, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS);
938 	lim_diag_mgmt_tx_event_report(mac, pMacHdr,
939 				      pe_session, QDF_STATUS_SUCCESS,
940 				      QDF_STATUS_SUCCESS);
941 
942 	if (pe_session->is_oui_auth_assoc_6mbps_2ghz_enable)
943 		min_rid = RATEID_6MBPS;
944 
945 	qdf_status =
946 		wma_tx_frame(mac, pPacket,
947 			   (uint16_t) (sizeof(tSirMacMgmtHdr) + nPayload),
948 			   TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7,
949 			   lim_tx_complete, pFrame, txFlag, smeSessionId, 0,
950 			   min_rid, 0);
951 	MTRACE(qdf_trace
952 		       (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE,
953 		       pe_session->peSessionId, qdf_status));
954 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
955 		pe_err("Failed to send Re-Association Request: %X!",
956 			qdf_status);
957 		/* Pkt will be freed up by the callback */
958 	}
959 
960 end:
961 	qdf_mem_free(frm);
962 err:
963 	/* Free up buffer allocated for mlmAssocReq */
964 	qdf_mem_free(pMlmReassocReq);
965 	pe_session->pLimMlmReassocReq = NULL;
966 
967 }
968 
lim_process_rx_scan_handler(struct wlan_objmgr_vdev * vdev,struct scan_event * event,void * arg)969 void lim_process_rx_scan_handler(struct wlan_objmgr_vdev *vdev,
970 				 struct scan_event *event,
971 				 void *arg)
972 {
973 	struct mac_context *mac_ctx;
974 	enum sir_scan_event_type event_type;
975 
976 	pe_debug("event: %u, id: 0x%x, requestor: 0x%x, freq: %u, reason: %u",
977 		 event->type, event->scan_id, event->requester,
978 		 event->chan_freq, event->reason);
979 
980 	mac_ctx = (struct mac_context *)arg;
981 	event_type = 0x1 << event->type;
982 
983 	qdf_mtrace(QDF_MODULE_ID_SCAN, QDF_MODULE_ID_PE, event->type,
984 		   event->vdev_id, event->scan_id);
985 
986 	switch (event_type) {
987 	case SIR_SCAN_EVENT_STARTED:
988 		break;
989 	case SIR_SCAN_EVENT_COMPLETED:
990 		pe_debug("No.of beacons and probe response received per scan %d",
991 			 mac_ctx->lim.beacon_probe_rsp_cnt_per_scan);
992 		fallthrough;
993 	case SIR_SCAN_EVENT_FOREIGN_CHANNEL:
994 	case SIR_SCAN_EVENT_START_FAILED:
995 		if ((mac_ctx->lim.req_id | PREAUTH_REQUESTOR_ID) ==
996 		    event->requester)
997 			lim_preauth_scan_event_handler(mac_ctx,
998 						       event_type,
999 						       event->vdev_id,
1000 						       event->scan_id);
1001 		break;
1002 	case SIR_SCAN_EVENT_BSS_CHANNEL:
1003 	case SIR_SCAN_EVENT_DEQUEUED:
1004 	case SIR_SCAN_EVENT_PREEMPTED:
1005 	default:
1006 		pe_debug("Received unhandled scan event %u", event_type);
1007 	}
1008 }
1009