mac80211: refactor debugfs function generation code
[linux-2.6.git] / net / mac80211 / debugfs.c
1
2 /*
3  * mac80211 debugfs for wireless PHYs
4  *
5  * Copyright 2007       Johannes Berg <johannes@sipsolutions.net>
6  *
7  * GPLv2
8  *
9  */
10
11 #include <linux/debugfs.h>
12 #include <linux/rtnetlink.h>
13 #include "ieee80211_i.h"
14 #include "driver-ops.h"
15 #include "rate.h"
16 #include "debugfs.h"
17
18 int mac80211_open_file_generic(struct inode *inode, struct file *file)
19 {
20         file->private_data = inode->i_private;
21         return 0;
22 }
23
24 #define DEBUGFS_FORMAT_BUFFER_SIZE 100
25
26 int mac80211_format_buffer(char __user *userbuf, size_t count,
27                                   loff_t *ppos, char *fmt, ...)
28 {
29         va_list args;
30         char buf[DEBUGFS_FORMAT_BUFFER_SIZE];
31         int res;
32
33         va_start(args, fmt);
34         res = vscnprintf(buf, sizeof(buf), fmt, args);
35         va_end(args);
36
37         return simple_read_from_buffer(userbuf, count, ppos, buf, res);
38 }
39
40 #define DEBUGFS_READONLY_FILE(name, fmt, value...)                      \
41 static ssize_t name## _read(struct file *file, char __user *userbuf,    \
42                             size_t count, loff_t *ppos)                 \
43 {                                                                       \
44         struct ieee80211_local *local = file->private_data;             \
45                                                                         \
46         return mac80211_format_buffer(userbuf, count, ppos,             \
47                                       fmt "\n", ##value);               \
48 }                                                                       \
49                                                                         \
50 static const struct file_operations name## _ops = {                     \
51         .read = name## _read,                                           \
52         .open = mac80211_open_file_generic,                             \
53         .llseek = generic_file_llseek,                                  \
54 };
55
56 #define DEBUGFS_ADD(name)                                               \
57         debugfs_create_file(#name, 0400, phyd, local, &name## _ops);
58
59 #define DEBUGFS_ADD_MODE(name, mode)                                    \
60         debugfs_create_file(#name, mode, phyd, local, &name## _ops);
61
62
63 DEBUGFS_READONLY_FILE(frequency, "%d",
64                       local->hw.conf.channel->center_freq);
65 DEBUGFS_READONLY_FILE(total_ps_buffered, "%d",
66                       local->total_ps_buffered);
67 DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
68                       local->wep_iv & 0xffffff);
69 DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s",
70         local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
71
72 static ssize_t tsf_read(struct file *file, char __user *user_buf,
73                              size_t count, loff_t *ppos)
74 {
75         struct ieee80211_local *local = file->private_data;
76         u64 tsf;
77
78         tsf = drv_get_tsf(local);
79
80         return mac80211_format_buffer(user_buf, count, ppos, "0x%016llx\n",
81                                       (unsigned long long) tsf);
82 }
83
84 static ssize_t tsf_write(struct file *file,
85                          const char __user *user_buf,
86                          size_t count, loff_t *ppos)
87 {
88         struct ieee80211_local *local = file->private_data;
89         unsigned long long tsf;
90         char buf[100];
91         size_t len;
92
93         len = min(count, sizeof(buf) - 1);
94         if (copy_from_user(buf, user_buf, len))
95                 return -EFAULT;
96         buf[len] = '\0';
97
98         if (strncmp(buf, "reset", 5) == 0) {
99                 if (local->ops->reset_tsf) {
100                         drv_reset_tsf(local);
101                         wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
102                 }
103         } else {
104                 tsf = simple_strtoul(buf, NULL, 0);
105                 if (local->ops->set_tsf) {
106                         drv_set_tsf(local, tsf);
107                         wiphy_info(local->hw.wiphy,
108                                    "debugfs set TSF to %#018llx\n", tsf);
109
110                 }
111         }
112
113         return count;
114 }
115
116 static const struct file_operations tsf_ops = {
117         .read = tsf_read,
118         .write = tsf_write,
119         .open = mac80211_open_file_generic,
120         .llseek = default_llseek,
121 };
122
123 static ssize_t reset_write(struct file *file, const char __user *user_buf,
124                            size_t count, loff_t *ppos)
125 {
126         struct ieee80211_local *local = file->private_data;
127
128         rtnl_lock();
129         __ieee80211_suspend(&local->hw);
130         __ieee80211_resume(&local->hw);
131         rtnl_unlock();
132
133         return count;
134 }
135
136 static const struct file_operations reset_ops = {
137         .write = reset_write,
138         .open = mac80211_open_file_generic,
139         .llseek = noop_llseek,
140 };
141
142 static ssize_t noack_read(struct file *file, char __user *user_buf,
143                           size_t count, loff_t *ppos)
144 {
145         struct ieee80211_local *local = file->private_data;
146
147         return mac80211_format_buffer(user_buf, count, ppos, "%d\n",
148                                       local->wifi_wme_noack_test);
149 }
150
151 static ssize_t noack_write(struct file *file,
152                            const char __user *user_buf,
153                            size_t count, loff_t *ppos)
154 {
155         struct ieee80211_local *local = file->private_data;
156         char buf[10];
157         size_t len;
158
159         len = min(count, sizeof(buf) - 1);
160         if (copy_from_user(buf, user_buf, len))
161                 return -EFAULT;
162         buf[len] = '\0';
163
164         local->wifi_wme_noack_test = !!simple_strtoul(buf, NULL, 0);
165
166         return count;
167 }
168
169 static const struct file_operations noack_ops = {
170         .read = noack_read,
171         .write = noack_write,
172         .open = mac80211_open_file_generic,
173         .llseek = default_llseek,
174 };
175
176 static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf,
177                                  size_t count, loff_t *ppos)
178 {
179         struct ieee80211_local *local = file->private_data;
180         return mac80211_format_buffer(user_buf, count, ppos, "0x%x\n",
181                                       local->uapsd_queues);
182 }
183
184 static ssize_t uapsd_queues_write(struct file *file,
185                                   const char __user *user_buf,
186                                   size_t count, loff_t *ppos)
187 {
188         struct ieee80211_local *local = file->private_data;
189         unsigned long val;
190         char buf[10];
191         size_t len;
192         int ret;
193
194         len = min(count, sizeof(buf) - 1);
195         if (copy_from_user(buf, user_buf, len))
196                 return -EFAULT;
197         buf[len] = '\0';
198
199         ret = strict_strtoul(buf, 0, &val);
200
201         if (ret)
202                 return -EINVAL;
203
204         if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
205                 return -ERANGE;
206
207         local->uapsd_queues = val;
208
209         return count;
210 }
211
212 static const struct file_operations uapsd_queues_ops = {
213         .read = uapsd_queues_read,
214         .write = uapsd_queues_write,
215         .open = mac80211_open_file_generic,
216         .llseek = default_llseek,
217 };
218
219 static ssize_t uapsd_max_sp_len_read(struct file *file, char __user *user_buf,
220                                      size_t count, loff_t *ppos)
221 {
222         struct ieee80211_local *local = file->private_data;
223
224         return mac80211_format_buffer(user_buf, count, ppos, "0x%x\n",
225                                       local->uapsd_max_sp_len);
226 }
227
228 static ssize_t uapsd_max_sp_len_write(struct file *file,
229                                       const char __user *user_buf,
230                                       size_t count, loff_t *ppos)
231 {
232         struct ieee80211_local *local = file->private_data;
233         unsigned long val;
234         char buf[10];
235         size_t len;
236         int ret;
237
238         len = min(count, sizeof(buf) - 1);
239         if (copy_from_user(buf, user_buf, len))
240                 return -EFAULT;
241         buf[len] = '\0';
242
243         ret = strict_strtoul(buf, 0, &val);
244
245         if (ret)
246                 return -EINVAL;
247
248         if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
249                 return -ERANGE;
250
251         local->uapsd_max_sp_len = val;
252
253         return count;
254 }
255
256 static const struct file_operations uapsd_max_sp_len_ops = {
257         .read = uapsd_max_sp_len_read,
258         .write = uapsd_max_sp_len_write,
259         .open = mac80211_open_file_generic,
260         .llseek = default_llseek,
261 };
262
263 static ssize_t channel_type_read(struct file *file, char __user *user_buf,
264                        size_t count, loff_t *ppos)
265 {
266         struct ieee80211_local *local = file->private_data;
267         const char *buf;
268
269         switch (local->hw.conf.channel_type) {
270         case NL80211_CHAN_NO_HT:
271                 buf = "no ht\n";
272                 break;
273         case NL80211_CHAN_HT20:
274                 buf = "ht20\n";
275                 break;
276         case NL80211_CHAN_HT40MINUS:
277                 buf = "ht40-\n";
278                 break;
279         case NL80211_CHAN_HT40PLUS:
280                 buf = "ht40+\n";
281                 break;
282         default:
283                 buf = "???";
284                 break;
285         }
286
287         return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
288 }
289
290 static const struct file_operations channel_type_ops = {
291         .read = channel_type_read,
292         .open = mac80211_open_file_generic,
293         .llseek = default_llseek,
294 };
295
296 static ssize_t queues_read(struct file *file, char __user *user_buf,
297                            size_t count, loff_t *ppos)
298 {
299         struct ieee80211_local *local = file->private_data;
300         unsigned long flags;
301         char buf[IEEE80211_MAX_QUEUES * 20];
302         int q, res = 0;
303
304         spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
305         for (q = 0; q < local->hw.queues; q++)
306                 res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q,
307                                 local->queue_stop_reasons[q],
308                                 skb_queue_len(&local->pending[q]));
309         spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
310
311         return simple_read_from_buffer(user_buf, count, ppos, buf, res);
312 }
313
314 static const struct file_operations queues_ops = {
315         .read = queues_read,
316         .open = mac80211_open_file_generic,
317         .llseek = default_llseek,
318 };
319
320 /* statistics stuff */
321
322 static ssize_t format_devstat_counter(struct ieee80211_local *local,
323         char __user *userbuf,
324         size_t count, loff_t *ppos,
325         int (*printvalue)(struct ieee80211_low_level_stats *stats, char *buf,
326                           int buflen))
327 {
328         struct ieee80211_low_level_stats stats;
329         char buf[20];
330         int res;
331
332         rtnl_lock();
333         res = drv_get_stats(local, &stats);
334         rtnl_unlock();
335         if (res)
336                 return res;
337         res = printvalue(&stats, buf, sizeof(buf));
338         return simple_read_from_buffer(userbuf, count, ppos, buf, res);
339 }
340
341 #define DEBUGFS_DEVSTATS_FILE(name)                                     \
342 static int print_devstats_##name(struct ieee80211_low_level_stats *stats,\
343                                  char *buf, int buflen)                 \
344 {                                                                       \
345         return scnprintf(buf, buflen, "%u\n", stats->name);             \
346 }                                                                       \
347 static ssize_t stats_ ##name## _read(struct file *file,                 \
348                                      char __user *userbuf,              \
349                                      size_t count, loff_t *ppos)        \
350 {                                                                       \
351         return format_devstat_counter(file->private_data,               \
352                                       userbuf,                          \
353                                       count,                            \
354                                       ppos,                             \
355                                       print_devstats_##name);           \
356 }                                                                       \
357                                                                         \
358 static const struct file_operations stats_ ##name## _ops = {            \
359         .read = stats_ ##name## _read,                                  \
360         .open = mac80211_open_file_generic,                             \
361         .llseek = generic_file_llseek,                                  \
362 };
363
364 #define DEBUGFS_STATS_ADD(name, field)                                  \
365         debugfs_create_u32(#name, 0400, statsd, (u32 *) &field);
366 #define DEBUGFS_DEVSTATS_ADD(name)                                      \
367         debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops);
368
369 DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount);
370 DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount);
371 DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount);
372 DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount);
373
374 void debugfs_hw_add(struct ieee80211_local *local)
375 {
376         struct dentry *phyd = local->hw.wiphy->debugfsdir;
377         struct dentry *statsd;
378
379         if (!phyd)
380                 return;
381
382         local->debugfs.keys = debugfs_create_dir("keys", phyd);
383
384         DEBUGFS_ADD(frequency);
385         DEBUGFS_ADD(total_ps_buffered);
386         DEBUGFS_ADD(wep_iv);
387         DEBUGFS_ADD(tsf);
388         DEBUGFS_ADD(queues);
389         DEBUGFS_ADD_MODE(reset, 0200);
390         DEBUGFS_ADD(noack);
391         DEBUGFS_ADD(uapsd_queues);
392         DEBUGFS_ADD(uapsd_max_sp_len);
393         DEBUGFS_ADD(channel_type);
394
395         statsd = debugfs_create_dir("statistics", phyd);
396
397         /* if the dir failed, don't put all the other things into the root! */
398         if (!statsd)
399                 return;
400
401         DEBUGFS_STATS_ADD(transmitted_fragment_count,
402                 local->dot11TransmittedFragmentCount);
403         DEBUGFS_STATS_ADD(multicast_transmitted_frame_count,
404                 local->dot11MulticastTransmittedFrameCount);
405         DEBUGFS_STATS_ADD(failed_count, local->dot11FailedCount);
406         DEBUGFS_STATS_ADD(retry_count, local->dot11RetryCount);
407         DEBUGFS_STATS_ADD(multiple_retry_count,
408                 local->dot11MultipleRetryCount);
409         DEBUGFS_STATS_ADD(frame_duplicate_count,
410                 local->dot11FrameDuplicateCount);
411         DEBUGFS_STATS_ADD(received_fragment_count,
412                 local->dot11ReceivedFragmentCount);
413         DEBUGFS_STATS_ADD(multicast_received_frame_count,
414                 local->dot11MulticastReceivedFrameCount);
415         DEBUGFS_STATS_ADD(transmitted_frame_count,
416                 local->dot11TransmittedFrameCount);
417 #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
418         DEBUGFS_STATS_ADD(tx_handlers_drop, local->tx_handlers_drop);
419         DEBUGFS_STATS_ADD(tx_handlers_queued, local->tx_handlers_queued);
420         DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted,
421                 local->tx_handlers_drop_unencrypted);
422         DEBUGFS_STATS_ADD(tx_handlers_drop_fragment,
423                 local->tx_handlers_drop_fragment);
424         DEBUGFS_STATS_ADD(tx_handlers_drop_wep,
425                 local->tx_handlers_drop_wep);
426         DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc,
427                 local->tx_handlers_drop_not_assoc);
428         DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port,
429                 local->tx_handlers_drop_unauth_port);
430         DEBUGFS_STATS_ADD(rx_handlers_drop, local->rx_handlers_drop);
431         DEBUGFS_STATS_ADD(rx_handlers_queued, local->rx_handlers_queued);
432         DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc,
433                 local->rx_handlers_drop_nullfunc);
434         DEBUGFS_STATS_ADD(rx_handlers_drop_defrag,
435                 local->rx_handlers_drop_defrag);
436         DEBUGFS_STATS_ADD(rx_handlers_drop_short,
437                 local->rx_handlers_drop_short);
438         DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan,
439                 local->rx_handlers_drop_passive_scan);
440         DEBUGFS_STATS_ADD(tx_expand_skb_head,
441                 local->tx_expand_skb_head);
442         DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned,
443                 local->tx_expand_skb_head_cloned);
444         DEBUGFS_STATS_ADD(rx_expand_skb_head,
445                 local->rx_expand_skb_head);
446         DEBUGFS_STATS_ADD(rx_expand_skb_head2,
447                 local->rx_expand_skb_head2);
448         DEBUGFS_STATS_ADD(rx_handlers_fragments,
449                 local->rx_handlers_fragments);
450         DEBUGFS_STATS_ADD(tx_status_drop,
451                 local->tx_status_drop);
452 #endif
453         DEBUGFS_DEVSTATS_ADD(dot11ACKFailureCount);
454         DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
455         DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount);
456         DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount);
457 }