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