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