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