1 /*
2  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-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_debugfs_offload.c
22  *
23  * WLAN Host Device Driver implementation to update
24  * debugfs with offload information
25  */
26 
27 #include <wlan_hdd_debugfs_csr.h>
28 #include <wlan_hdd_main.h>
29 #include <cds_sched.h>
30 #include <wma_api.h>
31 #include "qwlan_version.h"
32 #include "wmi_unified_param.h"
33 #include "wlan_pmo_common_public_struct.h"
34 #include "wlan_pmo_ns_public_struct.h"
35 #include "wlan_pmo_mc_addr_filtering_public_struct.h"
36 #include "wlan_pmo_ucfg_api.h"
37 #include "wlan_hdd_object_manager.h"
38 
39 /* IPv6 address string */
40 #define IPV6_MAC_ADDRESS_STR_LEN 47  /* Including null terminator */
41 
42 /**
43  * wlan_hdd_mc_addr_list_info_debugfs() - Populate mc addr list info
44  * @hdd_ctx: pointer to hdd context
45  * @adapter: pointer to adapter
46  * @buf: output buffer to hold mc addr list info
47  * @buf_avail_len: available buffer length
48  *
49  * Return: No.of bytes populated by this function in buffer
50  */
51 static ssize_t
wlan_hdd_mc_addr_list_info_debugfs(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter,uint8_t * buf,ssize_t buf_avail_len)52 wlan_hdd_mc_addr_list_info_debugfs(struct hdd_context *hdd_ctx,
53 				   struct hdd_adapter *adapter, uint8_t *buf,
54 				   ssize_t buf_avail_len)
55 {
56 	ssize_t length = 0;
57 	int ret;
58 	uint8_t i;
59 	struct pmo_mc_addr_list mc_addr_list = {0};
60 	QDF_STATUS status;
61 
62 	if (!ucfg_pmo_is_mc_addr_list_enabled(hdd_ctx->psoc)) {
63 		ret = scnprintf(buf, buf_avail_len,
64 				"\nMC addr ini is disabled\n");
65 		if (ret > 0)
66 			length = ret;
67 		return length;
68 	}
69 
70 	status = ucfg_pmo_get_mc_addr_list(hdd_ctx->psoc,
71 					   adapter->deflink->vdev_id,
72 					   &mc_addr_list);
73 	if (!QDF_IS_STATUS_SUCCESS(status)) {
74 		ret = scnprintf(buf, buf_avail_len,
75 				"\nMC addr list query is failed\n");
76 		if (ret > 0)
77 			length = ret;
78 		return length;
79 	}
80 
81 	if (mc_addr_list.mc_cnt == 0) {
82 		ret = scnprintf(buf, buf_avail_len,
83 				"\nMC addr list is empty\n");
84 		if (ret > 0)
85 			length = ret;
86 		return length;
87 	}
88 
89 	ret = scnprintf(buf, buf_avail_len,
90 			"\nMC ADDR LIST DETAILS (mc_cnt = %u)\n",
91 			mc_addr_list.mc_cnt);
92 	if (ret <= 0)
93 		return length;
94 	length += ret;
95 
96 	for (i = 0; i < mc_addr_list.mc_cnt; i++) {
97 		if (length >= buf_avail_len) {
98 			hdd_err("No sufficient buf_avail_len");
99 			return buf_avail_len;
100 		}
101 
102 		ret = scnprintf(buf + length, buf_avail_len - length,
103 				QDF_MAC_ADDR_FMT "\n",
104 				QDF_MAC_ADDR_REF(mc_addr_list.mc_addr[i].bytes));
105 		if (ret <= 0)
106 			return length;
107 		length += ret;
108 	}
109 
110 	if (length >= buf_avail_len) {
111 		hdd_err("No sufficient buf_avail_len");
112 		return buf_avail_len;
113 	}
114 	ret = scnprintf(buf + length, buf_avail_len - length,
115 			"mc_filter_applied = %u\n",
116 			mc_addr_list.is_filter_applied);
117 	if (ret <= 0)
118 		return length;
119 
120 	length += ret;
121 	return length;
122 }
123 
124 /**
125  * wlan_hdd_arp_offload_info_debugfs() - Populate arp offload info
126  * @hdd_ctx: pointer to hdd context
127  * @adapter: pointer to adapter
128  * @buf: output buffer to hold arp offload info
129  * @buf_avail_len: available buffer length
130  *
131  * Return: No.of bytes populated by this function in buffer
132  */
133 static ssize_t
wlan_hdd_arp_offload_info_debugfs(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter,uint8_t * buf,ssize_t buf_avail_len)134 wlan_hdd_arp_offload_info_debugfs(struct hdd_context *hdd_ctx,
135 				  struct hdd_adapter *adapter, uint8_t *buf,
136 				  ssize_t buf_avail_len)
137 {
138 	ssize_t length = 0;
139 	int ret_val;
140 	struct pmo_arp_offload_params info = {0};
141 	struct wlan_objmgr_vdev *vdev;
142 	QDF_STATUS status;
143 
144 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
145 					   WLAN_OSIF_POWER_ID);
146 	if (!vdev)
147 		return 0;
148 
149 	status = ucfg_pmo_get_arp_offload_params(vdev, &info);
150 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
151 	if (!QDF_IS_STATUS_SUCCESS(status)) {
152 		ret_val = scnprintf(buf, buf_avail_len,
153 				    "\nARP OFFLOAD QUERY FAILED\n");
154 		goto len_adj;
155 	}
156 
157 	if (!info.is_offload_applied)
158 		ret_val = scnprintf(buf, buf_avail_len,
159 				    "\nARP OFFLOAD: DISABLED\n");
160 	else
161 		ret_val = scnprintf(buf, buf_avail_len,
162 				    "\nARP OFFLOAD: ENABLED (%u.%u.%u.%u)\n",
163 				    info.host_ipv4_addr[0],
164 				    info.host_ipv4_addr[1],
165 				    info.host_ipv4_addr[2],
166 				    info.host_ipv4_addr[3]);
167 len_adj:
168 	if (ret_val <= 0)
169 		return length;
170 	length = ret_val;
171 
172 	return length;
173 }
174 
175 #ifdef WLAN_NS_OFFLOAD
176 /**
177  * ipv6_addr_string() - Get IPv6 addr string from array of octets
178  * @buffer: output buffer to hold string, caller should ensure size of
179  *          buffer is atleast IPV6_MAC_ADDRESS_STR_LEN
180  * @ipv6_addr: IPv6 address array
181  *
182  * Return: None
183  */
ipv6_addr_string(uint8_t * buffer,uint8_t * ipv6_addr)184 static void ipv6_addr_string(uint8_t *buffer, uint8_t *ipv6_addr)
185 {
186 	uint8_t *a = ipv6_addr;
187 
188 	scnprintf(buffer, IPV6_MAC_ADDRESS_STR_LEN,
189 		  "%02x%02x::%02x%02x::%02x%02x::%02x%02x::%02x%02x::%02x%02x::%02x%02x::%02x%02x",
190 		  (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5], (a)[6],
191 		  (a)[7], (a)[8], (a)[9], (a)[10], (a)[11], (a)[12], (a)[13],
192 		  (a)[14], (a)[15]);
193 }
194 
195 /**
196  * hdd_ipv6_scope_str() - Get string for PMO NS (IPv6) Addr scope
197  * @scope: scope id from enum pmo_ns_addr_scope
198  *
199  * Return: Meaningful string for enum pmo_ns_addr_scope
200  */
hdd_ipv6_scope_str(enum pmo_ns_addr_scope scope)201 static uint8_t *hdd_ipv6_scope_str(enum pmo_ns_addr_scope scope)
202 {
203 	switch (scope) {
204 	case PMO_NS_ADDR_SCOPE_NODELOCAL:
205 		return "Node Local";
206 	case PMO_NS_ADDR_SCOPE_LINKLOCAL:
207 		return "Link Local";
208 	case PMO_NS_ADDR_SCOPE_SITELOCAL:
209 		return "Site Local";
210 	case PMO_NS_ADDR_SCOPE_ORGLOCAL:
211 		return "Org Local";
212 	case PMO_NS_ADDR_SCOPE_GLOBAL:
213 		return "Global";
214 	default:
215 		return "Invalid";
216 	}
217 }
218 
219 /**
220  * wlan_hdd_ns_offload_info_debugfs() - Populate ns offload info
221  * @hdd_ctx: pointer to hdd context
222  * @adapter: pointer to adapter
223  * @buf: output buffer to hold ns offload info
224  * @buf_avail_len: available buffer length
225  *
226  * Return: No.of bytes populated by this function in buffer
227  */
228 static ssize_t
wlan_hdd_ns_offload_info_debugfs(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter,uint8_t * buf,ssize_t buf_avail_len)229 wlan_hdd_ns_offload_info_debugfs(struct hdd_context *hdd_ctx,
230 				 struct hdd_adapter *adapter, uint8_t *buf,
231 				 ssize_t buf_avail_len)
232 {
233 	ssize_t length = 0;
234 	int ret;
235 	struct pmo_ns_offload_params info = {0};
236 	struct wlan_objmgr_vdev *vdev;
237 	QDF_STATUS status;
238 	uint32_t i;
239 
240 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
241 					   WLAN_OSIF_POWER_ID);
242 	if (!vdev)
243 		return 0;
244 
245 	status = ucfg_pmo_get_ns_offload_params(vdev, &info);
246 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
247 	if (!QDF_IS_STATUS_SUCCESS(status)) {
248 		ret = scnprintf(buf, buf_avail_len,
249 				"\nNS OFFLOAD QUERY FAILED\n");
250 		if (ret <= 0)
251 			return length;
252 		length += ret;
253 
254 		return length;
255 	}
256 
257 	ret = scnprintf(buf, buf_avail_len,
258 			"\nNS OFFLOAD DETAILS\n");
259 	if (ret <= 0)
260 		return length;
261 	length += ret;
262 
263 	if (length >= buf_avail_len) {
264 		hdd_err("No sufficient buf_avail_len");
265 		return buf_avail_len;
266 	}
267 
268 	if (!info.is_offload_applied) {
269 		ret = scnprintf(buf + length, buf_avail_len - length,
270 				"NS offload is not enabled\n");
271 		if (ret <= 0)
272 			return length;
273 		length += ret;
274 
275 		return length;
276 	}
277 
278 	ret = scnprintf(buf + length, buf_avail_len - length,
279 			"NS offload enabled, %u ns addresses offloaded\n",
280 			info.num_ns_offload_count);
281 	if (ret <= 0)
282 		return length;
283 	length += ret;
284 
285 	for (i = 0; i < info.num_ns_offload_count; i++) {
286 		uint8_t ipv6_str[IPV6_MAC_ADDRESS_STR_LEN];
287 		uint8_t cast_string[12];
288 		uint8_t *scope_string;
289 
290 		if (length >= buf_avail_len) {
291 			hdd_err("No sufficient buf_avail_len");
292 			return buf_avail_len;
293 		}
294 
295 		ipv6_addr_string(ipv6_str, info.target_ipv6_addr[i]);
296 		scope_string = hdd_ipv6_scope_str(info.scope[i]);
297 
298 		if (info.target_ipv6_addr_ac_type[i] ==
299 		    PMO_IPV6_ADDR_AC_TYPE)
300 			strlcpy(cast_string, "(ANY CAST)", 12);
301 		else
302 			strlcpy(cast_string, "(UNI CAST)", 12);
303 
304 		ret = scnprintf(buf + length, buf_avail_len - length,
305 				"%u. %s %s and scope is: %s\n",
306 				(i + 1), ipv6_str, cast_string,
307 				scope_string);
308 		if (ret <= 0)
309 			return length;
310 		length += ret;
311 	}
312 
313 	return length;
314 }
315 #else
316 /**
317  * wlan_hdd_ns_offload_info_debugfs() - Populate ns offload info
318  * @hdd_ctx: pointer to hdd context
319  * @adapter: pointer to adapter
320  * @buf: output buffer to hold ns offload info
321  * @buf_avail_len: available buffer length
322  *
323  * Return: No.of bytes populated by this function in buffer
324  */
325 static ssize_t
wlan_hdd_ns_offload_info_debugfs(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter,uint8_t * buf,ssize_t buf_avail_len)326 wlan_hdd_ns_offload_info_debugfs(struct hdd_context *hdd_ctx,
327 				 struct hdd_adapter *adapter, uint8_t *buf,
328 				 ssize_t buf_avail_len)
329 {
330 	return 0;
331 }
332 #endif
333 
334 #ifdef FEATURE_WLAN_APF
335 /**
336  * wlan_hdd_apf_info_debugfs() - Populate apf offload info
337  * @hdd_ctx: pointer to hdd context
338  * @adapter: pointer to adapter
339  * @buf: output buffer to hold apf offload info
340  * @buf_avail_len: available buffer length
341  *
342  * Return: No.of bytes populated by this function in buffer
343  */
344 static ssize_t
wlan_hdd_apf_info_debugfs(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter,uint8_t * buf,ssize_t buf_avail_len)345 wlan_hdd_apf_info_debugfs(struct hdd_context *hdd_ctx,
346 			  struct hdd_adapter *adapter, uint8_t *buf,
347 			  ssize_t buf_avail_len)
348 {
349 	ssize_t length = 0;
350 	int ret_val;
351 	bool apf_enabled;
352 
353 	if (hdd_ctx->apf_version > 2)
354 		apf_enabled = adapter->apf_context.apf_enabled;
355 	else
356 		apf_enabled = hdd_ctx->apf_enabled_v2;
357 
358 	ret_val = scnprintf(buf, buf_avail_len,
359 			    "\nAPF OFFLOAD DETAILS, offload_applied: %u\n\n",
360 			    apf_enabled);
361 	if (ret_val <= 0)
362 		return length;
363 	length = ret_val;
364 
365 	return length;
366 }
367 #else
368 static ssize_t
wlan_hdd_apf_info_debugfs(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter,uint8_t * buf,ssize_t buf_avail_len)369 wlan_hdd_apf_info_debugfs(struct hdd_context *hdd_ctx,
370 			  struct hdd_adapter *adapter, uint8_t *buf,
371 			  ssize_t buf_avail_len)
372 {
373 	return 0;
374 }
375 #endif
376 
377 ssize_t
wlan_hdd_debugfs_update_filters_info(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter,uint8_t * buf,ssize_t buf_avail_len)378 wlan_hdd_debugfs_update_filters_info(struct hdd_context *hdd_ctx,
379 				     struct hdd_adapter *adapter,
380 				     uint8_t *buf, ssize_t buf_avail_len)
381 {
382 	ssize_t len;
383 	int ret_val;
384 	struct hdd_station_ctx *hdd_sta_ctx;
385 
386 	hdd_enter();
387 
388 	len = wlan_hdd_current_time_info_debugfs(buf, buf_avail_len);
389 
390 	if (len >= buf_avail_len) {
391 		hdd_err("No sufficient buf_avail_len");
392 		return buf_avail_len;
393 	}
394 
395 	if (adapter->device_mode != QDF_STA_MODE) {
396 		ret_val = scnprintf(buf + len, buf_avail_len - len,
397 				    "Interface is not operating in STA mode\n");
398 		if (ret_val <= 0)
399 			return len;
400 
401 		len += ret_val;
402 		return len;
403 	}
404 
405 	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
406 	if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
407 		ret_val = scnprintf(buf + len, buf_avail_len - len,
408 				    "\nSTA is not connected\n");
409 		if (ret_val <= 0)
410 			return len;
411 
412 		len += ret_val;
413 		return len;
414 	}
415 
416 	len += wlan_hdd_mc_addr_list_info_debugfs(hdd_ctx, adapter, buf + len,
417 						  buf_avail_len - len);
418 
419 	if (len >= buf_avail_len) {
420 		hdd_err("No sufficient buf_avail_len");
421 		return buf_avail_len;
422 	}
423 	len += wlan_hdd_arp_offload_info_debugfs(hdd_ctx, adapter, buf + len,
424 						 buf_avail_len - len);
425 
426 	if (len >= buf_avail_len) {
427 		hdd_err("No sufficient buf_avail_len");
428 		return buf_avail_len;
429 	}
430 	len += wlan_hdd_ns_offload_info_debugfs(hdd_ctx, adapter, buf + len,
431 						buf_avail_len - len);
432 
433 	if (len >= buf_avail_len) {
434 		hdd_err("No sufficient buf_avail_len");
435 		return buf_avail_len;
436 	}
437 	len += wlan_hdd_apf_info_debugfs(hdd_ctx, adapter, buf + len,
438 					 buf_avail_len - len);
439 
440 	hdd_exit();
441 
442 	return len;
443 }
444