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