1 /*
2  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. 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 #include <wlan_hdd_includes.h>
18 #include "osif_vdev_sync.h"
19 #include "os_if_qmi.h"
20 #include "cfg_ucfg_api.h"
21 #include "wlan_hdd_object_manager.h"
22 #include <wlan_hdd_sysfs.h>
23 #include "wlan_hdd_sysfs_direct_link_ut_cmd.h"
24 
25 #define MAX_SYSFS_DIRECT_LNK_UT_USER_COMMAND_LENGTH 512
26 
__hdd_sysfs_direct_link_ut_cmd_store(struct net_device * net_dev,char const * buf,size_t count)27 static ssize_t __hdd_sysfs_direct_link_ut_cmd_store(struct net_device *net_dev,
28 						    char const *buf,
29 						    size_t count)
30 {
31 	struct hdd_adapter *adapter = netdev_priv(net_dev);
32 	struct os_if_qmi_wfds_ut_cmd_info cmd_info;
33 	char buf_local[MAX_SYSFS_DIRECT_LNK_UT_USER_COMMAND_LENGTH + 1];
34 	char *sptr, *token;
35 	int ret;
36 	QDF_STATUS status;
37 
38 	if (hdd_validate_adapter(adapter))
39 		return -EINVAL;
40 
41 	ret = wlan_hdd_validate_context(adapter->hdd_ctx);
42 	if (ret)
43 		return ret;
44 
45 	if (!wlan_hdd_validate_modules_state(adapter->hdd_ctx))
46 		return -EINVAL;
47 
48 	ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local),
49 					      buf, count);
50 
51 	if (ret) {
52 		hdd_err("invalid input");
53 		return ret;
54 	}
55 
56 	sptr = buf_local;
57 
58 	token = strsep(&sptr, " ");
59 	if (!token)
60 		return -EINVAL;
61 	if (kstrtou32(token, 0, (uint32_t *)&cmd_info.cmd))
62 		return -EINVAL;
63 
64 	if (cmd_info.cmd >= WFDS_CMD_MAX)
65 		return -EINVAL;
66 
67 	if (cmd_info.cmd == WFDS_STOP_TRAFFIC || cmd_info.cmd == WFDS_GET_STATS)
68 		goto send_request;
69 
70 	token = strsep(&sptr, " ");
71 	if (!token)
72 		return -EINVAL;
73 	if (kstrtou32(token, 0, &cmd_info.duration))
74 		return -EINVAL;
75 
76 	token = strsep(&sptr, " ");
77 	if (!token)
78 		return -EINVAL;
79 	if (kstrtou32(token, 0, &cmd_info.flush_period))
80 		return -EINVAL;
81 
82 	token = strsep(&sptr, " ");
83 	if (!token)
84 		return -EINVAL;
85 	if (kstrtou32(token, 0, &cmd_info.num_pkts))
86 		return -EINVAL;
87 
88 	token = strsep(&sptr, " ");
89 	if (!token)
90 		return -EINVAL;
91 	if (kstrtou32(token, 0, &cmd_info.buf_size))
92 		return -EINVAL;
93 
94 	token = strsep(&sptr, " ");
95 	if (!token)
96 		return -EINVAL;
97 	if (kstrtou16(token, 0, &cmd_info.ether_type))
98 		return -EINVAL;
99 
100 	token = strsep(&sptr, " ");
101 	if (!token)
102 		return -EINVAL;
103 	qdf_mac_parse(token, &cmd_info.dest_mac);
104 
105 	if (cmd_info.cmd == WFDS_START_WHC) {
106 		token = strsep(&sptr, " ");
107 		if (!token)
108 			return -EINVAL;
109 		qdf_mac_parse(token, &cmd_info.src_mac);
110 
111 		token = strsep(&sptr, " ");
112 		if (!token)
113 			return -EINVAL;
114 		qdf_ipv4_parse(token, &cmd_info.dest_ip);
115 
116 		token = strsep(&sptr, " ");
117 		if (!token)
118 			return -EINVAL;
119 		qdf_ipv4_parse(token, &cmd_info.src_ip);
120 
121 		token = strsep(&sptr, " ");
122 		if (!token)
123 			return -EINVAL;
124 		if (kstrtou16(token, 0, &cmd_info.dest_port))
125 			return -EINVAL;
126 	} else if (cmd_info.cmd == WFDS_START_TRAFFIC) {
127 		qdf_copy_macaddr(&cmd_info.src_mac, &adapter->mac_addr);
128 	}
129 
130 send_request:
131 	status = os_if_qmi_wfds_send_ut_cmd_req_msg(&cmd_info);
132 	if (QDF_IS_STATUS_ERROR(status))
133 		hdd_err("failed to send command %d", status);
134 
135 	return count;
136 }
137 
hdd_sysfs_direct_link_ut_cmd_store(struct device * dev,struct device_attribute * attr,char const * buf,size_t count)138 static ssize_t hdd_sysfs_direct_link_ut_cmd_store(struct device *dev,
139 						  struct device_attribute *attr,
140 						  char const *buf, size_t count)
141 {
142 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
143 	struct osif_vdev_sync *vdev_sync;
144 	ssize_t err_size;
145 
146 	err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
147 	if (err_size)
148 		return err_size;
149 
150 	err_size = __hdd_sysfs_direct_link_ut_cmd_store(net_dev, buf, count);
151 
152 	osif_vdev_sync_op_stop(vdev_sync);
153 
154 	return err_size;
155 }
156 
157 static DEVICE_ATTR(direct_link_ut_cmd, 0660, NULL,
158 		   hdd_sysfs_direct_link_ut_cmd_store);
159 
hdd_sysfs_direct_link_ut_cmd_create(struct hdd_adapter * adapter)160 int hdd_sysfs_direct_link_ut_cmd_create(struct hdd_adapter *adapter)
161 {
162 	struct hdd_context *hdd_ctx = adapter->hdd_ctx;
163 	int error;
164 
165 	if (!hdd_ctx) {
166 		hdd_err("HDD context is NULL!");
167 		return -EINVAL;
168 	}
169 
170 	if (cfg_get(hdd_ctx->psoc, CFG_ENABLE_DIRECT_LINK_UT_CMD) == false)
171 		return -EINVAL;
172 
173 	error = device_create_file(&adapter->dev->dev,
174 				   &dev_attr_direct_link_ut_cmd);
175 	if (error)
176 		hdd_err("could not create traffic_end_indication sysfs file");
177 
178 	return error;
179 }
180 
hdd_sysfs_direct_link_ut_destroy(struct hdd_adapter * adapter)181 void hdd_sysfs_direct_link_ut_destroy(struct hdd_adapter *adapter)
182 {
183 	struct hdd_context *hdd_ctx = adapter->hdd_ctx;
184 
185 	if (!hdd_ctx) {
186 		hdd_err("HDD context is NULL!");
187 		return;
188 	}
189 
190 	if (cfg_get(hdd_ctx->psoc, CFG_ENABLE_DIRECT_LINK_UT_CMD) == false)
191 		return;
192 
193 	device_remove_file(&adapter->dev->dev,
194 			   &dev_attr_direct_link_ut_cmd);
195 }
196