1 /*
2  * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 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_reassoc_utils.c
22  *
23  * Host based roaming re-association utilities
24  */
25 
26 #include "cds_api.h"
27 #include "ani_global.h"
28 #include "wni_api.h"
29 #include "sir_common.h"
30 
31 #include "wni_cfg.h"
32 
33 #include "sch_api.h"
34 #include "utils_api.h"
35 #include "lim_utils.h"
36 #include "lim_assoc_utils.h"
37 #include "lim_security_utils.h"
38 #include "lim_ser_des_utils.h"
39 #include "lim_admit_control.h"
40 #include "lim_send_messages.h"
41 #include "lim_ft_defs.h"
42 #include "lim_session.h"
43 #include "lim_process_fils.h"
44 
45 #include "qdf_types.h"
46 #include "wma_types.h"
47 #include "lim_types.h"
48 
49 /**
50  * lim_update_re_assoc_globals() - Update reassoc global data
51  * @mac: Global MAC context
52  * @pAssocRsp: Reassociation response data
53  * @pe_session: PE Session
54  *
55  * This function is called to Update the Globals (LIM) during ReAssoc.
56  *
57  * Return: None
58  */
59 
lim_update_re_assoc_globals(struct mac_context * mac,tpSirAssocRsp pAssocRsp,struct pe_session * pe_session)60 void lim_update_re_assoc_globals(struct mac_context *mac, tpSirAssocRsp pAssocRsp,
61 				 struct pe_session *pe_session)
62 {
63 	/* Update the current Bss Information */
64 	qdf_mem_copy(pe_session->bssId,
65 		     pe_session->limReAssocbssId, sizeof(tSirMacAddr));
66 	pe_session->curr_op_freq = pe_session->lim_reassoc_chan_freq;
67 	pe_session->htSecondaryChannelOffset =
68 		pe_session->reAssocHtSupportedChannelWidthSet;
69 	pe_session->htRecommendedTxWidthSet =
70 		pe_session->reAssocHtRecommendedTxWidthSet;
71 	pe_session->htSecondaryChannelOffset =
72 		pe_session->reAssocHtSecondaryChannelOffset;
73 	pe_session->limCurrentBssCaps = pe_session->limReassocBssCaps;
74 	pe_session->limCurrentBssQosCaps =
75 		pe_session->limReassocBssQosCaps;
76 
77 	qdf_mem_copy((uint8_t *) &pe_session->ssId,
78 		     (uint8_t *) &pe_session->limReassocSSID,
79 		     pe_session->limReassocSSID.length + 1);
80 
81 	/* Store assigned AID for TIM processing */
82 	pe_session->limAID = pAssocRsp->aid & 0x3FFF;
83 	/** Set the State Back to ReAssoc Rsp*/
84 	pe_session->limMlmState = eLIM_MLM_WT_REASSOC_RSP_STATE;
85 	MTRACE(mac_trace
86 		       (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId,
87 		       pe_session->limMlmState));
88 
89 }
90 
91 /**
92  * @lim_handle_del_bss_in_re_assoc_context() - DEL BSS during reassociation
93  * @mac: Global MAC Context
94  * @sta: Station Hash entry
95  * @pe_session: PE Session
96  *
97  * While Processing the ReAssociation Response Frame in STA,
98  *     a.immediately after receiving the Reassoc Response the RxCleanUp is
99  *        being issued and the end of DelBSS the new BSS is being added.
100  *
101  *     b. If an AP rejects the ReAssociation (Disassoc/Deauth) with some context
102  *        change, We need to update CSR with ReAssocCNF Response with the
103  *        ReAssoc Fail and the reason Code, that is also being handled in the
104  *        DELBSS context only
105  *
106  * Return: None
107  */
lim_handle_del_bss_in_re_assoc_context(struct mac_context * mac,tpDphHashNode sta,struct pe_session * pe_session)108 void lim_handle_del_bss_in_re_assoc_context(struct mac_context *mac,
109 		tpDphHashNode sta, struct pe_session *pe_session)
110 {
111 	tLimMlmReassocCnf mlmReassocCnf;
112 	struct bss_description *bss_desc;
113 	/*
114 	 * Skipped the DeleteDPH Hash Entry as we need it for the new BSS
115 	 * Set the MlmState to IDLE
116 	 */
117 	pe_session->limMlmState = eLIM_MLM_IDLE_STATE;
118 	/* Update PE session Id */
119 	mlmReassocCnf.sessionId = pe_session->peSessionId;
120 	switch (pe_session->limSmeState) {
121 	case eLIM_SME_WT_REASSOC_STATE:
122 	{
123 		tpSirAssocRsp assocRsp;
124 		tpDphHashNode sta;
125 		QDF_STATUS retStatus = QDF_STATUS_SUCCESS;
126 		tpSchBeaconStruct beacon_struct;
127 
128 		beacon_struct = qdf_mem_malloc(sizeof(tSchBeaconStruct));
129 		if (!beacon_struct) {
130 			mlmReassocCnf.resultCode =
131 					eSIR_SME_RESOURCES_UNAVAILABLE;
132 			mlmReassocCnf.protStatusCode =
133 					STATUS_UNSPECIFIED_FAILURE;
134 			lim_delete_dph_hash_entry(mac, pe_session->bssId,
135 				DPH_STA_HASH_INDEX_PEER, pe_session);
136 			goto error;
137 		}
138 		/* Delete the older STA Table entry */
139 		lim_delete_dph_hash_entry(mac, pe_session->bssId,
140 				DPH_STA_HASH_INDEX_PEER, pe_session);
141 		/*
142 		 * Add an entry for AP to hash table
143 		 * maintained by DPH module
144 		 */
145 		sta = dph_add_hash_entry(mac,
146 				pe_session->limReAssocbssId,
147 				DPH_STA_HASH_INDEX_PEER,
148 				&pe_session->dph.dphHashTable);
149 		if (!sta) {
150 			/* Could not add hash table entry */
151 			pe_err("could not add hash entry at DPH for BSSID: "QDF_MAC_ADDR_FMT,
152 			       QDF_MAC_ADDR_REF(pe_session->limReAssocbssId));
153 			mlmReassocCnf.resultCode =
154 				eSIR_SME_RESOURCES_UNAVAILABLE;
155 			mlmReassocCnf.protStatusCode = eSIR_SME_SUCCESS;
156 			qdf_mem_free(beacon_struct);
157 			goto error;
158 		}
159 		/*
160 		 * While Processing the ReAssoc Response Frame the Rsp Frame
161 		 * is being stored to be used here for sending ADDBSS
162 		 */
163 		assocRsp =
164 			(tpSirAssocRsp) pe_session->limAssocResponseData;
165 
166 		bss_desc = &pe_session->pLimReAssocReq->bssDescription;
167 		lim_extract_ap_capabilities(mac,
168 			(uint8_t *)bss_desc->ieFields,
169 			lim_get_ielen_from_bss_description(bss_desc),
170 			beacon_struct);
171 
172 		lim_update_assoc_sta_datas(mac, sta, assocRsp,
173 			pe_session, beacon_struct);
174 		lim_update_re_assoc_globals(mac, assocRsp, pe_session);
175 		if (mac->lim.gLimProtectionControl !=
176 		    MLME_FORCE_POLICY_PROTECTION_DISABLE)
177 			lim_decide_sta_protection_on_assoc(mac,
178 				beacon_struct,
179 				pe_session);
180 		if (beacon_struct->erpPresent) {
181 			if (beacon_struct->erpIEInfo.barkerPreambleMode)
182 				pe_session->beaconParams.fShortPreamble = 0;
183 			else
184 				pe_session->beaconParams.fShortPreamble = 1;
185 		}
186 		/*
187 		 * updateBss flag is false, as in this case, PE is first
188 		 * deleting the existing BSS and then adding a new one
189 		 */
190 		if (QDF_STATUS_SUCCESS !=
191 		    lim_sta_send_add_bss(mac, assocRsp, beacon_struct,
192 				bss_desc,
193 				false, pe_session)) {
194 			pe_err("Posting ADDBSS in the ReAssocCtx Failed");
195 			retStatus = QDF_STATUS_E_FAILURE;
196 		}
197 		if (retStatus != QDF_STATUS_SUCCESS) {
198 			mlmReassocCnf.resultCode =
199 				eSIR_SME_RESOURCES_UNAVAILABLE;
200 			mlmReassocCnf.protStatusCode =
201 				STATUS_UNSPECIFIED_FAILURE;
202 			qdf_mem_free(assocRsp);
203 			mac->lim.gLimAssocResponseData = NULL;
204 			qdf_mem_free(beacon_struct);
205 			goto error;
206 		}
207 		qdf_mem_free(assocRsp->sha384_ft_subelem.gtk);
208 		qdf_mem_free(assocRsp->sha384_ft_subelem.igtk);
209 		qdf_mem_free(assocRsp);
210 		qdf_mem_free(beacon_struct);
211 		pe_session->limAssocResponseData = NULL;
212 	}
213 	break;
214 	default:
215 		pe_err("DelBss in wrong system Role and SME State");
216 		mlmReassocCnf.resultCode = eSIR_SME_REFUSED;
217 		mlmReassocCnf.protStatusCode =
218 			eSIR_SME_UNEXPECTED_REQ_RESULT_CODE;
219 		goto error;
220 	}
221 	return;
222 error:
223 	lim_post_sme_message(mac, LIM_MLM_REASSOC_CNF,
224 			     (uint32_t *) &mlmReassocCnf);
225 }
226 
227 /**
228  * @lim_handle_add_bss_in_re_assoc_context() - ADD BSS during reassociation
229  * @mac: Global MAC Context
230  * @sta: Station Hash entry
231  * @pe_session: PE Session
232  *
233  * While Processing the ReAssociation Response Frame in STA,
234  *     a. immediately after receiving the Reassoc Response the RxCleanUp is
235  *         being issued and the end of DelBSS the new BSS is being added.
236  *
237  *     b. If an AP rejects the ReAssociation (Disassoc/Deauth) with some context
238  *        change, We need to update CSR with ReAssocCNF Response with the
239  *        ReAssoc Fail and the reason Code, that is also being handled in the
240  *        DELBSS context only
241  *
242  * Return: None
243  */
lim_handle_add_bss_in_re_assoc_context(struct mac_context * mac,tpDphHashNode sta,struct pe_session * pe_session)244 void lim_handle_add_bss_in_re_assoc_context(struct mac_context *mac,
245 		tpDphHashNode sta, struct pe_session *pe_session)
246 {
247 	tLimMlmReassocCnf mlmReassocCnf;
248 	/** Skipped the DeleteDPH Hash Entry as we need it for the new BSS*/
249 	/** Set the MlmState to IDLE*/
250 	pe_session->limMlmState = eLIM_MLM_IDLE_STATE;
251 	MTRACE(mac_trace
252 		       (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId,
253 		       pe_session->limMlmState));
254 	switch (pe_session->limSmeState) {
255 	case eLIM_SME_WT_REASSOC_STATE: {
256 		tpSirAssocRsp assocRsp;
257 		tpDphHashNode sta;
258 		QDF_STATUS retStatus = QDF_STATUS_SUCCESS;
259 		tSchBeaconStruct *pBeaconStruct;
260 
261 		pBeaconStruct =
262 			qdf_mem_malloc(sizeof(tSchBeaconStruct));
263 		if (!pBeaconStruct) {
264 			mlmReassocCnf.resultCode =
265 				eSIR_SME_RESOURCES_UNAVAILABLE;
266 			mlmReassocCnf.protStatusCode =
267 				eSIR_SME_RESOURCES_UNAVAILABLE;
268 			goto Error;
269 		}
270 		/* Get the AP entry from DPH hash table */
271 		sta =
272 			dph_get_hash_entry(mac, DPH_STA_HASH_INDEX_PEER,
273 					   &pe_session->dph.dphHashTable);
274 		if (!sta) {
275 			pe_err("Fail to get STA PEER entry from hash");
276 			mlmReassocCnf.resultCode =
277 				eSIR_SME_RESOURCES_UNAVAILABLE;
278 			mlmReassocCnf.protStatusCode = eSIR_SME_SUCCESS;
279 			qdf_mem_free(pBeaconStruct);
280 			goto Error;
281 		}
282 		/*
283 		 * While Processing the ReAssoc Response Frame the Rsp Frame
284 		 * is being stored to be used here for sending ADDBSS
285 		 */
286 		assocRsp =
287 			(tpSirAssocRsp) pe_session->limAssocResponseData;
288 		lim_extract_ap_capabilities(mac,
289 				(uint8_t *)pe_session->pLimReAssocReq->bssDescription.ieFields,
290 				lim_get_ielen_from_bss_description
291 				(&pe_session->pLimReAssocReq->bssDescription),
292 				pBeaconStruct);
293 		lim_update_assoc_sta_datas(mac, sta, assocRsp,
294 					   pe_session, pBeaconStruct);
295 		lim_update_re_assoc_globals(mac, assocRsp, pe_session);
296 		if (mac->lim.gLimProtectionControl !=
297 		    MLME_FORCE_POLICY_PROTECTION_DISABLE)
298 			lim_decide_sta_protection_on_assoc(mac,
299 							   pBeaconStruct,
300 							   pe_session);
301 
302 		if (pBeaconStruct->erpPresent) {
303 			if (pBeaconStruct->erpIEInfo.barkerPreambleMode)
304 				pe_session->beaconParams.
305 				fShortPreamble = 0;
306 			else
307 				pe_session->beaconParams.
308 				fShortPreamble = 1;
309 		}
310 
311 		pe_session->isNonRoamReassoc = 1;
312 		if (QDF_STATUS_SUCCESS !=
313 		    lim_sta_send_add_bss(mac, assocRsp, pBeaconStruct,
314 					 &pe_session->pLimReAssocReq->
315 					 bssDescription, true,
316 					 pe_session)) {
317 			pe_err("Post ADDBSS in the ReAssocCtxt Failed");
318 			retStatus = QDF_STATUS_E_FAILURE;
319 		}
320 		if (retStatus != QDF_STATUS_SUCCESS) {
321 			mlmReassocCnf.resultCode =
322 				eSIR_SME_RESOURCES_UNAVAILABLE;
323 			mlmReassocCnf.protStatusCode =
324 				STATUS_UNSPECIFIED_FAILURE;
325 			qdf_mem_free(assocRsp);
326 			mac->lim.gLimAssocResponseData = NULL;
327 			qdf_mem_free(pBeaconStruct);
328 			goto Error;
329 		}
330 		qdf_mem_free(assocRsp->sha384_ft_subelem.gtk);
331 		qdf_mem_free(assocRsp->sha384_ft_subelem.igtk);
332 		qdf_mem_free(assocRsp);
333 		pe_session->limAssocResponseData = NULL;
334 		qdf_mem_free(pBeaconStruct);
335 	}
336 	break;
337 	default:
338 		pe_err("DelBss in the wrong system Role and SME State");
339 		mlmReassocCnf.resultCode = eSIR_SME_REFUSED;
340 		mlmReassocCnf.protStatusCode =
341 			eSIR_SME_UNEXPECTED_REQ_RESULT_CODE;
342 		goto Error;
343 	}
344 	return;
345 Error:
346 	lim_post_sme_message(mac, LIM_MLM_REASSOC_CNF,
347 			     (uint32_t *) &mlmReassocCnf);
348 }
349 
350 /**
351  * lim_is_reassoc_in_progress() - Check if reassoiciation is in progress
352  * @mac: Global MAC Context
353  * @pe_session: PE Session
354  *
355  * Return: true  When STA is waiting for Reassoc response from AP
356  *         else false
357  */
lim_is_reassoc_in_progress(struct mac_context * mac,struct pe_session * pe_session)358 bool lim_is_reassoc_in_progress(struct mac_context *mac, struct pe_session *pe_session)
359 {
360 	if (!pe_session)
361 		return false;
362 
363 	if (LIM_IS_STA_ROLE(pe_session) &&
364 	    (pe_session->limSmeState == eLIM_SME_WT_REASSOC_STATE))
365 		return true;
366 
367 	return false;
368 }
369 
370 /**
371  * lim_add_ft_sta_self()- function to add STA once we have connected with a
372  *          new AP
373  * @mac_ctx: pointer to global mac structure
374  * @assoc_id: association id for the station connection
375  * @session_entry: pe session entr
376  *
377  * This function is called to add a STA once we have connected with a new
378  * AP, that we have performed an FT to.
379  *
380  * The Add STA Response is created and now after the ADD Bss Is Successful
381  * we add the self sta. We update with the association id from the reassoc
382  * response from the AP.
383  *
384  * Return: QDF_STATUS_SUCCESS on success else QDF_STATUS failure codes
385  */
lim_add_ft_sta_self(struct mac_context * mac_ctx,uint16_t assoc_id,struct pe_session * session_entry)386 QDF_STATUS lim_add_ft_sta_self(struct mac_context *mac_ctx, uint16_t assoc_id,
387 				struct pe_session *session_entry)
388 {
389 	tpAddStaParams add_sta_params = NULL;
390 	QDF_STATUS ret_code = QDF_STATUS_SUCCESS;
391 	struct scheduler_msg msg_q = {0};
392 	tpDphHashNode sta_ds;
393 
394 	sta_ds = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER,
395 				    &session_entry->dph.dphHashTable);
396 
397 	if (!sta_ds) {
398 		pe_err("Could not get hash entry at DPH");
399 		return QDF_STATUS_E_FAILURE;
400 	}
401 
402 	add_sta_params = session_entry->ftPEContext.pAddStaReq;
403 	add_sta_params->assocId = assoc_id;
404 	add_sta_params->smesessionId = session_entry->smeSessionId;
405 
406 	qdf_mem_copy(add_sta_params->supportedRates.supportedMCSSet,
407 		     sta_ds->supportedRates.supportedMCSSet,
408 		     SIR_MAC_MAX_SUPPORTED_MCS_SET);
409 
410 	if (lim_is_fils_connection(session_entry))
411 		add_sta_params->no_ptk_4_way = true;
412 
413 	msg_q.type = WMA_ADD_STA_REQ;
414 	msg_q.reserved = 0;
415 	msg_q.bodyptr = add_sta_params;
416 	msg_q.bodyval = 0;
417 
418 	pe_debug("Sending WMA_ADD_STA_REQ (aid %d)", add_sta_params->assocId);
419 	MTRACE(mac_trace_msg_tx(mac_ctx, session_entry->peSessionId,
420 			 msg_q.type));
421 
422 	session_entry->limPrevMlmState = session_entry->limMlmState;
423 	MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE,
424 		session_entry->peSessionId, eLIM_MLM_WT_ADD_STA_RSP_STATE));
425 	session_entry->limMlmState = eLIM_MLM_WT_ADD_STA_RSP_STATE;
426 	ret_code = wma_post_ctrl_msg(mac_ctx, &msg_q);
427 	if (QDF_STATUS_SUCCESS != ret_code) {
428 		pe_err("Posting WMA_ADD_STA_REQ to HAL failed, reason=%X",
429 			ret_code);
430 		qdf_mem_free(add_sta_params);
431 	}
432 
433 	session_entry->ftPEContext.pAddStaReq = NULL;
434 	return ret_code;
435 }
436 
437 /**
438  * lim_restore_pre_reassoc_state() - Restore the pre-association context
439  * @mac: Global MAC Context
440  * @resultCode: Assoc response result
441  * @protStatusCode: Internal protocol status code
442  * @pe_session: PE Session
443  *
444  * This function is called on STA role whenever Reasociation
445  * Response with a reject code is received from AP.
446  * Reassociation failure timer is stopped, Old (or current) AP's
447  * context is restored both at Polaris & software
448  *
449  * Return: None
450  */
451 
452 void
lim_restore_pre_reassoc_state(struct mac_context * mac,tSirResultCodes resultCode,uint16_t protStatusCode,struct pe_session * pe_session)453 lim_restore_pre_reassoc_state(struct mac_context *mac,
454 		tSirResultCodes resultCode, uint16_t protStatusCode,
455 		struct pe_session *pe_session)
456 {
457 	tLimMlmReassocCnf mlmReassocCnf;
458 
459 	pe_debug("sessionid: %d protStatusCode: %d resultCode: %d",
460 		pe_session->smeSessionId, protStatusCode, resultCode);
461 
462 	pe_session->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE;
463 	MTRACE(mac_trace
464 		       (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId,
465 		       eLIM_MLM_LINK_ESTABLISHED_STATE));
466 
467 	/* 'Change' timer for future activations */
468 	lim_deactivate_and_change_timer(mac, eLIM_REASSOC_FAIL_TIMER);
469 
470 	/* @ToDo:Need to Integrate the STOP the Dataxfer to AP from 11H code */
471 
472 	mlmReassocCnf.resultCode = resultCode;
473 	mlmReassocCnf.protStatusCode = protStatusCode;
474 	mlmReassocCnf.sessionId = pe_session->peSessionId;
475 	lim_post_sme_message(mac,
476 			     LIM_MLM_REASSOC_CNF, (uint32_t *) &mlmReassocCnf);
477 }
478 
479 /**
480  * lim_post_reassoc_failure() - Post failure message to SME
481  * @mac: Global MAC Context
482  * @resultCode: Result Code
483  * @protStatusCode: Protocol Status Code
484  * @pe_session: PE Session
485  *
486  * Return: None
487  */
lim_post_reassoc_failure(struct mac_context * mac,tSirResultCodes resultCode,uint16_t protStatusCode,struct pe_session * pe_session)488 void lim_post_reassoc_failure(struct mac_context *mac,
489 		tSirResultCodes resultCode, uint16_t protStatusCode,
490 		struct pe_session *pe_session)
491 {
492 	tLimMlmReassocCnf mlmReassocCnf;
493 
494 	pe_session->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE;
495 	MTRACE(mac_trace
496 		       (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId,
497 		       eLIM_MLM_LINK_ESTABLISHED_STATE));
498 
499 	lim_deactivate_and_change_timer(mac, eLIM_REASSOC_FAIL_TIMER);
500 
501 	mlmReassocCnf.resultCode = resultCode;
502 	mlmReassocCnf.protStatusCode = protStatusCode;
503 	mlmReassocCnf.sessionId = pe_session->peSessionId;
504 	lim_post_sme_message(mac,
505 			     LIM_MLM_REASSOC_CNF, (uint32_t *) &mlmReassocCnf);
506 }
507 
508