xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlme/connection_mgr/utf/src/wlan_cm_utf_main.c (revision 97f44cd39e4ff816eaa1710279d28cf6b9e65ad9)
1 /*
2  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*
18  * DOC: Implements CM UTF
19  */
20 
21 #ifdef FEATURE_CM_UTF_ENABLE
22 #include <wlan_cm_utf.h>
23 #include <wlan_cm_api.h>
24 #include <qdf_str.h>
25 #include <wlan_cm_ucfg_api.h>
26 #include <include/wlan_mlme_cmn.h>
27 
28 #define CM_UTF_LIST_SIZE 1
29 
30 qdf_list_t wlan_cm_utf_list;
31 
32 static const char *cm_utf_test_names[] = {
33 	"CONNECT_SUCCESS",
34 	"DISCONNECT_SUCCESS",
35 	"PEER_CREATE_FAILURE",
36 	"PEER_CREATE_TIMEOUT",
37 	"PEER_DELETE_TIMEOUT",
38 	"AUTH_FAILURE",
39 	"AUTH_TIMEOUT",
40 	"ASSOC_FAILURE",
41 	"ASSOC_TIMEOUT",
42 	"CONNECT_SCAN_FAILURE",
43 	"CONNECT_SER_TIMEOUT",
44 	"DISCONNECT_SER_TIMEOUT",
45 	"CONNECT_SER_FAILED",
46 	"DISCONNECT_SER_FAIL",
47 };
48 
49 /* Structure to maintain debug information */
50 struct cm_utf_debugfs_info {
51 	const char *name;
52 	const struct file_operations *ops;
53 };
54 
55 #define DEBUG_FOO(func_base) { .name = #func_base,                      \
56 	.ops = &wlan_cm_utf_##func_base##_ops }
57 
58 /*
59  * wlan_cm_utf_##func_base##_open() - Open debugfs entry for respective command
60  * and event buffer.
61  * @inode: node for debug dir entry
62  * @file: file handler
63  *
64  * Return: open status
65  */
66 #define GENERATE_DEBUG_STRUCTS(func_base)                                     \
67 	static int wlan_cm_utf_##func_base##_open(struct inode *inode,        \
68 			struct file *file)                                    \
69 	{                                                                     \
70 		return single_open(file, wlan_cm_utf_##func_base##_show,      \
71 				   inode->i_private);                         \
72 	}                                                                     \
73 									      \
74 	static const struct file_operations wlan_cm_utf_##func_base##_ops = { \
75 		.open           = wlan_cm_utf_##func_base##_open,             \
76 		.read           = seq_read,                                   \
77 		.llseek         = seq_lseek,                                  \
78 		.write          = wlan_cm_utf_##func_base##_write,            \
79 		.release        = single_release,                             \
80 	};
81 
82 GENERATE_DEBUG_STRUCTS(scan_db_update);
83 GENERATE_DEBUG_STRUCTS(cm_test_id);
84 
85 struct cm_utf_debugfs_info cm_utf_debugfs_infos[NUM_UTF_DEBUGFS_INFOS] = {
86 	DEBUG_FOO(scan_db_update),
87 	DEBUG_FOO(cm_test_id),
88 };
89 
90 /**
91  * wlan_cm_debugfs_create() - Create debugfs entry for cm db
92  * @cm_utf: CM UTF object
93  *
94  * Return: QDF_STATUS
95  */
96 static QDF_STATUS wlan_cm_utf_debugfs_create(struct wlan_cm_utf *cm_utf)
97 {
98 	struct wlan_objmgr_vdev *vdev = cm_utf->vdev;
99 	struct wlan_objmgr_pdev *pdev;
100 	uint8_t pdev_id;
101 	uint8_t vdev_id;
102 	char name[32];
103 
104 	if (cm_utf->debugfs_de[0] || cm_utf->debugfs_de[1]) {
105 		mlme_info("CM UTF debugfs file already exist");
106 		return QDF_STATUS_SUCCESS;
107 	}
108 
109 	pdev = wlan_vdev_get_pdev(vdev);
110 	if (!pdev) {
111 		mlme_err("Pdev is Null");
112 		return QDF_STATUS_E_FAILURE;
113 	}
114 
115 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
116 	vdev_id = wlan_vdev_get_id(vdev);
117 
118 	snprintf(name, sizeof(name), "CM_UTF_PDEV%u_VDEV%u_SCAN",
119 		 pdev_id, vdev_id);
120 	cm_utf->debugfs_de[0] = debugfs_create_file(
121 				name, 0644, qdf_debugfs_get_root(),
122 				cm_utf, cm_utf_debugfs_infos[0].ops);
123 
124 	if (!cm_utf->debugfs_de[0]) {
125 		mlme_err("Failed to create debugfs entry");
126 		return QDF_STATUS_E_FAILURE;
127 	}
128 
129 	snprintf(name, sizeof(name), "CM_UTF_PDEV%u_VDEV%u_UTF",
130 		 pdev_id, vdev_id);
131 	cm_utf->debugfs_de[1] = debugfs_create_file(
132 				name, 0644, qdf_debugfs_get_root(),
133 				cm_utf, cm_utf_debugfs_infos[1].ops);
134 
135 	if (!cm_utf->debugfs_de[1]) {
136 		mlme_err("Failed to create debugfs entry");
137 		debugfs_remove(cm_utf->debugfs_de[0]);
138 		cm_utf->debugfs_de[0] = NULL;
139 		return QDF_STATUS_E_FAILURE;
140 	}
141 
142 	return QDF_STATUS_SUCCESS;
143 }
144 
145 /**
146  * wlan_cm_utf_debugfs_remove: Remove connection manager UTF debugfs entries
147  * @cm_utf: Connection Manager UTF object
148  *
149  * Return: None
150  */
151 static void wlan_cm_utf_debugfs_remove(struct wlan_cm_utf *cm_utf)
152 {
153 	if (cm_utf->debugfs_de[0]) {
154 		qdf_debugfs_remove_file(cm_utf->debugfs_de[0]);
155 		cm_utf->debugfs_de[0] = NULL;
156 	}
157 
158 	if (cm_utf->debugfs_de[1]) {
159 		qdf_debugfs_remove_file(cm_utf->debugfs_de[1]);
160 		cm_utf->debugfs_de[1] = NULL;
161 	}
162 }
163 
164 /**
165  * wlan_cm_utf_bss_peer_create_rsp: Connection manager UTF bss peer
166  * create response
167  * @cm_utf: Connection Manager UTF object
168  *
169  * Return: None
170  */
171 static void wlan_cm_utf_bss_peer_create_rsp(struct wlan_cm_utf *cm_utf)
172 {
173 	struct qdf_mac_addr *peer_mac;
174 	QDF_STATUS status;
175 
176 	peer_mac = cm_utf->utf_node.peer_mac;
177 	switch (cm_utf->test_id) {
178 	case CM_UTF_ID_PEER_CREATE_FAILURE:
179 		status = QDF_STATUS_E_FAILURE;
180 		break;
181 	default:
182 		status = QDF_STATUS_SUCCESS;
183 		break;
184 	}
185 	wlan_cm_bss_peer_create_rsp(cm_utf->vdev, status, peer_mac);
186 }
187 
188 /**
189  * wlan_cm_utf_bss_peer_delete_rsp: Connection manager UTF bss peer
190  * delete response
191  * @cm_utf: Connection Manager UTF object
192  *
193  * Return: None
194  */
195 static void wlan_cm_utf_bss_peer_delete_rsp(struct wlan_cm_utf *cm_utf)
196 {
197 	wlan_cm_bss_peer_delete_rsp(cm_utf->vdev, QDF_STATUS_SUCCESS);
198 }
199 
200 /**
201  * wlan_cm_utf_connect_rsp: Connection manager UTF connect response
202  * @cm_utf: Connection Manager UTF object
203  *
204  * Return: None
205  */
206 static void wlan_cm_utf_connect_rsp(struct wlan_cm_utf *cm_utf)
207 {
208 	struct wlan_cm_connect_rsp *cm_conn_rsp;
209 	struct wlan_cm_vdev_connect_req conn_req = cm_utf->utf_node.conn_req;
210 
211 	cm_conn_rsp = qdf_mem_malloc(sizeof(struct wlan_cm_connect_rsp));
212 	if (!cm_conn_rsp) {
213 		mlme_err("failed ta allocate memory");
214 		return;
215 	}
216 	qdf_mem_zero(cm_conn_rsp, sizeof(struct wlan_cm_connect_rsp));
217 
218 	cm_conn_rsp->vdev_id = conn_req.vdev_id;
219 	cm_conn_rsp->cm_id = conn_req.cm_id;
220 	cm_conn_rsp->aid = 1;
221 	cm_conn_rsp->connect_status = QDF_STATUS_E_FAILURE;
222 	cm_conn_rsp->reason_code = 0;
223 	cm_conn_rsp->freq = conn_req.bss->entry->channel.chan_freq;
224 	cm_conn_rsp->connect_ies.bcn_probe_rsp.ptr =
225 				conn_req.bss->entry->raw_frame.ptr;
226 	cm_conn_rsp->connect_ies.bcn_probe_rsp.len =
227 				conn_req.bss->entry->raw_frame.len;
228 	cm_conn_rsp->bssid = conn_req.bss->entry->bssid;
229 	cm_conn_rsp->ssid = conn_req.bss->entry->ssid;
230 
231 	switch (cm_utf->test_id) {
232 	case CM_UTF_ID_AUTH_FAILURE:
233 		cm_conn_rsp->reason = CM_AUTH_FAILED;
234 		break;
235 	case CM_UTF_ID_AUTH_TIMEOUT:
236 		cm_conn_rsp->reason = CM_AUTH_TIMEOUT;
237 		break;
238 	case CM_UTF_ID_ASSOC_FAILURE:
239 		cm_conn_rsp->reason = CM_ASSOC_FAILED;
240 		break;
241 	case CM_UTF_ID_ASSOC_TIMEOUT:
242 		cm_conn_rsp->reason = CM_ASSOC_TIMEOUT;
243 		break;
244 	default:
245 		cm_conn_rsp->connect_status = QDF_STATUS_SUCCESS;
246 		break;
247 	}
248 	wlan_cm_connect_rsp(cm_utf->vdev, cm_conn_rsp);
249 	qdf_mem_free(cm_conn_rsp);
250 }
251 
252 /**
253  * wlan_cm_utf_disconnect_rsp: Connection manager UTF disconnect response
254  * @cm_utf: Connection Manager UTF object
255  *
256  * Return: None
257  */
258 static void wlan_cm_utf_disconnect_rsp(struct wlan_cm_utf *cm_utf)
259 {
260 	struct wlan_cm_discon_rsp *cm_discon_rsp;
261 
262 	cm_discon_rsp = qdf_mem_malloc(sizeof(struct wlan_cm_discon_rsp));
263 	if (!cm_discon_rsp) {
264 		mlme_err("failed ta allocate memory");
265 		return;
266 	}
267 	cm_discon_rsp->req = cm_utf->utf_node.disconn_req;
268 
269 	wlan_cm_disconnect_rsp(cm_utf->vdev, cm_discon_rsp);
270 	qdf_mem_free(cm_discon_rsp);
271 }
272 
273 /**
274  * wlan_cm_utf_peer_del_ind: Connection manager UTF peer delete indication
275  * @cm_utf: Connection Manager UTF object
276  *
277  * Return: None
278  */
279 static void wlan_cm_utf_peer_del_ind(struct wlan_cm_utf *cm_utf)
280 {
281 	struct qdf_mac_addr peer_mac;
282 
283 	peer_mac.bytes[0] = 0x1;
284 	peer_mac.bytes[1] = 0x2;
285 	peer_mac.bytes[2] = 0x3;
286 	peer_mac.bytes[3] = 0x4;
287 	peer_mac.bytes[4] = 0x5;
288 	peer_mac.bytes[5] = 0x6;
289 
290 	wlan_cm_bss_peer_delete_ind(cm_utf->vdev, &peer_mac);
291 }
292 
293 static void wlan_cm_utf_stop_test(void *arg)
294 {
295 	struct wlan_cm_utf *cm_utf = (struct wlan_cm_utf *)arg;
296 
297 	mlme_err("No Response from CM");
298 	cm_utf->test_id = CM_UTF_ID_MAX;
299 }
300 
301 static void wlan_cm_utf_deliver_event(void *arg)
302 {
303 	struct wlan_cm_utf *cm_utf = (struct wlan_cm_utf *)arg;
304 
305 	qdf_sched_work(NULL, &cm_utf->cm_utf_work);
306 }
307 
308 /**
309  * wlan_cm_utf_default_connect_param: Update default connect req params
310  * for connection manager UTF
311  * @cm_utf: Connection Manager UTF object
312  *
313  * Return: None
314  */
315 static QDF_STATUS
316 wlan_cm_utf_default_connect_param(struct wlan_cm_utf *cm_utf)
317 {
318 	cm_utf->req.vdev_id = wlan_vdev_get_id(cm_utf->vdev);
319 	cm_utf->req.source = CM_OSIF_CONNECT;
320 	cm_utf->req.bssid.bytes[0] = 0x1;
321 	cm_utf->req.bssid.bytes[1] = 0x2;
322 	cm_utf->req.bssid.bytes[2] = 0x3;
323 	cm_utf->req.bssid.bytes[3] = 0x4;
324 	cm_utf->req.bssid.bytes[4] = 0x5;
325 	cm_utf->req.bssid.bytes[5] = 0x6;
326 	cm_utf->req.ssid.length = 6;
327 	qdf_str_lcopy(cm_utf->req.ssid.ssid, "CM_STA", cm_utf->req.ssid.length);
328 	cm_utf->req.chan_freq = 5200;
329 	cm_utf->req.crypto.wep_keys.key_len = 0;
330 	return QDF_STATUS_SUCCESS;
331 }
332 
333 static void wlan_cm_utf_work_cb(void *arg)
334 {
335 	struct wlan_cm_utf *cm_utf = (struct wlan_cm_utf *)arg;
336 	enum wlan_cm_utf_evt event_id = cm_utf->utf_node.evt_id;
337 
338 	switch (event_id) {
339 	case CM_UTF_BSS_PEER_CREATE_RESP:
340 		wlan_cm_utf_bss_peer_create_rsp(cm_utf);
341 		break;
342 	case CM_UTF_BSS_PEER_DELETE_RESP:
343 		wlan_cm_utf_bss_peer_delete_rsp(cm_utf);
344 		break;
345 	case CM_UTF_CONNECT_RESP:
346 		wlan_cm_utf_connect_rsp(cm_utf);
347 		break;
348 	case CM_UTF_DISCONNECT_RESP:
349 		wlan_cm_utf_disconnect_rsp(cm_utf);
350 		break;
351 	case CM_UTF_PEER_DELETE_IND:
352 		wlan_cm_utf_peer_del_ind(cm_utf);
353 		break;
354 	default:
355 		break;
356 	}
357 }
358 
359 QDF_STATUS wlan_cm_utf_attach(struct wlan_objmgr_vdev *vdev)
360 {
361 	struct wlan_cm_utf *cm_utf;
362 	QDF_STATUS status;
363 
364 	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) {
365 		mlme_err("Vdev is not a STA vdev");
366 		return QDF_STATUS_E_FAILURE;
367 	}
368 
369 	if (qdf_list_size(&wlan_cm_utf_list) == CM_UTF_LIST_SIZE) {
370 		mlme_err("List is at max size");
371 		return QDF_STATUS_E_FAILURE;
372 	}
373 
374 	if (!qdf_list_size(&wlan_cm_utf_list))
375 		qdf_list_create(&wlan_cm_utf_list, CM_UTF_LIST_SIZE);
376 
377 	cm_utf = (struct wlan_cm_utf *)
378 			qdf_mem_malloc(sizeof(struct wlan_cm_utf));
379 
380 	if (!cm_utf) {
381 		mlme_err("Failed to allocate CM utf context");
382 		qdf_list_destroy(&wlan_cm_utf_list);
383 		return QDF_STATUS_E_NOMEM;
384 	}
385 
386 	cm_utf->vdev = vdev;
387 	cm_utf->test_id = CM_UTF_ID_MAX;
388 	wlan_cm_utf_default_connect_param(cm_utf);
389 	status = wlan_cm_utf_debugfs_create(cm_utf);
390 	if (QDF_IS_STATUS_ERROR(status)) {
391 		qdf_mem_free(cm_utf);
392 		qdf_list_destroy(&wlan_cm_utf_list);
393 		return status;
394 	}
395 
396 	qdf_timer_init(NULL, &cm_utf->cm_utf_timer,
397 		       wlan_cm_utf_deliver_event, (void *)cm_utf,
398 		       QDF_TIMER_TYPE_WAKE_APPS);
399 
400 	qdf_timer_init(NULL, &cm_utf->cm_utf_test_timer,
401 		       wlan_cm_utf_stop_test, (void *)cm_utf,
402 		       QDF_TIMER_TYPE_WAKE_APPS);
403 
404 	qdf_create_work(NULL, &cm_utf->cm_utf_work,
405 			wlan_cm_utf_work_cb, cm_utf);
406 
407 	qdf_list_insert_back(&wlan_cm_utf_list, &cm_utf->cm_utf_node);
408 	mlme_err("CM UTF attach Success");
409 	return QDF_STATUS_SUCCESS;
410 }
411 
412 static struct wlan_cm_utf *wlan_cm_get_utf(struct wlan_objmgr_vdev *vdev)
413 {
414 	struct wlan_cm_utf *cm_utf;
415 	qdf_list_node_t *node;
416 	qdf_list_node_t *next_node;
417 
418 	if (!qdf_list_size(&wlan_cm_utf_list)) {
419 		mlme_err("UTF list is empty");
420 		return NULL;
421 	}
422 
423 	if (qdf_list_peek_front(&wlan_cm_utf_list, &next_node)
424 					!= QDF_STATUS_SUCCESS) {
425 		mlme_err("UTF list is empty");
426 		return NULL;
427 	}
428 
429 	do {
430 		node = next_node;
431 		cm_utf = qdf_container_of(node, struct wlan_cm_utf,
432 					  cm_utf_node);
433 		if (cm_utf->vdev == vdev)
434 			return cm_utf;
435 	} while (qdf_list_peek_next(&wlan_cm_utf_list, node, &next_node)
436 			== QDF_STATUS_SUCCESS);
437 
438 	return NULL;
439 }
440 
441 void wlan_cm_utf_detach(struct wlan_objmgr_vdev *vdev)
442 {
443 	struct wlan_cm_utf *cm_utf;
444 	QDF_STATUS status;
445 
446 	cm_utf = wlan_cm_get_utf(vdev);
447 	if (!cm_utf) {
448 		mlme_err("UTF not initialized for the vdev %d",
449 			 wlan_vdev_get_id(vdev));
450 		return;
451 	}
452 
453 	status = qdf_list_remove_node(&wlan_cm_utf_list,
454 				      &cm_utf->cm_utf_node);
455 	if (QDF_IS_STATUS_SUCCESS(status)) {
456 		qdf_timer_free(&cm_utf->cm_utf_timer);
457 		qdf_timer_free(&cm_utf->cm_utf_test_timer);
458 
459 		if (cm_utf->req.assoc_ie.ptr) {
460 			qdf_mem_free(cm_utf->req.assoc_ie.ptr);
461 			cm_utf->req.assoc_ie.ptr = NULL;
462 		}
463 
464 		if (cm_utf->req.crypto.wep_keys.key) {
465 			qdf_mem_free(cm_utf->req.crypto.wep_keys.key);
466 			cm_utf->req.crypto.wep_keys.key = NULL;
467 		}
468 
469 		qdf_disable_work(&cm_utf->cm_utf_work);
470 		wlan_cm_utf_debugfs_remove(cm_utf);
471 		qdf_mem_free(cm_utf);
472 		mlme_err("CM UTF Deinit Success");
473 		return;
474 	}
475 
476 	mlme_err("Failed to remove UTF node");
477 }
478 
479 QDF_STATUS wlan_cm_utf_bss_peer_create_req(struct wlan_objmgr_vdev *vdev,
480 					   struct qdf_mac_addr *peer_mac)
481 {
482 	struct wlan_cm_utf *cm_utf;
483 
484 	cm_utf = wlan_cm_get_utf(vdev);
485 	if (!cm_utf) {
486 		mlme_err("cm_utf is Null");
487 		return QDF_STATUS_E_FAILURE;
488 	}
489 
490 	switch (cm_utf->test_id) {
491 	case CM_UTF_ID_PEER_CREATE_TIMEOUT:
492 		break;
493 	default:
494 		cm_utf->utf_node.peer_mac = peer_mac;
495 		cm_utf->utf_node.evt_id = CM_UTF_BSS_PEER_CREATE_RESP;
496 		qdf_timer_start(&cm_utf->cm_utf_timer, 100);
497 		break;
498 	}
499 	return QDF_STATUS_SUCCESS;
500 }
501 
502 QDF_STATUS wlan_cm_utf_connect_req_active(
503 			struct wlan_objmgr_vdev *vdev,
504 			struct wlan_cm_vdev_connect_req *vdev_connect_req)
505 {
506 	//Resp API to be added
507 	return QDF_STATUS_SUCCESS;
508 }
509 
510 QDF_STATUS wlan_cm_utf_connect_req(
511 			struct wlan_objmgr_vdev *vdev,
512 			struct wlan_cm_vdev_connect_req *vdev_connect_req)
513 {
514 	struct wlan_cm_utf *cm_utf;
515 
516 	cm_utf = wlan_cm_get_utf(vdev);
517 	if (!cm_utf) {
518 		mlme_err("cm_utf is Null");
519 		return QDF_STATUS_E_FAILURE;
520 	}
521 
522 	switch (cm_utf->test_id) {
523 	case CM_UTF_ID_CONNECT_SER_TIMEOUT:
524 		break;
525 	default:
526 		qdf_mem_copy(&cm_utf->utf_node.conn_req, vdev_connect_req,
527 			     sizeof(struct wlan_cm_vdev_connect_req));
528 		cm_utf->utf_node.evt_id = CM_UTF_CONNECT_RESP;
529 		qdf_timer_start(&cm_utf->cm_utf_timer, 100);
530 		break;
531 	}
532 	return QDF_STATUS_SUCCESS;
533 }
534 
535 QDF_STATUS wlan_cm_utf_disconnect_req(
536 		struct wlan_objmgr_vdev *vdev,
537 		struct wlan_cm_vdev_discon_req *vdev_disconnect_req)
538 {
539 	struct wlan_cm_utf *cm_utf;
540 
541 	cm_utf = wlan_cm_get_utf(vdev);
542 	if (!cm_utf) {
543 		mlme_err("cm_utf is Null");
544 		return QDF_STATUS_E_FAILURE;
545 	}
546 
547 	switch (cm_utf->test_id) {
548 	case CM_UTF_ID_DISCONNECT_SER_TIMEOUT:
549 		break;
550 	default:
551 		qdf_mem_copy(&cm_utf->utf_node.disconn_req, vdev_disconnect_req,
552 			     sizeof(struct wlan_cm_vdev_discon_req));
553 		cm_utf->utf_node.evt_id = CM_UTF_PEER_DELETE_IND;
554 		qdf_timer_start(&cm_utf->cm_utf_timer, 100);
555 		break;
556 	}
557 	return QDF_STATUS_SUCCESS;
558 }
559 
560 QDF_STATUS wlan_cm_utf_bss_peer_delete_req(struct wlan_objmgr_vdev *vdev)
561 {
562 	struct wlan_cm_utf *cm_utf;
563 
564 	cm_utf = wlan_cm_get_utf(vdev);
565 	if (!cm_utf) {
566 		mlme_err("cm_utf is Null");
567 		return QDF_STATUS_E_FAILURE;
568 	}
569 
570 	switch (cm_utf->test_id) {
571 	case CM_UTF_ID_PEER_DELETE_TIMEOUT:
572 		break;
573 	default:
574 		cm_utf->utf_node.evt_id = CM_UTF_BSS_PEER_DELETE_RESP;
575 		qdf_timer_start(&cm_utf->cm_utf_timer, 100);
576 		break;
577 	}
578 	return QDF_STATUS_SUCCESS;
579 }
580 
581 QDF_STATUS wlan_cm_utf_vdev_down(struct wlan_objmgr_vdev *vdev)
582 {
583 	struct wlan_cm_utf *cm_utf;
584 
585 	cm_utf = wlan_cm_get_utf(vdev);
586 	if (!cm_utf) {
587 		mlme_err("cm_utf is Null");
588 		return QDF_STATUS_E_FAILURE;
589 	}
590 
591 	switch (cm_utf->test_id) {
592 	default:
593 		cm_utf->utf_node.evt_id = CM_UTF_DISCONNECT_RESP;
594 		qdf_timer_start(&cm_utf->cm_utf_timer, 100);
595 		break;
596 	}
597 	return QDF_STATUS_SUCCESS;
598 }
599 
600 static
601 QDF_STATUS wlan_cm_utf_validate_test(struct wlan_cm_utf *cm_utf,
602 				     struct wlan_cm_connect_rsp *cm_conn_rsp)
603 {
604 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
605 
606 	switch (cm_utf->test_id) {
607 	case CM_UTF_ID_PEER_CREATE_FAILURE:
608 	case CM_UTF_ID_PEER_CREATE_TIMEOUT:
609 		if (cm_conn_rsp->reason == CM_PEER_CREATE_FAILED) {
610 			// check (CM state to be valid as per test in all cases)
611 			status = QDF_STATUS_SUCCESS;
612 		}
613 		break;
614 	case CM_UTF_ID_CONNECT_SER_TIMEOUT:
615 	case CM_UTF_ID_CONNECT_SER_FAILED:
616 		if (cm_conn_rsp->reason == CM_SER_FAILURE)
617 			status = QDF_STATUS_SUCCESS;
618 		break;
619 	case CM_UTF_ID_CONNECT_SCAN_FAILURE:
620 		if (cm_conn_rsp->reason == CM_NO_CANDIDATE_FOUND)
621 			status = QDF_STATUS_SUCCESS;
622 		break;
623 	case CM_UTF_ID_AUTH_FAILURE:
624 		if (cm_conn_rsp->reason == CM_AUTH_FAILED)
625 			status = QDF_STATUS_SUCCESS;
626 		break;
627 	case CM_UTF_ID_AUTH_TIMEOUT:
628 		if (cm_conn_rsp->reason == CM_AUTH_TIMEOUT)
629 			status = QDF_STATUS_SUCCESS;
630 		break;
631 	case CM_UTF_ID_ASSOC_FAILURE:
632 		if (cm_conn_rsp->reason == CM_ASSOC_FAILED)
633 			status = QDF_STATUS_SUCCESS;
634 		break;
635 	case CM_UTF_ID_ASSOC_TIMEOUT:
636 		if (cm_conn_rsp->reason == CM_ASSOC_TIMEOUT)
637 			status = QDF_STATUS_SUCCESS;
638 		break;
639 	default:
640 		if (cm_conn_rsp->connect_status == QDF_STATUS_SUCCESS)
641 			status = QDF_STATUS_SUCCESS;
642 		break;
643 	}
644 
645 	return status;
646 }
647 
648 /**
649  * wlan_cm_utf_osif_connect_cb: Connection manager UTF
650  * connect callback handler
651  * @vdev: VDEV object
652  * @cm_conn_rsp: Connect Response
653  *
654  * Return: None
655  */
656 static QDF_STATUS
657 wlan_cm_utf_osif_connect_cb(struct wlan_objmgr_vdev *vdev,
658 			    struct wlan_cm_connect_rsp *cm_conn_rsp)
659 {
660 	struct wlan_cm_utf *cm_utf;
661 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
662 
663 	cm_utf = wlan_cm_get_utf(vdev);
664 	if (!cm_utf) {
665 		mlme_err("cm_utf is Null");
666 		return QDF_STATUS_E_FAILURE;
667 	}
668 
669 	if (cm_conn_rsp->cm_id != cm_utf->last_cmd_id ||
670 	    cm_utf->last_cmd_source != CM_OSIF_CONNECT) {
671 		mlme_err("Incorrect cmd id/source");
672 		return QDF_STATUS_E_FAILURE;
673 	}
674 
675 	status = wlan_cm_utf_validate_test(cm_utf, cm_conn_rsp);
676 	if (status == QDF_STATUS_SUCCESS)
677 		mlme_err("Test case Success for Test: %s",
678 			 cm_utf_test_names[cm_utf->test_id]);
679 	else
680 		mlme_err("Test case Failed for Test: %s",
681 			 cm_utf_test_names[cm_utf->test_id]);
682 
683 	qdf_timer_stop(&cm_utf->cm_utf_test_timer);
684 	cm_utf->test_id = CM_UTF_ID_MAX;
685 
686 	return status;
687 }
688 
689 /**
690  * wlan_cm_utf_osif_disconnect_cb: Connection manager UTF
691  * disconnect callback handler
692  * @vdev: VDEV object
693  * @cm_disconn_rsp: Disconnect Response
694  *
695  * Return: None
696  */
697 static QDF_STATUS wlan_cm_utf_osif_disconnect_cb(
698 		struct wlan_objmgr_vdev *vdev,
699 		struct wlan_cm_discon_rsp *cm_disconn_rsp)
700 {
701 	struct wlan_cm_utf *cm_utf;
702 
703 	cm_utf = wlan_cm_get_utf(vdev);
704 	if (!cm_utf) {
705 		mlme_err("cm_utf is Null");
706 		return QDF_STATUS_E_FAILURE;
707 	}
708 
709 	if (cm_disconn_rsp->req.cm_id != cm_utf->last_cmd_id ||
710 	    cm_disconn_rsp->req.req.source != cm_utf->last_cmd_source) {
711 		mlme_err("Incorrect cmd id/source");
712 		return QDF_STATUS_E_FAILURE;
713 	}
714 
715 	mlme_err("Test case Success for Test: %s",
716 		 cm_utf_test_names[cm_utf->test_id]);
717 	qdf_timer_stop(&cm_utf->cm_utf_test_timer);
718 	cm_utf->test_id = CM_UTF_ID_MAX;
719 
720 	return QDF_STATUS_SUCCESS;
721 }
722 
723 /**
724  * wlan_cm_utf_update_conn_id_and_src_cb: Connection manager UTF
725  * callback to update connect id and source of the connect request
726  * @vdev: VDEV object
727  * @cm_disconn_rsp: Disconnect Response
728  *
729  * Return: None
730  */
731 static QDF_STATUS wlan_cm_utf_update_conn_id_and_src_cb(
732 		struct wlan_objmgr_vdev *vdev,
733 		enum wlan_cm_source source, wlan_cm_id cm_id)
734 {
735 	struct wlan_cm_utf *cm_utf;
736 
737 	cm_utf = wlan_cm_get_utf(vdev);
738 	if (!cm_utf) {
739 		mlme_err("cm_utf is Null");
740 		return QDF_STATUS_E_FAILURE;
741 	}
742 
743 	cm_utf->last_cmd_id = cm_id;
744 	cm_utf->last_cmd_source = source;
745 
746 	return QDF_STATUS_SUCCESS;
747 }
748 
749 static struct mlme_cm_ops cm_ops = {
750 	.mlme_cm_connect_complete_cb = wlan_cm_utf_osif_connect_cb,
751 	.mlme_cm_failed_candidate_cb = NULL,
752 	.mlme_cm_update_id_and_src_cb =
753 			wlan_cm_utf_update_conn_id_and_src_cb,
754 	.mlme_cm_disconnect_complete_cb = wlan_cm_utf_osif_disconnect_cb,
755 	.mlme_cm_disconnect_start_cb = NULL,
756 };
757 
758 static struct mlme_cm_ops *osif_cm_get_global_ops(void)
759 {
760 	return &cm_ops;
761 }
762 
763 QDF_STATUS osif_cm_utf_register_cb(void)
764 {
765 	mlme_set_osif_cm_cb(osif_cm_get_global_ops);
766 	return QDF_STATUS_SUCCESS;
767 }
768 
769 /**
770  * wlan_cm_utf_update_connect_param: API to update connect req params
771  * @cm_utf: CM UTF object
772  * @buffer: user input buffer
773  *
774  * Return: None
775  *
776  */
777 static void
778 wlan_cm_utf_update_connect_param(struct wlan_cm_utf *cm_utf, char *buffer)
779 {
780 	char *token;
781 	uint8_t idx = 0;
782 
783 	token = qdf_str_sep(&buffer, "\n");
784 
785 	if (!token) {
786 		mlme_err("Invalid Parameters");
787 		return;
788 	}
789 
790 	if (cm_utf->req.assoc_ie.ptr) {
791 		qdf_mem_free(cm_utf->req.assoc_ie.ptr);
792 		cm_utf->req.assoc_ie.ptr = NULL;
793 	}
794 
795 	if (cm_utf->req.crypto.wep_keys.key) {
796 		qdf_mem_free(cm_utf->req.crypto.wep_keys.key);
797 		cm_utf->req.crypto.wep_keys.key = NULL;
798 	}
799 
800 	qdf_mem_zero(cm_utf->req.ssid.ssid, WLAN_SSID_MAX_LEN);
801 	if (sscanf(token, "%2x:%2x:%2x:%2x:%2x:%2x ,%2x:%2x:%2x:%2x:%2x:%2x "
802 		   ",%2x:%2x:%2x:%2x:%2x:%2x ,%u ,%u ,%u ,%u ,%u ,%u ,%u ,%u "
803 		   ",%u ,%u ,%u ,%u ,%u ,%s",
804 		   (unsigned int *)&cm_utf->req.bssid.bytes[0],
805 		   (unsigned int *)&cm_utf->req.bssid.bytes[1],
806 		   (unsigned int *)&cm_utf->req.bssid.bytes[2],
807 		   (unsigned int *)&cm_utf->req.bssid.bytes[3],
808 		   (unsigned int *)&cm_utf->req.bssid.bytes[4],
809 		   (unsigned int *)&cm_utf->req.bssid.bytes[5],
810 		   (unsigned int *)&cm_utf->req.prev_bssid.bytes[0],
811 		   (unsigned int *)&cm_utf->req.prev_bssid.bytes[1],
812 		   (unsigned int *)&cm_utf->req.prev_bssid.bytes[2],
813 		   (unsigned int *)&cm_utf->req.prev_bssid.bytes[3],
814 		   (unsigned int *)&cm_utf->req.prev_bssid.bytes[4],
815 		   (unsigned int *)&cm_utf->req.prev_bssid.bytes[5],
816 		   (unsigned int *)&cm_utf->req.bssid_hint.bytes[0],
817 		   (unsigned int *)&cm_utf->req.bssid_hint.bytes[1],
818 		   (unsigned int *)&cm_utf->req.bssid_hint.bytes[2],
819 		   (unsigned int *)&cm_utf->req.bssid_hint.bytes[3],
820 		   (unsigned int *)&cm_utf->req.bssid_hint.bytes[4],
821 		   (unsigned int *)&cm_utf->req.bssid_hint.bytes[5],
822 		   &cm_utf->req.chan_freq,
823 		   &cm_utf->req.crypto.wpa_versions,
824 		   &cm_utf->req.crypto.auth_type,
825 		   &cm_utf->req.crypto.group_cipher,
826 		   &cm_utf->req.crypto.ciphers_pairwise,
827 		   &cm_utf->req.crypto.akm_suites,
828 		   (unsigned int *)&cm_utf->req.crypto.rsn_caps,
829 		   &cm_utf->req.crypto.mgmt_ciphers,
830 		   (unsigned int *)&cm_utf->req.ht_caps,
831 		   (unsigned int *)&cm_utf->req.ht_caps_mask,
832 		   &cm_utf->req.vht_caps,
833 		   &cm_utf->req.vht_caps_mask,
834 		   (unsigned int *)&cm_utf->req.ssid.length,
835 		   cm_utf->req.ssid.ssid) != 32) {
836 		mlme_err("Invalid connect req params");
837 		return;
838 	}
839 
840 	qdf_err("Updated connect params %s", buffer);
841 	while ((token = qdf_str_sep(&buffer, ",")) != NULL) {
842 		switch (idx) {
843 		case 0:
844 			if (sscanf(token, "%u", &cm_utf->req.assoc_ie.len) != 1)
845 				return;
846 			if (!cm_utf->req.assoc_ie.len) {
847 				idx += 2;
848 				break;
849 			}
850 			idx++;
851 			break;
852 		case 1:
853 			cm_utf->req.assoc_ie.ptr =
854 				(uint8_t *)qdf_mem_malloc(cm_utf->req.assoc_ie.len);
855 			if (!cm_utf->req.assoc_ie.ptr) {
856 				mlme_err("Failed to alloc memory");
857 				return;
858 			}
859 			qdf_mem_copy(cm_utf->req.assoc_ie.ptr, token,
860 				     cm_utf->req.assoc_ie.len);
861 			idx++;
862 			break;
863 		case 2:
864 			if (sscanf(token, "%u",
865 				   (unsigned int *)&cm_utf->req.crypto.wep_keys.key_len) != 1)
866 				return;
867 			if (!cm_utf->req.crypto.wep_keys.key_len)
868 				return;
869 			idx++;
870 			break;
871 		case 3:
872 			cm_utf->req.crypto.wep_keys.key =
873 				(uint8_t *)qdf_mem_malloc(cm_utf->req.crypto.wep_keys.key_len);
874 			if (!cm_utf->req.crypto.wep_keys.key) {
875 				mlme_err("Failed to alloc memory");
876 				return;
877 			}
878 			qdf_mem_copy(cm_utf->req.crypto.wep_keys.key, token,
879 				     cm_utf->req.crypto.wep_keys.key_len);
880 			break;
881 		default:
882 			break;
883 		}
884 	}
885 }
886 
887 /**
888  * wlan_cm_utf_start_test: Connection manager UTF entry function
889  * @cm_utf: Connection Manager UTF object
890  * *test_id: Test ID requested by user
891  *
892  */
893 static void wlan_cm_utf_start_test(struct wlan_cm_utf *cm_utf, void *buffer)
894 {
895 	int reason = 0, ret;
896 	uint8_t i = 0;
897 	char *token;
898 	char *token2;
899 	char *buff = (char *)buffer;
900 	struct wlan_cm_disconnect_req req;
901 
902 	if (cm_utf->test_id != CM_UTF_ID_MAX) {
903 		mlme_err("Test Already in progress");
904 		return;
905 	}
906 
907 	token = qdf_str_sep(&buff, " ");
908 	if (token) {
909 		if (!qdf_str_cmp(token, "CONNECT_REQ")) {
910 			mlme_err("Update Connect Params");
911 			wlan_cm_utf_update_connect_param(cm_utf, buff);
912 			return;
913 		}
914 
915 		token2 = qdf_str_sep(&token, "\n");
916 		for (i = 0; i < CM_UTF_ID_MAX; i++) {
917 			if (!qdf_str_cmp(token2, cm_utf_test_names[i])) {
918 				cm_utf->test_id = i;
919 				break;
920 			}
921 		}
922 	}
923 
924 	if (cm_utf->test_id == CM_UTF_ID_MAX) {
925 		mlme_err("Invalid Test Case");
926 		return;
927 	}
928 
929 	mlme_err("Test ID: %d", cm_utf->test_id);
930 	switch (cm_utf->test_id) {
931 	case CM_UTF_ID_CONNECT_SUCCESS:
932 	case CM_UTF_ID_PEER_CREATE_FAILURE:
933 	case CM_UTF_ID_PEER_CREATE_TIMEOUT:
934 	case CM_UTF_ID_AUTH_FAILURE:
935 	case CM_UTF_ID_AUTH_TIMEOUT:
936 	case CM_UTF_ID_ASSOC_FAILURE:
937 	case CM_UTF_ID_ASSOC_TIMEOUT:
938 	case CM_UTF_ID_CONNECT_SCAN_FAILURE:
939 	case CM_UTF_ID_CONNECT_SER_TIMEOUT:
940 	case CM_UTF_ID_CONNECT_SER_FAILED:
941 		cm_utf->req.vdev_id = wlan_vdev_get_id(cm_utf->vdev);
942 		cm_utf->req.source = CM_OSIF_CONNECT;
943 		ucfg_cm_start_connect(cm_utf->vdev, &cm_utf->req);
944 		break;
945 	case CM_UTF_ID_DISCONNECT_SUCCESS:
946 	case CM_UTF_ID_DISCONNECT_SER_TIMEOUT:
947 	case CM_UTF_ID_DISCONNECT_SER_FAILED:
948 	case CM_UTF_ID_PEER_DELETE_TIMEOUT:
949 		token = qdf_str_sep(&buff, " ");
950 		if (!token) {
951 			mlme_err("Provide reason code for disconnect");
952 			cm_utf->test_id = CM_UTF_ID_MAX;
953 			return;
954 		} else {
955 			ret = qdf_kstrtoint(token, 0, &reason);
956 			if (ret) {
957 				mlme_err("Invalid disconnect reason");
958 				cm_utf->test_id = CM_UTF_ID_MAX;
959 				return;
960 			}
961 		}
962 		mlme_err("Disconnect reason %d", reason);
963 		req.vdev_id = wlan_vdev_get_id(cm_utf->vdev);
964 		req.source = CM_OSIF_DISCONNECT;
965 		req.reason_code = reason;
966 		ucfg_cm_start_disconnect(cm_utf->vdev, &req);
967 		break;
968 	default:
969 		mlme_err("Invalid test ID");
970 		cm_utf->test_id = CM_UTF_ID_MAX;
971 		qdf_timer_stop(&cm_utf->cm_utf_test_timer);
972 		break;
973 	}
974 
975 	if (cm_utf->test_id == CM_UTF_ID_PEER_DELETE_TIMEOUT ||
976 	    cm_utf->test_id == CM_UTF_ID_PEER_CREATE_TIMEOUT ||
977 	    cm_utf->test_id == CM_UTF_ID_DISCONNECT_SER_TIMEOUT ||
978 	    cm_utf->test_id == CM_UTF_ID_CONNECT_SER_TIMEOUT)
979 		qdf_timer_start(&cm_utf->cm_utf_test_timer, 70000);
980 	else
981 		qdf_timer_start(&cm_utf->cm_utf_test_timer, 10000);
982 }
983 
984 int wlan_cm_utf_cm_test_id_show(qdf_debugfs_file_t m, void *v)
985 {
986 	uint8_t i;
987 
988 	mlme_nofl_err("Usage:");
989 	for (i = 0; i < CM_UTF_ID_MAX; i++) {
990 		switch (i) {
991 		case CM_UTF_ID_DISCONNECT_SUCCESS:
992 		case CM_UTF_ID_DISCONNECT_SER_TIMEOUT:
993 		case CM_UTF_ID_DISCONNECT_SER_FAILED:
994 		case CM_UTF_ID_PEER_DELETE_TIMEOUT:
995 			mlme_nofl_err("%22s <reason>", cm_utf_test_names[i]);
996 			break;
997 		default:
998 			mlme_nofl_err("%22s", cm_utf_test_names[i]);
999 			break;
1000 		}
1001 	}
1002 	return 0;
1003 }
1004 
1005 ssize_t wlan_cm_utf_cm_test_id_write(struct file *file,
1006 				     const char __user *buf,
1007 				     size_t count, loff_t *ppos)
1008 {
1009 	struct wlan_cm_utf *cm_utf =
1010 			((struct seq_file *)file->private_data)->private;
1011 	char *locbuf;
1012 
1013 	if ((!buf) || (count <= 0))
1014 		return -EFAULT;
1015 
1016 	locbuf = (char *)qdf_mem_malloc(count + 1);
1017 
1018 	if (!locbuf)
1019 		return -EFAULT;
1020 
1021 	qdf_mem_zero(locbuf, count + 1);
1022 
1023 	if (copy_from_user(locbuf, buf, count))
1024 		return -EFAULT;
1025 
1026 	mlme_err("CM Start Test");
1027 	wlan_cm_utf_start_test(cm_utf, locbuf);
1028 	qdf_mem_free(locbuf);
1029 
1030 	return count;
1031 }
1032 #endif
1033