• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  // SPDX-License-Identifier: GPL-2.0
2  /* /proc routines for Host AP driver */
3  
4  #include <linux/types.h>
5  #include <linux/proc_fs.h>
6  #include <linux/export.h>
7  #include <net/lib80211.h>
8  
9  #include "hostap_wlan.h"
10  #include "hostap.h"
11  
12  #define PROC_LIMIT (PAGE_SIZE - 80)
13  
14  
15  #ifndef PRISM2_NO_PROCFS_DEBUG
prism2_debug_proc_show(struct seq_file * m,void * v)16  static int prism2_debug_proc_show(struct seq_file *m, void *v)
17  {
18  	local_info_t *local = m->private;
19  	int i;
20  
21  	seq_printf(m, "next_txfid=%d next_alloc=%d\n",
22  		   local->next_txfid, local->next_alloc);
23  	for (i = 0; i < PRISM2_TXFID_COUNT; i++)
24  		seq_printf(m, "FID: tx=%04X intransmit=%04X\n",
25  			   local->txfid[i], local->intransmitfid[i]);
26  	seq_printf(m, "FW TX rate control: %d\n", local->fw_tx_rate_control);
27  	seq_printf(m, "beacon_int=%d\n", local->beacon_int);
28  	seq_printf(m, "dtim_period=%d\n", local->dtim_period);
29  	seq_printf(m, "wds_max_connections=%d\n", local->wds_max_connections);
30  	seq_printf(m, "dev_enabled=%d\n", local->dev_enabled);
31  	seq_printf(m, "sw_tick_stuck=%d\n", local->sw_tick_stuck);
32  	for (i = 0; i < WEP_KEYS; i++) {
33  		if (local->crypt_info.crypt[i] &&
34  		    local->crypt_info.crypt[i]->ops) {
35  			seq_printf(m, "crypt[%d]=%s\n", i,
36  				   local->crypt_info.crypt[i]->ops->name);
37  		}
38  	}
39  	seq_printf(m, "pri_only=%d\n", local->pri_only);
40  	seq_printf(m, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI);
41  	seq_printf(m, "sram_type=%d\n", local->sram_type);
42  	seq_printf(m, "no_pri=%d\n", local->no_pri);
43  
44  	return 0;
45  }
46  
prism2_debug_proc_open(struct inode * inode,struct file * file)47  static int prism2_debug_proc_open(struct inode *inode, struct file *file)
48  {
49  	return single_open(file, prism2_debug_proc_show, PDE_DATA(inode));
50  }
51  
52  static const struct file_operations prism2_debug_proc_fops = {
53  	.open		= prism2_debug_proc_open,
54  	.read		= seq_read,
55  	.llseek		= seq_lseek,
56  	.release	= single_release,
57  };
58  #endif /* PRISM2_NO_PROCFS_DEBUG */
59  
60  
prism2_stats_proc_show(struct seq_file * m,void * v)61  static int prism2_stats_proc_show(struct seq_file *m, void *v)
62  {
63  	local_info_t *local = m->private;
64  	struct comm_tallies_sums *sums = &local->comm_tallies;
65  
66  	seq_printf(m, "TxUnicastFrames=%u\n", sums->tx_unicast_frames);
67  	seq_printf(m, "TxMulticastframes=%u\n", sums->tx_multicast_frames);
68  	seq_printf(m, "TxFragments=%u\n", sums->tx_fragments);
69  	seq_printf(m, "TxUnicastOctets=%u\n", sums->tx_unicast_octets);
70  	seq_printf(m, "TxMulticastOctets=%u\n", sums->tx_multicast_octets);
71  	seq_printf(m, "TxDeferredTransmissions=%u\n",
72  		   sums->tx_deferred_transmissions);
73  	seq_printf(m, "TxSingleRetryFrames=%u\n", sums->tx_single_retry_frames);
74  	seq_printf(m, "TxMultipleRetryFrames=%u\n",
75  		   sums->tx_multiple_retry_frames);
76  	seq_printf(m, "TxRetryLimitExceeded=%u\n",
77  		   sums->tx_retry_limit_exceeded);
78  	seq_printf(m, "TxDiscards=%u\n", sums->tx_discards);
79  	seq_printf(m, "RxUnicastFrames=%u\n", sums->rx_unicast_frames);
80  	seq_printf(m, "RxMulticastFrames=%u\n", sums->rx_multicast_frames);
81  	seq_printf(m, "RxFragments=%u\n", sums->rx_fragments);
82  	seq_printf(m, "RxUnicastOctets=%u\n", sums->rx_unicast_octets);
83  	seq_printf(m, "RxMulticastOctets=%u\n", sums->rx_multicast_octets);
84  	seq_printf(m, "RxFCSErrors=%u\n", sums->rx_fcs_errors);
85  	seq_printf(m, "RxDiscardsNoBuffer=%u\n", sums->rx_discards_no_buffer);
86  	seq_printf(m, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa);
87  	seq_printf(m, "RxDiscardsWEPUndecryptable=%u\n",
88  		   sums->rx_discards_wep_undecryptable);
89  	seq_printf(m, "RxMessageInMsgFragments=%u\n",
90  		   sums->rx_message_in_msg_fragments);
91  	seq_printf(m, "RxMessageInBadMsgFragments=%u\n",
92  		   sums->rx_message_in_bad_msg_fragments);
93  	/* FIX: this may grow too long for one page(?) */
94  
95  	return 0;
96  }
97  
prism2_stats_proc_open(struct inode * inode,struct file * file)98  static int prism2_stats_proc_open(struct inode *inode, struct file *file)
99  {
100  	return single_open(file, prism2_stats_proc_show, PDE_DATA(inode));
101  }
102  
103  static const struct file_operations prism2_stats_proc_fops = {
104  	.open		= prism2_stats_proc_open,
105  	.read		= seq_read,
106  	.llseek		= seq_lseek,
107  	.release	= single_release,
108  };
109  
110  
prism2_wds_proc_show(struct seq_file * m,void * v)111  static int prism2_wds_proc_show(struct seq_file *m, void *v)
112  {
113  	struct list_head *ptr = v;
114  	struct hostap_interface *iface;
115  
116  	iface = list_entry(ptr, struct hostap_interface, list);
117  	if (iface->type == HOSTAP_INTERFACE_WDS)
118  		seq_printf(m, "%s\t%pM\n",
119  			   iface->dev->name, iface->u.wds.remote_addr);
120  	return 0;
121  }
122  
prism2_wds_proc_start(struct seq_file * m,loff_t * _pos)123  static void *prism2_wds_proc_start(struct seq_file *m, loff_t *_pos)
124  {
125  	local_info_t *local = m->private;
126  	read_lock_bh(&local->iface_lock);
127  	return seq_list_start(&local->hostap_interfaces, *_pos);
128  }
129  
prism2_wds_proc_next(struct seq_file * m,void * v,loff_t * _pos)130  static void *prism2_wds_proc_next(struct seq_file *m, void *v, loff_t *_pos)
131  {
132  	local_info_t *local = m->private;
133  	return seq_list_next(v, &local->hostap_interfaces, _pos);
134  }
135  
prism2_wds_proc_stop(struct seq_file * m,void * v)136  static void prism2_wds_proc_stop(struct seq_file *m, void *v)
137  {
138  	local_info_t *local = m->private;
139  	read_unlock_bh(&local->iface_lock);
140  }
141  
142  static const struct seq_operations prism2_wds_proc_seqops = {
143  	.start	= prism2_wds_proc_start,
144  	.next	= prism2_wds_proc_next,
145  	.stop	= prism2_wds_proc_stop,
146  	.show	= prism2_wds_proc_show,
147  };
148  
prism2_wds_proc_open(struct inode * inode,struct file * file)149  static int prism2_wds_proc_open(struct inode *inode, struct file *file)
150  {
151  	int ret = seq_open(file, &prism2_wds_proc_seqops);
152  	if (ret == 0) {
153  		struct seq_file *m = file->private_data;
154  		m->private = PDE_DATA(inode);
155  	}
156  	return ret;
157  }
158  
159  static const struct file_operations prism2_wds_proc_fops = {
160  	.open		= prism2_wds_proc_open,
161  	.read		= seq_read,
162  	.llseek		= seq_lseek,
163  	.release	= seq_release,
164  };
165  
166  
prism2_bss_list_proc_show(struct seq_file * m,void * v)167  static int prism2_bss_list_proc_show(struct seq_file *m, void *v)
168  {
169  	local_info_t *local = m->private;
170  	struct list_head *ptr = v;
171  	struct hostap_bss_info *bss;
172  
173  	if (ptr == &local->bss_list) {
174  		seq_printf(m, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t"
175  			   "SSID(hex)\tWPA IE\n");
176  		return 0;
177  	}
178  
179  	bss = list_entry(ptr, struct hostap_bss_info, list);
180  	seq_printf(m, "%pM\t%lu\t%u\t0x%x\t",
181  		   bss->bssid, bss->last_update,
182  		   bss->count, bss->capab_info);
183  
184  	seq_printf(m, "%*pE", (int)bss->ssid_len, bss->ssid);
185  
186  	seq_putc(m, '\t');
187  	seq_printf(m, "%*phN", (int)bss->ssid_len, bss->ssid);
188  	seq_putc(m, '\t');
189  	seq_printf(m, "%*phN", (int)bss->wpa_ie_len, bss->wpa_ie);
190  	seq_putc(m, '\n');
191  	return 0;
192  }
193  
prism2_bss_list_proc_start(struct seq_file * m,loff_t * _pos)194  static void *prism2_bss_list_proc_start(struct seq_file *m, loff_t *_pos)
195  {
196  	local_info_t *local = m->private;
197  	spin_lock_bh(&local->lock);
198  	return seq_list_start_head(&local->bss_list, *_pos);
199  }
200  
prism2_bss_list_proc_next(struct seq_file * m,void * v,loff_t * _pos)201  static void *prism2_bss_list_proc_next(struct seq_file *m, void *v, loff_t *_pos)
202  {
203  	local_info_t *local = m->private;
204  	return seq_list_next(v, &local->bss_list, _pos);
205  }
206  
prism2_bss_list_proc_stop(struct seq_file * m,void * v)207  static void prism2_bss_list_proc_stop(struct seq_file *m, void *v)
208  {
209  	local_info_t *local = m->private;
210  	spin_unlock_bh(&local->lock);
211  }
212  
213  static const struct seq_operations prism2_bss_list_proc_seqops = {
214  	.start	= prism2_bss_list_proc_start,
215  	.next	= prism2_bss_list_proc_next,
216  	.stop	= prism2_bss_list_proc_stop,
217  	.show	= prism2_bss_list_proc_show,
218  };
219  
prism2_bss_list_proc_open(struct inode * inode,struct file * file)220  static int prism2_bss_list_proc_open(struct inode *inode, struct file *file)
221  {
222  	int ret = seq_open(file, &prism2_bss_list_proc_seqops);
223  	if (ret == 0) {
224  		struct seq_file *m = file->private_data;
225  		m->private = PDE_DATA(inode);
226  	}
227  	return ret;
228  }
229  
230  static const struct file_operations prism2_bss_list_proc_fops = {
231  	.open		= prism2_bss_list_proc_open,
232  	.read		= seq_read,
233  	.llseek		= seq_lseek,
234  	.release	= seq_release,
235  };
236  
237  
prism2_crypt_proc_show(struct seq_file * m,void * v)238  static int prism2_crypt_proc_show(struct seq_file *m, void *v)
239  {
240  	local_info_t *local = m->private;
241  	int i;
242  
243  	seq_printf(m, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx);
244  	for (i = 0; i < WEP_KEYS; i++) {
245  		if (local->crypt_info.crypt[i] &&
246  		    local->crypt_info.crypt[i]->ops &&
247  		    local->crypt_info.crypt[i]->ops->print_stats) {
248  			local->crypt_info.crypt[i]->ops->print_stats(
249  				m, local->crypt_info.crypt[i]->priv);
250  		}
251  	}
252  	return 0;
253  }
254  
prism2_crypt_proc_open(struct inode * inode,struct file * file)255  static int prism2_crypt_proc_open(struct inode *inode, struct file *file)
256  {
257  	return single_open(file, prism2_crypt_proc_show, PDE_DATA(inode));
258  }
259  
260  static const struct file_operations prism2_crypt_proc_fops = {
261  	.open		= prism2_crypt_proc_open,
262  	.read		= seq_read,
263  	.llseek		= seq_lseek,
264  	.release	= single_release,
265  };
266  
267  
prism2_pda_proc_read(struct file * file,char __user * buf,size_t count,loff_t * _pos)268  static ssize_t prism2_pda_proc_read(struct file *file, char __user *buf,
269  				    size_t count, loff_t *_pos)
270  {
271  	local_info_t *local = PDE_DATA(file_inode(file));
272  	size_t off;
273  
274  	if (local->pda == NULL || *_pos >= PRISM2_PDA_SIZE)
275  		return 0;
276  
277  	off = *_pos;
278  	if (count > PRISM2_PDA_SIZE - off)
279  		count = PRISM2_PDA_SIZE - off;
280  	if (copy_to_user(buf, local->pda + off, count) != 0)
281  		return -EFAULT;
282  	*_pos += count;
283  	return count;
284  }
285  
286  static const struct file_operations prism2_pda_proc_fops = {
287  	.read		= prism2_pda_proc_read,
288  	.llseek		= generic_file_llseek,
289  };
290  
291  
prism2_aux_dump_proc_no_read(struct file * file,char __user * buf,size_t bufsize,loff_t * _pos)292  static ssize_t prism2_aux_dump_proc_no_read(struct file *file, char __user *buf,
293  					    size_t bufsize, loff_t *_pos)
294  {
295  	return 0;
296  }
297  
298  static const struct file_operations prism2_aux_dump_proc_fops = {
299  	.read		= prism2_aux_dump_proc_no_read,
300  };
301  
302  
303  #ifdef PRISM2_IO_DEBUG
prism2_io_debug_proc_read(char * page,char ** start,off_t off,int count,int * eof,void * data)304  static int prism2_io_debug_proc_read(char *page, char **start, off_t off,
305  				     int count, int *eof, void *data)
306  {
307  	local_info_t *local = (local_info_t *) data;
308  	int head = local->io_debug_head;
309  	int start_bytes, left, copy, copied;
310  
311  	if (off + count > PRISM2_IO_DEBUG_SIZE * 4) {
312  		*eof = 1;
313  		if (off >= PRISM2_IO_DEBUG_SIZE * 4)
314  			return 0;
315  		count = PRISM2_IO_DEBUG_SIZE * 4 - off;
316  	}
317  
318  	copied = 0;
319  	start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4;
320  	left = count;
321  
322  	if (off < start_bytes) {
323  		copy = start_bytes - off;
324  		if (copy > count)
325  			copy = count;
326  		memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy);
327  		left -= copy;
328  		if (left > 0)
329  			memcpy(&page[copy], local->io_debug, left);
330  	} else {
331  		memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes),
332  		       left);
333  	}
334  
335  	*start = page;
336  
337  	return count;
338  }
339  #endif /* PRISM2_IO_DEBUG */
340  
341  
342  #ifndef PRISM2_NO_STATION_MODES
prism2_scan_results_proc_show(struct seq_file * m,void * v)343  static int prism2_scan_results_proc_show(struct seq_file *m, void *v)
344  {
345  	local_info_t *local = m->private;
346  	unsigned long entry;
347  	int i, len;
348  	struct hfa384x_hostscan_result *scanres;
349  	u8 *p;
350  
351  	if (v == SEQ_START_TOKEN) {
352  		seq_printf(m,
353  			   "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates SSID\n");
354  		return 0;
355  	}
356  
357  	entry = (unsigned long)v - 2;
358  	scanres = &local->last_scan_results[entry];
359  
360  	seq_printf(m, "%d %d %d %d 0x%02x %d %pM %d ",
361  		   le16_to_cpu(scanres->chid),
362  		   (s16) le16_to_cpu(scanres->anl),
363  		   (s16) le16_to_cpu(scanres->sl),
364  		   le16_to_cpu(scanres->beacon_interval),
365  		   le16_to_cpu(scanres->capability),
366  		   le16_to_cpu(scanres->rate),
367  		   scanres->bssid,
368  		   le16_to_cpu(scanres->atim));
369  
370  	p = scanres->sup_rates;
371  	for (i = 0; i < sizeof(scanres->sup_rates); i++) {
372  		if (p[i] == 0)
373  			break;
374  		seq_printf(m, "<%02x>", p[i]);
375  	}
376  	seq_putc(m, ' ');
377  
378  	p = scanres->ssid;
379  	len = le16_to_cpu(scanres->ssid_len);
380  	if (len > 32)
381  		len = 32;
382  	for (i = 0; i < len; i++) {
383  		unsigned char c = p[i];
384  		if (c >= 32 && c < 127)
385  			seq_putc(m, c);
386  		else
387  			seq_printf(m, "<%02x>", c);
388  	}
389  	seq_putc(m, '\n');
390  	return 0;
391  }
392  
prism2_scan_results_proc_start(struct seq_file * m,loff_t * _pos)393  static void *prism2_scan_results_proc_start(struct seq_file *m, loff_t *_pos)
394  {
395  	local_info_t *local = m->private;
396  	spin_lock_bh(&local->lock);
397  
398  	/* We have a header (pos 0) + N results to show (pos 1...N) */
399  	if (*_pos > local->last_scan_results_count)
400  		return NULL;
401  	return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */
402  }
403  
prism2_scan_results_proc_next(struct seq_file * m,void * v,loff_t * _pos)404  static void *prism2_scan_results_proc_next(struct seq_file *m, void *v, loff_t *_pos)
405  {
406  	local_info_t *local = m->private;
407  
408  	++*_pos;
409  	if (*_pos > local->last_scan_results_count)
410  		return NULL;
411  	return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */
412  }
413  
prism2_scan_results_proc_stop(struct seq_file * m,void * v)414  static void prism2_scan_results_proc_stop(struct seq_file *m, void *v)
415  {
416  	local_info_t *local = m->private;
417  	spin_unlock_bh(&local->lock);
418  }
419  
420  static const struct seq_operations prism2_scan_results_proc_seqops = {
421  	.start	= prism2_scan_results_proc_start,
422  	.next	= prism2_scan_results_proc_next,
423  	.stop	= prism2_scan_results_proc_stop,
424  	.show	= prism2_scan_results_proc_show,
425  };
426  
prism2_scan_results_proc_open(struct inode * inode,struct file * file)427  static int prism2_scan_results_proc_open(struct inode *inode, struct file *file)
428  {
429  	int ret = seq_open(file, &prism2_scan_results_proc_seqops);
430  	if (ret == 0) {
431  		struct seq_file *m = file->private_data;
432  		m->private = PDE_DATA(inode);
433  	}
434  	return ret;
435  }
436  
437  static const struct file_operations prism2_scan_results_proc_fops = {
438  	.open		= prism2_scan_results_proc_open,
439  	.read		= seq_read,
440  	.llseek		= seq_lseek,
441  	.release	= seq_release,
442  };
443  
444  
445  #endif /* PRISM2_NO_STATION_MODES */
446  
447  
hostap_init_proc(local_info_t * local)448  void hostap_init_proc(local_info_t *local)
449  {
450  	local->proc = NULL;
451  
452  	if (hostap_proc == NULL) {
453  		printk(KERN_WARNING "%s: hostap proc directory not created\n",
454  		       local->dev->name);
455  		return;
456  	}
457  
458  	local->proc = proc_mkdir(local->ddev->name, hostap_proc);
459  	if (local->proc == NULL) {
460  		printk(KERN_INFO "/proc/net/hostap/%s creation failed\n",
461  		       local->ddev->name);
462  		return;
463  	}
464  
465  #ifndef PRISM2_NO_PROCFS_DEBUG
466  	proc_create_data("debug", 0, local->proc,
467  			 &prism2_debug_proc_fops, local);
468  #endif /* PRISM2_NO_PROCFS_DEBUG */
469  	proc_create_data("stats", 0, local->proc,
470  			 &prism2_stats_proc_fops, local);
471  	proc_create_data("wds", 0, local->proc,
472  			 &prism2_wds_proc_fops, local);
473  	proc_create_data("pda", 0, local->proc,
474  			 &prism2_pda_proc_fops, local);
475  	proc_create_data("aux_dump", 0, local->proc,
476  			 local->func->read_aux_fops ?: &prism2_aux_dump_proc_fops,
477  			 local);
478  	proc_create_data("bss_list", 0, local->proc,
479  			 &prism2_bss_list_proc_fops, local);
480  	proc_create_data("crypt", 0, local->proc,
481  			 &prism2_crypt_proc_fops, local);
482  #ifdef PRISM2_IO_DEBUG
483  	proc_create_data("io_debug", 0, local->proc,
484  			 &prism2_io_debug_proc_fops, local);
485  #endif /* PRISM2_IO_DEBUG */
486  #ifndef PRISM2_NO_STATION_MODES
487  	proc_create_data("scan_results", 0, local->proc,
488  			 &prism2_scan_results_proc_fops, local);
489  #endif /* PRISM2_NO_STATION_MODES */
490  }
491  
492  
hostap_remove_proc(local_info_t * local)493  void hostap_remove_proc(local_info_t *local)
494  {
495  	proc_remove(local->proc);
496  }
497  
498  
499  EXPORT_SYMBOL(hostap_init_proc);
500  EXPORT_SYMBOL(hostap_remove_proc);
501