cfg80211: keep track of BSSes
[deliverable/linux.git] / net / mac80211 / debugfs_netdev.c
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 "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 read_unlock(&dev_base_lock);
37
38 if (ret != -EINVAL)
39 ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
40
41 return ret;
42 }
43
44 #define IEEE80211_IF_FMT(name, field, format_string) \
45 static ssize_t ieee80211_if_fmt_##name( \
46 const struct ieee80211_sub_if_data *sdata, char *buf, \
47 int buflen) \
48 { \
49 return scnprintf(buf, buflen, format_string, sdata->field); \
50 }
51 #define IEEE80211_IF_FMT_DEC(name, field) \
52 IEEE80211_IF_FMT(name, field, "%d\n")
53 #define IEEE80211_IF_FMT_HEX(name, field) \
54 IEEE80211_IF_FMT(name, field, "%#x\n")
55 #define IEEE80211_IF_FMT_SIZE(name, field) \
56 IEEE80211_IF_FMT(name, field, "%zd\n")
57
58 #define IEEE80211_IF_FMT_ATOMIC(name, field) \
59 static ssize_t ieee80211_if_fmt_##name( \
60 const struct ieee80211_sub_if_data *sdata, \
61 char *buf, int buflen) \
62 { \
63 return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\
64 }
65
66 #define IEEE80211_IF_FMT_MAC(name, field) \
67 static ssize_t ieee80211_if_fmt_##name( \
68 const struct ieee80211_sub_if_data *sdata, char *buf, \
69 int buflen) \
70 { \
71 return scnprintf(buf, buflen, "%pM\n", sdata->field); \
72 }
73
74 #define __IEEE80211_IF_FILE(name) \
75 static ssize_t ieee80211_if_read_##name(struct file *file, \
76 char __user *userbuf, \
77 size_t count, loff_t *ppos) \
78 { \
79 return ieee80211_if_read(file->private_data, \
80 userbuf, count, ppos, \
81 ieee80211_if_fmt_##name); \
82 } \
83 static const struct file_operations name##_ops = { \
84 .read = ieee80211_if_read_##name, \
85 .open = mac80211_open_file_generic, \
86 }
87
88 #define IEEE80211_IF_FILE(name, field, format) \
89 IEEE80211_IF_FMT_##format(name, field) \
90 __IEEE80211_IF_FILE(name)
91
92 /* common attributes */
93 IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
94 IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
95 IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
96
97 /* STA attributes */
98 IEEE80211_IF_FILE(state, u.mgd.state, DEC);
99 IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
100 IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC);
101 IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE);
102 IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
103 IEEE80211_IF_FILE(ap_capab, u.mgd.ap_capab, HEX);
104 IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
105 IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE);
106 IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC);
107 IEEE80211_IF_FILE(assoc_tries, u.mgd.assoc_tries, DEC);
108 IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC);
109 IEEE80211_IF_FILE(auth_transaction, u.mgd.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\n",
115 sdata->u.mgd.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "",
116 sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
117 sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
118 sdata->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
119 sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : "");
120 }
121 __IEEE80211_IF_FILE(flags);
122
123 /* AP attributes */
124 IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
125 IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
126
127 static ssize_t ieee80211_if_fmt_num_buffered_multicast(
128 const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
129 {
130 return scnprintf(buf, buflen, "%u\n",
131 skb_queue_len(&sdata->u.ap.ps_bc_buf));
132 }
133 __IEEE80211_IF_FILE(num_buffered_multicast);
134
135 /* WDS attributes */
136 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
137
138 #ifdef CONFIG_MAC80211_MESH
139 /* Mesh stats attributes */
140 IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
141 IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
142 IEEE80211_IF_FILE(dropped_frames_no_route,
143 u.mesh.mshstats.dropped_frames_no_route, DEC);
144 IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);
145
146 /* Mesh parameters */
147 IEEE80211_IF_FILE(dot11MeshMaxRetries,
148 u.mesh.mshcfg.dot11MeshMaxRetries, DEC);
149 IEEE80211_IF_FILE(dot11MeshRetryTimeout,
150 u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);
151 IEEE80211_IF_FILE(dot11MeshConfirmTimeout,
152 u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);
153 IEEE80211_IF_FILE(dot11MeshHoldingTimeout,
154 u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
155 IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC);
156 IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC);
157 IEEE80211_IF_FILE(dot11MeshMaxPeerLinks,
158 u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
159 IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout,
160 u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
161 IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval,
162 u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
163 IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime,
164 u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
165 IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries,
166 u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);
167 IEEE80211_IF_FILE(path_refresh_time,
168 u.mesh.mshcfg.path_refresh_time, DEC);
169 IEEE80211_IF_FILE(min_discovery_timeout,
170 u.mesh.mshcfg.min_discovery_timeout, DEC);
171 #endif
172
173
174 #define DEBUGFS_ADD(name, type)\
175 sdata->debugfs.type.name = debugfs_create_file(#name, 0400,\
176 sdata->debugfsdir, sdata, &name##_ops);
177
178 static void add_sta_files(struct ieee80211_sub_if_data *sdata)
179 {
180 DEBUGFS_ADD(drop_unencrypted, sta);
181 DEBUGFS_ADD(force_unicast_rateidx, sta);
182 DEBUGFS_ADD(max_ratectrl_rateidx, sta);
183
184 DEBUGFS_ADD(state, sta);
185 DEBUGFS_ADD(bssid, sta);
186 DEBUGFS_ADD(prev_bssid, sta);
187 DEBUGFS_ADD(ssid_len, sta);
188 DEBUGFS_ADD(aid, sta);
189 DEBUGFS_ADD(ap_capab, sta);
190 DEBUGFS_ADD(capab, sta);
191 DEBUGFS_ADD(extra_ie_len, sta);
192 DEBUGFS_ADD(auth_tries, sta);
193 DEBUGFS_ADD(assoc_tries, sta);
194 DEBUGFS_ADD(auth_alg, sta);
195 DEBUGFS_ADD(auth_transaction, sta);
196 DEBUGFS_ADD(flags, sta);
197 }
198
199 static void add_ap_files(struct ieee80211_sub_if_data *sdata)
200 {
201 DEBUGFS_ADD(drop_unencrypted, ap);
202 DEBUGFS_ADD(force_unicast_rateidx, ap);
203 DEBUGFS_ADD(max_ratectrl_rateidx, ap);
204
205 DEBUGFS_ADD(num_sta_ps, ap);
206 DEBUGFS_ADD(dtim_count, ap);
207 DEBUGFS_ADD(num_buffered_multicast, ap);
208 }
209
210 static void add_wds_files(struct ieee80211_sub_if_data *sdata)
211 {
212 DEBUGFS_ADD(drop_unencrypted, wds);
213 DEBUGFS_ADD(force_unicast_rateidx, wds);
214 DEBUGFS_ADD(max_ratectrl_rateidx, wds);
215
216 DEBUGFS_ADD(peer, wds);
217 }
218
219 static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
220 {
221 DEBUGFS_ADD(drop_unencrypted, vlan);
222 DEBUGFS_ADD(force_unicast_rateidx, vlan);
223 DEBUGFS_ADD(max_ratectrl_rateidx, vlan);
224 }
225
226 static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
227 {
228 }
229
230 #ifdef CONFIG_MAC80211_MESH
231 #define MESHSTATS_ADD(name)\
232 sdata->mesh_stats.name = debugfs_create_file(#name, 0400,\
233 sdata->mesh_stats_dir, sdata, &name##_ops);
234
235 static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
236 {
237 sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats",
238 sdata->debugfsdir);
239 MESHSTATS_ADD(fwded_frames);
240 MESHSTATS_ADD(dropped_frames_ttl);
241 MESHSTATS_ADD(dropped_frames_no_route);
242 MESHSTATS_ADD(estab_plinks);
243 }
244
245 #define MESHPARAMS_ADD(name)\
246 sdata->mesh_config.name = debugfs_create_file(#name, 0600,\
247 sdata->mesh_config_dir, sdata, &name##_ops);
248
249 static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
250 {
251 sdata->mesh_config_dir = debugfs_create_dir("mesh_config",
252 sdata->debugfsdir);
253 MESHPARAMS_ADD(dot11MeshMaxRetries);
254 MESHPARAMS_ADD(dot11MeshRetryTimeout);
255 MESHPARAMS_ADD(dot11MeshConfirmTimeout);
256 MESHPARAMS_ADD(dot11MeshHoldingTimeout);
257 MESHPARAMS_ADD(dot11MeshTTL);
258 MESHPARAMS_ADD(auto_open_plinks);
259 MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
260 MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
261 MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval);
262 MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime);
263 MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
264 MESHPARAMS_ADD(path_refresh_time);
265 MESHPARAMS_ADD(min_discovery_timeout);
266 }
267 #endif
268
269 static void add_files(struct ieee80211_sub_if_data *sdata)
270 {
271 if (!sdata->debugfsdir)
272 return;
273
274 switch (sdata->vif.type) {
275 case NL80211_IFTYPE_MESH_POINT:
276 #ifdef CONFIG_MAC80211_MESH
277 add_mesh_stats(sdata);
278 add_mesh_config(sdata);
279 #endif
280 break;
281 case NL80211_IFTYPE_STATION:
282 add_sta_files(sdata);
283 break;
284 case NL80211_IFTYPE_ADHOC:
285 /* XXX */
286 break;
287 case NL80211_IFTYPE_AP:
288 add_ap_files(sdata);
289 break;
290 case NL80211_IFTYPE_WDS:
291 add_wds_files(sdata);
292 break;
293 case NL80211_IFTYPE_MONITOR:
294 add_monitor_files(sdata);
295 break;
296 case NL80211_IFTYPE_AP_VLAN:
297 add_vlan_files(sdata);
298 break;
299 default:
300 break;
301 }
302 }
303
304 #define DEBUGFS_DEL(name, type) \
305 do { \
306 debugfs_remove(sdata->debugfs.type.name); \
307 sdata->debugfs.type.name = NULL; \
308 } while (0)
309
310 static void del_sta_files(struct ieee80211_sub_if_data *sdata)
311 {
312 DEBUGFS_DEL(drop_unencrypted, sta);
313 DEBUGFS_DEL(force_unicast_rateidx, sta);
314 DEBUGFS_DEL(max_ratectrl_rateidx, sta);
315
316 DEBUGFS_DEL(state, sta);
317 DEBUGFS_DEL(bssid, sta);
318 DEBUGFS_DEL(prev_bssid, sta);
319 DEBUGFS_DEL(ssid_len, sta);
320 DEBUGFS_DEL(aid, sta);
321 DEBUGFS_DEL(ap_capab, sta);
322 DEBUGFS_DEL(capab, sta);
323 DEBUGFS_DEL(extra_ie_len, sta);
324 DEBUGFS_DEL(auth_tries, sta);
325 DEBUGFS_DEL(assoc_tries, sta);
326 DEBUGFS_DEL(auth_alg, sta);
327 DEBUGFS_DEL(auth_transaction, sta);
328 DEBUGFS_DEL(flags, sta);
329 }
330
331 static void del_ap_files(struct ieee80211_sub_if_data *sdata)
332 {
333 DEBUGFS_DEL(drop_unencrypted, ap);
334 DEBUGFS_DEL(force_unicast_rateidx, ap);
335 DEBUGFS_DEL(max_ratectrl_rateidx, ap);
336
337 DEBUGFS_DEL(num_sta_ps, ap);
338 DEBUGFS_DEL(dtim_count, ap);
339 DEBUGFS_DEL(num_buffered_multicast, ap);
340 }
341
342 static void del_wds_files(struct ieee80211_sub_if_data *sdata)
343 {
344 DEBUGFS_DEL(drop_unencrypted, wds);
345 DEBUGFS_DEL(force_unicast_rateidx, wds);
346 DEBUGFS_DEL(max_ratectrl_rateidx, wds);
347
348 DEBUGFS_DEL(peer, wds);
349 }
350
351 static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
352 {
353 DEBUGFS_DEL(drop_unencrypted, vlan);
354 DEBUGFS_DEL(force_unicast_rateidx, vlan);
355 DEBUGFS_DEL(max_ratectrl_rateidx, vlan);
356 }
357
358 static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
359 {
360 }
361
362 #ifdef CONFIG_MAC80211_MESH
363 #define MESHSTATS_DEL(name) \
364 do { \
365 debugfs_remove(sdata->mesh_stats.name); \
366 sdata->mesh_stats.name = NULL; \
367 } while (0)
368
369 static void del_mesh_stats(struct ieee80211_sub_if_data *sdata)
370 {
371 MESHSTATS_DEL(fwded_frames);
372 MESHSTATS_DEL(dropped_frames_ttl);
373 MESHSTATS_DEL(dropped_frames_no_route);
374 MESHSTATS_DEL(estab_plinks);
375 debugfs_remove(sdata->mesh_stats_dir);
376 sdata->mesh_stats_dir = NULL;
377 }
378
379 #define MESHPARAMS_DEL(name) \
380 do { \
381 debugfs_remove(sdata->mesh_config.name); \
382 sdata->mesh_config.name = NULL; \
383 } while (0)
384
385 static void del_mesh_config(struct ieee80211_sub_if_data *sdata)
386 {
387 MESHPARAMS_DEL(dot11MeshMaxRetries);
388 MESHPARAMS_DEL(dot11MeshRetryTimeout);
389 MESHPARAMS_DEL(dot11MeshConfirmTimeout);
390 MESHPARAMS_DEL(dot11MeshHoldingTimeout);
391 MESHPARAMS_DEL(dot11MeshTTL);
392 MESHPARAMS_DEL(auto_open_plinks);
393 MESHPARAMS_DEL(dot11MeshMaxPeerLinks);
394 MESHPARAMS_DEL(dot11MeshHWMPactivePathTimeout);
395 MESHPARAMS_DEL(dot11MeshHWMPpreqMinInterval);
396 MESHPARAMS_DEL(dot11MeshHWMPnetDiameterTraversalTime);
397 MESHPARAMS_DEL(dot11MeshHWMPmaxPREQretries);
398 MESHPARAMS_DEL(path_refresh_time);
399 MESHPARAMS_DEL(min_discovery_timeout);
400 debugfs_remove(sdata->mesh_config_dir);
401 sdata->mesh_config_dir = NULL;
402 }
403 #endif
404
405 static void del_files(struct ieee80211_sub_if_data *sdata)
406 {
407 if (!sdata->debugfsdir)
408 return;
409
410 switch (sdata->vif.type) {
411 case NL80211_IFTYPE_MESH_POINT:
412 #ifdef CONFIG_MAC80211_MESH
413 del_mesh_stats(sdata);
414 del_mesh_config(sdata);
415 #endif
416 break;
417 case NL80211_IFTYPE_STATION:
418 del_sta_files(sdata);
419 break;
420 case NL80211_IFTYPE_ADHOC:
421 /* XXX */
422 break;
423 case NL80211_IFTYPE_AP:
424 del_ap_files(sdata);
425 break;
426 case NL80211_IFTYPE_WDS:
427 del_wds_files(sdata);
428 break;
429 case NL80211_IFTYPE_MONITOR:
430 del_monitor_files(sdata);
431 break;
432 case NL80211_IFTYPE_AP_VLAN:
433 del_vlan_files(sdata);
434 break;
435 default:
436 break;
437 }
438 }
439
440 static int notif_registered;
441
442 void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
443 {
444 char buf[10+IFNAMSIZ];
445
446 if (!notif_registered)
447 return;
448
449 sprintf(buf, "netdev:%s", sdata->dev->name);
450 sdata->debugfsdir = debugfs_create_dir(buf,
451 sdata->local->hw.wiphy->debugfsdir);
452 add_files(sdata);
453 }
454
455 void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
456 {
457 del_files(sdata);
458 debugfs_remove(sdata->debugfsdir);
459 sdata->debugfsdir = NULL;
460 }
461
462 static int netdev_notify(struct notifier_block *nb,
463 unsigned long state,
464 void *ndev)
465 {
466 struct net_device *dev = ndev;
467 struct dentry *dir;
468 struct ieee80211_sub_if_data *sdata;
469 char buf[10+IFNAMSIZ];
470
471 if (state != NETDEV_CHANGENAME)
472 return 0;
473
474 if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
475 return 0;
476
477 if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
478 return 0;
479
480 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
481
482 dir = sdata->debugfsdir;
483
484 if (!dir)
485 return 0;
486
487 sprintf(buf, "netdev:%s", dev->name);
488 if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
489 printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
490 "dir to %s\n", buf);
491
492 return 0;
493 }
494
495 static struct notifier_block mac80211_debugfs_netdev_notifier = {
496 .notifier_call = netdev_notify,
497 };
498
499 void ieee80211_debugfs_netdev_init(void)
500 {
501 int err;
502
503 err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
504 if (err) {
505 printk(KERN_ERR
506 "mac80211: failed to install netdev notifier,"
507 " disabling per-netdev debugfs!\n");
508 } else
509 notif_registered = 1;
510 }
511
512 void ieee80211_debugfs_netdev_exit(void)
513 {
514 unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
515 notif_registered = 0;
516 }
This page took 0.059515 seconds and 5 git commands to generate.