1 /*
2  * Copyright (c) 2022 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 /**
18  * DOC: wlan_hdd_add_timestamp.c
19  *
20  * Implementation for creating sysfs files:
21  *
22  * dp_pkt_add_ts
23  */
24 
25 #include <wlan_hdd_includes.h>
26 #include "osif_psoc_sync.h"
27 #include <wlan_hdd_sysfs.h>
28 #include <wlan_hdd_sysfs_add_timestamp.h>
29 #include "qdf_trace.h"
30 
31 #define MAX_USER_COMMAND_SIZE_TIMESTAMP 512
32 
hdd_set_dp_pkt_add_ts_info(char * in_str)33 static int hdd_set_dp_pkt_add_ts_info(char *in_str)
34 {
35 	char *str, *token, *substr, *subtoken;
36 	enum qdf_pkt_supported_proto proto;
37 	uint16_t port, offset;
38 	int ret;
39 
40 	str = in_str;
41 	while (1) {
42 		token = strsep(&str, ",");
43 		if (!token)
44 			break;
45 
46 		substr = token;
47 
48 		/* get protocol */
49 		subtoken = strsep(&substr, ":");
50 		if (!subtoken)
51 			return -EINVAL;
52 
53 		if (strncmp(subtoken, "TCP", 3) == 0) {
54 			proto = QDF_PKT_PROTO_TCP;
55 		} else if (strncmp(subtoken, "UDP", 3) == 0) {
56 			proto = QDF_PKT_PROTO_UDP;
57 		} else {
58 			hdd_err("protocol not supported");
59 			return -EINVAL;
60 		}
61 
62 		/* get destination port value */
63 		subtoken = strsep(&substr, ":");
64 		if (!subtoken)
65 			return -EINVAL;
66 
67 		ret = kstrtou16(subtoken, 0, &port);
68 		if (ret) {
69 			hdd_err("Invalid port value ret %d", ret);
70 			return -EINVAL;
71 		}
72 
73 		if (port < 1 || port > 65535) {
74 			hdd_err("port not valid");
75 			return -EINVAL;
76 		}
77 
78 		/* get offset */
79 		subtoken = strsep(&substr, ":");
80 		if (!subtoken)
81 			return -EINVAL;
82 
83 		ret = kstrtou16(subtoken, 0, &offset);
84 		if (ret) {
85 			hdd_err("Invalid offset value ret %d", ret);
86 			return -EINVAL;
87 		}
88 
89 		ret = qdf_set_dp_pkt_add_ts_info(proto, port, offset);
90 		if (ret) {
91 			hdd_err("pkt info set failed");
92 			return -EINVAL;
93 		}
94 	}
95 	return 0;
96 }
97 
98 static ssize_t
__hdd_sysfs_dp_pkt_add_ts_store(struct hdd_context * hdd_ctx,struct kobj_attribute * attr,char const * buf,size_t count)99 __hdd_sysfs_dp_pkt_add_ts_store(struct hdd_context *hdd_ctx,
100 				struct kobj_attribute *attr,
101 				char const *buf, size_t count)
102 {
103 	char buf_local[MAX_USER_COMMAND_SIZE_TIMESTAMP + 1];
104 	char *str;
105 	int ret;
106 
107 	if (!wlan_hdd_validate_modules_state(hdd_ctx))
108 		return -EINVAL;
109 
110 	ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local),
111 					      buf, count);
112 	if (ret) {
113 		hdd_err_rl("invalid input");
114 		return ret;
115 	}
116 
117 	str = skip_spaces(buf_local);
118 	if (strlen(str) == 0) {
119 		qdf_clear_dp_pkt_add_ts_info();
120 		return count;
121 	}
122 
123 	qdf_clear_dp_pkt_add_ts_info();
124 	ret = hdd_set_dp_pkt_add_ts_info(str);
125 	if (ret)
126 		hdd_err("all protocol do not set successfully");
127 	return count;
128 }
129 
hdd_sysfs_dp_pkt_add_ts_store(struct kobject * kobj,struct kobj_attribute * attr,char const * buf,size_t count)130 static ssize_t hdd_sysfs_dp_pkt_add_ts_store(struct kobject *kobj,
131 					     struct kobj_attribute *attr,
132 					     char const *buf, size_t count)
133 {
134 	struct osif_psoc_sync *psoc_sync;
135 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
136 	ssize_t errno_size;
137 	int ret;
138 
139 	ret = wlan_hdd_validate_context(hdd_ctx);
140 	if (ret != 0)
141 		return ret;
142 
143 	errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy),
144 					     &psoc_sync);
145 	if (errno_size)
146 		return errno_size;
147 
148 	errno_size = __hdd_sysfs_dp_pkt_add_ts_store(hdd_ctx, attr,
149 						     buf, count);
150 
151 	osif_psoc_sync_op_stop(psoc_sync);
152 
153 	return errno_size;
154 }
155 
156 static ssize_t
__hdd_sysfs_dp_pkt_add_ts_show(struct hdd_context * hdd_ctx,struct kobj_attribute * attr,char * buf)157 __hdd_sysfs_dp_pkt_add_ts_show(struct hdd_context *hdd_ctx,
158 			       struct kobj_attribute *attr, char *buf)
159 {
160 	if (!wlan_hdd_validate_modules_state(hdd_ctx))
161 		return -EINVAL;
162 
163 	return qdf_show_dp_pkt_add_ts_info(buf, PAGE_SIZE);
164 }
165 
hdd_sysfs_dp_pkt_add_ts_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)166 static ssize_t hdd_sysfs_dp_pkt_add_ts_show(struct kobject *kobj,
167 					    struct kobj_attribute *attr,
168 					    char *buf)
169 {
170 	struct osif_psoc_sync *psoc_sync;
171 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
172 	ssize_t errno_size;
173 	int ret;
174 
175 	ret = wlan_hdd_validate_context(hdd_ctx);
176 	if (ret != 0)
177 		return ret;
178 
179 	errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy),
180 					     &psoc_sync);
181 	if (errno_size)
182 		return errno_size;
183 
184 	errno_size = __hdd_sysfs_dp_pkt_add_ts_show(hdd_ctx, attr, buf);
185 
186 	osif_psoc_sync_op_stop(psoc_sync);
187 
188 	return errno_size;
189 }
190 
191 static struct kobj_attribute dp_pkt_add_ts_attribute =
192 	__ATTR(dp_pkt_add_ts, 0660, hdd_sysfs_dp_pkt_add_ts_show,
193 	       hdd_sysfs_dp_pkt_add_ts_store);
194 
hdd_sysfs_dp_pkt_add_ts_create(struct kobject * driver_kobject)195 int hdd_sysfs_dp_pkt_add_ts_create(struct kobject *driver_kobject)
196 {
197 	int error;
198 
199 	if (!driver_kobject) {
200 		hdd_err("could not get driver kobject!");
201 		return -EINVAL;
202 	}
203 
204 	error = sysfs_create_file(driver_kobject,
205 				  &dp_pkt_add_ts_attribute.attr);
206 	if (error)
207 		hdd_err("could not create dp_pkt_add_ts sysfs file");
208 
209 	return error;
210 }
211 
212 void
hdd_sysfs_dp_pkt_add_ts_destroy(struct kobject * driver_kobject)213 hdd_sysfs_dp_pkt_add_ts_destroy(struct kobject *driver_kobject)
214 {
215 	if (!driver_kobject) {
216 		hdd_err("could not get driver kobject!");
217 		return;
218 	}
219 	sysfs_remove_file(driver_kobject, &dp_pkt_add_ts_attribute.attr);
220 }
221