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