1 /*
2  * Copyright (c) 2012-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
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: wlan_hdd_ota_test.c
22  *
23  * WLAN OTA test functions
24  *
25  */
26 
27 #include "osif_sync.h"
28 #include <wlan_hdd_includes.h>
29 #include <linux/netdevice.h>
30 #include <linux/skbuff.h>
31 #include <linux/etherdevice.h>
32 #include <linux/if_ether.h>
33 #include <sme_power_save_api.h>
34 #include <wlan_hdd_ota_test.h>
35 
36 const struct nla_policy qca_wlan_vendor_ota_test_policy[
37 		QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX + 1] = {
38 	[QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE] = {.type = NLA_U8 },
39 };
40 
41 /**
42  * __wlan_hdd_cfg80211_set_ota_test() - enable/disable OTA test
43  * @wiphy: Pointer to wireless phy
44  * @wdev: Pointer to wireless device
45  * @data: Pointer to data
46  * @data_len: Data length
47  *
48  * Return: 0 on success, negative errno on failure
49  */
__wlan_hdd_cfg80211_set_ota_test(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)50 static int __wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy,
51 					    struct wireless_dev *wdev,
52 					    const void *data,
53 					    int data_len)
54 {
55 	struct net_device *dev = wdev->netdev;
56 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
57 	struct hdd_context *hdd_ctx  = wiphy_priv(wiphy);
58 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX + 1];
59 	uint8_t ota_enable = 0;
60 	QDF_STATUS status;
61 	uint32_t current_roam_state;
62 	mac_handle_t mac_handle;
63 
64 	hdd_enter_dev(dev);
65 
66 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
67 		hdd_err("Command not allowed in FTM mode");
68 		return -EPERM;
69 	}
70 
71 	if (wlan_hdd_validate_context(hdd_ctx) != 0)
72 		return -EINVAL;
73 
74 	if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX,
75 				    data, data_len,
76 				    qca_wlan_vendor_ota_test_policy)) {
77 		hdd_err("invalid attr");
78 		return -EINVAL;
79 	}
80 
81 	if (!tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE]) {
82 		hdd_err("attr ota test failed");
83 		return -EINVAL;
84 	}
85 
86 	ota_enable = nla_get_u8(
87 		tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE]);
88 
89 	hdd_debug(" OTA test enable = %d", ota_enable);
90 	if (ota_enable != 1) {
91 		hdd_err("Invalid value, only enable test mode is supported!");
92 		return -EINVAL;
93 	}
94 
95 	mac_handle = hdd_ctx->mac_handle;
96 	current_roam_state = sme_get_current_roam_state(
97 					mac_handle, adapter->deflink->vdev_id);
98 	status = sme_stop_roaming(mac_handle, adapter->deflink->vdev_id,
99 				  REASON_SME_ISSUED, RSO_INVALID_REQUESTOR);
100 	if (status != QDF_STATUS_SUCCESS) {
101 		hdd_err("Enable/Disable roaming failed");
102 		return -EINVAL;
103 	}
104 
105 	status = sme_ps_enable_disable(mac_handle, adapter->deflink->vdev_id,
106 				       SME_PS_DISABLE);
107 	if (status != QDF_STATUS_SUCCESS) {
108 		hdd_err("Enable/Disable power save failed");
109 		/* restore previous roaming setting */
110 		if (current_roam_state == eCSR_ROAMING_STATE_JOINING ||
111 		    current_roam_state == eCSR_ROAMING_STATE_JOINED)
112 			status = sme_start_roaming(mac_handle,
113 						 adapter->deflink->vdev_id,
114 						 REASON_SME_ISSUED,
115 						 RSO_INVALID_REQUESTOR);
116 		else if (current_roam_state == eCSR_ROAMING_STATE_STOP ||
117 			 current_roam_state == eCSR_ROAMING_STATE_IDLE)
118 			status = sme_stop_roaming(mac_handle,
119 						 adapter->deflink->vdev_id,
120 						 REASON_SME_ISSUED,
121 						 RSO_INVALID_REQUESTOR);
122 
123 		if (status != QDF_STATUS_SUCCESS)
124 			hdd_err("Restoring roaming state failed");
125 
126 		return -EINVAL;
127 	}
128 	return 0;
129 }
130 
wlan_hdd_cfg80211_set_ota_test(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)131 int wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy,
132 				   struct wireless_dev *wdev,
133 				   const void *data,
134 				   int data_len)
135 {
136 	struct osif_vdev_sync *vdev_sync;
137 	int errno;
138 
139 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
140 	if (errno)
141 		return errno;
142 
143 	errno = __wlan_hdd_cfg80211_set_ota_test(wiphy, wdev, data, data_len);
144 
145 	osif_vdev_sync_op_stop(vdev_sync);
146 
147 	return errno;
148 }
149 
150