xref: /wlan-driver/qcacld-3.0/core/mac/src/pe/lim/lim_ft_preauth.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2016-2021 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_ft_preauth.c
22  *
23  * Pre-Authentication implementation for host based roaming
24  */
25 #include <lim_send_messages.h>
26 #include <lim_types.h>
27 #include <lim_ft.h>
28 #include <lim_ft_defs.h>
29 #include <lim_utils.h>
30 #include <lim_prop_exts_utils.h>
31 #include <lim_assoc_utils.h>
32 #include <lim_session.h>
33 #include <lim_session_utils.h>
34 #include <lim_admit_control.h>
35 #include <wlan_scan_api.h>
36 #include "wma.h"
37 #include "wlan_crypto_global_api.h"
38 
39 /**
40  * lim_ft_cleanup_pre_auth_info() - Cleanup preauth related information
41  * @mac: Global MAC Context
42  * @pe_session: PE Session
43  *
44  * This routine is called to free the FT context, session and other
45  * information used during preauth operation.
46  *
47  * Return: None
48  */
lim_ft_cleanup_pre_auth_info(struct mac_context * mac,struct pe_session * pe_session)49 void lim_ft_cleanup_pre_auth_info(struct mac_context *mac,
50 		struct pe_session *pe_session)
51 {
52 	struct pe_session *pReAssocSessionEntry = NULL;
53 	uint8_t sessionId = 0;
54 
55 	if (!pe_session) {
56 		pe_err("pe_session is NULL");
57 		return;
58 	}
59 
60 	/* Nothing to be done if the session is not in STA mode */
61 	if (!LIM_IS_STA_ROLE(pe_session)) {
62 		pe_err("pe_session is not in STA mode");
63 		return;
64 	}
65 
66 	if (pe_session->ftPEContext.pFTPreAuthReq) {
67 		pReAssocSessionEntry =
68 			pe_find_session_by_bssid(mac,
69 						 pe_session->ftPEContext.
70 						 pFTPreAuthReq->preAuthbssId,
71 						 &sessionId);
72 
73 		if (pe_session->ftPEContext.pFTPreAuthReq->
74 		    pbssDescription) {
75 			qdf_mem_free(pe_session->ftPEContext.pFTPreAuthReq->
76 				     pbssDescription);
77 			pe_session->ftPEContext.pFTPreAuthReq->
78 			pbssDescription = NULL;
79 		}
80 		qdf_mem_free(pe_session->ftPEContext.pFTPreAuthReq);
81 		pe_session->ftPEContext.pFTPreAuthReq = NULL;
82 	}
83 
84 	if (pe_session->ftPEContext.pAddBssReq) {
85 		qdf_mem_free(pe_session->ftPEContext.pAddBssReq);
86 		pe_session->ftPEContext.pAddBssReq = NULL;
87 	}
88 
89 	if (pe_session->ftPEContext.pAddStaReq) {
90 		qdf_mem_free(pe_session->ftPEContext.pAddStaReq);
91 		pe_session->ftPEContext.pAddStaReq = NULL;
92 	}
93 
94 	/* The session is being deleted, cleanup the contents */
95 	qdf_mem_zero(&pe_session->ftPEContext, sizeof(tftPEContext));
96 
97 	/* Delete the session created while handling pre-auth response */
98 	if (pReAssocSessionEntry) {
99 		/* If we have successful pre-auth response, then we would have
100 		 * created a session on which reassoc request will be sent
101 		 */
102 		if (pReAssocSessionEntry->valid &&
103 		    pReAssocSessionEntry->limSmeState ==
104 		    eLIM_SME_WT_REASSOC_STATE) {
105 			pe_debug("Deleting Preauth session(%d)",
106 				 pReAssocSessionEntry->peSessionId);
107 			pe_delete_session(mac, pReAssocSessionEntry);
108 		}
109 	}
110 }
111 
112 /*
113  * lim_process_ft_pre_auth_req() - process ft pre auth req
114  *
115  * @mac_ctx:    global mac ctx
116  * @ft_pre_auth_req:  ft preauth request
117  *
118  * In this function, we process the FT Pre Auth Req:
119  *   We receive Pre-Auth, suspend link, register a call back. In the call back,
120  *   we will need to accept frames from the new bssid. Send out the auth req to
121  *   new AP. Start timer and when the timer is done or if we receive the Auth
122  *   response. We change channel. Resume link
123  *
124  * Return: value to indicate if buffer was consumed
125  */
lim_process_ft_pre_auth_req(struct mac_context * mac_ctx,tpSirFTPreAuthReq ft_pre_auth_req)126 bool lim_process_ft_pre_auth_req(struct mac_context *mac_ctx,
127 				 tpSirFTPreAuthReq ft_pre_auth_req)
128 {
129 	bool buf_consumed = false;
130 	struct pe_session *session;
131 	uint8_t session_id;
132 
133 	if (!ft_pre_auth_req) {
134 		pe_err("tSirFTPreAuthReq is NULL");
135 		return buf_consumed;
136 	}
137 
138 	/* Get the current session entry */
139 	session = pe_find_session_by_bssid(mac_ctx,
140 					   ft_pre_auth_req->currbssId,
141 					   &session_id);
142 	if (!session) {
143 		pe_err("Unable to find session for the bssid "
144 			QDF_MAC_ADDR_FMT,
145 			QDF_MAC_ADDR_REF(ft_pre_auth_req->currbssId));
146 		/* Post the FT Pre Auth Response to SME */
147 		lim_post_ft_pre_auth_rsp(mac_ctx, QDF_STATUS_E_FAILURE, NULL, 0,
148 					 session);
149 		buf_consumed = true;
150 		return buf_consumed;
151 	}
152 
153 	/* Nothing to be done if the session is not in STA mode */
154 	if (!LIM_IS_STA_ROLE(session)) {
155 		pe_err("session is not in STA mode");
156 		buf_consumed = true;
157 		return buf_consumed;
158 	}
159 
160 	/* Can set it only after sending auth */
161 	session->ftPEContext.ftPreAuthStatus = QDF_STATUS_E_FAILURE;
162 	session->ftPEContext.ftPreAuthSession = true;
163 
164 	/* Indicate that this is the session on which preauth is being done */
165 	if (session->ftPEContext.pFTPreAuthReq) {
166 		if (session->ftPEContext.pFTPreAuthReq->pbssDescription) {
167 			qdf_mem_free(
168 			  session->ftPEContext.pFTPreAuthReq->pbssDescription);
169 			session->ftPEContext.pFTPreAuthReq->pbssDescription =
170 									NULL;
171 		}
172 		qdf_mem_free(session->ftPEContext.pFTPreAuthReq);
173 		session->ftPEContext.pFTPreAuthReq = NULL;
174 	}
175 
176 	/* We need information from the Pre-Auth Req. Lets save that */
177 	session->ftPEContext.pFTPreAuthReq = ft_pre_auth_req;
178 
179 	pe_debug("PRE Auth ft_ies_length=%02x%02x%02x",
180 		session->ftPEContext.pFTPreAuthReq->ft_ies[0],
181 		session->ftPEContext.pFTPreAuthReq->ft_ies[1],
182 		session->ftPEContext.pFTPreAuthReq->ft_ies[2]);
183 #ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM    /* FEATURE_WLAN_DIAG_SUPPORT */
184 	lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_PRE_AUTH_REQ_EVENT,
185 			      session, 0, 0);
186 #endif
187 
188 	/*
189 	 * Dont need to suspend if APs are in same channel and DUT
190 	 * is not in MCC state
191 	 */
192 	if ((session->curr_op_freq !=
193 	     session->ftPEContext.pFTPreAuthReq->pre_auth_channel_freq)
194 	    || lim_is_in_mcc(mac_ctx)) {
195 		/* Need to suspend link only if the channels are different */
196 		pe_debug("Performing pre-auth on diff channel(session %pK)",
197 			session);
198 		lim_send_preauth_scan_offload(mac_ctx, session,
199 					session->ftPEContext.pFTPreAuthReq);
200 	} else {
201 		pe_debug("Performing pre-auth on same channel (session %pK)",
202 			session);
203 		/* We are in the same channel. Perform pre-auth */
204 		lim_perform_ft_pre_auth(mac_ctx, QDF_STATUS_SUCCESS, NULL,
205 					session);
206 	}
207 
208 	return buf_consumed;
209 }
210 
211 /**
212  * lim_perform_ft_pre_auth() - Perform preauthentication
213  * @mac: Global MAC Context
214  * @status: Status Code
215  * @data: pre-auth data
216  * @pe_session: PE Session
217  *
218  * This routine will trigger the sending of authentication frame
219  * to the peer.
220  *
221  * Return: None
222  */
lim_perform_ft_pre_auth(struct mac_context * mac,QDF_STATUS status,uint32_t * data,struct pe_session * pe_session)223 void lim_perform_ft_pre_auth(struct mac_context *mac, QDF_STATUS status,
224 			     uint32_t *data, struct pe_session *pe_session)
225 {
226 	tSirMacAuthFrameBody authFrame;
227 	bool is_open = false;
228 
229 	if (!pe_session) {
230 		pe_err("pe_session is NULL");
231 		return;
232 	}
233 
234 	if (cm_is_open_mode(pe_session->vdev))
235 		is_open = true;
236 
237 	if (pe_session->is11Rconnection &&
238 	    pe_session->ftPEContext.pFTPreAuthReq) {
239 		/* Only 11r assoc has FT IEs */
240 		if ((!is_open) &&
241 		     (pe_session->ftPEContext.pFTPreAuthReq->ft_ies_length
242 									== 0)) {
243 			pe_err("FTIEs for Auth Req Seq 1 is absent");
244 			goto preauth_fail;
245 		}
246 	}
247 
248 	if (status != QDF_STATUS_SUCCESS) {
249 		pe_err("Change channel not successful for FT pre-auth");
250 		goto preauth_fail;
251 	}
252 
253 	/* Nothing to be done if the session is not in STA mode */
254 	if (!LIM_IS_STA_ROLE(pe_session)) {
255 		pe_err("pe_session is not in STA mode");
256 		return;
257 	}
258 	if (cm_is_auth_type_sae(pe_session->vdev)) {
259 		struct qdf_mac_addr *pre_auth_bssid = (struct qdf_mac_addr *)
260 			pe_session->ftPEContext.pFTPreAuthReq->preAuthbssId;
261 
262 		lim_trigger_auth_req_sae(mac, pe_session, pre_auth_bssid);
263 		return;
264 	}
265 	pe_debug("Entered wait auth2 state for FT (old session %pK)",
266 			pe_session);
267 	if (pe_session->is11Rconnection) {
268 		/* Now we are on the right channel and need to send out Auth1
269 		 * and receive Auth2
270 		 */
271 		authFrame.authAlgoNumber = eSIR_FT_AUTH;
272 	} else {
273 		/* Will need to make isESEconnection a enum may be for further
274 		 * improvements to this to match this algorithm number
275 		 */
276 		authFrame.authAlgoNumber = eSIR_OPEN_SYSTEM;
277 	}
278 	authFrame.authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_1;
279 	authFrame.authStatusCode = 0;
280 
281 	mac->lim.lim_timers.g_lim_periodic_auth_retry_timer.sessionId =
282 				pe_session->peSessionId;
283 
284 	/* Start timer here to come back to operating channel */
285 	mac->lim.lim_timers.gLimFTPreAuthRspTimer.sessionId =
286 		pe_session->peSessionId;
287 	if (TX_SUCCESS !=
288 	    tx_timer_activate(&mac->lim.lim_timers.gLimFTPreAuthRspTimer)) {
289 		pe_err("FT Auth Rsp Timer Start Failed");
290 		goto preauth_fail;
291 	}
292 	MTRACE(mac_trace(mac, TRACE_CODE_TIMER_ACTIVATE,
293 		pe_session->peSessionId, eLIM_FT_PREAUTH_RSP_TIMER));
294 
295 	pe_debug("FT Auth Rsp Timer Started");
296 #ifdef FEATURE_WLAN_DIAG_SUPPORT
297 	lim_diag_event_report(mac, WLAN_PE_DIAG_ROAM_AUTH_START_EVENT,
298 			mac->lim.pe_session, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS);
299 #endif
300 	if (pe_session->ftPEContext.pFTPreAuthReq)
301 		lim_send_auth_mgmt_frame(mac, &authFrame,
302 			 pe_session->ftPEContext.pFTPreAuthReq->preAuthbssId,
303 			 LIM_NO_WEP_IN_FC, pe_session);
304 
305 	return;
306 
307 preauth_fail:
308 	lim_handle_ft_pre_auth_rsp(mac, QDF_STATUS_E_FAILURE, NULL, 0, pe_session);
309 	return;
310 }
311 
312 /**
313  * lim_ft_setup_auth_session() - Fill the FT Session
314  * @mac: Global MAC Context
315  * @pe_session: PE Session
316  *
317  * Setup the session and the add bss req for the pre-auth AP.
318  *
319  * Return: Success or Failure Status
320  */
lim_ft_setup_auth_session(struct mac_context * mac,struct pe_session * pe_session)321 QDF_STATUS lim_ft_setup_auth_session(struct mac_context *mac,
322 					struct pe_session *pe_session)
323 {
324 	struct pe_session *ft_session = NULL;
325 	uint8_t sessionId = 0;
326 	struct sSirFTPreAuthReq *req;
327 	QDF_STATUS status;
328 
329 	ft_session =
330 		pe_find_session_by_bssid(mac, pe_session->limReAssocbssId,
331 					 &sessionId);
332 	if (!ft_session) {
333 		pe_err("No session found for bssid: "QDF_MAC_ADDR_FMT,
334 			QDF_MAC_ADDR_REF(pe_session->limReAssocbssId));
335 		return QDF_STATUS_E_FAILURE;
336 	}
337 
338 	/* Nothing to be done if the session is not in STA mode */
339 	if (!LIM_IS_STA_ROLE(pe_session)) {
340 		pe_err("pe_session is not in STA mode");
341 		return QDF_STATUS_E_FAILURE;
342 	}
343 
344 	req = pe_session->ftPEContext.pFTPreAuthReq;
345 	if (req && req->pbssDescription) {
346 		status = lim_fill_ft_session(mac,
347 					     req->pbssDescription, ft_session,
348 					     pe_session, WLAN_PHYMODE_AUTO);
349 		if (QDF_IS_STATUS_ERROR(status))
350 			pe_err("Failed to fill ft session for vdev id %d",
351 			       ft_session->vdev_id);
352 
353 		lim_ft_prepare_add_bss_req(mac, ft_session,
354 					   req->pbssDescription);
355 	}
356 
357 	return QDF_STATUS_SUCCESS;
358 }
359 
360 /**
361  * lim_ft_process_pre_auth_result() - Process the Auth frame
362  * @mac: Global MAC context
363  * @pe_session: PE Session
364  *
365  * Return: None
366  */
lim_ft_process_pre_auth_result(struct mac_context * mac,struct pe_session * pe_session)367 static void lim_ft_process_pre_auth_result(struct mac_context *mac,
368 					   struct pe_session *pe_session)
369 {
370 	if (!pe_session ||
371 	    !pe_session->ftPEContext.pFTPreAuthReq)
372 		return;
373 
374 	/* Nothing to be done if the session is not in STA mode */
375 	if (!LIM_IS_STA_ROLE(pe_session)) {
376 		pe_err("pe_session is not in STA mode");
377 		return;
378 	}
379 
380 	if (pe_session->ftPEContext.ftPreAuthStatus == QDF_STATUS_SUCCESS) {
381 		pe_session->ftPEContext.ftPreAuthStatus =
382 			lim_ft_setup_auth_session(mac, pe_session);
383 	}
384 	/* Post the FT Pre Auth Response to SME */
385 	lim_post_ft_pre_auth_rsp(mac,
386 		pe_session->ftPEContext.ftPreAuthStatus,
387 		pe_session->ftPEContext.saved_auth_rsp,
388 		pe_session->ftPEContext.saved_auth_rsp_length,
389 		pe_session);
390 }
391 
392 /**
393  * lim_handle_ft_pre_auth_rsp() - Handle the Auth response
394  * @mac: Global MAC Context
395  * @status: Status Code
396  * @auth_rsp: Auth Response
397  * @auth_rsp_length: Auth response length
398  * @pe_session: PE Session
399  *
400  * Send the FT Pre Auth Response to SME whenever we have a status
401  * ready to be sent to SME
402  *
403  * SME will be the one to send it up to the supplicant to receive
404  * FTIEs which will be required for Reassoc Req.
405  *
406  * @Return: None
407  */
lim_handle_ft_pre_auth_rsp(struct mac_context * mac,QDF_STATUS status,uint8_t * auth_rsp,uint16_t auth_rsp_length,struct pe_session * pe_session)408 void lim_handle_ft_pre_auth_rsp(struct mac_context *mac, QDF_STATUS status,
409 				uint8_t *auth_rsp, uint16_t auth_rsp_length,
410 				struct pe_session *pe_session)
411 {
412 	struct pe_session *ft_session = NULL;
413 	uint8_t sessionId = 0;
414 	struct bss_description *pbssDescription = NULL;
415 #ifdef FEATURE_WLAN_DIAG_SUPPORT
416 	lim_diag_event_report(mac, WLAN_PE_DIAG_PRE_AUTH_RSP_EVENT,
417 			      pe_session, (uint16_t) status, 0);
418 #endif
419 
420 	/* Nothing to be done if the session is not in STA mode */
421 	if (!LIM_IS_STA_ROLE(pe_session)) {
422 		pe_err("pe_session is not in STA mode");
423 		return;
424 	}
425 
426 	/* Save the status of pre-auth */
427 	pe_session->ftPEContext.ftPreAuthStatus = status;
428 
429 	/* Save the auth rsp, so we can send it to
430 	 * SME once we resume link
431 	 */
432 	pe_session->ftPEContext.saved_auth_rsp_length = 0;
433 	if ((auth_rsp) && (auth_rsp_length < MAX_FTIE_SIZE)) {
434 		qdf_mem_copy(pe_session->ftPEContext.saved_auth_rsp,
435 			     auth_rsp, auth_rsp_length);
436 		pe_session->ftPEContext.saved_auth_rsp_length =
437 			auth_rsp_length;
438 	}
439 
440 	if (!pe_session->ftPEContext.pFTPreAuthReq ||
441 	    !pe_session->ftPEContext.pFTPreAuthReq->pbssDescription) {
442 		pe_err("pFTPreAuthReq or pbssDescription is NULL");
443 		return;
444 	}
445 
446 	/* Create FT session for the re-association at this point */
447 	if (pe_session->ftPEContext.ftPreAuthStatus == QDF_STATUS_SUCCESS) {
448 		pbssDescription =
449 		      pe_session->ftPEContext.pFTPreAuthReq->pbssDescription;
450 		ft_session =
451 			pe_create_session(mac, pbssDescription->bssId,
452 					  &sessionId,
453 					  mac->lim.max_sta_of_pe_session,
454 					  pe_session->bssType,
455 					  pe_session->vdev_id);
456 		if (!ft_session) {
457 			pe_err("Session not created for pre-auth 11R AP");
458 			status = QDF_STATUS_E_FAILURE;
459 			pe_session->ftPEContext.ftPreAuthStatus = status;
460 			goto send_rsp;
461 		}
462 
463 		sir_copy_mac_addr(ft_session->self_mac_addr,
464 				  pe_session->self_mac_addr);
465 		sir_copy_mac_addr(ft_session->limReAssocbssId,
466 				  pbssDescription->bssId);
467 
468 		/* Update the beacon/probe filter in mac_ctx */
469 		lim_set_bcn_probe_filter(mac, ft_session, 0);
470 
471 		if (ft_session->bssType == eSIR_INFRASTRUCTURE_MODE)
472 			ft_session->limSystemRole = eLIM_STA_ROLE;
473 		else
474 			pe_err("Invalid bss type");
475 
476 		ft_session->limPrevSmeState = ft_session->limSmeState;
477 		ft_session->ht_config = pe_session->ht_config;
478 		ft_session->limSmeState = eLIM_SME_WT_REASSOC_STATE;
479 
480 		if (wlan_reg_is_24ghz_ch_freq(pe_session->ftPEContext.
481 		    pFTPreAuthReq->pre_auth_channel_freq))
482 			ft_session->vdev_nss = mac->vdev_type_nss_2g.sta;
483 		else
484 			ft_session->vdev_nss = mac->vdev_type_nss_5g.sta;
485 
486 		/* Update the ReAssoc BSSID of the current session */
487 		sir_copy_mac_addr(pe_session->limReAssocbssId,
488 				  pbssDescription->bssId);
489 		pe_debug("created session (%pK) with id = %d BSSID = "QDF_MAC_ADDR_FMT,
490 			 ft_session, ft_session->peSessionId,
491 			 QDF_MAC_ADDR_REF(pe_session->limReAssocbssId));
492 	}
493 send_rsp:
494 	if ((pe_session->curr_op_freq !=
495 	     pe_session->ftPEContext.pFTPreAuthReq->pre_auth_channel_freq) ||
496 	    lim_is_in_mcc(mac)) {
497 		pe_debug("Pre auth on diff freq as connected AP freq %d or mcc pe sessions exist, so abort scan",
498 			 pe_session->ftPEContext.pFTPreAuthReq->pre_auth_channel_freq);
499 
500 		/* Need to move to the original AP channel */
501 		lim_process_abort_scan_ind(mac, pe_session->smeSessionId,
502 			pe_session->ftPEContext.pFTPreAuthReq->scan_id,
503 			mac->lim.req_id | PREAUTH_REQUESTOR_ID);
504 	}
505 	/*
506 	 * Send resp to connection manager, even in case scan needs abort,
507 	 * scan complete will be no-op.
508 	 */
509 	lim_ft_process_pre_auth_result(mac, pe_session);
510 }
511 
512 /*
513  * lim_process_ft_preauth_rsp_timeout() - process ft preauth rsp timeout
514  *
515  * @mac_ctx:		global mac ctx
516  *
517  * This function is called if preauth response is not received from the AP
518  * within this timeout while FT in progress
519  *
520  * Return: void
521  */
lim_process_ft_preauth_rsp_timeout(struct mac_context * mac_ctx)522 void lim_process_ft_preauth_rsp_timeout(struct mac_context *mac_ctx)
523 {
524 	struct pe_session *session;
525 
526 	/*
527 	 * We have failed pre auth. We need to resume link and get back on
528 	 * home channel
529 	 */
530 	pe_err("FT Pre-Auth Time Out!!!!");
531 	session = pe_find_session_by_session_id(mac_ctx,
532 		     mac_ctx->lim.lim_timers.gLimFTPreAuthRspTimer.sessionId);
533 	if (!session) {
534 		pe_err("Session Does not exist for given sessionID");
535 		return;
536 	}
537 
538 	/* Nothing to be done if the session is not in STA mode */
539 	if (!LIM_IS_STA_ROLE(session)) {
540 		pe_err("session is not in STA mode");
541 		return;
542 	}
543 
544 	/* Reset the flag to indicate preauth request session */
545 	session->ftPEContext.ftPreAuthSession = false;
546 
547 	if (!session->ftPEContext.pFTPreAuthReq) {
548 		/* Auth Rsp might already be posted to SME and ftcleanup done */
549 		pe_err("pFTPreAuthReq is NULL sessionId: %d",
550 		       mac_ctx->lim.lim_timers.gLimFTPreAuthRspTimer.sessionId);
551 		return;
552 	}
553 
554 	/*
555 	 * To handle the race condition where we receive preauth rsp after
556 	 * timer has expired.
557 	 */
558 	if (true ==
559 	    session->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed) {
560 		pe_err("Auth rsp already posted to SME (session %pK)",
561 			session);
562 		return;
563 	} else {
564 		/*
565 		 * Here we are sending preauth rsp with failure state
566 		 * and which is forwarded to SME. Now, if we receive an preauth
567 		 * resp from AP with success it would create a FT pesession, but
568 		 * will be dropped in SME leaving behind the pesession. Mark
569 		 * Preauth rsp processed so that any rsp from AP is dropped in
570 		 * lim_process_auth_frame_no_session.
571 		 */
572 		pe_debug("Auth rsp not yet posted to SME (session %pK)",
573 			session);
574 		session->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed = true;
575 	}
576 
577 	/*
578 	 * Attempted at Pre-Auth and failed. If we are off channel. We need
579 	 * to get back to home channel
580 	 */
581 	lim_handle_ft_pre_auth_rsp(mac_ctx, QDF_STATUS_E_FAILURE, NULL, 0, session);
582 }
583 
584 /*
585  * lim_cm_post_preauth_rsp() - post preauth response to osif.
586  *
587  * @mac_ctx:		global mac ctx
588  * @status:		status code to post in auth rsp
589  * @auth_rsp:		pointer to auth rsp FT ie
590  * @auth_rsp_length:	len of the IE field
591  * @session:	        pe session
592  *
593  * post preauth response to osif.
594  *
595  * Return: void
596  */
597 static void
lim_cm_post_preauth_rsp(struct mac_context * mac_ctx,QDF_STATUS status,uint8_t * auth_rsp,uint16_t auth_rsp_length,struct pe_session * session)598 lim_cm_post_preauth_rsp(struct mac_context *mac_ctx, QDF_STATUS status,
599 			uint8_t *auth_rsp, uint16_t auth_rsp_length,
600 			struct pe_session *session)
601 {
602 	QDF_STATUS qdf_status;
603 	struct scheduler_msg rsp_msg = {0};
604 	struct wlan_preauth_rsp *rsp;
605 
606 	rsp = qdf_mem_malloc(sizeof(*rsp));
607 	if (!rsp)
608 		return;
609 
610 	rsp->psoc = mac_ctx->psoc;
611 	if (session) {
612 		/* Nothing to be done if the session is not in STA mode */
613 		if (!LIM_IS_STA_ROLE(session)) {
614 			pe_err("session is not in STA mode");
615 			qdf_mem_free(rsp);
616 			return;
617 		}
618 		rsp->vdev_id = session->vdev_id;
619 		/* The bssid of the AP we are sending Auth1 to. */
620 		if (session->ftPEContext.pFTPreAuthReq)
621 			qdf_mem_copy(rsp->pre_auth_bssid.bytes,
622 				     session->ftPEContext.
623 						pFTPreAuthReq->preAuthbssId,
624 				     QDF_MAC_ADDR_SIZE);
625 	}
626 	rsp->status = status;
627 
628 	/* Attach the auth response now back to osif */
629 	rsp->ft_ie_length = 0;
630 	if (auth_rsp && (auth_rsp_length < MAX_FTIE_SIZE)) {
631 		/* Only 11r assoc has FT IEs */
632 		qdf_mem_copy(rsp->ft_ie, auth_rsp, auth_rsp_length);
633 		rsp->ft_ie_length = auth_rsp_length;
634 	}
635 
636 	rsp_msg.bodyptr = rsp;
637 	rsp_msg.callback = cm_handle_preauth_rsp;
638 
639 	qdf_status = scheduler_post_message(
640 				QDF_MODULE_ID_PE, QDF_MODULE_ID_OS_IF,
641 				QDF_MODULE_ID_OS_IF, &rsp_msg);
642 
643 	if (QDF_IS_STATUS_ERROR(qdf_status)) {
644 		pe_err("Failed to post preauth rsp to sme vdev_id %d",
645 		       rsp->vdev_id);
646 		qdf_mem_free(rsp);
647 	}
648 }
649 
650 /*
651  * lim_post_ft_pre_auth_rsp() - post ft pre auth response to SME.
652  *
653  * @mac_ctx:		global mac ctx
654  * @status:		status code to post in auth rsp
655  * @auth_rsp:		pointer to auth rsp FT ie
656  * @auth_rsp_length:	len of the IE field
657  * @session:	        pe session
658  *
659  * post pre auth response to SME.
660  *
661  * Return: void
662  */
lim_post_ft_pre_auth_rsp(struct mac_context * mac_ctx,QDF_STATUS status,uint8_t * auth_rsp,uint16_t auth_rsp_length,struct pe_session * session)663 void lim_post_ft_pre_auth_rsp(struct mac_context *mac_ctx,
664 			      QDF_STATUS status,
665 			      uint8_t *auth_rsp,
666 			      uint16_t auth_rsp_length,
667 			      struct pe_session *session)
668 {
669 #ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM    /* FEATURE_WLAN_DIAG_SUPPORT */
670 	if (status == QDF_STATUS_SUCCESS)
671 		lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_PREAUTH_DONE,
672 				      session, status, 0);
673 #endif
674 	lim_cm_post_preauth_rsp(mac_ctx, status, auth_rsp, auth_rsp_length,
675 				session);
676 }
677 
678 /**
679  * lim_send_preauth_scan_offload() - Send scan command to handle preauth.
680  *
681  * @mac_ctx: Pointer to Global MAC structure
682  * @session_entry: pe session
683  * @ft_preauth_req: Preauth request with parameters
684  *
685  * Builds a single channel scan request and sends it to scan module.
686  * Scan dwell time is the time allocated to go to preauth candidate
687  * channel for auth frame exchange.
688  *
689  * Return: Status of sending message to scan module.
690  */
lim_send_preauth_scan_offload(struct mac_context * mac_ctx,struct pe_session * session_entry,tSirFTPreAuthReq * ft_preauth_req)691 QDF_STATUS lim_send_preauth_scan_offload(struct mac_context *mac_ctx,
692 					 struct pe_session *session_entry,
693 					 tSirFTPreAuthReq *ft_preauth_req)
694 {
695 	struct scan_start_request *req;
696 	struct wlan_objmgr_vdev *vdev;
697 	uint8_t vdev_id;
698 	QDF_STATUS status = QDF_STATUS_SUCCESS;
699 
700 	if (!session_entry) {
701 		pe_err("Session entry is NULL");
702 		return QDF_STATUS_E_FAILURE;
703 	}
704 
705 	vdev_id = session_entry->smeSessionId;
706 
707 	req = qdf_mem_malloc(sizeof(*req));
708 	if (!req)
709 		return QDF_STATUS_E_NOMEM;
710 
711 	qdf_mem_zero(req, sizeof(*req));
712 
713 	vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev,
714 						    vdev_id,
715 						    WLAN_LEGACY_MAC_ID);
716 	if (!vdev) {
717 		pe_err("vdev_id %d: vdev is NULL", vdev_id);
718 		qdf_mem_free(req);
719 		return QDF_STATUS_E_FAILURE;
720 	}
721 
722 	wlan_scan_init_default_params(vdev, req);
723 
724 	qdf_mem_copy(req->scan_req.bssid_list,
725 		     (uint8_t *)ft_preauth_req->currbssId,
726 		     QDF_MAC_ADDR_SIZE);
727 
728 	req->scan_req.scan_id = wlan_scan_get_scan_id(mac_ctx->psoc);
729 	if (!req->scan_req.scan_id) {
730 		wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
731 		qdf_mem_free(req);
732 		pe_err("Invalid scan ID");
733 		return QDF_STATUS_E_FAILURE;
734 	}
735 	ft_preauth_req->scan_id = req->scan_req.scan_id;
736 	req->scan_req.vdev_id = vdev_id;
737 	req->scan_req.scan_req_id = mac_ctx->lim.req_id | PREAUTH_REQUESTOR_ID;
738 	req->scan_req.scan_priority = SCAN_PRIORITY_VERY_HIGH;
739 	req->scan_req.scan_f_passive = true;
740 
741 	req->scan_req.chan_list.num_chan = 1;
742 	req->scan_req.chan_list.chan[0].freq =
743 			ft_preauth_req->pre_auth_channel_freq;
744 
745 	req->scan_req.dwell_time_active = LIM_FT_PREAUTH_ACTIVE_SCAN_TIME;
746 	req->scan_req.dwell_time_passive = LIM_FT_PREAUTH_PASSIVE_SCAN_TIME;
747 
748 	status = wlan_scan_start(req);
749 	if (QDF_IS_STATUS_ERROR(status))
750 		/* Don't free req here, ucfg_scan_start will do free */
751 		pe_info("Issue scan req failed");
752 	wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
753 	return status;
754 }
755 
lim_preauth_scan_event_handler(struct mac_context * mac_ctx,enum sir_scan_event_type event,uint8_t vdev_id,uint32_t scan_id)756 void lim_preauth_scan_event_handler(struct mac_context *mac_ctx,
757 				    enum sir_scan_event_type event,
758 				    uint8_t vdev_id, uint32_t scan_id)
759 {
760 	struct pe_session *session_entry;
761 
762 	session_entry = pe_find_session_by_scan_id(mac_ctx, scan_id);
763 	/* Pre-auth request is sent */
764 	if (session_entry) {
765 		if ((event == SIR_SCAN_EVENT_FOREIGN_CHANNEL) &&
766 		    (session_entry->ftPEContext.ftPreAuthStatus
767 		     == QDF_STATUS_SUCCESS)) {
768 			pe_err("Pre-auth is done, skip sending pre-auth req");
769 			return;
770 		}
771 	} else {
772 		/* For the first pre-auth request
773 		 * need to get it by sme session id (vdev id)
774 		 */
775 		session_entry = pe_find_session_by_vdev_id(mac_ctx, vdev_id);
776 	}
777 
778 	if (!session_entry) {
779 		pe_err("vdev_id :%d PeSessionId:%d does not exist", vdev_id,
780 			mac_ctx->lim.lim_timers.gLimFTPreAuthRspTimer.sessionId);
781 		return;
782 	}
783 
784 	switch (event) {
785 	case SIR_SCAN_EVENT_START_FAILED:
786 		/* Scan command is rejected by firmware */
787 		pe_err("Failed to start preauth scan");
788 		lim_post_ft_pre_auth_rsp(mac_ctx, QDF_STATUS_E_FAILURE, NULL, 0,
789 					 session_entry);
790 		return;
791 
792 	case SIR_SCAN_EVENT_COMPLETED:
793 		/*
794 		 * Scan either completed successfully or or got terminated
795 		 * after successful auth, or timed out. Either way, STA
796 		 * is back to home channel. Data traffic can continue.
797 		 * Don't do anything as preauth timer/auth resp will take care
798 		 * of the sending resp to the connection manager.
799 		 */
800 		break;
801 
802 	case SIR_SCAN_EVENT_FOREIGN_CHANNEL:
803 		/* Sta is on candidate channel. Send auth */
804 		lim_perform_ft_pre_auth(mac_ctx, QDF_STATUS_SUCCESS, NULL,
805 					session_entry);
806 		break;
807 	default:
808 		/* Don't print message for scan events that are ignored */
809 		break;
810 	}
811 }
812 
813