1 /** @file moal_proc.c
2 *
3 * @brief This file contains functions for proc file.
4 *
5 *
6 * Copyright 2008-2022 NXP
7 *
8 * This software file (the File) is distributed by NXP
9 * under the terms of the GNU General Public License Version 2, June 1991
10 * (the License). You may use, redistribute and/or modify the File in
11 * accordance with the terms and conditions of the License, a copy of which
12 * is available by writing to the Free Software Foundation, Inc.,
13 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
14 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
15 *
16 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
18 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
19 * this warranty disclaimer.
20 *
21 */
22
23 /********************************************************
24 Change log:
25 10/21/2008: initial version
26 ********************************************************/
27
28 #include "moal_main.h"
29 #ifdef UAP_SUPPORT
30 #include "moal_uap.h"
31 #endif
32 #ifdef SDIO
33 #include "moal_sdio.h"
34 #endif
35
36 /********************************************************
37 Local Variables
38 ********************************************************/
39 #ifdef CONFIG_PROC_FS
40 #define STATUS_PROC "wifi_status"
41 #define MWLAN_PROC "mwlan"
42 #define WLAN_PROC "adapter%d"
43 /** Proc mwlan directory entry */
44 static struct proc_dir_entry *proc_mwlan;
45
46 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
47 #define PROC_DIR NULL
48 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
49 #define PROC_DIR (&proc_root)
50 #else
51 #define PROC_DIR proc_net
52 #endif
53
54 #ifdef STA_SUPPORT
55 static char *szModes[] = {
56 "Unknown",
57 "Managed",
58 "Ad-hoc",
59 "Auto",
60 };
61 #endif
62
63 /********************************************************
64 Global Variables
65 ********************************************************/
66 int wifi_status;
67
68 /********************************************************
69 Local Functions
70 ********************************************************/
71 /**
72 * @brief Proc read function for info
73 *
74 * @param sfp pointer to seq_file structure
75 * @param data
76 *
77 * @return Number of output data
78 */
woal_info_proc_read(struct seq_file * sfp,void * data)79 static int woal_info_proc_read(struct seq_file *sfp, void *data)
80 {
81 struct net_device *netdev = (struct net_device *)sfp->private;
82 char fmt[MLAN_MAX_VER_STR_LEN];
83 moal_private *priv = (moal_private *)netdev_priv(netdev);
84 mlan_fw_info fw_info;
85 #ifdef STA_SUPPORT
86 int i = 0;
87 moal_handle *handle = NULL;
88 mlan_bss_info info;
89 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
90 struct dev_mc_list *mcptr = netdev->mc_list;
91 int mc_count = netdev->mc_count;
92 #else
93 struct netdev_hw_addr *mcptr = NULL;
94 int mc_count = netdev_mc_count(netdev);
95 #endif /* < 2.6.35 */
96 #else
97 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
98 int i = 0;
99 #endif /* >= 2.6.29 */
100 #endif
101 #ifdef UAP_SUPPORT
102 mlan_ds_uap_stats ustats;
103 #endif
104 union {
105 t_u32 l;
106 t_u8 c[4];
107 } ver;
108
109 fw_info.uuid_lo = fw_info.uuid_hi = 0x0ULL;
110
111 ENTER();
112
113 if (priv == NULL)
114 goto exit;
115 #ifdef STA_SUPPORT
116 handle = priv->phandle;
117 if (handle == NULL)
118 goto exit;
119 #endif
120
121 if (!MODULE_GET) {
122 LEAVE();
123 return 0;
124 }
125
126 memset(fmt, 0, sizeof(fmt));
127 #ifdef UAP_SUPPORT
128 memset(&ustats, 0, sizeof(ustats));
129 if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
130 seq_printf(sfp, "driver_name = "
131 "\"uap\"\n");
132 woal_uap_get_version(priv, fmt, sizeof(fmt) - 1);
133 if (MLAN_STATUS_SUCCESS !=
134 woal_uap_get_stats(priv, MOAL_IOCTL_WAIT, &ustats)) {
135 MODULE_PUT;
136 LEAVE();
137 return -EFAULT;
138 }
139 }
140 #endif /* UAP_SUPPORT*/
141 #ifdef STA_SUPPORT
142 memset(&info, 0, sizeof(info));
143 if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
144 woal_get_version(handle, fmt, sizeof(fmt) - 1);
145 if (MLAN_STATUS_SUCCESS !=
146 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &info)) {
147 MODULE_PUT;
148 LEAVE();
149 return -EFAULT;
150 }
151 seq_printf(sfp, "driver_name = "
152 "\"wlan\"\n");
153 }
154 #endif
155 seq_printf(sfp, "driver_version = %s", fmt);
156 seq_printf(sfp, "\ninterface_name=\"%s\"\n", netdev->name);
157 ver.l = handle->fw_release_number;
158 seq_printf(sfp, "firmware_major_version=%u.%u.%u\n", ver.c[2], ver.c[1],
159 ver.c[0]);
160
161 woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
162 if (fw_info.uuid_lo || fw_info.uuid_hi)
163 seq_printf(sfp, "uuid = %llx%llx\n", fw_info.uuid_lo,
164 fw_info.uuid_hi);
165 #ifdef WIFI_DIRECT_SUPPORT
166 if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
167 if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
168 seq_printf(sfp, "bss_mode = \"WIFIDIRECT-Client\"\n");
169 else
170 seq_printf(sfp, "bss_mode = \"WIFIDIRECT-GO\"\n");
171 }
172 #endif
173 #ifdef STA_SUPPORT
174 if (priv->bss_type == MLAN_BSS_TYPE_STA)
175 seq_printf(sfp, "bss_mode =\"%s\"\n", szModes[info.bss_mode]);
176 #endif
177 seq_printf(sfp, "media_state=\"%s\"\n",
178 ((priv->media_connected == MFALSE) ? "Disconnected" :
179 "Connected"));
180 seq_printf(sfp, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
181 netdev->dev_addr[0], netdev->dev_addr[1],
182 netdev->dev_addr[2], netdev->dev_addr[3],
183 netdev->dev_addr[4], netdev->dev_addr[5]);
184 #ifdef STA_SUPPORT
185 if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
186 seq_printf(sfp, "multicast_count=\"%d\"\n", mc_count);
187 seq_printf(sfp, "essid=\"%s\"\n", info.ssid.ssid);
188 seq_printf(sfp, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
189 info.bssid[0], info.bssid[1], info.bssid[2],
190 info.bssid[3], info.bssid[4], info.bssid[5]);
191 seq_printf(sfp, "channel=\"%d\"\n", (int)info.bss_chan);
192 seq_printf(sfp, "region_code = \"%02x\"\n",
193 (t_u8)info.region_code);
194
195 /*
196 * Put out the multicast list
197 */
198 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
199 for (i = 0; i < netdev->mc_count; i++) {
200 seq_printf(
201 sfp,
202 "multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
203 i, mcptr->dmi_addr[0], mcptr->dmi_addr[1],
204 mcptr->dmi_addr[2], mcptr->dmi_addr[3],
205 mcptr->dmi_addr[4], mcptr->dmi_addr[5]);
206
207 mcptr = mcptr->next;
208 }
209 #else
210 netdev_for_each_mc_addr (mcptr, netdev)
211 seq_printf(
212 sfp,
213 "multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
214 i++, mcptr->addr[0], mcptr->addr[1],
215 mcptr->addr[2], mcptr->addr[3], mcptr->addr[4],
216 mcptr->addr[5]);
217 #endif /* < 2.6.35 */
218 }
219 #endif
220 seq_printf(sfp, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
221 seq_printf(sfp, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
222 seq_printf(sfp, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
223 seq_printf(sfp, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
224 seq_printf(sfp, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
225 seq_printf(sfp, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
226 seq_printf(sfp, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
227 seq_printf(sfp, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
228 seq_printf(sfp, "carrier %s\n",
229 ((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
230 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
231 for (i = 0; i < (int)netdev->num_tx_queues; i++) {
232 seq_printf(sfp, "tx queue %d: %s\n", i,
233 ((netif_tx_queue_stopped(
234 netdev_get_tx_queue(netdev, 0))) ?
235 "stopped" :
236 "started"));
237 }
238 #else
239 seq_printf(sfp, "tx queue %s\n",
240 ((netif_queue_stopped(priv->netdev)) ? "stopped" :
241 "started"));
242 #endif
243 #ifdef UAP_SUPPORT
244 if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
245 seq_printf(sfp, "tkip_mic_failures = %u\n",
246 ustats.tkip_mic_failures);
247 seq_printf(sfp, "ccmp_decrypt_errors = %u\n",
248 ustats.ccmp_decrypt_errors);
249 seq_printf(sfp, "wep_undecryptable_count = %u\n",
250 ustats.wep_undecryptable_count);
251 seq_printf(sfp, "wep_icv_error_count = %u\n",
252 ustats.wep_icv_error_count);
253 seq_printf(sfp, "decrypt_failure_count = %u\n",
254 ustats.decrypt_failure_count);
255 seq_printf(sfp, "mcast_tx_count = %u\n", ustats.mcast_tx_count);
256 seq_printf(sfp, "failed_count = %u\n", ustats.failed_count);
257 seq_printf(sfp, "retry_count = %u\n", ustats.retry_count);
258 seq_printf(sfp, "multiple_retry_count = %u\n",
259 ustats.multi_retry_count);
260 seq_printf(sfp, "frame_duplicate_count = %u\n",
261 ustats.frame_dup_count);
262 seq_printf(sfp, "rts_success_count = %u\n",
263 ustats.rts_success_count);
264 seq_printf(sfp, "rts_failure_count = %u\n",
265 ustats.rts_failure_count);
266 seq_printf(sfp, "ack_failure_count = %u\n",
267 ustats.ack_failure_count);
268 seq_printf(sfp, "rx_fragment_count = %u\n",
269 ustats.rx_fragment_count);
270 seq_printf(sfp, "mcast_rx_frame_count = %u\n",
271 ustats.mcast_rx_frame_count);
272 seq_printf(sfp, "fcs_error_count = %u\n",
273 ustats.fcs_error_count);
274 seq_printf(sfp, "tx_frame_count = %u\n", ustats.tx_frame_count);
275 seq_printf(sfp, "rsna_tkip_cm_invoked = %u\n",
276 ustats.rsna_tkip_cm_invoked);
277 seq_printf(sfp, "rsna_4way_hshk_failures = %u\n",
278 ustats.rsna_4way_hshk_failures);
279 }
280 #endif /* UAP_SUPPORT */
281 seq_printf(sfp, "=== tp_acnt.on:%d drop_point:%d ===\n",
282 handle->tp_acnt.on, handle->tp_acnt.drop_point);
283 seq_printf(sfp, "====Tx accounting====\n");
284 for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
285 seq_printf(sfp, "[%d] Tx packets : %lu\n", i,
286 handle->tp_acnt.tx_packets[i]);
287 seq_printf(sfp, "[%d] Tx packets last: %lu\n", i,
288 handle->tp_acnt.tx_packets_last[i]);
289 seq_printf(sfp, "[%d] Tx packets rate: %lu\n", i,
290 handle->tp_acnt.tx_packets_rate[i]);
291 seq_printf(sfp, "[%d] Tx bytes : %lu\n", i,
292 handle->tp_acnt.tx_bytes[i]);
293 seq_printf(sfp, "[%d] Tx bytes last : %lu\n", i,
294 handle->tp_acnt.tx_bytes_last[i]);
295 seq_printf(sfp, "[%d] Tx bytes rate : %luMbps\n", i,
296 handle->tp_acnt.tx_bytes_rate[i] * 8 / 1024 / 1024);
297 }
298 seq_printf(sfp, "Tx amsdu cnt : %lu\n",
299 handle->tp_acnt.tx_amsdu_cnt);
300 seq_printf(sfp, "Tx amsdu cnt last : %lu\n",
301 handle->tp_acnt.tx_amsdu_cnt_last);
302 seq_printf(sfp, "Tx amsdu cnt rate : %lu\n",
303 handle->tp_acnt.tx_amsdu_cnt_rate);
304 seq_printf(sfp, "Tx amsdu pkt cnt : %lu\n",
305 handle->tp_acnt.tx_amsdu_pkt_cnt);
306 seq_printf(sfp, "Tx amsdu pkt cnt last : %lu\n",
307 handle->tp_acnt.tx_amsdu_pkt_cnt_last);
308 seq_printf(sfp, "Tx amsdu pkt cnt rate : %lu\n",
309 handle->tp_acnt.tx_amsdu_pkt_cnt_rate);
310 seq_printf(sfp, "Tx intr cnt : %lu\n",
311 handle->tp_acnt.tx_intr_cnt);
312 seq_printf(sfp, "Tx intr last : %lu\n",
313 handle->tp_acnt.tx_intr_last);
314 seq_printf(sfp, "Tx intr rate : %lu\n",
315 handle->tp_acnt.tx_intr_rate);
316 seq_printf(sfp, "Tx pending : %lu\n",
317 handle->tp_acnt.tx_pending);
318 seq_printf(sfp, "Tx xmit skb realloc : %lu\n",
319 handle->tp_acnt.tx_xmit_skb_realloc_cnt);
320 seq_printf(sfp, "Tx stop queue cnt : %lu\n",
321 handle->tp_acnt.tx_stop_queue_cnt);
322 seq_printf(sfp, "====Rx accounting====\n");
323 for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
324 seq_printf(sfp, "[%d] Rx packets : %lu\n", i,
325 handle->tp_acnt.rx_packets[i]);
326 seq_printf(sfp, "[%d] Rx packets last: %lu\n", i,
327 handle->tp_acnt.rx_packets_last[i]);
328 seq_printf(sfp, "[%d] Rx packets rate: %lu\n", i,
329 handle->tp_acnt.rx_packets_rate[i]);
330 seq_printf(sfp, "[%d] Rx bytes : %lu\n", i,
331 handle->tp_acnt.rx_bytes[i]);
332 seq_printf(sfp, "[%d] Rx bytes last : %lu\n", i,
333 handle->tp_acnt.rx_bytes_last[i]);
334 seq_printf(sfp, "[%d] Rx bytes rate : %luMbps\n", i,
335 handle->tp_acnt.rx_bytes_rate[i] * 8 / 1024 / 1024);
336 }
337 seq_printf(sfp, "Rx amsdu cnt : %lu\n",
338 handle->tp_acnt.rx_amsdu_cnt);
339 seq_printf(sfp, "Rx amsdu cnt last : %lu\n",
340 handle->tp_acnt.rx_amsdu_cnt_last);
341 seq_printf(sfp, "Rx amsdu cnt rate : %lu\n",
342 handle->tp_acnt.rx_amsdu_cnt_rate);
343 seq_printf(sfp, "Rx amsdu pkt cnt : %lu\n",
344 handle->tp_acnt.rx_amsdu_pkt_cnt);
345 seq_printf(sfp, "Rx amsdu pkt cnt last : %lu\n",
346 handle->tp_acnt.rx_amsdu_pkt_cnt_last);
347 seq_printf(sfp, "Rx amsdu pkt cnt rate : %lu\n",
348 handle->tp_acnt.rx_amsdu_pkt_cnt_rate);
349 seq_printf(sfp, "Rx intr cnt : %lu\n",
350 handle->tp_acnt.rx_intr_cnt);
351 seq_printf(sfp, "Rx intr last : %lu\n",
352 handle->tp_acnt.rx_intr_last);
353 seq_printf(sfp, "Rx intr rate : %lu\n",
354 handle->tp_acnt.rx_intr_rate);
355 seq_printf(sfp, "Rx pending : %lu\n",
356 handle->tp_acnt.rx_pending);
357 seq_printf(sfp, "Rx pause : %lu\n",
358 handle->tp_acnt.rx_paused_cnt);
359 seq_printf(sfp, "Rx rdptr full cnt : %lu\n",
360 handle->tp_acnt.rx_rdptr_full_cnt);
361 exit:
362 LEAVE();
363 MODULE_PUT;
364 return 0;
365 }
366
woal_info_proc_open(struct inode * inode,struct file * file)367 static int woal_info_proc_open(struct inode *inode, struct file *file)
368 {
369 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
370 return single_open(file, woal_info_proc_read, pde_data(inode));
371 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
372 return single_open(file, woal_info_proc_read, PDE_DATA(inode));
373 #else
374 return single_open(file, woal_info_proc_read, PDE(inode)->data);
375 #endif
376 }
377
378 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
379 static const struct proc_ops info_proc_fops = {
380 .proc_open = woal_info_proc_open,
381 .proc_read = seq_read,
382 .proc_lseek = seq_lseek,
383 .proc_release = single_release,
384 };
385 #else
386 static const struct file_operations info_proc_fops = {
387 .owner = THIS_MODULE,
388 .open = woal_info_proc_open,
389 .read = seq_read,
390 .llseek = seq_lseek,
391 .release = single_release,
392 };
393 #endif
394
395 #ifdef SDIO
396 #define CMD52_STR_LEN 50
397 /*
398 * @brief Parse cmd52 string
399 *
400 * @param buffer A pointer user buffer
401 * @param len Length user buffer
402 * @param func Parsed func number
403 * @param reg Parsed reg value
404 * @param val Parsed value to set
405 * @return BT_STATUS_SUCCESS
406 */
parse_cmd52_string(const char * buffer,size_t len,int * func,int * reg,int * val)407 static int parse_cmd52_string(const char *buffer, size_t len, int *func,
408 int *reg, int *val)
409 {
410 int ret = MLAN_STATUS_SUCCESS;
411 char *string = NULL;
412 char *pos = NULL;
413 gfp_t flag;
414
415 ENTER();
416 flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
417 string = kzalloc(CMD52_STR_LEN, flag);
418 if (string == NULL)
419 return -ENOMEM;
420
421 moal_memcpy_ext(NULL, string, buffer + strlen("sdcmd52rw="),
422 len - strlen("sdcmd52rw="), CMD52_STR_LEN - 1);
423 string = strstrip(string);
424
425 *func = -1;
426 *reg = -1;
427 *val = -1;
428
429 /* Get func */
430 pos = strsep(&string, " \t");
431 if (pos)
432 *func = woal_string_to_number(pos);
433
434 /* Get reg */
435 pos = strsep(&string, " \t");
436 if (pos)
437 *reg = woal_string_to_number(pos);
438
439 /* Get val (optional) */
440 pos = strsep(&string, " \t");
441 if (pos)
442 *val = woal_string_to_number(pos);
443 kfree(string);
444 LEAVE();
445 return ret;
446 }
447 #endif
448
449 /**
450 * @brief config proc write function
451 *
452 * @param f file pointer
453 * @param buf pointer to data buffer
454 * @param count data number to write
455 * @param off Offset
456 *
457 * @return number of data
458 */
woal_config_write(struct file * f,const char __user * buf,size_t count,loff_t * off)459 static ssize_t woal_config_write(struct file *f, const char __user *buf,
460 size_t count, loff_t *off)
461 {
462 char databuf[200];
463 char *line = NULL;
464 t_u32 config_data = 0;
465 struct seq_file *sfp = f->private_data;
466 moal_handle *handle = (moal_handle *)sfp->private;
467
468 #ifdef SDIO
469 int func = 0, reg = 0, val = 0;
470 #endif
471 moal_handle *ref_handle = NULL;
472 t_u32 cmd = 0;
473 int copy_len;
474 moal_private *priv = NULL;
475
476 ENTER();
477 if (!MODULE_GET) {
478 LEAVE();
479 return 0;
480 }
481
482 if (count >= sizeof(databuf)) {
483 MODULE_PUT;
484 LEAVE();
485 return (int)count;
486 }
487 memset(databuf, 0, sizeof(databuf));
488 copy_len = MIN((sizeof(databuf) - 1), count);
489 if (copy_from_user(databuf, buf, copy_len)) {
490 MODULE_PUT;
491 LEAVE();
492 return 0;
493 }
494 line = databuf;
495 if (!strncmp(databuf, "soft_reset", strlen("soft_reset"))) {
496 line += strlen("soft_reset") + 1;
497 config_data = (t_u32)woal_string_to_number(line);
498 PRINTM(MINFO, "soft_reset: %d\n", (int)config_data);
499 if (woal_request_soft_reset(handle) == MLAN_STATUS_SUCCESS)
500 handle->hardware_status = HardwareStatusReset;
501 else
502 PRINTM(MERROR, "Could not perform soft reset\n");
503 }
504 if (!strncmp(databuf, "drv_mode", strlen("drv_mode"))) {
505 line += strlen("drv_mode") + 1;
506 config_data = (t_u32)woal_string_to_number(line);
507 PRINTM(MINFO, "drv_mode: %d\n", (int)config_data);
508 if (config_data != (t_u32)handle->params.drv_mode)
509 if (woal_switch_drv_mode(handle, config_data) !=
510 MLAN_STATUS_SUCCESS) {
511 PRINTM(MERROR, "Could not switch drv mode\n");
512 }
513 }
514 #ifdef SDIO
515 if (IS_SD(handle->card_type)) {
516 if (!strncmp(databuf, "sdcmd52rw=", strlen("sdcmd52rw=")) &&
517 count > strlen("sdcmd52rw=")) {
518 parse_cmd52_string((const char *)databuf, (size_t)count,
519 &func, ®, &val);
520 woal_sdio_read_write_cmd52(handle, func, reg, val);
521 }
522 }
523 #endif /* SD */
524 if (!strncmp(databuf, "debug_dump", strlen("debug_dump"))) {
525 PRINTM(MERROR, "Recevie debug_dump command\n");
526 #ifdef USB
527 if (!IS_USB(handle->card_type))
528 #endif
529 handle->driver_status = MTRUE;
530 ref_handle = (moal_handle *)handle->pref_mac;
531 if (ref_handle) {
532 priv = woal_get_priv(ref_handle, MLAN_BSS_ROLE_ANY);
533 if (priv) {
534 handle->fw_dump_status = MTRUE;
535 woal_mlan_debug_info(priv);
536 woal_moal_debug_info(priv, NULL, MFALSE);
537 }
538 }
539 priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
540 if (priv) {
541 handle->fw_dump_status = MTRUE;
542 woal_mlan_debug_info(priv);
543 woal_moal_debug_info(priv, NULL, MFALSE);
544 handle->ops.dump_fw_info(handle);
545 }
546 }
547
548 if (!strncmp(databuf, "fwdump_file=", strlen("fwdump_file="))) {
549 int len = copy_len - strlen("fwdump_file=");
550 gfp_t flag;
551 if (len) {
552 kfree(handle->fwdump_fname);
553 flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC :
554 GFP_KERNEL;
555 handle->fwdump_fname = kzalloc(len, flag);
556 if (handle->fwdump_fname)
557 moal_memcpy_ext(handle, handle->fwdump_fname,
558 databuf +
559 strlen("fwdump_file="),
560 len - 1, len - 1);
561 }
562 }
563 if (!strncmp(databuf, "fw_reload", strlen("fw_reload"))) {
564 if (!strncmp(databuf, "fw_reload=", strlen("fw_reload="))) {
565 line += strlen("fw_reload") + 1;
566 config_data = (t_u32)woal_string_to_number(line);
567 }
568 #ifdef SDIO_MMC
569 else if (IS_SD(handle->card_type))
570 config_data = FW_RELOAD_SDIO_INBAND_RESET;
571 #endif
572 PRINTM(MMSG, "Request fw_reload=%d\n", config_data);
573 woal_request_fw_reload(handle, config_data);
574 }
575 if (!strncmp(databuf, "drop_point=", strlen("drop_point="))) {
576 line += strlen("drop_point") + 1;
577 config_data = (t_u32)woal_string_to_number(line);
578 if (config_data) {
579 handle->tp_acnt.on = 1;
580 handle->tp_acnt.drop_point = config_data;
581 if (handle->is_tp_acnt_timer_set == MFALSE) {
582 woal_initialize_timer(&handle->tp_acnt.timer,
583 woal_tp_acnt_timer_func,
584 handle);
585 handle->is_tp_acnt_timer_set = MTRUE;
586 woal_mod_timer(&handle->tp_acnt.timer, 1000);
587 }
588 } else {
589 if (handle->is_tp_acnt_timer_set) {
590 woal_cancel_timer(&handle->tp_acnt.timer);
591 handle->is_tp_acnt_timer_set = MFALSE;
592 }
593 memset((void *)&handle->tp_acnt, 0,
594 sizeof(moal_tp_acnt_t));
595 }
596 priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
597 if (priv)
598 woal_set_tp_state(priv);
599 PRINTM(MMSG, "on=%d drop_point=%d\n", handle->tp_acnt.on,
600 handle->tp_acnt.drop_point);
601 }
602 if (!strncmp(databuf, "hssetpara=", strlen("hssetpara="))) {
603 line += strlen("hssetpara") + 1;
604 PRINTM(MCMND, "hssetpara=%s\n", line);
605 woal_process_proc_hssetpara(handle, line);
606 }
607 if (!strncmp(databuf, "rf_test_mode", strlen("rf_test_mode"))) {
608 line += strlen("rf_test_mode") + 1;
609 config_data = (t_u32)woal_string_to_number(line);
610 PRINTM(MINFO, "RF test mode: %d\n", (int)config_data);
611 if (config_data != (t_u32)handle->rf_test_mode)
612 if (woal_process_rf_test_mode(handle, config_data) !=
613 MLAN_STATUS_SUCCESS)
614 PRINTM(MERROR, "Could not set RF test mode\n");
615 }
616 if (!strncmp(databuf, "tx_antenna", strlen("tx_antenna"))) {
617 line += strlen("tx_antenna") + 1;
618 config_data = (t_u32)woal_string_to_number(line);
619 cmd = MFG_CMD_TX_ANT;
620 }
621 if (!strncmp(databuf, "rx_antenna", strlen("rx_antenna"))) {
622 line += strlen("rx_antenna") + 1;
623 config_data = (t_u32)woal_string_to_number(line);
624 cmd = MFG_CMD_RX_ANT;
625 }
626 if (!strncmp(databuf, "radio_mode", strlen("radio_mode"))) {
627 line += strlen("radio_mode") + 1;
628 config_data = (t_u32)woal_string_to_number(line);
629 cmd = MFG_CMD_RADIO_MODE_CFG;
630 }
631 if (!strncmp(databuf, "channel", strlen("channel"))) {
632 line += strlen("channel") + 1;
633 config_data = (t_u32)woal_string_to_number(line);
634 cmd = MFG_CMD_RF_CHAN;
635 }
636 if (!strncmp(databuf, "band", strlen("band"))) {
637 line += strlen("band") + 1;
638 config_data = (t_u32)woal_string_to_number(line);
639 cmd = MFG_CMD_RF_BAND_AG;
640 }
641 if (!strncmp(databuf, "bw", strlen("bw"))) {
642 line += strlen("bw") + 1;
643 config_data = (t_u32)woal_string_to_number(line);
644 cmd = MFG_CMD_RF_CHANNELBW;
645 }
646 if (!strncmp(databuf, "get_and_reset_per", strlen("get_and_reset_per")))
647 cmd = MFG_CMD_CLR_RX_ERR;
648 if (!strncmp(databuf, "tx_power=", strlen("tx_power=")) &&
649 count > strlen("tx_power="))
650 cmd = MFG_CMD_RFPWR;
651 if (!strncmp(databuf, "tx_frame=", strlen("tx_frame=")) &&
652 count > strlen("tx_frame="))
653 cmd = MFG_CMD_TX_FRAME;
654 if (!strncmp(databuf, "tx_continuous=", strlen("tx_continuous=")) &&
655 count > strlen("tx_continuous="))
656 cmd = MFG_CMD_TX_CONT;
657 if (!strncmp(databuf, "he_tb_tx=", strlen("he_tb_tx=")) &&
658 count > strlen("he_tb_tx="))
659 cmd = MFG_CMD_CONFIG_MAC_HE_TB_TX;
660
661 if (cmd && handle->rf_test_mode &&
662 (woal_process_rf_test_mode_cmd(
663 handle, cmd, (const char *)databuf, (size_t)count,
664 MLAN_ACT_SET, config_data) != MLAN_STATUS_SUCCESS)) {
665 PRINTM(MERROR, "RF test mode cmd error\n");
666 }
667 if (cmd && !handle->rf_test_mode)
668 PRINTM(MERROR, "RF test mode is disabled\n");
669 MODULE_PUT;
670 LEAVE();
671 return (int)count;
672 }
673
674 /**
675 * @brief config proc read function
676 *
677 * @param sfp pointer to seq_file structure
678 * @param data
679 *
680 * @return number of output data
681 */
woal_config_read(struct seq_file * sfp,void * data)682 static int woal_config_read(struct seq_file *sfp, void *data)
683 {
684 moal_handle *handle = (moal_handle *)sfp->private;
685 int i;
686 moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
687 mlan_ds_hs_cfg hscfg;
688
689 ENTER();
690
691 if (!MODULE_GET) {
692 LEAVE();
693 return 0;
694 }
695
696 seq_printf(sfp, "hardware_status=%d\n", (int)handle->hardware_status);
697 seq_printf(sfp, "netlink_num=%d\n", (int)handle->netlink_num);
698 seq_printf(sfp, "drv_mode=%d\n", (int)handle->params.drv_mode);
699 if (priv) {
700 memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
701 woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT,
702 &hscfg);
703 seq_printf(sfp, "hssetpara=%d,0x%x,%d,%d\n", hscfg.conditions,
704 hscfg.gpio, hscfg.gap, hscfg.hs_wake_interval);
705 }
706 #ifdef SDIO
707 if (IS_SD(handle->card_type)) {
708 seq_printf(sfp, "sdcmd52rw=%d 0x%0x 0x%02X\n",
709 handle->cmd52_func, handle->cmd52_reg,
710 handle->cmd52_val);
711 }
712 #endif /* SD */
713 seq_printf(sfp, "rf_test_mode=%u\n", handle->rf_test_mode);
714 if (handle->rf_test_mode && handle->rf_data) {
715 seq_printf(sfp, "tx_antenna=%u\n", handle->rf_data->tx_antenna);
716 seq_printf(sfp, "rx_antenna=%u\n", handle->rf_data->rx_antenna);
717 seq_printf(sfp, "band=%u\n", handle->rf_data->band);
718 seq_printf(sfp, "bw=%u\n", handle->rf_data->bandwidth);
719 if (handle->rf_data->channel)
720 seq_printf(sfp, "channel=%u\n",
721 handle->rf_data->channel);
722 else
723 seq_printf(sfp, "channel=\n");
724 if (handle->rf_data->radio_mode[0])
725 seq_printf(sfp, "radio_mode[0]=%u\n",
726 handle->rf_data->radio_mode[0]);
727 else
728 seq_printf(sfp, "radio_mode[0]=\n");
729 if (handle->rf_data->radio_mode[1])
730 seq_printf(sfp, "radio_mode[1]=%u\n",
731 handle->rf_data->radio_mode[1]);
732 else
733 seq_printf(sfp, "radio_mode[1]=\n");
734 seq_printf(sfp, "total rx pkt count=%u\n",
735 handle->rf_data->rx_tot_pkt_count);
736 seq_printf(sfp, "rx multicast/broadcast pkt count=%u\n",
737 handle->rf_data->rx_mcast_bcast_pkt_count);
738 seq_printf(sfp, "rx fcs error pkt count=%u\n",
739 handle->rf_data->rx_pkt_fcs_err_count);
740 if (handle->rf_data->tx_power_data[0]) {
741 seq_printf(sfp, "tx_power=%u",
742 handle->rf_data->tx_power_data[0]);
743 seq_printf(sfp, " %u",
744 handle->rf_data->tx_power_data[1]);
745 seq_printf(sfp, " %u\n",
746 handle->rf_data->tx_power_data[2]);
747 } else
748 seq_printf(sfp, "tx_power=\n");
749 seq_printf(sfp, "tx_continuous=%u",
750 handle->rf_data->tx_cont_data[0]);
751 if (handle->rf_data->tx_cont_data[0] == MTRUE) {
752 seq_printf(sfp, " %u",
753 handle->rf_data->tx_cont_data[1]);
754 seq_printf(sfp, " 0x%x",
755 handle->rf_data->tx_cont_data[2]);
756 for (i = 3; i < 6; i++)
757 seq_printf(sfp, " %u",
758 handle->rf_data->tx_cont_data[i]);
759 }
760 seq_printf(sfp, "\n");
761 seq_printf(sfp, "tx_frame=%u",
762 handle->rf_data->tx_frame_data[0]);
763 if (handle->rf_data->tx_frame_data[0] == MTRUE) {
764 seq_printf(sfp, " %u",
765 handle->rf_data->tx_frame_data[1]);
766 seq_printf(sfp, " 0x%x",
767 handle->rf_data->tx_frame_data[2]);
768 for (i = 3; i < 13; i++)
769 seq_printf(sfp, " %u",
770 handle->rf_data->tx_frame_data[i]);
771 for (i = 13; i < 20; i++)
772 seq_printf(sfp, " %d",
773 handle->rf_data->tx_frame_data[i]);
774 seq_printf(sfp, " %02x:%02x:%02x:%02x:%02x:%02x",
775 handle->rf_data->bssid[0],
776 handle->rf_data->bssid[1],
777 handle->rf_data->bssid[2],
778 handle->rf_data->bssid[3],
779 handle->rf_data->bssid[4],
780 handle->rf_data->bssid[5]);
781 }
782 seq_printf(sfp, "\n");
783 seq_printf(sfp, "he_tb_tx=%u", handle->rf_data->he_tb_tx[0]);
784 if (handle->rf_data->he_tb_tx[0] == MTRUE) {
785 seq_printf(sfp, " %u", handle->rf_data->he_tb_tx[1]);
786 seq_printf(sfp, " %u", handle->rf_data->he_tb_tx[2]);
787 seq_printf(sfp, " %u", handle->rf_data->he_tb_tx[3]);
788 seq_printf(sfp, " %u", handle->rf_data->he_tb_tx[4]);
789 }
790 seq_printf(sfp, "\n");
791 }
792 MODULE_PUT;
793 LEAVE();
794 return 0;
795 }
796
woal_config_proc_open(struct inode * inode,struct file * file)797 static int woal_config_proc_open(struct inode *inode, struct file *file)
798 {
799 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
800 return single_open(file, woal_config_read, pde_data(inode));
801 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
802 return single_open(file, woal_config_read, PDE_DATA(inode));
803 #else
804 return single_open(file, woal_config_read, PDE(inode)->data);
805 #endif
806 }
807
808 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
809 static const struct proc_ops config_proc_fops = {
810 .proc_open = woal_config_proc_open,
811 .proc_read = seq_read,
812 .proc_lseek = seq_lseek,
813 .proc_release = single_release,
814 .proc_write = woal_config_write,
815 };
816 #else
817 static const struct file_operations config_proc_fops = {
818 .owner = THIS_MODULE,
819 .open = woal_config_proc_open,
820 .read = seq_read,
821 .llseek = seq_lseek,
822 .release = single_release,
823 .write = woal_config_write,
824 };
825 #endif
826
woal_drv_dump_read(struct seq_file * sfp,void * data)827 static int woal_drv_dump_read(struct seq_file *sfp, void *data)
828 {
829 moal_handle *handle = (moal_handle *)sfp->private;
830 int ret = 0;
831
832 ENTER();
833
834 if (MODULE_GET == 0) {
835 LEAVE();
836 return 0;
837 }
838
839 if (!handle) {
840 PRINTM(MERROR, "handle is NULL!\n");
841 LEAVE();
842 return 0;
843 }
844 if (!handle->drv_dump_buf || !handle->drv_dump_len)
845 handle->drv_dump_buf =
846 woal_dump_drv_info(handle, &handle->drv_dump_len);
847 if (!handle->drv_dump_buf || !handle->drv_dump_len) {
848 PRINTM(MERROR,
849 "driver dump buffer is NULL or total length is zero\n");
850 goto done;
851 }
852 if (sfp->size < handle->drv_dump_len) {
853 PRINTM(MERROR,
854 "drv dump size too big, size=%d, drv_dump_len=%d\n",
855 (int)sfp->size, handle->drv_dump_len);
856 sfp->count = sfp->size;
857 ret = 0;
858 MODULE_PUT;
859 return ret;
860 }
861 memset(sfp->buf, 0x00, sfp->size);
862 sfp->count = handle->drv_dump_len;
863 moal_memcpy_ext(handle, sfp->buf, handle->drv_dump_buf,
864 handle->drv_dump_len, sfp->size);
865 done:
866 moal_vfree(handle, handle->drv_dump_buf);
867 handle->drv_dump_len = 0;
868 handle->drv_dump_buf = NULL;
869 MODULE_PUT;
870 LEAVE();
871 return 0;
872 }
873
woal_drv_dump_proc_open(struct inode * inode,struct file * file)874 static int woal_drv_dump_proc_open(struct inode *inode, struct file *file)
875 {
876 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
877 return single_open(file, woal_drv_dump_read, pde_data(inode));
878 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
879 return single_open(file, woal_drv_dump_read, PDE_DATA(inode));
880 #else
881 return single_open(file, woal_drv_dump_read, PDE(inode)->data);
882 #endif
883 }
884
885 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
886 static const struct proc_ops drv_dump_fops = {
887 .proc_open = woal_drv_dump_proc_open,
888 .proc_read = seq_read,
889 .proc_lseek = seq_lseek,
890 .proc_release = single_release,
891 };
892 #else
893 static const struct file_operations drv_dump_fops = {
894 .owner = THIS_MODULE,
895 .open = woal_drv_dump_proc_open,
896 .read = seq_read,
897 .llseek = seq_lseek,
898 .release = single_release,
899 };
900 #endif
901
woal_fw_dump_read(struct seq_file * sfp,void * data)902 static int woal_fw_dump_read(struct seq_file *sfp, void *data)
903 {
904 moal_handle *handle = (moal_handle *)sfp->private;
905 int ret = 0;
906
907 ENTER();
908
909 if (MODULE_GET == 0) {
910 LEAVE();
911 return 0;
912 }
913
914 if (!handle) {
915 PRINTM(MERROR, "handle is null!\n");
916 goto done;
917 }
918
919 if (handle->fw_dump == MTRUE) {
920 PRINTM(MERROR, "fw dump is in progress\n");
921 goto done;
922 }
923
924 if (!handle->fw_dump_buf || !handle->fw_dump_len) {
925 PRINTM(MERROR,
926 "fw dump buffer is NULL or total length is zero\n");
927 goto done;
928 }
929
930 if (sfp->size < handle->fw_dump_len) {
931 PRINTM(MERROR,
932 "fw dump size too big, size=%d, fw_dump_len=%ld\n",
933 (int)sfp->size, (long int)handle->fw_dump_len);
934 sfp->count = sfp->size;
935 ret = 0;
936 MODULE_PUT;
937 return ret;
938 }
939
940 sfp->count = handle->fw_dump_len;
941 moal_memcpy_ext(handle, sfp->buf, handle->fw_dump_buf,
942 handle->fw_dump_len, sfp->size);
943 moal_vfree(handle, handle->fw_dump_buf);
944 handle->fw_dump_buf = NULL;
945 handle->fw_dump_len = 0;
946
947 done:
948 MODULE_PUT;
949 LEAVE();
950 return 0;
951 }
952
woal_fw_dump_proc_open(struct inode * inode,struct file * file)953 static int woal_fw_dump_proc_open(struct inode *inode, struct file *file)
954 {
955 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
956 return single_open(file, woal_fw_dump_read, pde_data(inode));
957 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
958 return single_open(file, woal_fw_dump_read, PDE_DATA(inode));
959 #else
960 return single_open(file, woal_fw_dump_read, PDE(inode)->data);
961 #endif
962 }
963
964 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
965 static const struct proc_ops fw_dump_fops = {
966 .proc_open = woal_fw_dump_proc_open,
967 .proc_read = seq_read,
968 .proc_lseek = seq_lseek,
969 .proc_release = single_release,
970 };
971 #else
972 static const struct file_operations fw_dump_fops = {
973 .owner = THIS_MODULE,
974 .open = woal_fw_dump_proc_open,
975 .read = seq_read,
976 .llseek = seq_lseek,
977 .release = single_release,
978 };
979 #endif
980
981 /**
982 * @brief wifi status proc read function
983 *
984 * @param sfp pointer to seq_file structure
985 * @param data
986 *
987 * @return number of output data
988 */
woal_wifi_status_read(struct seq_file * sfp,void * data)989 static int woal_wifi_status_read(struct seq_file *sfp, void *data)
990 {
991 ENTER();
992
993 if (!MODULE_GET) {
994 LEAVE();
995 return 0;
996 }
997
998 seq_printf(sfp, "%d\n", wifi_status);
999
1000 MODULE_PUT;
1001 LEAVE();
1002 return 0;
1003 }
1004
woal_wifi_status_proc_open(struct inode * inode,struct file * file)1005 static int woal_wifi_status_proc_open(struct inode *inode, struct file *file)
1006 {
1007 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
1008 return single_open(file, woal_wifi_status_read, pde_data(inode));
1009 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
1010 return single_open(file, woal_wifi_status_read, PDE_DATA(inode));
1011 #else
1012 return single_open(file, woal_wifi_status_read, PDE(inode)->data);
1013 #endif
1014 }
1015
1016 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
1017 static const struct proc_ops wifi_status_proc_fops = {
1018 .proc_open = woal_wifi_status_proc_open,
1019 .proc_read = seq_read,
1020 .proc_lseek = seq_lseek,
1021 .proc_release = single_release,
1022 };
1023 #else
1024 static const struct file_operations wifi_status_proc_fops = {
1025 .owner = THIS_MODULE,
1026 .open = woal_wifi_status_proc_open,
1027 .read = seq_read,
1028 .llseek = seq_lseek,
1029 .release = single_release,
1030 };
1031 #endif
1032
1033 /********************************************************
1034 Global Functions
1035 ********************************************************/
1036 /**
1037 * @brief Convert string to number
1038 *
1039 * @param s Pointer to numbered string
1040 *
1041 * @return Converted number from string s
1042 */
woal_string_to_number(char * s)1043 int woal_string_to_number(char *s)
1044 {
1045 int r = 0;
1046 int base = 0;
1047 int pn = 1;
1048
1049 if (!strncmp(s, "-", 1)) {
1050 pn = -1;
1051 s++;
1052 }
1053 if (!strncmp(s, "0x", 2) || !strncmp(s, "0X", 2)) {
1054 base = 16;
1055 s += 2;
1056 } else
1057 base = 10;
1058
1059 for (; *s; s++) {
1060 if ((*s >= '0') && (*s <= '9'))
1061 r = (r * base) + (*s - '0');
1062 else if ((*s >= 'A') && (*s <= 'F'))
1063 r = (r * base) + (*s - 'A' + 10);
1064 else if ((*s >= 'a') && (*s <= 'f'))
1065 r = (r * base) + (*s - 'a' + 10);
1066 else
1067 break;
1068 }
1069
1070 return r * pn;
1071 }
1072
1073 /**
1074 * @brief This function creates proc mwlan directory
1075 * directory structure
1076 *
1077 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1078 */
woal_root_proc_init(void)1079 mlan_status woal_root_proc_init(void)
1080 {
1081 ENTER();
1082
1083 PRINTM(MINFO, "Create /proc/mwlan directory\n");
1084
1085 proc_mwlan = proc_mkdir(MWLAN_PROC, PROC_DIR);
1086 if (!proc_mwlan) {
1087 PRINTM(MERROR,
1088 "woal_root_proc_init: Cannot create /proc/mwlan\n");
1089 LEAVE();
1090 return MLAN_STATUS_FAILURE;
1091 }
1092
1093 /* create /proc/mwlan/wifi_status */
1094 proc_create_data(STATUS_PROC, 0666, proc_mwlan, &wifi_status_proc_fops,
1095 NULL);
1096
1097 LEAVE();
1098 return MLAN_STATUS_SUCCESS;
1099 }
1100
1101 /**
1102 * @brief This function removes proc mwlan directory
1103 * directory structure
1104 *
1105 * @return N/A
1106 */
woal_root_proc_remove(void)1107 void woal_root_proc_remove(void)
1108 {
1109 ENTER();
1110
1111 remove_proc_entry(STATUS_PROC, proc_mwlan);
1112
1113 remove_proc_entry(MWLAN_PROC, PROC_DIR);
1114 proc_mwlan = NULL;
1115
1116 LEAVE();
1117 }
1118
1119 /**
1120 * @brief Create the top level proc directory
1121 *
1122 * @param handle Pointer to woal_handle
1123 *
1124 * @return N/A
1125 */
woal_proc_init(moal_handle * handle)1126 void woal_proc_init(moal_handle *handle)
1127 {
1128 struct proc_dir_entry *r;
1129 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
1130 struct proc_dir_entry *pde = proc_mwlan;
1131 #endif
1132 char config_proc_dir[20];
1133 char drv_dump_dir[20];
1134 char fw_dump_dir[20];
1135
1136 ENTER();
1137
1138 if (handle->proc_wlan) {
1139 PRINTM(MMSG, "woal_proc_init: proc_wlan is already exist %s\n",
1140 handle->proc_wlan_name);
1141 goto done;
1142 }
1143
1144 snprintf(handle->proc_wlan_name, sizeof(handle->proc_wlan_name),
1145 WLAN_PROC, handle->handle_idx);
1146 PRINTM(MINFO, "Create Proc Interface %s\n", handle->proc_wlan_name);
1147
1148 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
1149 /* Check if directory already exists */
1150 for (pde = pde->subdir; pde; pde = pde->next) {
1151 if (pde->namelen &&
1152 !strcmp(handle->proc_wlan_name, pde->name)) {
1153 /* Directory exists */
1154 PRINTM(MWARN, "proc interface already exists!\n");
1155 handle->proc_wlan = pde;
1156 break;
1157 }
1158 }
1159 if (pde == NULL) {
1160 handle->proc_wlan =
1161 proc_mkdir(handle->proc_wlan_name, proc_mwlan);
1162 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
1163 if (handle->proc_wlan)
1164 atomic_set(&handle->proc_wlan->count, 1);
1165 #endif
1166 }
1167 #else
1168 handle->proc_wlan = proc_mkdir(handle->proc_wlan_name, proc_mwlan);
1169 #endif
1170 if (!handle->proc_wlan) {
1171 PRINTM(MERROR, "Cannot create proc interface %s!\n",
1172 handle->proc_wlan_name);
1173 goto done;
1174 }
1175
1176 strcpy(config_proc_dir, "config");
1177 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
1178 r = proc_create_data(config_proc_dir, 0666, handle->proc_wlan,
1179 &config_proc_fops, handle);
1180 #else
1181 r = create_proc_entry(config_proc_dir, 0644, handle->proc_wlan);
1182 if (r) {
1183 r->data = handle;
1184 r->proc_fops = &config_proc_fops;
1185 }
1186 #endif
1187 if (!r)
1188 PRINTM(MERROR, "Fail to create proc config\n");
1189
1190 strcpy(drv_dump_dir, "drv_dump");
1191 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
1192 r = proc_create_data(drv_dump_dir, 0644, handle->proc_wlan,
1193 &drv_dump_fops, handle);
1194 #else
1195 r = create_proc_entry(drv_dump_dir, 0644, handle->proc_wlan);
1196 if (r) {
1197 r->data = handle;
1198 r->proc_fops = &drv_dump_fops;
1199 }
1200 #endif
1201 if (!r)
1202 PRINTM(MERROR, "Failed to create proc drv dump\n");
1203
1204 strcpy(fw_dump_dir, "fw_dump");
1205 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
1206 r = proc_create_data(fw_dump_dir, 0644, handle->proc_wlan,
1207 &fw_dump_fops, handle);
1208 #else
1209 r = create_proc_entry(fw_dump_dir, 0644, handle->proc_wlan);
1210 if (r) {
1211 r->data = handle;
1212 r->proc_fops = &fw_dump_fops;
1213 }
1214 #endif
1215 if (!r)
1216 PRINTM(MERROR, "Failed to create proc fw dump\n");
1217
1218 done:
1219 LEAVE();
1220 }
1221
1222 /**
1223 * @brief Remove the top level proc directory
1224 *
1225 * @param handle pointer moal_handle
1226 *
1227 * @return N/A
1228 */
woal_proc_exit(moal_handle * handle)1229 void woal_proc_exit(moal_handle *handle)
1230 {
1231 char config_proc_dir[20];
1232 char drv_dump_dir[20];
1233 char fw_dump_dir[20];
1234
1235 ENTER();
1236
1237 PRINTM(MINFO, "Remove Proc Interface %s\n", handle->proc_wlan_name);
1238 if (handle->proc_wlan) {
1239 strcpy(config_proc_dir, "config");
1240 remove_proc_entry(config_proc_dir, handle->proc_wlan);
1241 strcpy(drv_dump_dir, "drv_dump");
1242 remove_proc_entry(drv_dump_dir, handle->proc_wlan);
1243 strcpy(fw_dump_dir, "fw_dump");
1244 remove_proc_entry(fw_dump_dir, handle->proc_wlan);
1245
1246 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
1247 /* Remove only if we are the only instance using this */
1248 if (atomic_read(&(handle->proc_wlan->count)) > 1) {
1249 PRINTM(MWARN, "More than one interface using proc!\n");
1250 } else {
1251 #endif
1252 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
1253 atomic_dec(&(handle->proc_wlan->count));
1254 #endif
1255 remove_proc_entry(handle->proc_wlan_name, proc_mwlan);
1256
1257 handle->proc_wlan = NULL;
1258 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
1259 }
1260 #endif
1261 }
1262 if (handle->fw_dump_buf) {
1263 moal_vfree(handle, handle->fw_dump_buf);
1264 handle->fw_dump_buf = NULL;
1265 handle->fw_dump_len = 0;
1266 }
1267 if (handle->drv_dump_buf) {
1268 moal_vfree(handle, handle->drv_dump_buf);
1269 handle->drv_dump_len = 0;
1270 handle->drv_dump_buf = NULL;
1271 }
1272 LEAVE();
1273 }
1274
1275 /**
1276 * @brief Create proc file for interface
1277 *
1278 * @param priv pointer moal_private
1279 *
1280 * @return N/A
1281 */
woal_create_proc_entry(moal_private * priv)1282 void woal_create_proc_entry(moal_private *priv)
1283 {
1284 struct proc_dir_entry *r;
1285 struct net_device *dev = priv->netdev;
1286 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
1287 char proc_dir_name[22];
1288 #endif
1289
1290 ENTER();
1291
1292 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
1293 if (!priv->proc_entry) {
1294 memset(proc_dir_name, 0, sizeof(proc_dir_name));
1295 memcpy(proc_dir_name, priv->phandle->proc_wlan_name,
1296 sizeof(proc_dir_name) - 2);
1297 proc_dir_name[strlen(proc_dir_name)] = '/';
1298
1299 if (strlen(dev->name) >
1300 ((sizeof(proc_dir_name) - 1) - (strlen(proc_dir_name)))) {
1301 PRINTM(MERROR,
1302 "Failed to create proc entry, device name is too long\n");
1303 LEAVE();
1304 return;
1305 }
1306 strcat(proc_dir_name, dev->name);
1307 /* Try to create adapterX/dev_name directory first under
1308 * /proc/mwlan/ */
1309 priv->proc_entry = proc_mkdir(proc_dir_name, proc_mwlan);
1310 if (priv->proc_entry) {
1311 /* Success. Continue normally */
1312 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
1313 if (!priv->phandle->proc_wlan) {
1314 priv->phandle->proc_wlan =
1315 priv->proc_entry->parent;
1316 }
1317 atomic_inc(&(priv->phandle->proc_wlan->count));
1318 #endif
1319 } else {
1320 /* Failure. adapterX/ may not exist. Try to create that
1321 * first */
1322 priv->phandle->proc_wlan = proc_mkdir(
1323 priv->phandle->proc_wlan_name, proc_mwlan);
1324 if (!priv->phandle->proc_wlan) {
1325 /* Failure. Something broken */
1326 LEAVE();
1327 return;
1328 } else {
1329 /* Success. Now retry creating mlanX */
1330 priv->proc_entry =
1331 proc_mkdir(proc_dir_name, proc_mwlan);
1332 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
1333 atomic_inc(&(priv->phandle->proc_wlan->count));
1334 #endif
1335 }
1336 }
1337 #else
1338 if (priv->phandle->proc_wlan && !priv->proc_entry) {
1339 priv->proc_entry =
1340 proc_mkdir(dev->name, priv->phandle->proc_wlan);
1341 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
1342 atomic_inc(&(priv->phandle->proc_wlan->count));
1343 #endif /* < 3.10.0 */
1344 #endif /* < 2.6.26 */
1345 strcpy(priv->proc_entry_name, dev->name);
1346 if (priv->proc_entry) {
1347 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
1348 r = proc_create_data("info", 0, priv->proc_entry,
1349 &info_proc_fops, dev);
1350 #else
1351 r = create_proc_entry("info", 0, priv->proc_entry);
1352 if (r) {
1353 r->data = dev;
1354 r->proc_fops = &info_proc_fops;
1355 }
1356 #endif
1357 if (!r)
1358 PRINTM(MMSG, "Fail to create proc info\n");
1359 }
1360 }
1361
1362 LEAVE();
1363 }
1364
1365 /**
1366 * @brief Remove proc file
1367 *
1368 * @param priv Pointer moal_private
1369 *
1370 * @return N/A
1371 */
1372 void woal_proc_remove(moal_private *priv)
1373 {
1374 ENTER();
1375 if (priv->phandle->proc_wlan && priv->proc_entry) {
1376 remove_proc_entry("info", priv->proc_entry);
1377 remove_proc_entry(priv->proc_entry_name,
1378 priv->phandle->proc_wlan);
1379 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
1380 atomic_dec(&(priv->phandle->proc_wlan->count));
1381 #endif
1382 priv->proc_entry = NULL;
1383 }
1384 LEAVE();
1385 }
1386 #endif
1387