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