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