diff options
author | Jiri Benc <jbenc@suse.cz> | 2007-05-05 14:46:38 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-05-05 14:46:38 -0400 |
commit | e9f207f0ff90bf60b825800d7450e6f2ff2eab88 (patch) | |
tree | 22bd39116f2cae8d4ce6169eb91e4b9a7204770f /net/mac80211 | |
parent | f0706e828e96d0fa4e80c0d25aa98523f6d589a0 (diff) |
[MAC80211]: Add debugfs attributes.
Export various mac80211 internal variables through debugfs.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/Kconfig | 9 | ||||
-rw-r--r-- | net/mac80211/Makefile | 1 | ||||
-rw-r--r-- | net/mac80211/debugfs.c | 433 | ||||
-rw-r--r-- | net/mac80211/debugfs.h | 16 | ||||
-rw-r--r-- | net/mac80211/debugfs_key.c | 252 | ||||
-rw-r--r-- | net/mac80211/debugfs_key.h | 34 | ||||
-rw-r--r-- | net/mac80211/debugfs_netdev.c | 440 | ||||
-rw-r--r-- | net/mac80211/debugfs_netdev.h | 30 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 246 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.h | 12 | ||||
-rw-r--r-- | net/mac80211/ieee80211.c | 14 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 127 | ||||
-rw-r--r-- | net/mac80211/ieee80211_iface.c | 8 | ||||
-rw-r--r-- | net/mac80211/ieee80211_ioctl.c | 22 | ||||
-rw-r--r-- | net/mac80211/ieee80211_key.h | 17 | ||||
-rw-r--r-- | net/mac80211/ieee80211_rate.h | 22 | ||||
-rw-r--r-- | net/mac80211/rc80211_simple.c | 71 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 108 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 19 |
19 files changed, 1866 insertions, 15 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index d761b53fb84c..6fffb3845ab6 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -20,6 +20,15 @@ config MAC80211_LEDS | |||
20 | This option enables a few LED triggers for different | 20 | This option enables a few LED triggers for different |
21 | packet receive/transmit events. | 21 | packet receive/transmit events. |
22 | 22 | ||
23 | config MAC80211_DEBUGFS | ||
24 | bool "Export mac80211 internals in DebugFS" | ||
25 | depends on MAC80211 && DEBUG_FS | ||
26 | ---help--- | ||
27 | Select this to see extensive information about | ||
28 | the internal state of mac80211 in debugfs. | ||
29 | |||
30 | Say N unless you know you need this. | ||
31 | |||
23 | config MAC80211_DEBUG | 32 | config MAC80211_DEBUG |
24 | bool "Enable debugging output" | 33 | bool "Enable debugging output" |
25 | depends on MAC80211 | 34 | depends on MAC80211 |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 79dea99bb482..e9738dad2d7c 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -1,6 +1,7 @@ | |||
1 | obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o | 1 | obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o |
2 | 2 | ||
3 | mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o | 3 | mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o |
4 | mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o | ||
4 | 5 | ||
5 | mac80211-objs := \ | 6 | mac80211-objs := \ |
6 | ieee80211.o \ | 7 | ieee80211.o \ |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c new file mode 100644 index 000000000000..bb6c0feb2d48 --- /dev/null +++ b/net/mac80211/debugfs.c | |||
@@ -0,0 +1,433 @@ | |||
1 | /* | ||
2 | * mac80211 debugfs for wireless PHYs | ||
3 | * | ||
4 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * GPLv2 | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/debugfs.h> | ||
11 | #include <linux/rtnetlink.h> | ||
12 | #include "ieee80211_i.h" | ||
13 | #include "ieee80211_rate.h" | ||
14 | #include "debugfs.h" | ||
15 | |||
16 | int mac80211_open_file_generic(struct inode *inode, struct file *file) | ||
17 | { | ||
18 | file->private_data = inode->i_private; | ||
19 | return 0; | ||
20 | } | ||
21 | |||
22 | static const char *ieee80211_mode_str(int mode) | ||
23 | { | ||
24 | switch (mode) { | ||
25 | case MODE_IEEE80211A: | ||
26 | return "IEEE 802.11a"; | ||
27 | case MODE_IEEE80211B: | ||
28 | return "IEEE 802.11b"; | ||
29 | case MODE_IEEE80211G: | ||
30 | return "IEEE 802.11g"; | ||
31 | case MODE_ATHEROS_TURBO: | ||
32 | return "Atheros Turbo (5 GHz)"; | ||
33 | default: | ||
34 | return "UNKNOWN"; | ||
35 | } | ||
36 | } | ||
37 | |||
38 | static ssize_t modes_read(struct file *file, char __user *userbuf, | ||
39 | size_t count, loff_t *ppos) | ||
40 | { | ||
41 | struct ieee80211_local *local = file->private_data; | ||
42 | struct ieee80211_hw_mode *mode; | ||
43 | char buf[150], *p = buf; | ||
44 | |||
45 | /* FIXME: locking! */ | ||
46 | list_for_each_entry(mode, &local->modes_list, list) { | ||
47 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
48 | "%s\n", ieee80211_mode_str(mode->mode)); | ||
49 | } | ||
50 | |||
51 | return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); | ||
52 | } | ||
53 | |||
54 | static const struct file_operations modes_ops = { | ||
55 | .read = modes_read, | ||
56 | .open = mac80211_open_file_generic, | ||
57 | }; | ||
58 | |||
59 | #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ | ||
60 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ | ||
61 | size_t count, loff_t *ppos) \ | ||
62 | { \ | ||
63 | struct ieee80211_local *local = file->private_data; \ | ||
64 | char buf[buflen]; \ | ||
65 | int res; \ | ||
66 | \ | ||
67 | res = scnprintf(buf, buflen, fmt "\n", ##value); \ | ||
68 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
69 | } \ | ||
70 | \ | ||
71 | static const struct file_operations name## _ops = { \ | ||
72 | .read = name## _read, \ | ||
73 | .open = mac80211_open_file_generic, \ | ||
74 | }; | ||
75 | |||
76 | #define DEBUGFS_ADD(name) \ | ||
77 | local->debugfs.name = debugfs_create_file(#name, 0444, phyd, \ | ||
78 | local, &name## _ops); | ||
79 | |||
80 | #define DEBUGFS_DEL(name) \ | ||
81 | debugfs_remove(local->debugfs.name); \ | ||
82 | local->debugfs.name = NULL; | ||
83 | |||
84 | |||
85 | DEBUGFS_READONLY_FILE(channel, 20, "%d", | ||
86 | local->hw.conf.channel); | ||
87 | DEBUGFS_READONLY_FILE(frequency, 20, "%d", | ||
88 | local->hw.conf.freq); | ||
89 | DEBUGFS_READONLY_FILE(radar_detect, 20, "%d", | ||
90 | local->hw.conf.radar_detect); | ||
91 | DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d", | ||
92 | local->hw.conf.antenna_sel_tx); | ||
93 | DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d", | ||
94 | local->hw.conf.antenna_sel_rx); | ||
95 | DEBUGFS_READONLY_FILE(bridge_packets, 20, "%d", | ||
96 | local->bridge_packets); | ||
97 | DEBUGFS_READONLY_FILE(key_tx_rx_threshold, 20, "%d", | ||
98 | local->key_tx_rx_threshold); | ||
99 | DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", | ||
100 | local->rts_threshold); | ||
101 | DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", | ||
102 | local->fragmentation_threshold); | ||
103 | DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d", | ||
104 | local->short_retry_limit); | ||
105 | DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", | ||
106 | local->long_retry_limit); | ||
107 | DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", | ||
108 | local->total_ps_buffered); | ||
109 | DEBUGFS_READONLY_FILE(mode, 20, "%s", | ||
110 | ieee80211_mode_str(local->hw.conf.phymode)); | ||
111 | DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x", | ||
112 | local->wep_iv & 0xffffff); | ||
113 | DEBUGFS_READONLY_FILE(tx_power_reduction, 20, "%d.%d dBm", | ||
114 | local->hw.conf.tx_power_reduction / 10, | ||
115 | local->hw.conf.tx_power_reduction & 10); | ||
116 | DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s", | ||
117 | local->rate_ctrl ? local->rate_ctrl->ops->name : "<unset>"); | ||
118 | |||
119 | /* statistics stuff */ | ||
120 | |||
121 | static inline int rtnl_lock_local(struct ieee80211_local *local) | ||
122 | { | ||
123 | rtnl_lock(); | ||
124 | if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) { | ||
125 | rtnl_unlock(); | ||
126 | return -ENODEV; | ||
127 | } | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | #define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \ | ||
132 | DEBUGFS_READONLY_FILE(stats_ ##name, buflen, fmt, ##value) | ||
133 | |||
134 | static ssize_t format_devstat_counter(struct ieee80211_local *local, | ||
135 | char __user *userbuf, | ||
136 | size_t count, loff_t *ppos, | ||
137 | int (*printvalue)(struct ieee80211_low_level_stats *stats, char *buf, | ||
138 | int buflen)) | ||
139 | { | ||
140 | struct ieee80211_low_level_stats stats; | ||
141 | char buf[20]; | ||
142 | int res; | ||
143 | |||
144 | if (!local->ops->get_stats) | ||
145 | return -EOPNOTSUPP; | ||
146 | |||
147 | res = rtnl_lock_local(local); | ||
148 | if (res) | ||
149 | return res; | ||
150 | |||
151 | res = local->ops->get_stats(local_to_hw(local), &stats); | ||
152 | rtnl_unlock(); | ||
153 | if (!res) | ||
154 | res = printvalue(&stats, buf, sizeof(buf)); | ||
155 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
156 | } | ||
157 | |||
158 | #define DEBUGFS_DEVSTATS_FILE(name) \ | ||
159 | static int print_devstats_##name(struct ieee80211_low_level_stats *stats,\ | ||
160 | char *buf, int buflen) \ | ||
161 | { \ | ||
162 | return scnprintf(buf, buflen, "%u\n", stats->name); \ | ||
163 | } \ | ||
164 | static ssize_t stats_ ##name## _read(struct file *file, \ | ||
165 | char __user *userbuf, \ | ||
166 | size_t count, loff_t *ppos) \ | ||
167 | { \ | ||
168 | return format_devstat_counter(file->private_data, \ | ||
169 | userbuf, \ | ||
170 | count, \ | ||
171 | ppos, \ | ||
172 | print_devstats_##name); \ | ||
173 | } \ | ||
174 | \ | ||
175 | static const struct file_operations stats_ ##name## _ops = { \ | ||
176 | .read = stats_ ##name## _read, \ | ||
177 | .open = mac80211_open_file_generic, \ | ||
178 | }; | ||
179 | |||
180 | #define DEBUGFS_STATS_ADD(name) \ | ||
181 | local->debugfs.stats.name = debugfs_create_file(#name, 0444, statsd,\ | ||
182 | local, &stats_ ##name## _ops); | ||
183 | |||
184 | #define DEBUGFS_STATS_DEL(name) \ | ||
185 | debugfs_remove(local->debugfs.stats.name); \ | ||
186 | local->debugfs.stats.name = NULL; | ||
187 | |||
188 | DEBUGFS_STATS_FILE(transmitted_fragment_count, 20, "%u", | ||
189 | local->dot11TransmittedFragmentCount); | ||
190 | DEBUGFS_STATS_FILE(multicast_transmitted_frame_count, 20, "%u", | ||
191 | local->dot11MulticastTransmittedFrameCount); | ||
192 | DEBUGFS_STATS_FILE(failed_count, 20, "%u", | ||
193 | local->dot11FailedCount); | ||
194 | DEBUGFS_STATS_FILE(retry_count, 20, "%u", | ||
195 | local->dot11RetryCount); | ||
196 | DEBUGFS_STATS_FILE(multiple_retry_count, 20, "%u", | ||
197 | local->dot11MultipleRetryCount); | ||
198 | DEBUGFS_STATS_FILE(frame_duplicate_count, 20, "%u", | ||
199 | local->dot11FrameDuplicateCount); | ||
200 | DEBUGFS_STATS_FILE(received_fragment_count, 20, "%u", | ||
201 | local->dot11ReceivedFragmentCount); | ||
202 | DEBUGFS_STATS_FILE(multicast_received_frame_count, 20, "%u", | ||
203 | local->dot11MulticastReceivedFrameCount); | ||
204 | DEBUGFS_STATS_FILE(transmitted_frame_count, 20, "%u", | ||
205 | local->dot11TransmittedFrameCount); | ||
206 | DEBUGFS_STATS_FILE(wep_undecryptable_count, 20, "%u", | ||
207 | local->dot11WEPUndecryptableCount); | ||
208 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
209 | DEBUGFS_STATS_FILE(tx_handlers_drop, 20, "%u", | ||
210 | local->tx_handlers_drop); | ||
211 | DEBUGFS_STATS_FILE(tx_handlers_queued, 20, "%u", | ||
212 | local->tx_handlers_queued); | ||
213 | DEBUGFS_STATS_FILE(tx_handlers_drop_unencrypted, 20, "%u", | ||
214 | local->tx_handlers_drop_unencrypted); | ||
215 | DEBUGFS_STATS_FILE(tx_handlers_drop_fragment, 20, "%u", | ||
216 | local->tx_handlers_drop_fragment); | ||
217 | DEBUGFS_STATS_FILE(tx_handlers_drop_wep, 20, "%u", | ||
218 | local->tx_handlers_drop_wep); | ||
219 | DEBUGFS_STATS_FILE(tx_handlers_drop_not_assoc, 20, "%u", | ||
220 | local->tx_handlers_drop_not_assoc); | ||
221 | DEBUGFS_STATS_FILE(tx_handlers_drop_unauth_port, 20, "%u", | ||
222 | local->tx_handlers_drop_unauth_port); | ||
223 | DEBUGFS_STATS_FILE(rx_handlers_drop, 20, "%u", | ||
224 | local->rx_handlers_drop); | ||
225 | DEBUGFS_STATS_FILE(rx_handlers_queued, 20, "%u", | ||
226 | local->rx_handlers_queued); | ||
227 | DEBUGFS_STATS_FILE(rx_handlers_drop_nullfunc, 20, "%u", | ||
228 | local->rx_handlers_drop_nullfunc); | ||
229 | DEBUGFS_STATS_FILE(rx_handlers_drop_defrag, 20, "%u", | ||
230 | local->rx_handlers_drop_defrag); | ||
231 | DEBUGFS_STATS_FILE(rx_handlers_drop_short, 20, "%u", | ||
232 | local->rx_handlers_drop_short); | ||
233 | DEBUGFS_STATS_FILE(rx_handlers_drop_passive_scan, 20, "%u", | ||
234 | local->rx_handlers_drop_passive_scan); | ||
235 | DEBUGFS_STATS_FILE(tx_expand_skb_head, 20, "%u", | ||
236 | local->tx_expand_skb_head); | ||
237 | DEBUGFS_STATS_FILE(tx_expand_skb_head_cloned, 20, "%u", | ||
238 | local->tx_expand_skb_head_cloned); | ||
239 | DEBUGFS_STATS_FILE(rx_expand_skb_head, 20, "%u", | ||
240 | local->rx_expand_skb_head); | ||
241 | DEBUGFS_STATS_FILE(rx_expand_skb_head2, 20, "%u", | ||
242 | local->rx_expand_skb_head2); | ||
243 | DEBUGFS_STATS_FILE(rx_handlers_fragments, 20, "%u", | ||
244 | local->rx_handlers_fragments); | ||
245 | DEBUGFS_STATS_FILE(tx_status_drop, 20, "%u", | ||
246 | local->tx_status_drop); | ||
247 | |||
248 | static ssize_t stats_wme_rx_queue_read(struct file *file, | ||
249 | char __user *userbuf, | ||
250 | size_t count, loff_t *ppos) | ||
251 | { | ||
252 | struct ieee80211_local *local = file->private_data; | ||
253 | char buf[NUM_RX_DATA_QUEUES*15], *p = buf; | ||
254 | int i; | ||
255 | |||
256 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | ||
257 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
258 | "%u\n", local->wme_rx_queue[i]); | ||
259 | |||
260 | return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); | ||
261 | } | ||
262 | |||
263 | static const struct file_operations stats_wme_rx_queue_ops = { | ||
264 | .read = stats_wme_rx_queue_read, | ||
265 | .open = mac80211_open_file_generic, | ||
266 | }; | ||
267 | |||
268 | static ssize_t stats_wme_tx_queue_read(struct file *file, | ||
269 | char __user *userbuf, | ||
270 | size_t count, loff_t *ppos) | ||
271 | { | ||
272 | struct ieee80211_local *local = file->private_data; | ||
273 | char buf[NUM_TX_DATA_QUEUES*15], *p = buf; | ||
274 | int i; | ||
275 | |||
276 | for (i = 0; i < NUM_TX_DATA_QUEUES; i++) | ||
277 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
278 | "%u\n", local->wme_tx_queue[i]); | ||
279 | |||
280 | return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); | ||
281 | } | ||
282 | |||
283 | static const struct file_operations stats_wme_tx_queue_ops = { | ||
284 | .read = stats_wme_tx_queue_read, | ||
285 | .open = mac80211_open_file_generic, | ||
286 | }; | ||
287 | #endif | ||
288 | |||
289 | DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount); | ||
290 | DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount); | ||
291 | DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount); | ||
292 | DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount); | ||
293 | |||
294 | |||
295 | void debugfs_hw_add(struct ieee80211_local *local) | ||
296 | { | ||
297 | struct dentry *phyd = local->hw.wiphy->debugfsdir; | ||
298 | struct dentry *statsd; | ||
299 | |||
300 | if (!phyd) | ||
301 | return; | ||
302 | |||
303 | local->debugfs.stations = debugfs_create_dir("stations", phyd); | ||
304 | local->debugfs.keys = debugfs_create_dir("keys", phyd); | ||
305 | |||
306 | DEBUGFS_ADD(channel); | ||
307 | DEBUGFS_ADD(frequency); | ||
308 | DEBUGFS_ADD(radar_detect); | ||
309 | DEBUGFS_ADD(antenna_sel_tx); | ||
310 | DEBUGFS_ADD(antenna_sel_rx); | ||
311 | DEBUGFS_ADD(bridge_packets); | ||
312 | DEBUGFS_ADD(key_tx_rx_threshold); | ||
313 | DEBUGFS_ADD(rts_threshold); | ||
314 | DEBUGFS_ADD(fragmentation_threshold); | ||
315 | DEBUGFS_ADD(short_retry_limit); | ||
316 | DEBUGFS_ADD(long_retry_limit); | ||
317 | DEBUGFS_ADD(total_ps_buffered); | ||
318 | DEBUGFS_ADD(mode); | ||
319 | DEBUGFS_ADD(wep_iv); | ||
320 | DEBUGFS_ADD(tx_power_reduction); | ||
321 | DEBUGFS_ADD(modes); | ||
322 | |||
323 | statsd = debugfs_create_dir("statistics", phyd); | ||
324 | local->debugfs.statistics = statsd; | ||
325 | |||
326 | /* if the dir failed, don't put all the other things into the root! */ | ||
327 | if (!statsd) | ||
328 | return; | ||
329 | |||
330 | DEBUGFS_STATS_ADD(transmitted_fragment_count); | ||
331 | DEBUGFS_STATS_ADD(multicast_transmitted_frame_count); | ||
332 | DEBUGFS_STATS_ADD(failed_count); | ||
333 | DEBUGFS_STATS_ADD(retry_count); | ||
334 | DEBUGFS_STATS_ADD(multiple_retry_count); | ||
335 | DEBUGFS_STATS_ADD(frame_duplicate_count); | ||
336 | DEBUGFS_STATS_ADD(received_fragment_count); | ||
337 | DEBUGFS_STATS_ADD(multicast_received_frame_count); | ||
338 | DEBUGFS_STATS_ADD(transmitted_frame_count); | ||
339 | DEBUGFS_STATS_ADD(wep_undecryptable_count); | ||
340 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
341 | DEBUGFS_STATS_ADD(tx_handlers_drop); | ||
342 | DEBUGFS_STATS_ADD(tx_handlers_queued); | ||
343 | DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted); | ||
344 | DEBUGFS_STATS_ADD(tx_handlers_drop_fragment); | ||
345 | DEBUGFS_STATS_ADD(tx_handlers_drop_wep); | ||
346 | DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc); | ||
347 | DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port); | ||
348 | DEBUGFS_STATS_ADD(rx_handlers_drop); | ||
349 | DEBUGFS_STATS_ADD(rx_handlers_queued); | ||
350 | DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc); | ||
351 | DEBUGFS_STATS_ADD(rx_handlers_drop_defrag); | ||
352 | DEBUGFS_STATS_ADD(rx_handlers_drop_short); | ||
353 | DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan); | ||
354 | DEBUGFS_STATS_ADD(tx_expand_skb_head); | ||
355 | DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned); | ||
356 | DEBUGFS_STATS_ADD(rx_expand_skb_head); | ||
357 | DEBUGFS_STATS_ADD(rx_expand_skb_head2); | ||
358 | DEBUGFS_STATS_ADD(rx_handlers_fragments); | ||
359 | DEBUGFS_STATS_ADD(tx_status_drop); | ||
360 | DEBUGFS_STATS_ADD(wme_tx_queue); | ||
361 | DEBUGFS_STATS_ADD(wme_rx_queue); | ||
362 | #endif | ||
363 | DEBUGFS_STATS_ADD(dot11ACKFailureCount); | ||
364 | DEBUGFS_STATS_ADD(dot11RTSFailureCount); | ||
365 | DEBUGFS_STATS_ADD(dot11FCSErrorCount); | ||
366 | DEBUGFS_STATS_ADD(dot11RTSSuccessCount); | ||
367 | } | ||
368 | |||
369 | void debugfs_hw_del(struct ieee80211_local *local) | ||
370 | { | ||
371 | DEBUGFS_DEL(channel); | ||
372 | DEBUGFS_DEL(frequency); | ||
373 | DEBUGFS_DEL(radar_detect); | ||
374 | DEBUGFS_DEL(antenna_sel_tx); | ||
375 | DEBUGFS_DEL(antenna_sel_rx); | ||
376 | DEBUGFS_DEL(bridge_packets); | ||
377 | DEBUGFS_DEL(key_tx_rx_threshold); | ||
378 | DEBUGFS_DEL(rts_threshold); | ||
379 | DEBUGFS_DEL(fragmentation_threshold); | ||
380 | DEBUGFS_DEL(short_retry_limit); | ||
381 | DEBUGFS_DEL(long_retry_limit); | ||
382 | DEBUGFS_DEL(total_ps_buffered); | ||
383 | DEBUGFS_DEL(mode); | ||
384 | DEBUGFS_DEL(wep_iv); | ||
385 | DEBUGFS_DEL(tx_power_reduction); | ||
386 | DEBUGFS_DEL(modes); | ||
387 | |||
388 | DEBUGFS_STATS_DEL(transmitted_fragment_count); | ||
389 | DEBUGFS_STATS_DEL(multicast_transmitted_frame_count); | ||
390 | DEBUGFS_STATS_DEL(failed_count); | ||
391 | DEBUGFS_STATS_DEL(retry_count); | ||
392 | DEBUGFS_STATS_DEL(multiple_retry_count); | ||
393 | DEBUGFS_STATS_DEL(frame_duplicate_count); | ||
394 | DEBUGFS_STATS_DEL(received_fragment_count); | ||
395 | DEBUGFS_STATS_DEL(multicast_received_frame_count); | ||
396 | DEBUGFS_STATS_DEL(transmitted_frame_count); | ||
397 | DEBUGFS_STATS_DEL(wep_undecryptable_count); | ||
398 | DEBUGFS_STATS_DEL(num_scans); | ||
399 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
400 | DEBUGFS_STATS_DEL(tx_handlers_drop); | ||
401 | DEBUGFS_STATS_DEL(tx_handlers_queued); | ||
402 | DEBUGFS_STATS_DEL(tx_handlers_drop_unencrypted); | ||
403 | DEBUGFS_STATS_DEL(tx_handlers_drop_fragment); | ||
404 | DEBUGFS_STATS_DEL(tx_handlers_drop_wep); | ||
405 | DEBUGFS_STATS_DEL(tx_handlers_drop_not_assoc); | ||
406 | DEBUGFS_STATS_DEL(tx_handlers_drop_unauth_port); | ||
407 | DEBUGFS_STATS_DEL(rx_handlers_drop); | ||
408 | DEBUGFS_STATS_DEL(rx_handlers_queued); | ||
409 | DEBUGFS_STATS_DEL(rx_handlers_drop_nullfunc); | ||
410 | DEBUGFS_STATS_DEL(rx_handlers_drop_defrag); | ||
411 | DEBUGFS_STATS_DEL(rx_handlers_drop_short); | ||
412 | DEBUGFS_STATS_DEL(rx_handlers_drop_passive_scan); | ||
413 | DEBUGFS_STATS_DEL(tx_expand_skb_head); | ||
414 | DEBUGFS_STATS_DEL(tx_expand_skb_head_cloned); | ||
415 | DEBUGFS_STATS_DEL(rx_expand_skb_head); | ||
416 | DEBUGFS_STATS_DEL(rx_expand_skb_head2); | ||
417 | DEBUGFS_STATS_DEL(rx_handlers_fragments); | ||
418 | DEBUGFS_STATS_DEL(tx_status_drop); | ||
419 | DEBUGFS_STATS_DEL(wme_tx_queue); | ||
420 | DEBUGFS_STATS_DEL(wme_rx_queue); | ||
421 | #endif | ||
422 | DEBUGFS_STATS_DEL(dot11ACKFailureCount); | ||
423 | DEBUGFS_STATS_DEL(dot11RTSFailureCount); | ||
424 | DEBUGFS_STATS_DEL(dot11FCSErrorCount); | ||
425 | DEBUGFS_STATS_DEL(dot11RTSSuccessCount); | ||
426 | |||
427 | debugfs_remove(local->debugfs.statistics); | ||
428 | local->debugfs.statistics = NULL; | ||
429 | debugfs_remove(local->debugfs.stations); | ||
430 | local->debugfs.stations = NULL; | ||
431 | debugfs_remove(local->debugfs.keys); | ||
432 | local->debugfs.keys = NULL; | ||
433 | } | ||
diff --git a/net/mac80211/debugfs.h b/net/mac80211/debugfs.h new file mode 100644 index 000000000000..dd2541935c27 --- /dev/null +++ b/net/mac80211/debugfs.h | |||
@@ -0,0 +1,16 @@ | |||
1 | #ifndef __MAC80211_DEBUGFS_H | ||
2 | #define __MAC80211_DEBUGFS_H | ||
3 | |||
4 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
5 | extern void debugfs_hw_add(struct ieee80211_local *local); | ||
6 | extern void debugfs_hw_del(struct ieee80211_local *local); | ||
7 | extern int mac80211_open_file_generic(struct inode *inode, struct file *file); | ||
8 | #else | ||
9 | static inline void debugfs_hw_add(struct ieee80211_local *local) | ||
10 | { | ||
11 | return; | ||
12 | } | ||
13 | static inline void debugfs_hw_del(struct ieee80211_local *local) {} | ||
14 | #endif | ||
15 | |||
16 | #endif /* __MAC80211_DEBUGFS_H */ | ||
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c new file mode 100644 index 000000000000..7d56dc9e7326 --- /dev/null +++ b/net/mac80211/debugfs_key.c | |||
@@ -0,0 +1,252 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2005 Devicescape Software, Inc. | ||
3 | * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> | ||
4 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kobject.h> | ||
12 | #include "ieee80211_i.h" | ||
13 | #include "ieee80211_key.h" | ||
14 | #include "debugfs.h" | ||
15 | #include "debugfs_key.h" | ||
16 | |||
17 | #define KEY_READ(name, buflen, format_string) \ | ||
18 | static ssize_t key_##name##_read(struct file *file, \ | ||
19 | char __user *userbuf, \ | ||
20 | size_t count, loff_t *ppos) \ | ||
21 | { \ | ||
22 | char buf[buflen]; \ | ||
23 | struct ieee80211_key *key = file->private_data; \ | ||
24 | int res = scnprintf(buf, buflen, format_string, key->name); \ | ||
25 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
26 | } | ||
27 | #define KEY_READ_D(name) KEY_READ(name, 20, "%d\n") | ||
28 | |||
29 | #define KEY_OPS(name) \ | ||
30 | static const struct file_operations key_ ##name## _ops = { \ | ||
31 | .read = key_##name##_read, \ | ||
32 | .open = mac80211_open_file_generic, \ | ||
33 | } | ||
34 | |||
35 | #define KEY_FILE(name, format) \ | ||
36 | KEY_READ_##format(name) \ | ||
37 | KEY_OPS(name) | ||
38 | |||
39 | KEY_FILE(keylen, D); | ||
40 | KEY_FILE(force_sw_encrypt, D); | ||
41 | KEY_FILE(keyidx, D); | ||
42 | KEY_FILE(hw_key_idx, D); | ||
43 | KEY_FILE(tx_rx_count, D); | ||
44 | |||
45 | static ssize_t key_algorithm_read(struct file *file, | ||
46 | char __user *userbuf, | ||
47 | size_t count, loff_t *ppos) | ||
48 | { | ||
49 | char *alg; | ||
50 | struct ieee80211_key *key = file->private_data; | ||
51 | |||
52 | switch (key->alg) { | ||
53 | case ALG_WEP: | ||
54 | alg = "WEP\n"; | ||
55 | break; | ||
56 | case ALG_TKIP: | ||
57 | alg = "TKIP\n"; | ||
58 | break; | ||
59 | case ALG_CCMP: | ||
60 | alg = "CCMP\n"; | ||
61 | break; | ||
62 | default: | ||
63 | return 0; | ||
64 | } | ||
65 | return simple_read_from_buffer(userbuf, count, ppos, alg, strlen(alg)); | ||
66 | } | ||
67 | KEY_OPS(algorithm); | ||
68 | |||
69 | static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, | ||
70 | size_t count, loff_t *ppos) | ||
71 | { | ||
72 | const u8 *tpn; | ||
73 | char buf[20]; | ||
74 | int len; | ||
75 | struct ieee80211_key *key = file->private_data; | ||
76 | |||
77 | switch (key->alg) { | ||
78 | case ALG_WEP: | ||
79 | len = scnprintf(buf, sizeof(buf), "\n"); | ||
80 | case ALG_TKIP: | ||
81 | len = scnprintf(buf, sizeof(buf), "%08x %04x\n", | ||
82 | key->u.tkip.iv32, | ||
83 | key->u.tkip.iv16); | ||
84 | case ALG_CCMP: | ||
85 | tpn = key->u.ccmp.tx_pn; | ||
86 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", | ||
87 | tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]); | ||
88 | default: | ||
89 | return 0; | ||
90 | } | ||
91 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | ||
92 | } | ||
93 | KEY_OPS(tx_spec); | ||
94 | |||
95 | static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | ||
96 | size_t count, loff_t *ppos) | ||
97 | { | ||
98 | struct ieee80211_key *key = file->private_data; | ||
99 | char buf[14*NUM_RX_DATA_QUEUES+1], *p = buf; | ||
100 | int i, len; | ||
101 | const u8 *rpn; | ||
102 | |||
103 | switch (key->alg) { | ||
104 | case ALG_WEP: | ||
105 | len = scnprintf(buf, sizeof(buf), "\n"); | ||
106 | case ALG_TKIP: | ||
107 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | ||
108 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
109 | "%08x %04x\n", | ||
110 | key->u.tkip.iv32_rx[i], | ||
111 | key->u.tkip.iv16_rx[i]); | ||
112 | len = p - buf; | ||
113 | case ALG_CCMP: | ||
114 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) { | ||
115 | rpn = key->u.ccmp.rx_pn[i]; | ||
116 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
117 | "%02x%02x%02x%02x%02x%02x\n", | ||
118 | rpn[0], rpn[1], rpn[2], | ||
119 | rpn[3], rpn[4], rpn[5]); | ||
120 | } | ||
121 | len = p - buf; | ||
122 | default: | ||
123 | return 0; | ||
124 | } | ||
125 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | ||
126 | } | ||
127 | KEY_OPS(rx_spec); | ||
128 | |||
129 | static ssize_t key_replays_read(struct file *file, char __user *userbuf, | ||
130 | size_t count, loff_t *ppos) | ||
131 | { | ||
132 | struct ieee80211_key *key = file->private_data; | ||
133 | char buf[20]; | ||
134 | int len; | ||
135 | |||
136 | if (key->alg != ALG_CCMP) | ||
137 | return 0; | ||
138 | len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); | ||
139 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | ||
140 | } | ||
141 | KEY_OPS(replays); | ||
142 | |||
143 | static ssize_t key_key_read(struct file *file, char __user *userbuf, | ||
144 | size_t count, loff_t *ppos) | ||
145 | { | ||
146 | struct ieee80211_key *key = file->private_data; | ||
147 | int i, res, bufsize = 2*key->keylen+2; | ||
148 | char *buf = kmalloc(bufsize, GFP_KERNEL); | ||
149 | char *p = buf; | ||
150 | |||
151 | for (i = 0; i < key->keylen; i++) | ||
152 | p += scnprintf(p, bufsize+buf-p, "%02x", key->key[i]); | ||
153 | p += scnprintf(p, bufsize+buf-p, "\n"); | ||
154 | res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); | ||
155 | kfree(buf); | ||
156 | return res; | ||
157 | } | ||
158 | KEY_OPS(key); | ||
159 | |||
160 | #define DEBUGFS_ADD(name) \ | ||
161 | key->debugfs.name = debugfs_create_file(#name, 0400,\ | ||
162 | key->debugfs.dir, key, &key_##name##_ops); | ||
163 | |||
164 | void ieee80211_debugfs_key_add(struct ieee80211_local *local, | ||
165 | struct ieee80211_key *key) | ||
166 | { | ||
167 | char buf[20]; | ||
168 | |||
169 | if (!local->debugfs.keys) | ||
170 | return; | ||
171 | |||
172 | sprintf(buf, "%d", key->keyidx); | ||
173 | key->debugfs.dir = debugfs_create_dir(buf, | ||
174 | local->debugfs.keys); | ||
175 | |||
176 | if (!key->debugfs.dir) | ||
177 | return; | ||
178 | |||
179 | DEBUGFS_ADD(keylen); | ||
180 | DEBUGFS_ADD(force_sw_encrypt); | ||
181 | DEBUGFS_ADD(keyidx); | ||
182 | DEBUGFS_ADD(hw_key_idx); | ||
183 | DEBUGFS_ADD(tx_rx_count); | ||
184 | DEBUGFS_ADD(algorithm); | ||
185 | DEBUGFS_ADD(tx_spec); | ||
186 | DEBUGFS_ADD(rx_spec); | ||
187 | DEBUGFS_ADD(replays); | ||
188 | DEBUGFS_ADD(key); | ||
189 | }; | ||
190 | |||
191 | #define DEBUGFS_DEL(name) \ | ||
192 | debugfs_remove(key->debugfs.name); key->debugfs.name = NULL; | ||
193 | |||
194 | void ieee80211_debugfs_key_remove(struct ieee80211_key *key) | ||
195 | { | ||
196 | if (!key) | ||
197 | return; | ||
198 | |||
199 | DEBUGFS_DEL(keylen); | ||
200 | DEBUGFS_DEL(force_sw_encrypt); | ||
201 | DEBUGFS_DEL(keyidx); | ||
202 | DEBUGFS_DEL(hw_key_idx); | ||
203 | DEBUGFS_DEL(tx_rx_count); | ||
204 | DEBUGFS_DEL(algorithm); | ||
205 | DEBUGFS_DEL(tx_spec); | ||
206 | DEBUGFS_DEL(rx_spec); | ||
207 | DEBUGFS_DEL(replays); | ||
208 | DEBUGFS_DEL(key); | ||
209 | |||
210 | debugfs_remove(key->debugfs.stalink); | ||
211 | key->debugfs.stalink = NULL; | ||
212 | debugfs_remove(key->debugfs.dir); | ||
213 | key->debugfs.dir = NULL; | ||
214 | } | ||
215 | void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) | ||
216 | { | ||
217 | char buf[50]; | ||
218 | |||
219 | if (!sdata->debugfsdir) | ||
220 | return; | ||
221 | |||
222 | sprintf(buf, "../keys/%d", sdata->default_key->keyidx); | ||
223 | sdata->debugfs.default_key = | ||
224 | debugfs_create_symlink("default_key", sdata->debugfsdir, buf); | ||
225 | } | ||
226 | void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata) | ||
227 | { | ||
228 | if (!sdata) | ||
229 | return; | ||
230 | |||
231 | debugfs_remove(sdata->debugfs.default_key); | ||
232 | sdata->debugfs.default_key = NULL; | ||
233 | } | ||
234 | void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key, | ||
235 | struct sta_info *sta) | ||
236 | { | ||
237 | char buf[50]; | ||
238 | |||
239 | if (!key->debugfs.dir) | ||
240 | return; | ||
241 | |||
242 | sprintf(buf, "../sta/" MAC_FMT, MAC_ARG(sta->addr)); | ||
243 | key->debugfs.stalink = | ||
244 | debugfs_create_symlink("station", key->debugfs.dir, buf); | ||
245 | } | ||
246 | |||
247 | void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, | ||
248 | struct sta_info *sta) | ||
249 | { | ||
250 | debugfs_remove(key->debugfs.stalink); | ||
251 | key->debugfs.stalink = NULL; | ||
252 | } | ||
diff --git a/net/mac80211/debugfs_key.h b/net/mac80211/debugfs_key.h new file mode 100644 index 000000000000..aecfce395da6 --- /dev/null +++ b/net/mac80211/debugfs_key.h | |||
@@ -0,0 +1,34 @@ | |||
1 | #ifndef __MAC80211_DEBUGFS_KEY_H | ||
2 | #define __MAC80211_DEBUGFS_KEY_H | ||
3 | |||
4 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
5 | void ieee80211_debugfs_key_add(struct ieee80211_local *local, | ||
6 | struct ieee80211_key *key); | ||
7 | void ieee80211_debugfs_key_remove(struct ieee80211_key *key); | ||
8 | void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata); | ||
9 | void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata); | ||
10 | void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key, | ||
11 | struct sta_info *sta); | ||
12 | void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, | ||
13 | struct sta_info *sta); | ||
14 | #else | ||
15 | static inline void ieee80211_debugfs_key_add(struct ieee80211_local *local, | ||
16 | struct ieee80211_key *key) | ||
17 | {} | ||
18 | static inline void ieee80211_debugfs_key_remove(struct ieee80211_key *key) | ||
19 | {} | ||
20 | static inline void ieee80211_debugfs_key_add_default( | ||
21 | struct ieee80211_sub_if_data *sdata) | ||
22 | {} | ||
23 | static inline void ieee80211_debugfs_key_remove_default( | ||
24 | struct ieee80211_sub_if_data *sdata) | ||
25 | {} | ||
26 | static inline void ieee80211_debugfs_key_sta_link( | ||
27 | struct ieee80211_key *key, struct sta_info *sta) | ||
28 | {} | ||
29 | static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, | ||
30 | struct sta_info *sta) | ||
31 | {} | ||
32 | #endif | ||
33 | |||
34 | #endif /* __MAC80211_DEBUGFS_KEY_H */ | ||
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c new file mode 100644 index 000000000000..9e3964638bad --- /dev/null +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -0,0 +1,440 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> | ||
3 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/device.h> | ||
12 | #include <linux/if.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/netdevice.h> | ||
15 | #include <linux/rtnetlink.h> | ||
16 | #include <linux/notifier.h> | ||
17 | #include <net/mac80211.h> | ||
18 | #include <net/cfg80211.h> | ||
19 | #include "ieee80211_i.h" | ||
20 | #include "ieee80211_rate.h" | ||
21 | #include "debugfs.h" | ||
22 | #include "debugfs_netdev.h" | ||
23 | |||
24 | static ssize_t ieee80211_if_read( | ||
25 | struct ieee80211_sub_if_data *sdata, | ||
26 | char __user *userbuf, | ||
27 | size_t count, loff_t *ppos, | ||
28 | ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int)) | ||
29 | { | ||
30 | char buf[70]; | ||
31 | ssize_t ret = -EINVAL; | ||
32 | |||
33 | read_lock(&dev_base_lock); | ||
34 | if (sdata->dev->reg_state == NETREG_REGISTERED) { | ||
35 | ret = (*format)(sdata, buf, sizeof(buf)); | ||
36 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret); | ||
37 | } | ||
38 | read_unlock(&dev_base_lock); | ||
39 | return ret; | ||
40 | } | ||
41 | |||
42 | #define IEEE80211_IF_FMT(name, field, format_string) \ | ||
43 | static ssize_t ieee80211_if_fmt_##name( \ | ||
44 | const struct ieee80211_sub_if_data *sdata, char *buf, \ | ||
45 | int buflen) \ | ||
46 | { \ | ||
47 | return scnprintf(buf, buflen, format_string, sdata->field); \ | ||
48 | } | ||
49 | #define IEEE80211_IF_FMT_DEC(name, field) \ | ||
50 | IEEE80211_IF_FMT(name, field, "%d\n") | ||
51 | #define IEEE80211_IF_FMT_HEX(name, field) \ | ||
52 | IEEE80211_IF_FMT(name, field, "%#x\n") | ||
53 | #define IEEE80211_IF_FMT_SIZE(name, field) \ | ||
54 | IEEE80211_IF_FMT(name, field, "%zd\n") | ||
55 | |||
56 | #define IEEE80211_IF_FMT_ATOMIC(name, field) \ | ||
57 | static ssize_t ieee80211_if_fmt_##name( \ | ||
58 | const struct ieee80211_sub_if_data *sdata, \ | ||
59 | char *buf, int buflen) \ | ||
60 | { \ | ||
61 | return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\ | ||
62 | } | ||
63 | |||
64 | #define IEEE80211_IF_FMT_MAC(name, field) \ | ||
65 | static ssize_t ieee80211_if_fmt_##name( \ | ||
66 | const struct ieee80211_sub_if_data *sdata, char *buf, \ | ||
67 | int buflen) \ | ||
68 | { \ | ||
69 | return scnprintf(buf, buflen, MAC_FMT "\n", MAC_ARG(sdata->field));\ | ||
70 | } | ||
71 | |||
72 | #define __IEEE80211_IF_FILE(name) \ | ||
73 | static ssize_t ieee80211_if_read_##name(struct file *file, \ | ||
74 | char __user *userbuf, \ | ||
75 | size_t count, loff_t *ppos) \ | ||
76 | { \ | ||
77 | return ieee80211_if_read(file->private_data, \ | ||
78 | userbuf, count, ppos, \ | ||
79 | ieee80211_if_fmt_##name); \ | ||
80 | } \ | ||
81 | static const struct file_operations name##_ops = { \ | ||
82 | .read = ieee80211_if_read_##name, \ | ||
83 | .open = mac80211_open_file_generic, \ | ||
84 | } | ||
85 | |||
86 | #define IEEE80211_IF_FILE(name, field, format) \ | ||
87 | IEEE80211_IF_FMT_##format(name, field) \ | ||
88 | __IEEE80211_IF_FILE(name) | ||
89 | |||
90 | /* common attributes */ | ||
91 | IEEE80211_IF_FILE(channel_use, channel_use, DEC); | ||
92 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); | ||
93 | IEEE80211_IF_FILE(eapol, eapol, DEC); | ||
94 | IEEE80211_IF_FILE(ieee8021_x, ieee802_1x, DEC); | ||
95 | |||
96 | /* STA/IBSS attributes */ | ||
97 | IEEE80211_IF_FILE(state, u.sta.state, DEC); | ||
98 | IEEE80211_IF_FILE(bssid, u.sta.bssid, MAC); | ||
99 | IEEE80211_IF_FILE(prev_bssid, u.sta.prev_bssid, MAC); | ||
100 | IEEE80211_IF_FILE(ssid_len, u.sta.ssid_len, SIZE); | ||
101 | IEEE80211_IF_FILE(aid, u.sta.aid, DEC); | ||
102 | IEEE80211_IF_FILE(ap_capab, u.sta.ap_capab, HEX); | ||
103 | IEEE80211_IF_FILE(capab, u.sta.capab, HEX); | ||
104 | IEEE80211_IF_FILE(extra_ie_len, u.sta.extra_ie_len, SIZE); | ||
105 | IEEE80211_IF_FILE(auth_tries, u.sta.auth_tries, DEC); | ||
106 | IEEE80211_IF_FILE(assoc_tries, u.sta.assoc_tries, DEC); | ||
107 | IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX); | ||
108 | IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC); | ||
109 | IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC); | ||
110 | |||
111 | static ssize_t ieee80211_if_fmt_flags( | ||
112 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
113 | { | ||
114 | return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n", | ||
115 | sdata->u.sta.ssid_set ? "SSID\n" : "", | ||
116 | sdata->u.sta.bssid_set ? "BSSID\n" : "", | ||
117 | sdata->u.sta.prev_bssid_set ? "prev BSSID\n" : "", | ||
118 | sdata->u.sta.authenticated ? "AUTH\n" : "", | ||
119 | sdata->u.sta.associated ? "ASSOC\n" : "", | ||
120 | sdata->u.sta.probereq_poll ? "PROBEREQ POLL\n" : "", | ||
121 | sdata->u.sta.use_protection ? "CTS prot\n" : ""); | ||
122 | } | ||
123 | __IEEE80211_IF_FILE(flags); | ||
124 | |||
125 | /* AP attributes */ | ||
126 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); | ||
127 | IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC); | ||
128 | IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); | ||
129 | IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC); | ||
130 | IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC); | ||
131 | IEEE80211_IF_FILE(max_ratectrl_rateidx, u.ap.max_ratectrl_rateidx, DEC); | ||
132 | |||
133 | static ssize_t ieee80211_if_fmt_num_buffered_multicast( | ||
134 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
135 | { | ||
136 | return scnprintf(buf, buflen, "%u\n", | ||
137 | skb_queue_len(&sdata->u.ap.ps_bc_buf)); | ||
138 | } | ||
139 | __IEEE80211_IF_FILE(num_buffered_multicast); | ||
140 | |||
141 | static ssize_t ieee80211_if_fmt_beacon_head_len( | ||
142 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
143 | { | ||
144 | if (sdata->u.ap.beacon_head) | ||
145 | return scnprintf(buf, buflen, "%d\n", | ||
146 | sdata->u.ap.beacon_head_len); | ||
147 | return scnprintf(buf, buflen, "\n"); | ||
148 | } | ||
149 | __IEEE80211_IF_FILE(beacon_head_len); | ||
150 | |||
151 | static ssize_t ieee80211_if_fmt_beacon_tail_len( | ||
152 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
153 | { | ||
154 | if (sdata->u.ap.beacon_tail) | ||
155 | return scnprintf(buf, buflen, "%d\n", | ||
156 | sdata->u.ap.beacon_tail_len); | ||
157 | return scnprintf(buf, buflen, "\n"); | ||
158 | } | ||
159 | __IEEE80211_IF_FILE(beacon_tail_len); | ||
160 | |||
161 | /* WDS attributes */ | ||
162 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); | ||
163 | |||
164 | /* VLAN attributes */ | ||
165 | IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC); | ||
166 | |||
167 | /* MONITOR attributes */ | ||
168 | static ssize_t ieee80211_if_fmt_mode( | ||
169 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
170 | { | ||
171 | struct ieee80211_local *local = sdata->local; | ||
172 | |||
173 | return scnprintf(buf, buflen, "%s\n", | ||
174 | ((local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) || | ||
175 | local->open_count == local->monitors) ? | ||
176 | "hard" : "soft"); | ||
177 | } | ||
178 | __IEEE80211_IF_FILE(mode); | ||
179 | |||
180 | |||
181 | #define DEBUGFS_ADD(name, type)\ | ||
182 | sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\ | ||
183 | sdata->debugfsdir, sdata, &name##_ops); | ||
184 | |||
185 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) | ||
186 | { | ||
187 | DEBUGFS_ADD(channel_use, sta); | ||
188 | DEBUGFS_ADD(drop_unencrypted, sta); | ||
189 | DEBUGFS_ADD(eapol, sta); | ||
190 | DEBUGFS_ADD(ieee8021_x, sta); | ||
191 | DEBUGFS_ADD(state, sta); | ||
192 | DEBUGFS_ADD(bssid, sta); | ||
193 | DEBUGFS_ADD(prev_bssid, sta); | ||
194 | DEBUGFS_ADD(ssid_len, sta); | ||
195 | DEBUGFS_ADD(aid, sta); | ||
196 | DEBUGFS_ADD(ap_capab, sta); | ||
197 | DEBUGFS_ADD(capab, sta); | ||
198 | DEBUGFS_ADD(extra_ie_len, sta); | ||
199 | DEBUGFS_ADD(auth_tries, sta); | ||
200 | DEBUGFS_ADD(assoc_tries, sta); | ||
201 | DEBUGFS_ADD(auth_algs, sta); | ||
202 | DEBUGFS_ADD(auth_alg, sta); | ||
203 | DEBUGFS_ADD(auth_transaction, sta); | ||
204 | DEBUGFS_ADD(flags, sta); | ||
205 | } | ||
206 | |||
207 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) | ||
208 | { | ||
209 | DEBUGFS_ADD(channel_use, ap); | ||
210 | DEBUGFS_ADD(drop_unencrypted, ap); | ||
211 | DEBUGFS_ADD(eapol, ap); | ||
212 | DEBUGFS_ADD(ieee8021_x, ap); | ||
213 | DEBUGFS_ADD(num_sta_ps, ap); | ||
214 | DEBUGFS_ADD(dtim_period, ap); | ||
215 | DEBUGFS_ADD(dtim_count, ap); | ||
216 | DEBUGFS_ADD(num_beacons, ap); | ||
217 | DEBUGFS_ADD(force_unicast_rateidx, ap); | ||
218 | DEBUGFS_ADD(max_ratectrl_rateidx, ap); | ||
219 | DEBUGFS_ADD(num_buffered_multicast, ap); | ||
220 | DEBUGFS_ADD(beacon_head_len, ap); | ||
221 | DEBUGFS_ADD(beacon_tail_len, ap); | ||
222 | } | ||
223 | |||
224 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) | ||
225 | { | ||
226 | DEBUGFS_ADD(channel_use, wds); | ||
227 | DEBUGFS_ADD(drop_unencrypted, wds); | ||
228 | DEBUGFS_ADD(eapol, wds); | ||
229 | DEBUGFS_ADD(ieee8021_x, wds); | ||
230 | DEBUGFS_ADD(peer, wds); | ||
231 | } | ||
232 | |||
233 | static void add_vlan_files(struct ieee80211_sub_if_data *sdata) | ||
234 | { | ||
235 | DEBUGFS_ADD(channel_use, vlan); | ||
236 | DEBUGFS_ADD(drop_unencrypted, vlan); | ||
237 | DEBUGFS_ADD(eapol, vlan); | ||
238 | DEBUGFS_ADD(ieee8021_x, vlan); | ||
239 | DEBUGFS_ADD(vlan_id, vlan); | ||
240 | } | ||
241 | |||
242 | static void add_monitor_files(struct ieee80211_sub_if_data *sdata) | ||
243 | { | ||
244 | DEBUGFS_ADD(mode, monitor); | ||
245 | } | ||
246 | |||
247 | static void add_files(struct ieee80211_sub_if_data *sdata) | ||
248 | { | ||
249 | if (!sdata->debugfsdir) | ||
250 | return; | ||
251 | |||
252 | switch (sdata->type) { | ||
253 | case IEEE80211_IF_TYPE_STA: | ||
254 | case IEEE80211_IF_TYPE_IBSS: | ||
255 | add_sta_files(sdata); | ||
256 | break; | ||
257 | case IEEE80211_IF_TYPE_AP: | ||
258 | add_ap_files(sdata); | ||
259 | break; | ||
260 | case IEEE80211_IF_TYPE_WDS: | ||
261 | add_wds_files(sdata); | ||
262 | break; | ||
263 | case IEEE80211_IF_TYPE_MNTR: | ||
264 | add_monitor_files(sdata); | ||
265 | break; | ||
266 | case IEEE80211_IF_TYPE_VLAN: | ||
267 | add_vlan_files(sdata); | ||
268 | break; | ||
269 | default: | ||
270 | break; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | #define DEBUGFS_DEL(name, type)\ | ||
275 | debugfs_remove(sdata->debugfs.type.name);\ | ||
276 | sdata->debugfs.type.name = NULL; | ||
277 | |||
278 | static void del_sta_files(struct ieee80211_sub_if_data *sdata) | ||
279 | { | ||
280 | DEBUGFS_DEL(channel_use, sta); | ||
281 | DEBUGFS_DEL(drop_unencrypted, sta); | ||
282 | DEBUGFS_DEL(eapol, sta); | ||
283 | DEBUGFS_DEL(ieee8021_x, sta); | ||
284 | DEBUGFS_DEL(state, sta); | ||
285 | DEBUGFS_DEL(bssid, sta); | ||
286 | DEBUGFS_DEL(prev_bssid, sta); | ||
287 | DEBUGFS_DEL(ssid_len, sta); | ||
288 | DEBUGFS_DEL(aid, sta); | ||
289 | DEBUGFS_DEL(ap_capab, sta); | ||
290 | DEBUGFS_DEL(capab, sta); | ||
291 | DEBUGFS_DEL(extra_ie_len, sta); | ||
292 | DEBUGFS_DEL(auth_tries, sta); | ||
293 | DEBUGFS_DEL(assoc_tries, sta); | ||
294 | DEBUGFS_DEL(auth_algs, sta); | ||
295 | DEBUGFS_DEL(auth_alg, sta); | ||
296 | DEBUGFS_DEL(auth_transaction, sta); | ||
297 | DEBUGFS_DEL(flags, sta); | ||
298 | } | ||
299 | |||
300 | static void del_ap_files(struct ieee80211_sub_if_data *sdata) | ||
301 | { | ||
302 | DEBUGFS_DEL(channel_use, ap); | ||
303 | DEBUGFS_DEL(drop_unencrypted, ap); | ||
304 | DEBUGFS_DEL(eapol, ap); | ||
305 | DEBUGFS_DEL(ieee8021_x, ap); | ||
306 | DEBUGFS_DEL(num_sta_ps, ap); | ||
307 | DEBUGFS_DEL(dtim_period, ap); | ||
308 | DEBUGFS_DEL(dtim_count, ap); | ||
309 | DEBUGFS_DEL(num_beacons, ap); | ||
310 | DEBUGFS_DEL(force_unicast_rateidx, ap); | ||
311 | DEBUGFS_DEL(max_ratectrl_rateidx, ap); | ||
312 | DEBUGFS_DEL(num_buffered_multicast, ap); | ||
313 | DEBUGFS_DEL(beacon_head_len, ap); | ||
314 | DEBUGFS_DEL(beacon_tail_len, ap); | ||
315 | } | ||
316 | |||
317 | static void del_wds_files(struct ieee80211_sub_if_data *sdata) | ||
318 | { | ||
319 | DEBUGFS_DEL(channel_use, wds); | ||
320 | DEBUGFS_DEL(drop_unencrypted, wds); | ||
321 | DEBUGFS_DEL(eapol, wds); | ||
322 | DEBUGFS_DEL(ieee8021_x, wds); | ||
323 | DEBUGFS_DEL(peer, wds); | ||
324 | } | ||
325 | |||
326 | static void del_vlan_files(struct ieee80211_sub_if_data *sdata) | ||
327 | { | ||
328 | DEBUGFS_DEL(channel_use, vlan); | ||
329 | DEBUGFS_DEL(drop_unencrypted, vlan); | ||
330 | DEBUGFS_DEL(eapol, vlan); | ||
331 | DEBUGFS_DEL(ieee8021_x, vlan); | ||
332 | DEBUGFS_DEL(vlan_id, vlan); | ||
333 | } | ||
334 | |||
335 | static void del_monitor_files(struct ieee80211_sub_if_data *sdata) | ||
336 | { | ||
337 | DEBUGFS_DEL(mode, monitor); | ||
338 | } | ||
339 | |||
340 | static void del_files(struct ieee80211_sub_if_data *sdata, int type) | ||
341 | { | ||
342 | if (!sdata->debugfsdir) | ||
343 | return; | ||
344 | |||
345 | switch (type) { | ||
346 | case IEEE80211_IF_TYPE_STA: | ||
347 | case IEEE80211_IF_TYPE_IBSS: | ||
348 | del_sta_files(sdata); | ||
349 | break; | ||
350 | case IEEE80211_IF_TYPE_AP: | ||
351 | del_ap_files(sdata); | ||
352 | break; | ||
353 | case IEEE80211_IF_TYPE_WDS: | ||
354 | del_wds_files(sdata); | ||
355 | break; | ||
356 | case IEEE80211_IF_TYPE_MNTR: | ||
357 | del_monitor_files(sdata); | ||
358 | break; | ||
359 | case IEEE80211_IF_TYPE_VLAN: | ||
360 | del_vlan_files(sdata); | ||
361 | break; | ||
362 | default: | ||
363 | break; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | static int notif_registered; | ||
368 | |||
369 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) | ||
370 | { | ||
371 | char buf[10+IFNAMSIZ]; | ||
372 | |||
373 | if (!notif_registered) | ||
374 | return; | ||
375 | |||
376 | sprintf(buf, "netdev:%s", sdata->dev->name); | ||
377 | sdata->debugfsdir = debugfs_create_dir(buf, | ||
378 | sdata->local->hw.wiphy->debugfsdir); | ||
379 | } | ||
380 | |||
381 | void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) | ||
382 | { | ||
383 | del_files(sdata, sdata->type); | ||
384 | debugfs_remove(sdata->debugfsdir); | ||
385 | sdata->debugfsdir = NULL; | ||
386 | } | ||
387 | |||
388 | void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata, | ||
389 | int oldtype) | ||
390 | { | ||
391 | del_files(sdata, oldtype); | ||
392 | add_files(sdata); | ||
393 | } | ||
394 | |||
395 | static int netdev_notify(struct notifier_block * nb, | ||
396 | unsigned long state, | ||
397 | void *ndev) | ||
398 | { | ||
399 | struct net_device *dev = ndev; | ||
400 | char buf[10+IFNAMSIZ]; | ||
401 | |||
402 | if (state != NETDEV_CHANGENAME) | ||
403 | return 0; | ||
404 | |||
405 | if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) | ||
406 | return 0; | ||
407 | |||
408 | if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) | ||
409 | return 0; | ||
410 | |||
411 | /* TODO | ||
412 | sprintf(buf, "netdev:%s", dev->name); | ||
413 | debugfs_rename(IEEE80211_DEV_TO_SUB_IF(dev)->debugfsdir, buf); | ||
414 | */ | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | static struct notifier_block mac80211_debugfs_netdev_notifier = { | ||
420 | .notifier_call = netdev_notify, | ||
421 | }; | ||
422 | |||
423 | void ieee80211_debugfs_netdev_init(void) | ||
424 | { | ||
425 | int err; | ||
426 | |||
427 | err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier); | ||
428 | if (err) { | ||
429 | printk(KERN_ERR | ||
430 | "mac80211: failed to install netdev notifier," | ||
431 | " disabling per-netdev debugfs!\n"); | ||
432 | } else | ||
433 | notif_registered = 1; | ||
434 | } | ||
435 | |||
436 | void ieee80211_debugfs_netdev_exit(void) | ||
437 | { | ||
438 | unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier); | ||
439 | notif_registered = 0; | ||
440 | } | ||
diff --git a/net/mac80211/debugfs_netdev.h b/net/mac80211/debugfs_netdev.h new file mode 100644 index 000000000000..a690071fde8a --- /dev/null +++ b/net/mac80211/debugfs_netdev.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* routines exported for debugfs handling */ | ||
2 | |||
3 | #ifndef __IEEE80211_DEBUGFS_NETDEV_H | ||
4 | #define __IEEE80211_DEBUGFS_NETDEV_H | ||
5 | |||
6 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
7 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata); | ||
8 | void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata); | ||
9 | void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata, | ||
10 | int oldtype); | ||
11 | void ieee80211_debugfs_netdev_init(void); | ||
12 | void ieee80211_debugfs_netdev_exit(void); | ||
13 | #else | ||
14 | static inline void ieee80211_debugfs_add_netdev( | ||
15 | struct ieee80211_sub_if_data *sdata) | ||
16 | {} | ||
17 | static inline void ieee80211_debugfs_remove_netdev( | ||
18 | struct ieee80211_sub_if_data *sdata) | ||
19 | {} | ||
20 | static inline void ieee80211_debugfs_change_if_type( | ||
21 | struct ieee80211_sub_if_data *sdata, int oldtype) | ||
22 | {} | ||
23 | static inline void ieee80211_debugfs_netdev_init(void) | ||
24 | {} | ||
25 | |||
26 | static inline void ieee80211_debugfs_netdev_exit(void) | ||
27 | {} | ||
28 | #endif | ||
29 | |||
30 | #endif /* __IEEE80211_DEBUGFS_NETDEV_H */ | ||
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c new file mode 100644 index 000000000000..d41e696f3980 --- /dev/null +++ b/net/mac80211/debugfs_sta.c | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2005 Devicescape Software, Inc. | ||
3 | * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> | ||
4 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/debugfs.h> | ||
12 | #include <linux/ieee80211.h> | ||
13 | #include "ieee80211_i.h" | ||
14 | #include "debugfs.h" | ||
15 | #include "debugfs_sta.h" | ||
16 | #include "sta_info.h" | ||
17 | |||
18 | /* sta attributtes */ | ||
19 | |||
20 | #define STA_READ(name, buflen, field, format_string) \ | ||
21 | static ssize_t sta_ ##name## _read(struct file *file, \ | ||
22 | char __user *userbuf, \ | ||
23 | size_t count, loff_t *ppos) \ | ||
24 | { \ | ||
25 | int res; \ | ||
26 | struct sta_info *sta = file->private_data; \ | ||
27 | char buf[buflen]; \ | ||
28 | res = scnprintf(buf, buflen, format_string, sta->field); \ | ||
29 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
30 | } | ||
31 | #define STA_READ_D(name, field) STA_READ(name, 20, field, "%d\n") | ||
32 | #define STA_READ_U(name, field) STA_READ(name, 20, field, "%u\n") | ||
33 | #define STA_READ_LU(name, field) STA_READ(name, 20, field, "%lu\n") | ||
34 | #define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n") | ||
35 | |||
36 | #define STA_READ_RATE(name, field) \ | ||
37 | static ssize_t sta_##name##_read(struct file *file, \ | ||
38 | char __user *userbuf, \ | ||
39 | size_t count, loff_t *ppos) \ | ||
40 | { \ | ||
41 | struct sta_info *sta = file->private_data; \ | ||
42 | struct ieee80211_local *local = wdev_priv(sta->dev->ieee80211_ptr);\ | ||
43 | struct ieee80211_hw_mode *mode = local->oper_hw_mode; \ | ||
44 | char buf[20]; \ | ||
45 | int res = scnprintf(buf, sizeof(buf), "%d\n", \ | ||
46 | (sta->field >= 0 && \ | ||
47 | sta->field < mode->num_rates) ? \ | ||
48 | mode->rates[sta->field].rate : -1); \ | ||
49 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
50 | } | ||
51 | |||
52 | #define STA_OPS(name) \ | ||
53 | static const struct file_operations sta_ ##name## _ops = { \ | ||
54 | .read = sta_##name##_read, \ | ||
55 | .open = mac80211_open_file_generic, \ | ||
56 | } | ||
57 | |||
58 | #define STA_FILE(name, field, format) \ | ||
59 | STA_READ_##format(name, field) \ | ||
60 | STA_OPS(name) | ||
61 | |||
62 | STA_FILE(aid, aid, D); | ||
63 | STA_FILE(key_idx_compression, key_idx_compression, D); | ||
64 | STA_FILE(dev, dev->name, S); | ||
65 | STA_FILE(vlan_id, vlan_id, D); | ||
66 | STA_FILE(rx_packets, rx_packets, LU); | ||
67 | STA_FILE(tx_packets, tx_packets, LU); | ||
68 | STA_FILE(rx_bytes, rx_bytes, LU); | ||
69 | STA_FILE(tx_bytes, tx_bytes, LU); | ||
70 | STA_FILE(rx_duplicates, num_duplicates, LU); | ||
71 | STA_FILE(rx_fragments, rx_fragments, LU); | ||
72 | STA_FILE(rx_dropped, rx_dropped, LU); | ||
73 | STA_FILE(tx_fragments, tx_fragments, LU); | ||
74 | STA_FILE(tx_filtered, tx_filtered_count, LU); | ||
75 | STA_FILE(txrate, txrate, RATE); | ||
76 | STA_FILE(last_txrate, last_txrate, RATE); | ||
77 | STA_FILE(tx_retry_failed, tx_retry_failed, LU); | ||
78 | STA_FILE(tx_retry_count, tx_retry_count, LU); | ||
79 | STA_FILE(last_rssi, last_rssi, D); | ||
80 | STA_FILE(last_signal, last_signal, D); | ||
81 | STA_FILE(last_noise, last_noise, D); | ||
82 | STA_FILE(channel_use, channel_use, D); | ||
83 | STA_FILE(wep_weak_iv_count, wep_weak_iv_count, D); | ||
84 | |||
85 | static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | ||
86 | size_t count, loff_t *ppos) | ||
87 | { | ||
88 | char buf[100]; | ||
89 | struct sta_info *sta = file->private_data; | ||
90 | int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s", | ||
91 | sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "", | ||
92 | sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "", | ||
93 | sta->flags & WLAN_STA_PS ? "PS\n" : "", | ||
94 | sta->flags & WLAN_STA_TIM ? "TIM\n" : "", | ||
95 | sta->flags & WLAN_STA_PERM ? "PERM\n" : "", | ||
96 | sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", | ||
97 | sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", | ||
98 | sta->flags & WLAN_STA_WME ? "WME\n" : "", | ||
99 | sta->flags & WLAN_STA_WDS ? "WDS\n" : ""); | ||
100 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
101 | } | ||
102 | STA_OPS(flags); | ||
103 | |||
104 | static ssize_t sta_num_ps_buf_frames_read(struct file *file, | ||
105 | char __user *userbuf, | ||
106 | size_t count, loff_t *ppos) | ||
107 | { | ||
108 | char buf[20]; | ||
109 | struct sta_info *sta = file->private_data; | ||
110 | int res = scnprintf(buf, sizeof(buf), "%u\n", | ||
111 | skb_queue_len(&sta->ps_tx_buf)); | ||
112 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
113 | } | ||
114 | STA_OPS(num_ps_buf_frames); | ||
115 | |||
116 | static ssize_t sta_last_ack_rssi_read(struct file *file, char __user *userbuf, | ||
117 | size_t count, loff_t *ppos) | ||
118 | { | ||
119 | char buf[100]; | ||
120 | struct sta_info *sta = file->private_data; | ||
121 | int res = scnprintf(buf, sizeof(buf), "%d %d %d\n", | ||
122 | sta->last_ack_rssi[0], | ||
123 | sta->last_ack_rssi[1], | ||
124 | sta->last_ack_rssi[2]); | ||
125 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
126 | } | ||
127 | STA_OPS(last_ack_rssi); | ||
128 | |||
129 | static ssize_t sta_last_ack_ms_read(struct file *file, char __user *userbuf, | ||
130 | size_t count, loff_t *ppos) | ||
131 | { | ||
132 | char buf[20]; | ||
133 | struct sta_info *sta = file->private_data; | ||
134 | int res = scnprintf(buf, sizeof(buf), "%d\n", | ||
135 | sta->last_ack ? | ||
136 | jiffies_to_msecs(jiffies - sta->last_ack) : -1); | ||
137 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
138 | } | ||
139 | STA_OPS(last_ack_ms); | ||
140 | |||
141 | static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf, | ||
142 | size_t count, loff_t *ppos) | ||
143 | { | ||
144 | char buf[20]; | ||
145 | struct sta_info *sta = file->private_data; | ||
146 | int res = scnprintf(buf, sizeof(buf), "%d\n", | ||
147 | jiffies_to_msecs(jiffies - sta->last_rx)); | ||
148 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
149 | } | ||
150 | STA_OPS(inactive_ms); | ||
151 | |||
152 | static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, | ||
153 | size_t count, loff_t *ppos) | ||
154 | { | ||
155 | char buf[15*NUM_RX_DATA_QUEUES], *p = buf; | ||
156 | int i; | ||
157 | struct sta_info *sta = file->private_data; | ||
158 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | ||
159 | p += scnprintf(p, sizeof(buf)+buf-p, "%x ", | ||
160 | sta->last_seq_ctrl[i]); | ||
161 | p += scnprintf(p, sizeof(buf)+buf-p, "\n"); | ||
162 | return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); | ||
163 | } | ||
164 | STA_OPS(last_seq_ctrl); | ||
165 | |||
166 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
167 | static ssize_t sta_wme_rx_queue_read(struct file *file, char __user *userbuf, | ||
168 | size_t count, loff_t *ppos) | ||
169 | { | ||
170 | char buf[15*NUM_RX_DATA_QUEUES], *p = buf; | ||
171 | int i; | ||
172 | struct sta_info *sta = file->private_data; | ||
173 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | ||
174 | p += scnprintf(p, sizeof(buf)+buf-p, "%u ", | ||
175 | sta->wme_rx_queue[i]); | ||
176 | p += scnprintf(p, sizeof(buf)+buf-p, "\n"); | ||
177 | return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); | ||
178 | } | ||
179 | STA_OPS(wme_rx_queue); | ||
180 | |||
181 | static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf, | ||
182 | size_t count, loff_t *ppos) | ||
183 | { | ||
184 | char buf[15*NUM_TX_DATA_QUEUES], *p = buf; | ||
185 | int i; | ||
186 | struct sta_info *sta = file->private_data; | ||
187 | for (i = 0; i < NUM_TX_DATA_QUEUES; i++) | ||
188 | p += scnprintf(p, sizeof(buf)+buf-p, "%u ", | ||
189 | sta->wme_tx_queue[i]); | ||
190 | p += scnprintf(p, sizeof(buf)+buf-p, "\n"); | ||
191 | return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); | ||
192 | } | ||
193 | STA_OPS(wme_tx_queue); | ||
194 | #endif | ||
195 | |||
196 | #define DEBUGFS_ADD(name) \ | ||
197 | sta->debugfs.name = debugfs_create_file(#name, 0444, \ | ||
198 | sta->debugfs.dir, sta, &sta_ ##name## _ops); | ||
199 | |||
200 | #define DEBUGFS_DEL(name) \ | ||
201 | debugfs_remove(sta->debugfs.name);\ | ||
202 | sta->debugfs.name = NULL; | ||
203 | |||
204 | |||
205 | void ieee80211_sta_debugfs_add(struct sta_info *sta) | ||
206 | { | ||
207 | char buf[3*6]; | ||
208 | struct dentry *stations_dir = sta->local->debugfs.stations; | ||
209 | |||
210 | if (!stations_dir) | ||
211 | return; | ||
212 | |||
213 | sprintf(buf, MAC_FMT, MAC_ARG(sta->addr)); | ||
214 | |||
215 | sta->debugfs.dir = debugfs_create_dir(buf, stations_dir); | ||
216 | if (!sta->debugfs.dir) | ||
217 | return; | ||
218 | |||
219 | DEBUGFS_ADD(flags); | ||
220 | DEBUGFS_ADD(num_ps_buf_frames); | ||
221 | DEBUGFS_ADD(last_ack_rssi); | ||
222 | DEBUGFS_ADD(last_ack_ms); | ||
223 | DEBUGFS_ADD(inactive_ms); | ||
224 | DEBUGFS_ADD(last_seq_ctrl); | ||
225 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
226 | DEBUGFS_ADD(wme_rx_queue); | ||
227 | DEBUGFS_ADD(wme_tx_queue); | ||
228 | #endif | ||
229 | } | ||
230 | |||
231 | void ieee80211_sta_debugfs_remove(struct sta_info *sta) | ||
232 | { | ||
233 | DEBUGFS_DEL(flags); | ||
234 | DEBUGFS_DEL(num_ps_buf_frames); | ||
235 | DEBUGFS_DEL(last_ack_rssi); | ||
236 | DEBUGFS_DEL(last_ack_ms); | ||
237 | DEBUGFS_DEL(inactive_ms); | ||
238 | DEBUGFS_DEL(last_seq_ctrl); | ||
239 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
240 | DEBUGFS_DEL(wme_rx_queue); | ||
241 | DEBUGFS_DEL(wme_tx_queue); | ||
242 | #endif | ||
243 | |||
244 | debugfs_remove(sta->debugfs.dir); | ||
245 | sta->debugfs.dir = NULL; | ||
246 | } | ||
diff --git a/net/mac80211/debugfs_sta.h b/net/mac80211/debugfs_sta.h new file mode 100644 index 000000000000..574a1cd54b96 --- /dev/null +++ b/net/mac80211/debugfs_sta.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #ifndef __MAC80211_DEBUGFS_STA_H | ||
2 | #define __MAC80211_DEBUGFS_STA_H | ||
3 | |||
4 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
5 | void ieee80211_sta_debugfs_add(struct sta_info *sta); | ||
6 | void ieee80211_sta_debugfs_remove(struct sta_info *sta); | ||
7 | #else | ||
8 | static inline void ieee80211_sta_debugfs_add(struct sta_info *sta) {} | ||
9 | static inline void ieee80211_sta_debugfs_remove(struct sta_info *sta) {} | ||
10 | #endif | ||
11 | |||
12 | #endif /* __MAC80211_DEBUGFS_STA_H */ | ||
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 48a832d4e175..6e36df67f8d5 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c | |||
@@ -35,6 +35,9 @@ | |||
35 | #include "aes_ccm.h" | 35 | #include "aes_ccm.h" |
36 | #include "ieee80211_led.h" | 36 | #include "ieee80211_led.h" |
37 | #include "ieee80211_cfg.h" | 37 | #include "ieee80211_cfg.h" |
38 | #include "debugfs.h" | ||
39 | #include "debugfs_netdev.h" | ||
40 | #include "debugfs_key.h" | ||
38 | 41 | ||
39 | /* privid for wiphys to determine whether they belong to us or not */ | 42 | /* privid for wiphys to determine whether they belong to us or not */ |
40 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; | 43 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; |
@@ -108,6 +111,7 @@ static void ieee80211_key_release(struct kref *kref) | |||
108 | key = container_of(kref, struct ieee80211_key, kref); | 111 | key = container_of(kref, struct ieee80211_key, kref); |
109 | if (key->alg == ALG_CCMP) | 112 | if (key->alg == ALG_CCMP) |
110 | ieee80211_aes_key_free(key->u.ccmp.tfm); | 113 | ieee80211_aes_key_free(key->u.ccmp.tfm); |
114 | ieee80211_debugfs_key_remove(key); | ||
111 | kfree(key); | 115 | kfree(key); |
112 | } | 116 | } |
113 | 117 | ||
@@ -4704,6 +4708,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
4704 | goto fail_workqueue; | 4708 | goto fail_workqueue; |
4705 | } | 4709 | } |
4706 | 4710 | ||
4711 | debugfs_hw_add(local); | ||
4712 | |||
4707 | local->hw.conf.beacon_int = 1000; | 4713 | local->hw.conf.beacon_int = 1000; |
4708 | 4714 | ||
4709 | local->wstats_flags |= local->hw.max_rssi ? | 4715 | local->wstats_flags |= local->hw.max_rssi ? |
@@ -4731,6 +4737,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
4731 | if (result < 0) | 4737 | if (result < 0) |
4732 | goto fail_dev; | 4738 | goto fail_dev; |
4733 | 4739 | ||
4740 | ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); | ||
4741 | |||
4734 | result = ieee80211_init_rate_ctrl_alg(local, NULL); | 4742 | result = ieee80211_init_rate_ctrl_alg(local, NULL); |
4735 | if (result < 0) { | 4743 | if (result < 0) { |
4736 | printk(KERN_DEBUG "%s: Failed to initialize rate control " | 4744 | printk(KERN_DEBUG "%s: Failed to initialize rate control " |
@@ -4765,11 +4773,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
4765 | fail_wep: | 4773 | fail_wep: |
4766 | rate_control_deinitialize(local); | 4774 | rate_control_deinitialize(local); |
4767 | fail_rate: | 4775 | fail_rate: |
4776 | ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); | ||
4768 | unregister_netdevice(local->mdev); | 4777 | unregister_netdevice(local->mdev); |
4769 | fail_dev: | 4778 | fail_dev: |
4770 | rtnl_unlock(); | 4779 | rtnl_unlock(); |
4771 | sta_info_stop(local); | 4780 | sta_info_stop(local); |
4772 | fail_sta_info: | 4781 | fail_sta_info: |
4782 | debugfs_hw_del(local); | ||
4773 | destroy_workqueue(local->hw.workqueue); | 4783 | destroy_workqueue(local->hw.workqueue); |
4774 | fail_workqueue: | 4784 | fail_workqueue: |
4775 | wiphy_unregister(local->hw.wiphy); | 4785 | wiphy_unregister(local->hw.wiphy); |
@@ -4844,6 +4854,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
4844 | ieee80211_clear_tx_pending(local); | 4854 | ieee80211_clear_tx_pending(local); |
4845 | sta_info_stop(local); | 4855 | sta_info_stop(local); |
4846 | rate_control_deinitialize(local); | 4856 | rate_control_deinitialize(local); |
4857 | debugfs_hw_del(local); | ||
4847 | 4858 | ||
4848 | for (i = 0; i < NUM_IEEE80211_MODES; i++) { | 4859 | for (i = 0; i < NUM_IEEE80211_MODES; i++) { |
4849 | kfree(local->supp_rates[i]); | 4860 | kfree(local->supp_rates[i]); |
@@ -4953,6 +4964,8 @@ static int __init ieee80211_init(void) | |||
4953 | return ret; | 4964 | return ret; |
4954 | } | 4965 | } |
4955 | 4966 | ||
4967 | ieee80211_debugfs_netdev_init(); | ||
4968 | |||
4956 | return 0; | 4969 | return 0; |
4957 | } | 4970 | } |
4958 | 4971 | ||
@@ -4960,6 +4973,7 @@ static int __init ieee80211_init(void) | |||
4960 | static void __exit ieee80211_exit(void) | 4973 | static void __exit ieee80211_exit(void) |
4961 | { | 4974 | { |
4962 | ieee80211_wme_unregister(); | 4975 | ieee80211_wme_unregister(); |
4976 | ieee80211_debugfs_netdev_exit(); | ||
4963 | } | 4977 | } |
4964 | 4978 | ||
4965 | 4979 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ae94d6461798..af4d14d0b969 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -307,6 +307,65 @@ struct ieee80211_sub_if_data { | |||
307 | } u; | 307 | } u; |
308 | int channel_use; | 308 | int channel_use; |
309 | int channel_use_raw; | 309 | int channel_use_raw; |
310 | |||
311 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
312 | struct dentry *debugfsdir; | ||
313 | union { | ||
314 | struct { | ||
315 | struct dentry *channel_use; | ||
316 | struct dentry *drop_unencrypted; | ||
317 | struct dentry *eapol; | ||
318 | struct dentry *ieee8021_x; | ||
319 | struct dentry *state; | ||
320 | struct dentry *bssid; | ||
321 | struct dentry *prev_bssid; | ||
322 | struct dentry *ssid_len; | ||
323 | struct dentry *aid; | ||
324 | struct dentry *ap_capab; | ||
325 | struct dentry *capab; | ||
326 | struct dentry *extra_ie_len; | ||
327 | struct dentry *auth_tries; | ||
328 | struct dentry *assoc_tries; | ||
329 | struct dentry *auth_algs; | ||
330 | struct dentry *auth_alg; | ||
331 | struct dentry *auth_transaction; | ||
332 | struct dentry *flags; | ||
333 | } sta; | ||
334 | struct { | ||
335 | struct dentry *channel_use; | ||
336 | struct dentry *drop_unencrypted; | ||
337 | struct dentry *eapol; | ||
338 | struct dentry *ieee8021_x; | ||
339 | struct dentry *num_sta_ps; | ||
340 | struct dentry *dtim_period; | ||
341 | struct dentry *dtim_count; | ||
342 | struct dentry *num_beacons; | ||
343 | struct dentry *force_unicast_rateidx; | ||
344 | struct dentry *max_ratectrl_rateidx; | ||
345 | struct dentry *num_buffered_multicast; | ||
346 | struct dentry *beacon_head_len; | ||
347 | struct dentry *beacon_tail_len; | ||
348 | } ap; | ||
349 | struct { | ||
350 | struct dentry *channel_use; | ||
351 | struct dentry *drop_unencrypted; | ||
352 | struct dentry *eapol; | ||
353 | struct dentry *ieee8021_x; | ||
354 | struct dentry *peer; | ||
355 | } wds; | ||
356 | struct { | ||
357 | struct dentry *channel_use; | ||
358 | struct dentry *drop_unencrypted; | ||
359 | struct dentry *eapol; | ||
360 | struct dentry *ieee8021_x; | ||
361 | struct dentry *vlan_id; | ||
362 | } vlan; | ||
363 | struct { | ||
364 | struct dentry *mode; | ||
365 | } monitor; | ||
366 | struct dentry *default_key; | ||
367 | } debugfs; | ||
368 | #endif | ||
310 | }; | 369 | }; |
311 | 370 | ||
312 | #define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev) | 371 | #define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev) |
@@ -444,6 +503,10 @@ struct ieee80211_local { | |||
444 | u32 stat_time; | 503 | u32 stat_time; |
445 | struct timer_list stat_timer; | 504 | struct timer_list stat_timer; |
446 | 505 | ||
506 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
507 | struct work_struct sta_debugfs_add; | ||
508 | #endif | ||
509 | |||
447 | enum { | 510 | enum { |
448 | STA_ANTENNA_SEL_AUTO = 0, | 511 | STA_ANTENNA_SEL_AUTO = 0, |
449 | STA_ANTENNA_SEL_SW_CTRL = 1, | 512 | STA_ANTENNA_SEL_SW_CTRL = 1, |
@@ -500,6 +563,70 @@ struct ieee80211_local { | |||
500 | * (1 << MODE_*) */ | 563 | * (1 << MODE_*) */ |
501 | 564 | ||
502 | int user_space_mlme; | 565 | int user_space_mlme; |
566 | |||
567 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
568 | struct local_debugfsdentries { | ||
569 | struct dentry *channel; | ||
570 | struct dentry *frequency; | ||
571 | struct dentry *radar_detect; | ||
572 | struct dentry *antenna_sel_tx; | ||
573 | struct dentry *antenna_sel_rx; | ||
574 | struct dentry *bridge_packets; | ||
575 | struct dentry *key_tx_rx_threshold; | ||
576 | struct dentry *rts_threshold; | ||
577 | struct dentry *fragmentation_threshold; | ||
578 | struct dentry *short_retry_limit; | ||
579 | struct dentry *long_retry_limit; | ||
580 | struct dentry *total_ps_buffered; | ||
581 | struct dentry *mode; | ||
582 | struct dentry *wep_iv; | ||
583 | struct dentry *tx_power_reduction; | ||
584 | struct dentry *modes; | ||
585 | struct dentry *statistics; | ||
586 | struct local_debugfsdentries_statsdentries { | ||
587 | struct dentry *transmitted_fragment_count; | ||
588 | struct dentry *multicast_transmitted_frame_count; | ||
589 | struct dentry *failed_count; | ||
590 | struct dentry *retry_count; | ||
591 | struct dentry *multiple_retry_count; | ||
592 | struct dentry *frame_duplicate_count; | ||
593 | struct dentry *received_fragment_count; | ||
594 | struct dentry *multicast_received_frame_count; | ||
595 | struct dentry *transmitted_frame_count; | ||
596 | struct dentry *wep_undecryptable_count; | ||
597 | struct dentry *num_scans; | ||
598 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
599 | struct dentry *tx_handlers_drop; | ||
600 | struct dentry *tx_handlers_queued; | ||
601 | struct dentry *tx_handlers_drop_unencrypted; | ||
602 | struct dentry *tx_handlers_drop_fragment; | ||
603 | struct dentry *tx_handlers_drop_wep; | ||
604 | struct dentry *tx_handlers_drop_not_assoc; | ||
605 | struct dentry *tx_handlers_drop_unauth_port; | ||
606 | struct dentry *rx_handlers_drop; | ||
607 | struct dentry *rx_handlers_queued; | ||
608 | struct dentry *rx_handlers_drop_nullfunc; | ||
609 | struct dentry *rx_handlers_drop_defrag; | ||
610 | struct dentry *rx_handlers_drop_short; | ||
611 | struct dentry *rx_handlers_drop_passive_scan; | ||
612 | struct dentry *tx_expand_skb_head; | ||
613 | struct dentry *tx_expand_skb_head_cloned; | ||
614 | struct dentry *rx_expand_skb_head; | ||
615 | struct dentry *rx_expand_skb_head2; | ||
616 | struct dentry *rx_handlers_fragments; | ||
617 | struct dentry *tx_status_drop; | ||
618 | struct dentry *wme_tx_queue; | ||
619 | struct dentry *wme_rx_queue; | ||
620 | #endif | ||
621 | struct dentry *dot11ACKFailureCount; | ||
622 | struct dentry *dot11RTSFailureCount; | ||
623 | struct dentry *dot11FCSErrorCount; | ||
624 | struct dentry *dot11RTSSuccessCount; | ||
625 | } stats; | ||
626 | struct dentry *stations; | ||
627 | struct dentry *keys; | ||
628 | } debugfs; | ||
629 | #endif | ||
503 | }; | 630 | }; |
504 | 631 | ||
505 | static inline struct ieee80211_local *hw_to_local( | 632 | static inline struct ieee80211_local *hw_to_local( |
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 64267d4b31a4..cf0f32e8c2a2 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <net/mac80211.h> | 14 | #include <net/mac80211.h> |
15 | #include "ieee80211_i.h" | 15 | #include "ieee80211_i.h" |
16 | #include "sta_info.h" | 16 | #include "sta_info.h" |
17 | #include "debugfs_netdev.h" | ||
17 | 18 | ||
18 | void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) | 19 | void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) |
19 | { | 20 | { |
@@ -73,6 +74,7 @@ int ieee80211_if_add(struct net_device *dev, const char *name, | |||
73 | if (ret) | 74 | if (ret) |
74 | goto fail; | 75 | goto fail; |
75 | 76 | ||
77 | ieee80211_debugfs_add_netdev(sdata); | ||
76 | ieee80211_if_set_type(ndev, type); | 78 | ieee80211_if_set_type(ndev, type); |
77 | 79 | ||
78 | write_lock_bh(&local->sub_if_lock); | 80 | write_lock_bh(&local->sub_if_lock); |
@@ -126,6 +128,8 @@ int ieee80211_if_add_mgmt(struct ieee80211_local *local) | |||
126 | if (ret) | 128 | if (ret) |
127 | goto fail; | 129 | goto fail; |
128 | 130 | ||
131 | ieee80211_debugfs_add_netdev(nsdata); | ||
132 | |||
129 | if (local->open_count > 0) | 133 | if (local->open_count > 0) |
130 | dev_open(ndev); | 134 | dev_open(ndev); |
131 | local->apdev = ndev; | 135 | local->apdev = ndev; |
@@ -142,6 +146,7 @@ void ieee80211_if_del_mgmt(struct ieee80211_local *local) | |||
142 | 146 | ||
143 | ASSERT_RTNL(); | 147 | ASSERT_RTNL(); |
144 | apdev = local->apdev; | 148 | apdev = local->apdev; |
149 | ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(apdev)); | ||
145 | local->apdev = NULL; | 150 | local->apdev = NULL; |
146 | unregister_netdevice(apdev); | 151 | unregister_netdevice(apdev); |
147 | } | 152 | } |
@@ -150,6 +155,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) | |||
150 | { | 155 | { |
151 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 156 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
152 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 157 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
158 | int oldtype = sdata->type; | ||
153 | 159 | ||
154 | sdata->type = type; | 160 | sdata->type = type; |
155 | switch (type) { | 161 | switch (type) { |
@@ -195,6 +201,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) | |||
195 | printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x", | 201 | printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x", |
196 | dev->name, __FUNCTION__, type); | 202 | dev->name, __FUNCTION__, type); |
197 | } | 203 | } |
204 | ieee80211_debugfs_change_if_type(sdata, oldtype); | ||
198 | ieee80211_update_default_wep_only(local); | 205 | ieee80211_update_default_wep_only(local); |
199 | } | 206 | } |
200 | 207 | ||
@@ -303,6 +310,7 @@ void __ieee80211_if_del(struct ieee80211_local *local, | |||
303 | { | 310 | { |
304 | struct net_device *dev = sdata->dev; | 311 | struct net_device *dev = sdata->dev; |
305 | 312 | ||
313 | ieee80211_debugfs_remove_netdev(sdata); | ||
306 | unregister_netdevice(dev); | 314 | unregister_netdevice(dev); |
307 | /* Except master interface, the net_device will be freed by | 315 | /* Except master interface, the net_device will be freed by |
308 | * net_device->destructor (i. e. ieee80211_if_free). */ | 316 | * net_device->destructor (i. e. ieee80211_if_free). */ |
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 73909ec85f2a..352f03bd8a3a 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "ieee80211_rate.h" | 25 | #include "ieee80211_rate.h" |
26 | #include "wpa.h" | 26 | #include "wpa.h" |
27 | #include "aes_ccm.h" | 27 | #include "aes_ccm.h" |
28 | #include "debugfs_key.h" | ||
28 | 29 | ||
29 | static int ieee80211_regdom = 0x10; /* FCC */ | 30 | static int ieee80211_regdom = 0x10; /* FCC */ |
30 | module_param(ieee80211_regdom, int, 0444); | 31 | module_param(ieee80211_regdom, int, 0444); |
@@ -180,8 +181,11 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
180 | } | 181 | } |
181 | kfree(keyconf); | 182 | kfree(keyconf); |
182 | 183 | ||
183 | if (set_tx_key || sdata->default_key == key) | 184 | if (set_tx_key || sdata->default_key == key) { |
185 | ieee80211_debugfs_key_remove_default(sdata); | ||
184 | sdata->default_key = NULL; | 186 | sdata->default_key = NULL; |
187 | } | ||
188 | ieee80211_debugfs_key_remove(key); | ||
185 | if (sta) | 189 | if (sta) |
186 | sta->key = NULL; | 190 | sta->key = NULL; |
187 | else | 191 | else |
@@ -221,13 +225,19 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
221 | } | 225 | } |
222 | } | 226 | } |
223 | 227 | ||
224 | if (set_tx_key || sdata->default_key == old_key) | 228 | if (set_tx_key || sdata->default_key == old_key) { |
229 | ieee80211_debugfs_key_remove_default(sdata); | ||
225 | sdata->default_key = NULL; | 230 | sdata->default_key = NULL; |
231 | } | ||
232 | ieee80211_debugfs_key_remove(old_key); | ||
226 | if (sta) | 233 | if (sta) |
227 | sta->key = key; | 234 | sta->key = key; |
228 | else | 235 | else |
229 | sdata->keys[idx] = key; | 236 | sdata->keys[idx] = key; |
230 | ieee80211_key_free(old_key); | 237 | ieee80211_key_free(old_key); |
238 | ieee80211_debugfs_key_add(local, key); | ||
239 | if (sta) | ||
240 | ieee80211_debugfs_key_sta_link(key, sta); | ||
231 | 241 | ||
232 | if (try_hwaccel && | 242 | if (try_hwaccel && |
233 | (alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP)) | 243 | (alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP)) |
@@ -236,6 +246,8 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
236 | 246 | ||
237 | if (set_tx_key || (!sta && !sdata->default_key && key)) { | 247 | if (set_tx_key || (!sta && !sdata->default_key && key)) { |
238 | sdata->default_key = key; | 248 | sdata->default_key = key; |
249 | if (key) | ||
250 | ieee80211_debugfs_key_add_default(sdata); | ||
239 | 251 | ||
240 | if (local->ops->set_key_idx && | 252 | if (local->ops->set_key_idx && |
241 | local->ops->set_key_idx(local_to_hw(local), idx)) | 253 | local->ops->set_key_idx(local_to_hw(local), idx)) |
@@ -1505,8 +1517,12 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev, | |||
1505 | alg = ALG_NONE; | 1517 | alg = ALG_NONE; |
1506 | else if (erq->length == 0) { | 1518 | else if (erq->length == 0) { |
1507 | /* No key data - just set the default TX key index */ | 1519 | /* No key data - just set the default TX key index */ |
1508 | if (sdata->default_key != sdata->keys[idx]) | 1520 | if (sdata->default_key != sdata->keys[idx]) { |
1521 | ieee80211_debugfs_key_remove_default(sdata); | ||
1509 | sdata->default_key = sdata->keys[idx]; | 1522 | sdata->default_key = sdata->keys[idx]; |
1523 | if (sdata->default_key) | ||
1524 | ieee80211_debugfs_key_add_default(sdata); | ||
1525 | } | ||
1510 | return 0; | 1526 | return 0; |
1511 | } | 1527 | } |
1512 | 1528 | ||
diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h index da67d87705d7..c33384912782 100644 --- a/net/mac80211/ieee80211_key.h +++ b/net/mac80211/ieee80211_key.h | |||
@@ -83,6 +83,23 @@ struct ieee80211_key { | |||
83 | * (used only for broadcast keys). */ | 83 | * (used only for broadcast keys). */ |
84 | s8 keyidx; /* WEP key index */ | 84 | s8 keyidx; /* WEP key index */ |
85 | 85 | ||
86 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
87 | struct { | ||
88 | struct dentry *stalink; | ||
89 | struct dentry *dir; | ||
90 | struct dentry *keylen; | ||
91 | struct dentry *force_sw_encrypt; | ||
92 | struct dentry *keyidx; | ||
93 | struct dentry *hw_key_idx; | ||
94 | struct dentry *tx_rx_count; | ||
95 | struct dentry *algorithm; | ||
96 | struct dentry *tx_spec; | ||
97 | struct dentry *rx_spec; | ||
98 | struct dentry *replays; | ||
99 | struct dentry *key; | ||
100 | } debugfs; | ||
101 | #endif | ||
102 | |||
86 | u8 key[0]; | 103 | u8 key[0]; |
87 | }; | 104 | }; |
88 | 105 | ||
diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h index 710f5685cedd..f021a028d9d0 100644 --- a/net/mac80211/ieee80211_rate.h +++ b/net/mac80211/ieee80211_rate.h | |||
@@ -56,6 +56,9 @@ struct rate_control_ops { | |||
56 | 56 | ||
57 | int (*add_attrs)(void *priv, struct kobject *kobj); | 57 | int (*add_attrs)(void *priv, struct kobject *kobj); |
58 | void (*remove_attrs)(void *priv, struct kobject *kobj); | 58 | void (*remove_attrs)(void *priv, struct kobject *kobj); |
59 | void (*add_sta_debugfs)(void *priv, void *priv_sta, | ||
60 | struct dentry *dir); | ||
61 | void (*remove_sta_debugfs)(void *priv, void *priv_sta); | ||
59 | }; | 62 | }; |
60 | 63 | ||
61 | struct rate_control_ref { | 64 | struct rate_control_ref { |
@@ -119,4 +122,23 @@ static inline void rate_control_free_sta(struct rate_control_ref *ref, | |||
119 | ref->ops->free_sta(ref->priv, priv); | 122 | ref->ops->free_sta(ref->priv, priv); |
120 | } | 123 | } |
121 | 124 | ||
125 | static inline void rate_control_add_sta_debugfs(struct sta_info *sta) | ||
126 | { | ||
127 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
128 | struct rate_control_ref *ref = sta->rate_ctrl; | ||
129 | if (sta->debugfs.dir && ref->ops->add_sta_debugfs) | ||
130 | ref->ops->add_sta_debugfs(ref->priv, sta->rate_ctrl_priv, | ||
131 | sta->debugfs.dir); | ||
132 | #endif | ||
133 | } | ||
134 | |||
135 | static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) | ||
136 | { | ||
137 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
138 | struct rate_control_ref *ref = sta->rate_ctrl; | ||
139 | if (ref->ops->remove_sta_debugfs) | ||
140 | ref->ops->remove_sta_debugfs(ref->priv, sta->rate_ctrl_priv); | ||
141 | #endif | ||
142 | } | ||
143 | |||
122 | #endif /* IEEE80211_RATE_H */ | 144 | #endif /* IEEE80211_RATE_H */ |
diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index 68bddaeee005..2048cfd1ca70 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <net/mac80211.h> | 18 | #include <net/mac80211.h> |
19 | #include "ieee80211_i.h" | 19 | #include "ieee80211_i.h" |
20 | #include "ieee80211_rate.h" | 20 | #include "ieee80211_rate.h" |
21 | #include "debugfs.h" | ||
21 | 22 | ||
22 | 23 | ||
23 | /* This is a minimal implementation of TX rate controlling that can be used | 24 | /* This is a minimal implementation of TX rate controlling that can be used |
@@ -121,6 +122,11 @@ struct sta_rate_control { | |||
121 | unsigned long avg_rate_update; | 122 | unsigned long avg_rate_update; |
122 | u32 tx_avg_rate_sum; | 123 | u32 tx_avg_rate_sum; |
123 | u32 tx_avg_rate_num; | 124 | u32 tx_avg_rate_num; |
125 | |||
126 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
127 | struct dentry *tx_avg_rate_sum_dentry; | ||
128 | struct dentry *tx_avg_rate_num_dentry; | ||
129 | #endif | ||
124 | }; | 130 | }; |
125 | 131 | ||
126 | 132 | ||
@@ -327,6 +333,67 @@ static void rate_control_simple_free_sta(void *priv, void *priv_sta) | |||
327 | kfree(rctrl); | 333 | kfree(rctrl); |
328 | } | 334 | } |
329 | 335 | ||
336 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
337 | |||
338 | static int open_file_generic(struct inode *inode, struct file *file) | ||
339 | { | ||
340 | file->private_data = inode->i_private; | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static ssize_t sta_tx_avg_rate_sum_read(struct file *file, | ||
345 | char __user *userbuf, | ||
346 | size_t count, loff_t *ppos) | ||
347 | { | ||
348 | struct sta_rate_control *srctrl = file->private_data; | ||
349 | char buf[20]; | ||
350 | |||
351 | sprintf(buf, "%d\n", srctrl->tx_avg_rate_sum); | ||
352 | return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); | ||
353 | } | ||
354 | |||
355 | static const struct file_operations sta_tx_avg_rate_sum_ops = { | ||
356 | .read = sta_tx_avg_rate_sum_read, | ||
357 | .open = open_file_generic, | ||
358 | }; | ||
359 | |||
360 | static ssize_t sta_tx_avg_rate_num_read(struct file *file, | ||
361 | char __user *userbuf, | ||
362 | size_t count, loff_t *ppos) | ||
363 | { | ||
364 | struct sta_rate_control *srctrl = file->private_data; | ||
365 | char buf[20]; | ||
366 | |||
367 | sprintf(buf, "%d\n", srctrl->tx_avg_rate_num); | ||
368 | return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); | ||
369 | } | ||
370 | |||
371 | static const struct file_operations sta_tx_avg_rate_num_ops = { | ||
372 | .read = sta_tx_avg_rate_num_read, | ||
373 | .open = open_file_generic, | ||
374 | }; | ||
375 | |||
376 | static void rate_control_simple_add_sta_debugfs(void *priv, void *priv_sta, | ||
377 | struct dentry *dir) | ||
378 | { | ||
379 | struct sta_rate_control *srctrl = priv_sta; | ||
380 | |||
381 | srctrl->tx_avg_rate_num_dentry = | ||
382 | debugfs_create_file("rc_simple_sta_tx_avg_rate_num", 0400, | ||
383 | dir, srctrl, &sta_tx_avg_rate_num_ops); | ||
384 | srctrl->tx_avg_rate_sum_dentry = | ||
385 | debugfs_create_file("rc_simple_sta_tx_avg_rate_sum", 0400, | ||
386 | dir, srctrl, &sta_tx_avg_rate_sum_ops); | ||
387 | } | ||
388 | |||
389 | static void rate_control_simple_remove_sta_debugfs(void *priv, void *priv_sta) | ||
390 | { | ||
391 | struct sta_rate_control *srctrl = priv_sta; | ||
392 | |||
393 | debugfs_remove(srctrl->tx_avg_rate_sum_dentry); | ||
394 | debugfs_remove(srctrl->tx_avg_rate_num_dentry); | ||
395 | } | ||
396 | #endif | ||
330 | 397 | ||
331 | static struct rate_control_ops rate_control_simple = { | 398 | static struct rate_control_ops rate_control_simple = { |
332 | .module = THIS_MODULE, | 399 | .module = THIS_MODULE, |
@@ -339,6 +406,10 @@ static struct rate_control_ops rate_control_simple = { | |||
339 | .free = rate_control_simple_free, | 406 | .free = rate_control_simple_free, |
340 | .alloc_sta = rate_control_simple_alloc_sta, | 407 | .alloc_sta = rate_control_simple_alloc_sta, |
341 | .free_sta = rate_control_simple_free_sta, | 408 | .free_sta = rate_control_simple_free_sta, |
409 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
410 | .add_sta_debugfs = rate_control_simple_add_sta_debugfs, | ||
411 | .remove_sta_debugfs = rate_control_simple_remove_sta_debugfs, | ||
412 | #endif | ||
342 | }; | 413 | }; |
343 | 414 | ||
344 | 415 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index cddaf578dc8f..ab7b1f067c6e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -19,6 +19,8 @@ | |||
19 | #include "ieee80211_i.h" | 19 | #include "ieee80211_i.h" |
20 | #include "ieee80211_rate.h" | 20 | #include "ieee80211_rate.h" |
21 | #include "sta_info.h" | 21 | #include "sta_info.h" |
22 | #include "debugfs_key.h" | ||
23 | #include "debugfs_sta.h" | ||
22 | 24 | ||
23 | /* Caller must hold local->sta_lock */ | 25 | /* Caller must hold local->sta_lock */ |
24 | static void sta_info_hash_add(struct ieee80211_local *local, | 26 | static void sta_info_hash_add(struct ieee80211_local *local, |
@@ -120,6 +122,8 @@ static void sta_info_release(struct kref *kref) | |||
120 | } | 122 | } |
121 | rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); | 123 | rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); |
122 | rate_control_put(sta->rate_ctrl); | 124 | rate_control_put(sta->rate_ctrl); |
125 | if (sta->key) | ||
126 | ieee80211_debugfs_key_sta_del(sta->key, sta); | ||
123 | kfree(sta); | 127 | kfree(sta); |
124 | } | 128 | } |
125 | 129 | ||
@@ -173,9 +177,42 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, | |||
173 | local->mdev->name, MAC_ARG(addr)); | 177 | local->mdev->name, MAC_ARG(addr)); |
174 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 178 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
175 | 179 | ||
180 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
181 | if (!in_interrupt()) { | ||
182 | sta->debugfs_registered = 1; | ||
183 | ieee80211_sta_debugfs_add(sta); | ||
184 | rate_control_add_sta_debugfs(sta); | ||
185 | } else { | ||
186 | /* debugfs entry adding might sleep, so schedule process | ||
187 | * context task for adding entry for STAs that do not yet | ||
188 | * have one. */ | ||
189 | queue_work(local->hw.workqueue, &local->sta_debugfs_add); | ||
190 | } | ||
191 | #endif | ||
192 | |||
176 | return sta; | 193 | return sta; |
177 | } | 194 | } |
178 | 195 | ||
196 | static void finish_sta_info_free(struct ieee80211_local *local, | ||
197 | struct sta_info *sta) | ||
198 | { | ||
199 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
200 | printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n", | ||
201 | local->mdev->name, MAC_ARG(sta->addr)); | ||
202 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
203 | |||
204 | if (sta->key) { | ||
205 | ieee80211_debugfs_key_remove(sta->key); | ||
206 | ieee80211_key_free(sta->key); | ||
207 | sta->key = NULL; | ||
208 | } | ||
209 | |||
210 | rate_control_remove_sta_debugfs(sta); | ||
211 | ieee80211_sta_debugfs_remove(sta); | ||
212 | |||
213 | sta_info_put(sta); | ||
214 | } | ||
215 | |||
179 | static void sta_info_remove(struct sta_info *sta) | 216 | static void sta_info_remove(struct sta_info *sta) |
180 | { | 217 | { |
181 | struct ieee80211_local *local = sta->local; | 218 | struct ieee80211_local *local = sta->local; |
@@ -239,17 +276,13 @@ void sta_info_free(struct sta_info *sta, int locked) | |||
239 | sta->key_idx_compression = HW_KEY_IDX_INVALID; | 276 | sta->key_idx_compression = HW_KEY_IDX_INVALID; |
240 | } | 277 | } |
241 | 278 | ||
242 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 279 | #ifdef CONFIG_MAC80211_DEBUGFS |
243 | printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n", | 280 | if (in_atomic()) { |
244 | local->mdev->name, MAC_ARG(sta->addr)); | 281 | list_add(&sta->list, &local->deleted_sta_list); |
245 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 282 | queue_work(local->hw.workqueue, &local->sta_debugfs_add); |
246 | 283 | } else | |
247 | if (sta->key) { | 284 | #endif |
248 | ieee80211_key_free(sta->key); | 285 | finish_sta_info_free(local, sta); |
249 | sta->key = NULL; | ||
250 | } | ||
251 | |||
252 | sta_info_put(sta); | ||
253 | } | 286 | } |
254 | 287 | ||
255 | 288 | ||
@@ -322,6 +355,50 @@ static void sta_info_cleanup(unsigned long data) | |||
322 | add_timer(&local->sta_cleanup); | 355 | add_timer(&local->sta_cleanup); |
323 | } | 356 | } |
324 | 357 | ||
358 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
359 | static void sta_info_debugfs_add_task(struct work_struct *work) | ||
360 | { | ||
361 | struct ieee80211_local *local = | ||
362 | container_of(work, struct ieee80211_local, sta_debugfs_add); | ||
363 | struct sta_info *sta, *tmp; | ||
364 | |||
365 | while (1) { | ||
366 | spin_lock_bh(&local->sta_lock); | ||
367 | if (!list_empty(&local->deleted_sta_list)) { | ||
368 | sta = list_entry(local->deleted_sta_list.next, | ||
369 | struct sta_info, list); | ||
370 | list_del(local->deleted_sta_list.next); | ||
371 | } else | ||
372 | sta = NULL; | ||
373 | spin_unlock_bh(&local->sta_lock); | ||
374 | if (!sta) | ||
375 | break; | ||
376 | finish_sta_info_free(local, sta); | ||
377 | } | ||
378 | |||
379 | while (1) { | ||
380 | sta = NULL; | ||
381 | spin_lock_bh(&local->sta_lock); | ||
382 | list_for_each_entry(tmp, &local->sta_list, list) { | ||
383 | if (!tmp->debugfs_registered) { | ||
384 | sta = tmp; | ||
385 | __sta_info_get(sta); | ||
386 | break; | ||
387 | } | ||
388 | } | ||
389 | spin_unlock_bh(&local->sta_lock); | ||
390 | |||
391 | if (!sta) | ||
392 | break; | ||
393 | |||
394 | sta->debugfs_registered = 1; | ||
395 | ieee80211_sta_debugfs_add(sta); | ||
396 | rate_control_add_sta_debugfs(sta); | ||
397 | sta_info_put(sta); | ||
398 | } | ||
399 | } | ||
400 | #endif | ||
401 | |||
325 | void sta_info_init(struct ieee80211_local *local) | 402 | void sta_info_init(struct ieee80211_local *local) |
326 | { | 403 | { |
327 | spin_lock_init(&local->sta_lock); | 404 | spin_lock_init(&local->sta_lock); |
@@ -332,6 +409,10 @@ void sta_info_init(struct ieee80211_local *local) | |||
332 | local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; | 409 | local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; |
333 | local->sta_cleanup.data = (unsigned long) local; | 410 | local->sta_cleanup.data = (unsigned long) local; |
334 | local->sta_cleanup.function = sta_info_cleanup; | 411 | local->sta_cleanup.function = sta_info_cleanup; |
412 | |||
413 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
414 | INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_task); | ||
415 | #endif | ||
335 | } | 416 | } |
336 | 417 | ||
337 | int sta_info_start(struct ieee80211_local *local) | 418 | int sta_info_start(struct ieee80211_local *local) |
@@ -347,7 +428,10 @@ void sta_info_stop(struct ieee80211_local *local) | |||
347 | del_timer(&local->sta_cleanup); | 428 | del_timer(&local->sta_cleanup); |
348 | 429 | ||
349 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { | 430 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { |
350 | /* We don't need locking at this point. */ | 431 | /* sta_info_free must be called with 0 as the last |
432 | * parameter to ensure all debugfs sta entries are | ||
433 | * unregistered. We don't need locking at this | ||
434 | * point. */ | ||
351 | sta_info_free(sta, 0); | 435 | sta_info_free(sta, 0); |
352 | } | 436 | } |
353 | } | 437 | } |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index f26e1c294395..b5591d2f60a4 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -98,6 +98,9 @@ struct sta_info { | |||
98 | * filtering; used only if sta->key is not | 98 | * filtering; used only if sta->key is not |
99 | * set */ | 99 | * set */ |
100 | 100 | ||
101 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
102 | int debugfs_registered; | ||
103 | #endif | ||
101 | int assoc_ap; /* whether this is an AP that we are | 104 | int assoc_ap; /* whether this is an AP that we are |
102 | * associated with as a client */ | 105 | * associated with as a client */ |
103 | 106 | ||
@@ -109,6 +112,22 @@ struct sta_info { | |||
109 | int vlan_id; | 112 | int vlan_id; |
110 | 113 | ||
111 | u16 listen_interval; | 114 | u16 listen_interval; |
115 | |||
116 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
117 | struct sta_info_debugfsdentries { | ||
118 | struct dentry *dir; | ||
119 | struct dentry *flags; | ||
120 | struct dentry *num_ps_buf_frames; | ||
121 | struct dentry *last_ack_rssi; | ||
122 | struct dentry *last_ack_ms; | ||
123 | struct dentry *inactive_ms; | ||
124 | struct dentry *last_seq_ctrl; | ||
125 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
126 | struct dentry *wme_rx_queue; | ||
127 | struct dentry *wme_tx_queue; | ||
128 | #endif | ||
129 | } debugfs; | ||
130 | #endif | ||
112 | }; | 131 | }; |
113 | 132 | ||
114 | 133 | ||