xref: /linux/net/wireless/wext-proc.c (revision 35de87bf598ca48d5cd5cc7f328ce00df2b5fb59)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * This file implement the Wireless Extensions proc API.
4  *
5  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
6  * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
7  */
8 
9 /*
10  * The /proc/net/wireless file is a human readable user-space interface
11  * exporting various wireless specific statistics from the wireless devices.
12  * This is the most popular part of the Wireless Extensions ;-)
13  *
14  * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
15  * The content of the file is basically the content of "struct iw_statistics".
16  */
17 
18 #include <linux/module.h>
19 #include <linux/proc_fs.h>
20 #include <linux/seq_file.h>
21 #include <linux/wireless.h>
22 #include <linux/netdevice.h>
23 #include <linux/rtnetlink.h>
24 #include <net/iw_handler.h>
25 #include <net/wext.h>
26 
27 
28 static void wireless_seq_printf_stats(struct seq_file *seq,
29 				      struct net_device *dev)
30 {
31 	/* Get stats from the driver */
32 	struct iw_statistics *stats = get_wireless_stats(dev);
33 	static struct iw_statistics nullstats = {};
34 
35 	/* show device if it's wireless regardless of current stats */
36 	if (!stats) {
37 #ifdef CONFIG_WIRELESS_EXT
38 		if (dev->wireless_handlers)
39 			stats = &nullstats;
40 #endif
41 #ifdef CONFIG_CFG80211
42 		if (dev->ieee80211_ptr)
43 			stats = &nullstats;
44 #endif
45 	}
46 
47 	if (stats) {
48 		seq_printf(seq, "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d "
49 				"%6d %6d   %6d\n",
50 			   dev->name, stats->status, stats->qual.qual,
51 			   stats->qual.updated & IW_QUAL_QUAL_UPDATED
52 			   ? '.' : ' ',
53 			   ((__s32) stats->qual.level) -
54 			   ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
55 			   stats->qual.updated & IW_QUAL_LEVEL_UPDATED
56 			   ? '.' : ' ',
57 			   ((__s32) stats->qual.noise) -
58 			   ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
59 			   stats->qual.updated & IW_QUAL_NOISE_UPDATED
60 			   ? '.' : ' ',
61 			   stats->discard.nwid, stats->discard.code,
62 			   stats->discard.fragment, stats->discard.retries,
63 			   stats->discard.misc, stats->miss.beacon);
64 
65 		if (stats != &nullstats)
66 			stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
67 	}
68 }
69 
70 /* ---------------------------------------------------------------- */
71 /*
72  * Print info for /proc/net/wireless (print all entries)
73  */
74 static int wireless_dev_seq_show(struct seq_file *seq, void *v)
75 {
76 	might_sleep();
77 
78 	if (v == SEQ_START_TOKEN)
79 		seq_printf(seq, "Inter-| sta-|   Quality        |   Discarded "
80 				"packets               | Missed | WE\n"
81 				" face | tus | link level noise |  nwid  "
82 				"crypt   frag  retry   misc | beacon | %d\n",
83 			   WIRELESS_EXT);
84 	else
85 		wireless_seq_printf_stats(seq, v);
86 	return 0;
87 }
88 
89 static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos)
90 {
91 	struct net *net = seq_file_net(seq);
92 	loff_t off;
93 	struct net_device *dev;
94 
95 	rtnl_lock();
96 	if (!*pos)
97 		return SEQ_START_TOKEN;
98 
99 	off = 1;
100 	for_each_netdev(net, dev)
101 		if (off++ == *pos)
102 			return dev;
103 	return NULL;
104 }
105 
106 static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
107 {
108 	struct net *net = seq_file_net(seq);
109 
110 	++*pos;
111 
112 	return v == SEQ_START_TOKEN ?
113 		first_net_device(net) : next_net_device(v);
114 }
115 
116 static void wireless_dev_seq_stop(struct seq_file *seq, void *v)
117 {
118 	rtnl_unlock();
119 }
120 
121 static const struct seq_operations wireless_seq_ops = {
122 	.start = wireless_dev_seq_start,
123 	.next  = wireless_dev_seq_next,
124 	.stop  = wireless_dev_seq_stop,
125 	.show  = wireless_dev_seq_show,
126 };
127 
128 int __net_init wext_proc_init(struct net *net)
129 {
130 	/* Create /proc/net/wireless entry */
131 	if (!proc_create_net("wireless", 0444, net->proc_net,
132 			&wireless_seq_ops, sizeof(struct seq_net_private)))
133 		return -ENOMEM;
134 
135 	return 0;
136 }
137 
138 void __net_exit wext_proc_exit(struct net *net)
139 {
140 	remove_proc_entry("wireless", net->proc_net);
141 }
142