1 /*
2  * Copyright (c) 2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /**
19  * DOC: wlan_cm_host_roam_preauth.c
20  *
21  * Implements general roam pre-auth functionality for connection manager
22  */
23 
24 #include "wlan_cm_vdev_api.h"
25 #include "wni_api.h"
26 #include <wlan_cm_api.h>
27 #include "wlan_cm_roam_api.h"
28 #include "wlan_cm_roam_public_struct.h"
29 #include "wlan_cm_public_struct.h"
30 #include "wlan_mlme_vdev_mgr_interface.h"
31 #include "connection_mgr/core/src/wlan_cm_roam.h"
32 #include "connection_mgr/core/src/wlan_cm_sm.h"
33 #include "connection_mgr/core/src/wlan_cm_main_api.h"
34 
35 #define MAX_NUM_PREAUTH_RETRIES 3
36 #define CM_PREAUTH_TIMEOUT 10000
37 #define REASSOC_TIMER_DURATION 60
38 
cm_get_valid_preauth_candidate(struct cm_roam_req * cm_req)39 static QDF_STATUS cm_get_valid_preauth_candidate(struct cm_roam_req *cm_req)
40 {
41 	qdf_list_t *candidate_list;
42 	qdf_list_node_t *cur_node = NULL;
43 	struct scan_cache_node *prev_candidate;
44 	bool new_candidate = false;
45 	uint8_t vdev_id = cm_req->req.vdev_id;
46 
47 	candidate_list = cm_req->candidate_list;
48 	if (!candidate_list || !qdf_list_size(candidate_list)) {
49 		mlme_info(CM_PREFIX_FMT "no valid candidate found",
50 			  CM_PREFIX_REF(vdev_id, cm_req->cm_id));
51 		return QDF_STATUS_E_EMPTY;
52 	}
53 
54 	prev_candidate = cm_req->cur_candidate;
55 	if (!prev_candidate) {
56 		qdf_list_peek_front(candidate_list, &cur_node);
57 		new_candidate = true;
58 	} else if (cm_req->num_preauth_retry >= MAX_NUM_PREAUTH_RETRIES) {
59 		qdf_list_peek_next(candidate_list, &prev_candidate->node,
60 				   &cur_node);
61 		new_candidate = true;
62 	}
63 
64 	if (new_candidate) {
65 		if (!cur_node) {
66 			mlme_debug(CM_PREFIX_FMT "All candidates tried",
67 				   CM_PREFIX_REF(vdev_id, cm_req->cm_id));
68 			return QDF_STATUS_E_FAILURE;
69 		}
70 		cm_req->num_preauth_retry = 0;
71 		cm_req->cur_candidate = qdf_container_of(cur_node,
72 							 struct scan_cache_node,
73 							 node);
74 	}
75 
76 	cm_req->num_preauth_retry++;
77 
78 	mlme_debug(CM_PREFIX_FMT "Try preauth attempt no. %d for " QDF_MAC_ADDR_FMT,
79 		   CM_PREFIX_REF(vdev_id, cm_req->cm_id),
80 		   cm_req->num_preauth_retry,
81 		   QDF_MAC_ADDR_REF(cm_req->cur_candidate->entry->bssid.bytes));
82 
83 	return QDF_STATUS_SUCCESS;
84 }
85 
cm_preauth_fail(struct cnx_mgr * cm_ctx,struct wlan_cm_preauth_fail * preauth_fail_rsp)86 void cm_preauth_fail(struct cnx_mgr *cm_ctx,
87 		     struct wlan_cm_preauth_fail *preauth_fail_rsp)
88 {
89 	struct cm_req *cm_req;
90 	wlan_cm_id cm_id;
91 
92 	cm_id = preauth_fail_rsp->cm_id;
93 	cm_req = cm_get_req_by_cm_id(cm_ctx, cm_id);
94 	/*
95 	 * If the entry is not present in the list, it must have been cleared
96 	 * already.
97 	 */
98 	if (!cm_req)
99 		return;
100 
101 	if (cm_get_state(cm_ctx) == WLAN_CM_S_CONNECTED)
102 		cm_mlme_roam_preauth_fail(cm_ctx->vdev, &cm_req->roam_req.req,
103 					  preauth_fail_rsp->reason);
104 
105 	mlme_debug(CM_PREFIX_FMT,
106 		   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id));
107 
108 	if (cm_req->roam_req.req.source == CM_ROAMING_HOST &&
109 	    cm_get_state(cm_ctx) == WLAN_CM_S_CONNECTED)
110 		wlan_cm_disconnect(cm_ctx->vdev, CM_ROAM_DISCONNECT,
111 				   REASON_USER_TRIGGERED_ROAM_FAILURE, NULL);
112 
113 	cm_remove_cmd(cm_ctx, &cm_id);
114 }
115 
116 static void
cm_preauth_handle_event_post_fail(struct cnx_mgr * cm_ctx,wlan_cm_id cm_id)117 cm_preauth_handle_event_post_fail(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
118 {
119 	struct wlan_cm_preauth_fail preauth_fail_rsp;
120 
121 	preauth_fail_rsp.cm_id = cm_id;
122 	preauth_fail_rsp.reason = CM_ABORT_DUE_TO_NEW_REQ_RECVD;
123 
124 	cm_preauth_fail(cm_ctx, &preauth_fail_rsp);
125 }
126 
127 static QDF_STATUS
cm_preauth_cmd_timeout(struct cnx_mgr * cm_ctx,wlan_cm_id cm_id)128 cm_preauth_cmd_timeout(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
129 {
130 	QDF_STATUS status;
131 	struct wlan_cm_preauth_fail preauth_fail_rsp;
132 
133 	preauth_fail_rsp.cm_id = cm_id;
134 	preauth_fail_rsp.reason = CM_SER_TIMEOUT;
135 
136 	status = cm_sm_deliver_event(
137 			cm_ctx->vdev, WLAN_CM_SM_EV_PREAUTH_FAIL,
138 			sizeof(struct wlan_cm_preauth_fail), &preauth_fail_rsp);
139 	if (QDF_IS_STATUS_ERROR(status))
140 		cm_preauth_handle_event_post_fail(cm_ctx, cm_id);
141 
142 	return status;
143 }
144 
145 static QDF_STATUS
cm_ser_preauth_cb(struct wlan_serialization_command * cmd,enum wlan_serialization_cb_reason reason)146 cm_ser_preauth_cb(struct wlan_serialization_command *cmd,
147 		  enum wlan_serialization_cb_reason reason)
148 {
149 	QDF_STATUS status = QDF_STATUS_SUCCESS;
150 	struct wlan_objmgr_vdev *vdev;
151 	struct cnx_mgr *cm_ctx;
152 
153 	if (!cmd) {
154 		mlme_err("cmd is NULL, reason: %d", reason);
155 		QDF_ASSERT(0);
156 		return QDF_STATUS_E_NULL_VALUE;
157 	}
158 
159 	vdev = cmd->vdev;
160 	cm_ctx = cm_get_cm_ctx(vdev);
161 	if (!cm_ctx)
162 		return QDF_STATUS_E_NULL_VALUE;
163 
164 	switch (reason) {
165 	case WLAN_SER_CB_ACTIVATE_CMD:
166 		if (cmd->activation_reason == SER_PENDING_TO_ACTIVE)
167 			status = cm_sm_deliver_event(
168 					vdev, WLAN_CM_SM_EV_PREAUTH_ACTIVE,
169 					sizeof(wlan_cm_id), &cmd->cmd_id);
170 		else
171 			status = cm_sm_deliver_event_sync(
172 					cm_ctx, WLAN_CM_SM_EV_PREAUTH_ACTIVE,
173 					sizeof(wlan_cm_id), &cmd->cmd_id);
174 		if (QDF_IS_STATUS_SUCCESS(status))
175 			break;
176 		/*
177 		 * Handle failure if posting fails, i.e. the SM state has
178 		 * changed or head cm_id doesn't match the active cm_id.
179 		 * connect active should be handled only in JOIN_PENDING. If
180 		 * new command has been received connect activation should be
181 		 * aborted from here with connect req cleanup.
182 		 */
183 		cm_preauth_handle_event_post_fail(cm_ctx, cmd->cmd_id);
184 		break;
185 	case WLAN_SER_CB_CANCEL_CMD:
186 		/* command removed from pending list. */
187 		break;
188 	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
189 		mlme_err(CM_PREFIX_FMT "Active command timeout",
190 			 CM_PREFIX_REF(wlan_vdev_get_id(vdev), cmd->cmd_id));
191 		QDF_ASSERT(0);
192 
193 		cm_preauth_cmd_timeout(cm_ctx, cmd->cmd_id);
194 		break;
195 	case WLAN_SER_CB_RELEASE_MEM_CMD:
196 		cm_reset_active_cm_id(vdev, cmd->cmd_id);
197 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
198 		break;
199 	default:
200 		QDF_ASSERT(0);
201 		status = QDF_STATUS_E_INVAL;
202 		break;
203 	}
204 
205 	return status;
206 }
207 
cm_ser_preauth_req(struct cnx_mgr * cm_ctx,struct cm_req * cm_req)208 static QDF_STATUS cm_ser_preauth_req(struct cnx_mgr *cm_ctx,
209 				     struct cm_req *cm_req)
210 {
211 	struct wlan_serialization_command cmd = {0, };
212 	enum wlan_serialization_status ser_cmd_status;
213 	QDF_STATUS status;
214 	uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
215 
216 	status = wlan_objmgr_vdev_try_get_ref(cm_ctx->vdev, WLAN_MLME_CM_ID);
217 	if (QDF_IS_STATUS_ERROR(status)) {
218 		mlme_err(CM_PREFIX_FMT "unable to get reference",
219 			 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
220 		return status;
221 	}
222 
223 	cmd.cmd_type = WLAN_SER_CMD_PERFORM_PRE_AUTH;
224 	cmd.cmd_id = cm_req->cm_id;
225 	cmd.cmd_cb = cm_ser_preauth_cb;
226 	cmd.source = WLAN_UMAC_COMP_MLME;
227 	cmd.is_high_priority = false;
228 	cmd.cmd_timeout_duration = CM_PREAUTH_TIMEOUT;
229 	cmd.vdev = cm_ctx->vdev;
230 	cmd.is_blocking = true;
231 
232 	ser_cmd_status = wlan_serialization_request(&cmd);
233 	switch (ser_cmd_status) {
234 	case WLAN_SER_CMD_PENDING:
235 		/* command moved to pending list.Do nothing */
236 		break;
237 	case WLAN_SER_CMD_ACTIVE:
238 		/* command moved to active list. Do nothing */
239 		break;
240 	default:
241 		mlme_err(CM_PREFIX_FMT "ser cmd status %d",
242 			 CM_PREFIX_REF(vdev_id, cm_req->cm_id), ser_cmd_status);
243 		wlan_objmgr_vdev_release_ref(cm_ctx->vdev, WLAN_MLME_CM_ID);
244 
245 		return QDF_STATUS_E_FAILURE;
246 	}
247 
248 	return QDF_STATUS_SUCCESS;
249 }
250 
251 QDF_STATUS
cm_send_preauth_start_fail(struct cnx_mgr * cm_ctx,wlan_cm_id cm_id,enum wlan_cm_connect_fail_reason reason)252 cm_send_preauth_start_fail(struct cnx_mgr *cm_ctx,
253 			   wlan_cm_id cm_id,
254 			   enum wlan_cm_connect_fail_reason reason)
255 {
256 	QDF_STATUS status;
257 	struct wlan_cm_preauth_fail preauth_fail_rsp;
258 
259 	preauth_fail_rsp.cm_id = cm_id;
260 	preauth_fail_rsp.reason = reason;
261 
262 	status = cm_sm_deliver_event_sync(
263 			cm_ctx, WLAN_CM_SM_EV_PREAUTH_FAIL,
264 			sizeof(struct wlan_cm_preauth_fail), &preauth_fail_rsp);
265 	if (QDF_IS_STATUS_ERROR(status))
266 		cm_preauth_handle_event_post_fail(cm_ctx, cm_id);
267 
268 	return status;
269 }
270 
cm_flush_invalid_preauth_ap(struct cnx_mgr * cm_ctx,struct cm_roam_req * roam_req)271 static void cm_flush_invalid_preauth_ap(struct cnx_mgr *cm_ctx,
272 					struct cm_roam_req *roam_req)
273 {
274 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
275 	qdf_list_t *candidate_list;
276 	struct scan_cache_node *scan_node = NULL;
277 	struct qdf_mac_addr connected_bssid;
278 	bool is_valid;
279 	uint8_t vdev_id = roam_req->req.vdev_id;
280 	struct wlan_objmgr_psoc *psoc;
281 	uint8_t enable_mcc_mode = false;
282 	qdf_freq_t conc_freq, bss_freq;
283 
284 	/*
285 	 * Only When entering first time (ie cur_candidate is NULL),
286 	 * flush invalid APs from the list and if list is not NULL.
287 	 */
288 	if (roam_req->cur_candidate || !roam_req->candidate_list)
289 		return;
290 
291 	psoc = wlan_vdev_get_psoc(cm_ctx->vdev);
292 	if (!psoc)
293 		return;
294 
295 	wlan_mlme_get_mcc_feature(psoc, &enable_mcc_mode);
296 
297 	wlan_vdev_get_bss_peer_mac(cm_ctx->vdev, &connected_bssid);
298 
299 	candidate_list = roam_req->candidate_list;
300 
301 	qdf_list_peek_front(candidate_list, &cur_node);
302 
303 	while (cur_node) {
304 		is_valid = true;
305 		qdf_list_peek_next(candidate_list, cur_node, &next_node);
306 		scan_node = qdf_container_of(cur_node, struct scan_cache_node,
307 					     node);
308 		bss_freq = scan_node->entry->channel.chan_freq;
309 		if (qdf_is_macaddr_equal(&connected_bssid,
310 					 &scan_node->entry->bssid)) {
311 			mlme_debug(CM_PREFIX_FMT "Remove connected AP " QDF_MAC_ADDR_FMT " from list",
312 				   CM_PREFIX_REF(vdev_id, roam_req->cm_id),
313 				   QDF_MAC_ADDR_REF(connected_bssid.bytes));
314 			is_valid = false;
315 		}
316 
317 		/*
318 		 * Continue if MCC is disabled in INI and if AP
319 		 * will create MCC
320 		 */
321 		if (policy_mgr_concurrent_open_sessions_running(psoc) &&
322 		    !enable_mcc_mode) {
323 			conc_freq = wlan_get_conc_freq();
324 			if (conc_freq && (conc_freq != bss_freq)) {
325 				mlme_info(CM_PREFIX_FMT "Remove AP " QDF_MAC_ADDR_FMT ", MCC not supported. freq %d conc_freq %d",
326 					  CM_PREFIX_REF(vdev_id, roam_req->cm_id),
327 					  QDF_MAC_ADDR_REF(connected_bssid.bytes),
328 					  bss_freq, conc_freq);
329 				is_valid = false;
330 			}
331 		}
332 
333 		if (!is_valid) {
334 			qdf_list_remove_node(candidate_list, cur_node);
335 			util_scan_free_cache_entry(scan_node->entry);
336 			qdf_mem_free(scan_node);
337 		}
338 
339 		cur_node = next_node;
340 		next_node = NULL;
341 	}
342 }
343 
cm_host_roam_preauth_start(struct cnx_mgr * cm_ctx,struct cm_req * cm_req)344 QDF_STATUS cm_host_roam_preauth_start(struct cnx_mgr *cm_ctx,
345 				      struct cm_req *cm_req)
346 {
347 	QDF_STATUS status;
348 
349 	cm_flush_invalid_preauth_ap(cm_ctx, &cm_req->roam_req);
350 
351 	status = cm_get_valid_preauth_candidate(&cm_req->roam_req);
352 	if (QDF_IS_STATUS_ERROR(status))
353 		return status;
354 
355 	return cm_ser_preauth_req(cm_ctx, cm_req);
356 }
357 
cm_free_preauth_req(struct wlan_preauth_req * preauth_req)358 void cm_free_preauth_req(struct wlan_preauth_req *preauth_req)
359 {
360 	if (!preauth_req)
361 		return;
362 
363 	util_scan_free_cache_entry(preauth_req->entry);
364 	preauth_req->entry = NULL;
365 	qdf_mem_free(preauth_req);
366 }
367 
cm_flush_preauth_req(struct scheduler_msg * msg)368 static QDF_STATUS cm_flush_preauth_req(struct scheduler_msg *msg)
369 {
370 	struct wlan_preauth_req *preauth_req;
371 
372 	if (!msg || !msg->bodyptr) {
373 		mlme_err("msg or msg->bodyptr is NULL");
374 		return QDF_STATUS_E_INVAL;
375 	}
376 
377 	preauth_req = msg->bodyptr;
378 	cm_free_preauth_req(preauth_req);
379 
380 	return QDF_STATUS_SUCCESS;
381 }
382 
383 static QDF_STATUS
cm_issue_preauth_req(struct cnx_mgr * cm_ctx,struct cm_roam_req * roam_req)384 cm_issue_preauth_req(struct cnx_mgr *cm_ctx, struct cm_roam_req *roam_req)
385 {
386 	struct wlan_preauth_req *preauth_req;
387 	struct scheduler_msg msg;
388 	QDF_STATUS status;
389 
390 	qdf_mem_zero(&msg, sizeof(msg));
391 	preauth_req = qdf_mem_malloc(sizeof(*preauth_req));
392 	if (!preauth_req)
393 		return QDF_STATUS_E_NOMEM;
394 
395 	preauth_req->vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
396 	preauth_req->entry =
397 		util_scan_copy_cache_entry(roam_req->cur_candidate->entry);
398 
399 	if (!preauth_req->entry) {
400 		qdf_mem_free(preauth_req);
401 		return QDF_STATUS_E_NOMEM;
402 	}
403 
404 	msg.bodyptr = preauth_req;
405 	msg.type = CM_PREAUTH_REQ;
406 	msg.flush_callback = cm_flush_preauth_req;
407 
408 	status = scheduler_post_message(QDF_MODULE_ID_MLME,
409 					QDF_MODULE_ID_PE,
410 					QDF_MODULE_ID_PE, &msg);
411 	if (QDF_IS_STATUS_ERROR(status)) {
412 		mlme_err(CM_PREFIX_FMT "msg post fail",
413 			 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
414 				       roam_req->cm_id));
415 		cm_free_preauth_req(preauth_req);
416 	}
417 
418 	return status;
419 }
420 
cm_preauth_active(struct cnx_mgr * cm_ctx,wlan_cm_id * cm_id)421 QDF_STATUS cm_preauth_active(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id)
422 {
423 	struct cm_req *cm_req;
424 	struct cm_roam_req *roam_req;
425 	QDF_STATUS status;
426 
427 	cm_req = cm_get_req_by_cm_id(cm_ctx, *cm_id);
428 	if (!cm_req)
429 		return QDF_STATUS_E_INVAL;
430 
431 	cm_ctx->active_cm_id = *cm_id;
432 	roam_req = &cm_req->roam_req;
433 
434 	status = cm_issue_preauth_req(cm_ctx, roam_req);
435 	if (QDF_IS_STATUS_ERROR(status))
436 		cm_send_preauth_start_fail(cm_ctx, *cm_id, CM_GENERIC_FAILURE);
437 
438 	return status;
439 }
440 
441 #ifdef FEATURE_WLAN_ESE
cm_update_cckmtsf(uint32_t * timestamp0,uint32_t * timestamp1,uint64_t * incr)442 static void cm_update_cckmtsf(uint32_t *timestamp0, uint32_t *timestamp1,
443 			      uint64_t *incr)
444 {
445 	uint64_t timestamp64 = ((uint64_t)*timestamp1 << 32) | (*timestamp0);
446 
447 	timestamp64 = (uint64_t)(timestamp64 + (*incr));
448 	*timestamp0 = (uint32_t)(timestamp64 & 0xffffffff);
449 	*timestamp1 = (uint32_t)((timestamp64 >> 32) & 0xffffffff);
450 }
451 
452 /**
453  * cm_roam_read_tsf() - read TSF
454  * @cm_ctx: connection manager context
455  * @rsp: preauth response
456  *
457  * This function reads the TSF and also add the time elapsed since last
458  * beacon or probe response reception from the hand off AP to arrive at
459  * the latest TSF value.
460  *
461  * Return: none
462  */
cm_roam_read_tsf(struct cnx_mgr * cm_ctx,struct wlan_preauth_rsp * rsp)463 static void cm_roam_read_tsf(struct cnx_mgr *cm_ctx,
464 			     struct wlan_preauth_rsp *rsp)
465 {
466 	struct cm_req *cm_req;
467 	struct scan_cache_entry *scan_entry;
468 	uint64_t timer_diff = 0;
469 
470 	cm_req = cm_get_req_by_cm_id(cm_ctx, rsp->cm_id);
471 	if (!cm_req)
472 		return;
473 	if (!cm_req->roam_req.cur_candidate ||
474 	    !cm_req->roam_req.cur_candidate->entry)
475 		return;
476 
477 	scan_entry = cm_req->roam_req.cur_candidate->entry;
478 	qdf_mem_copy(rsp->timestamp, scan_entry->tsf_info.data, 8);
479 
480 	/* Get the time diff in nano seconds */
481 	timer_diff = qdf_get_monotonic_boottime_ns() - scan_entry->boottime_ns;
482 	/* Convert msec to micro sec timer */
483 	timer_diff = do_div(timer_diff, SYSTEM_TIME_NSEC_TO_USEC);
484 	/*  Update the TSF with the difference in system time */
485 	cm_update_cckmtsf(&rsp->timestamp[0], &rsp->timestamp[1],
486 			  &timer_diff);
487 }
488 #else
cm_roam_read_tsf(struct cnx_mgr * cm_ctx,struct wlan_preauth_rsp * rsp)489 static inline void cm_roam_read_tsf(struct cnx_mgr *cm_ctx,
490 				    struct wlan_preauth_rsp *rsp)
491 {}
492 #endif
493 
494 #define MD_IE_ID 54
495 
cm_reassoc_timer_callback(void * context)496 void cm_reassoc_timer_callback(void *context)
497 {
498 	QDF_STATUS status;
499 	struct reassoc_timer_ctx *ctx = context;
500 	struct cnx_mgr *cm_ctx;
501 	struct wlan_objmgr_vdev *vdev;
502 	wlan_cm_id cm_id = ctx->cm_id;
503 	uint8_t vdev_id = ctx->vdev_id;
504 
505 	vdev = wlan_objmgr_get_vdev_by_id_from_pdev(ctx->pdev, vdev_id,
506 						    WLAN_MLME_CM_ID);
507 	if (!vdev) {
508 		mlme_err(CM_PREFIX_FMT "vdev object is NULL",
509 			 CM_PREFIX_REF(vdev_id, cm_id));
510 		return;
511 	}
512 
513 	cm_ctx = cm_get_cm_ctx(vdev);
514 	if (!cm_ctx)
515 		goto rel_ref;
516 
517 	status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_REASSOC_TIMER,
518 				     sizeof(wlan_cm_id), &cm_id);
519 
520 	if (QDF_IS_STATUS_ERROR(status))
521 		cm_preauth_handle_event_post_fail(cm_ctx, cm_id);
522 
523 rel_ref:
524 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
525 }
526 
cm_preauth_success(struct cnx_mgr * cm_ctx,struct wlan_preauth_rsp * rsp)527 void cm_preauth_success(struct cnx_mgr *cm_ctx, struct wlan_preauth_rsp *rsp)
528 {
529 	QDF_STATUS status;
530 	struct mlme_legacy_priv *mlme_priv;
531 	struct rso_config *rso_cfg;
532 	struct wlan_objmgr_pdev *pdev;
533 	struct wlan_objmgr_vdev *vdev;
534 	uint8_t vdev_id = rsp->vdev_id;
535 	wlan_cm_id cm_id = rsp->cm_id;
536 	struct cm_roam_values_copy config;
537 	bool is_11r;
538 
539 	vdev = cm_ctx->vdev;
540 	pdev = wlan_vdev_get_pdev(vdev);
541 	if (!pdev || !rsp->psoc) {
542 		mlme_err(CM_PREFIX_FMT "pdev or psoc is NULL",
543 			 CM_PREFIX_REF(vdev_id, cm_id));
544 		goto err;
545 	}
546 
547 	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
548 	if (!mlme_priv) {
549 		mlme_err(CM_PREFIX_FMT "vdev ext priv is NULL",
550 			 CM_PREFIX_REF(vdev_id, cm_id));
551 		goto err;
552 	}
553 
554 	rso_cfg = wlan_cm_get_rso_config(vdev);
555 	if (!rso_cfg) {
556 		mlme_err(CM_PREFIX_FMT "rso_cfg is NULL",
557 			 CM_PREFIX_REF(vdev_id, cm_id));
558 		goto err;
559 	}
560 
561 	mlme_err(CM_PREFIX_FMT "Preauth success with " QDF_MAC_ADDR_FMT,
562 		 CM_PREFIX_REF(vdev_id, rsp->cm_id),
563 		 QDF_MAC_ADDR_REF(rsp->pre_auth_bssid.bytes));
564 
565 	cm_csr_preauth_done(vdev);
566 
567 	qdf_mem_copy(rsp->ric_ies,
568 		     mlme_priv->connect_info.ft_info.ric_ies,
569 		     mlme_priv->connect_info.ft_info.ric_ies_length);
570 	rsp->ric_ies_length = mlme_priv->connect_info.ft_info.ric_ies_length;
571 
572 	mlme_priv->connect_info.ft_info.ft_state = FT_REASSOC_REQ_WAIT;
573 
574 	/* start reassoc timer */
575 	rso_cfg->ctx.pdev = pdev;
576 	rso_cfg->ctx.vdev_id = vdev_id;
577 	rso_cfg->ctx.cm_id = cm_id;
578 
579 	status = qdf_mc_timer_start(&rso_cfg->reassoc_timer,
580 				    REASSOC_TIMER_DURATION);
581 	if (QDF_IS_STATUS_ERROR(status)) {
582 		mlme_err(CM_PREFIX_FMT "start reassoc timer failed, status %d",
583 			 CM_PREFIX_REF(vdev_id, cm_id), status);
584 		goto err;
585 	}
586 
587 	wlan_cm_roam_cfg_get_value(rsp->psoc, vdev_id, IS_11R_CONNECTION,
588 				   &config);
589 	is_11r = config.bool_value;
590 	if (is_11r)
591 		mlme_cm_osif_ft_preauth_complete(vdev, rsp);
592 
593 	if (wlan_cm_get_ese_assoc(pdev, vdev_id)) {
594 		cm_roam_read_tsf(cm_ctx, rsp);
595 		mlme_cm_osif_cckm_preauth_complete(vdev, rsp);
596 	}
597 
598 	if (cm_is_fast_roam_enabled(rsp->psoc) &&
599 	    cm_is_rsn_or_8021x_sha256_auth_type(vdev))
600 		mlme_cm_osif_pmksa_candidate_notify(vdev, &rsp->pre_auth_bssid,
601 						    1, false);
602 
603 	mlme_priv->connect_info.ft_info.add_mdie = false;
604 	if (!(is_11r && cm_is_open_mode(vdev)))
605 		return;
606 
607 	qdf_mem_zero(mlme_priv->connect_info.ft_info.reassoc_ft_ie,
608 		     MAX_FTIE_SIZE);
609 	mlme_priv->connect_info.ft_info.reassoc_ie_len = 0;
610 
611 	if (wlan_get_ie_ptr_from_eid(MD_IE_ID, rsp->ft_ie, rsp->ft_ie_length))
612 		mlme_priv->connect_info.ft_info.add_mdie = true;
613 
614 	if (!mlme_priv->connect_info.ft_info.ric_ies_length)
615 		return;
616 
617 	/* Copy the RIC IEs to reassoc IEs */
618 	qdf_mem_copy(mlme_priv->connect_info.ft_info.reassoc_ft_ie,
619 		     mlme_priv->connect_info.ft_info.ric_ies,
620 		     mlme_priv->connect_info.ft_info.ric_ies_length);
621 	mlme_priv->connect_info.ft_info.reassoc_ie_len =
622 			mlme_priv->connect_info.ft_info.ric_ies_length;
623 	mlme_priv->connect_info.ft_info.add_mdie = true;
624 	return;
625 
626 err:
627 	rsp->status = QDF_STATUS_E_ABORTED;
628 	status = cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_PREAUTH_RESP,
629 					  sizeof(*rsp), rsp);
630 	if (QDF_IS_STATUS_ERROR(status))
631 		cm_preauth_handle_event_post_fail(cm_ctx, cm_id);
632 }
633 
634 static QDF_STATUS
cm_hanlde_preauth_failure(struct cnx_mgr * cm_ctx,wlan_cm_id cm_id)635 cm_hanlde_preauth_failure(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
636 {
637 	QDF_STATUS status;
638 	struct wlan_cm_preauth_fail preauth_fail_rsp;
639 
640 	preauth_fail_rsp.cm_id = cm_id;
641 	preauth_fail_rsp.reason = CM_GENERIC_FAILURE;
642 
643 	status = cm_sm_deliver_event_sync(
644 			cm_ctx, WLAN_CM_SM_EV_PREAUTH_FAIL,
645 			sizeof(struct wlan_cm_preauth_fail), &preauth_fail_rsp);
646 	if (QDF_IS_STATUS_ERROR(status))
647 		cm_preauth_handle_event_post_fail(cm_ctx, cm_id);
648 
649 	return status;
650 }
651 
cm_preauth_done_resp(struct cnx_mgr * cm_ctx,struct wlan_preauth_rsp * rsp)652 void cm_preauth_done_resp(struct cnx_mgr *cm_ctx, struct wlan_preauth_rsp *rsp)
653 {
654 	QDF_STATUS status;
655 	struct cm_req *cm_req;
656 	wlan_cm_id cm_id = rsp->cm_id;
657 
658 	if (QDF_IS_STATUS_ERROR(rsp->status)) {
659 		cm_req = cm_get_req_by_cm_id(cm_ctx, cm_id);
660 		if (!cm_req)
661 			return;
662 		mlme_info(CM_PREFIX_FMT "Preauth attempt no. %d failed for " QDF_MAC_ADDR_FMT,
663 			  CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id),
664 			  cm_req->roam_req.num_preauth_retry,
665 			  QDF_MAC_ADDR_REF(rsp->pre_auth_bssid.bytes));
666 
667 		/* retry again with same or new candidate */
668 		status = cm_host_roam_preauth_start(cm_ctx, cm_req);
669 		if (QDF_IS_STATUS_ERROR(status))
670 			cm_hanlde_preauth_failure(cm_ctx, cm_id);
671 	} else {
672 		status = cm_sm_deliver_event_sync(cm_ctx,
673 						  WLAN_CM_SM_EV_PREAUTH_DONE,
674 						  sizeof(*rsp), rsp);
675 		if (QDF_IS_STATUS_ERROR(status))
676 			cm_preauth_handle_event_post_fail(cm_ctx, cm_id);
677 	}
678 }
679 
680 /**
681  * cm_remove_preauth_cmd_from_serialization() - Remove preauth cmd
682  * from serialization
683  * @cm_ctx: connection manager context
684  * @cm_id: cm id of roam req
685  *
686  * Return: void
687  */
cm_remove_preauth_cmd_from_serialization(struct cnx_mgr * cm_ctx,wlan_cm_id cm_id)688 static void cm_remove_preauth_cmd_from_serialization(struct cnx_mgr *cm_ctx,
689 						     wlan_cm_id cm_id)
690 {
691 	struct wlan_serialization_queued_cmd_info cmd_info;
692 
693 	qdf_mem_zero(&cmd_info, sizeof(cmd_info));
694 	cmd_info.vdev = cm_ctx->vdev;
695 	cmd_info.cmd_id = cm_id;
696 	cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD;
697 	cmd_info.cmd_type = WLAN_SER_CMD_PERFORM_PRE_AUTH;
698 
699 	mlme_debug(CM_PREFIX_FMT "Remove cmd type %d from active",
700 		   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id),
701 		   cmd_info.cmd_type);
702 	cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE;
703 	wlan_serialization_remove_cmd(&cmd_info);
704 }
705 
cm_preauth_rsp(struct wlan_objmgr_vdev * vdev,struct wlan_preauth_rsp * rsp)706 static QDF_STATUS cm_preauth_rsp(struct wlan_objmgr_vdev *vdev,
707 				 struct wlan_preauth_rsp *rsp)
708 {
709 	QDF_STATUS status;
710 	struct cnx_mgr *cm_ctx;
711 	wlan_cm_id cm_id;
712 	uint32_t prefix;
713 
714 	cm_ctx = cm_get_cm_ctx(vdev);
715 	if (!cm_ctx)
716 		return QDF_STATUS_E_NULL_VALUE;
717 
718 	cm_id = cm_ctx->active_cm_id;
719 	prefix = CM_ID_GET_PREFIX(cm_id);
720 
721 	if (prefix != ROAM_REQ_PREFIX) {
722 		mlme_err(CM_PREFIX_FMT "active req is not roam req",
723 			 CM_PREFIX_REF(wlan_vdev_get_id(vdev), cm_id));
724 		return QDF_STATUS_E_INVAL;
725 	}
726 	rsp->cm_id = cm_id;
727 
728 	mlme_debug(CM_PREFIX_FMT "preauth resp status %d for " QDF_MAC_ADDR_FMT,
729 		   CM_PREFIX_REF(wlan_vdev_get_id(vdev), cm_id),
730 		   rsp->status, QDF_MAC_ADDR_REF(rsp->pre_auth_bssid.bytes));
731 
732 	cm_remove_preauth_cmd_from_serialization(cm_ctx, cm_id);
733 
734 	status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_PREAUTH_RESP,
735 				     sizeof(*rsp), rsp);
736 	if (QDF_IS_STATUS_ERROR(status))
737 		cm_preauth_handle_event_post_fail(cm_ctx, cm_id);
738 
739 	return status;
740 }
741 
cm_handle_preauth_rsp(struct scheduler_msg * msg)742 QDF_STATUS cm_handle_preauth_rsp(struct scheduler_msg *msg)
743 {
744 	QDF_STATUS status = QDF_STATUS_SUCCESS;
745 	struct wlan_preauth_rsp *rsp = NULL;
746 	struct wlan_objmgr_vdev *vdev;
747 
748 	if (!msg || !msg->bodyptr) {
749 		status = QDF_STATUS_E_FAILURE;
750 		goto end;
751 	}
752 
753 	rsp = (struct wlan_preauth_rsp *)msg->bodyptr;
754 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(rsp->psoc, rsp->vdev_id,
755 						    WLAN_MLME_CM_ID);
756 	if (!vdev) {
757 		mlme_err("vdev_id: %d : vdev not found, status %d",
758 			 rsp->vdev_id, rsp->status);
759 		status = QDF_STATUS_E_INVAL;
760 		goto end;
761 	}
762 
763 	status = cm_preauth_rsp(vdev, rsp);
764 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
765 end:
766 	if (rsp)
767 		qdf_mem_free(rsp);
768 
769 	return status;
770 }
771