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_algs, u.mgd.auth_algs, HEX); 109 IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC); 110 IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC); 111 112 static 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 */ 127 IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); 128 IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); 129 130 static 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 */ 139 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); 140 141 #ifdef CONFIG_MAC80211_MESH 142 /* Mesh stats attributes */ 143 IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC); 144 IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC); 145 IEEE80211_IF_FILE(dropped_frames_no_route, 146 u.mesh.mshstats.dropped_frames_no_route, DEC); 147 IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC); 148 149 /* Mesh parameters */ 150 IEEE80211_IF_FILE(dot11MeshMaxRetries, 151 u.mesh.mshcfg.dot11MeshMaxRetries, DEC); 152 IEEE80211_IF_FILE(dot11MeshRetryTimeout, 153 u.mesh.mshcfg.dot11MeshRetryTimeout, DEC); 154 IEEE80211_IF_FILE(dot11MeshConfirmTimeout, 155 u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC); 156 IEEE80211_IF_FILE(dot11MeshHoldingTimeout, 157 u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC); 158 IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC); 159 IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC); 160 IEEE80211_IF_FILE(dot11MeshMaxPeerLinks, 161 u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC); 162 IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout, 163 u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC); 164 IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval, 165 u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC); 166 IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime, 167 u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC); 168 IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries, 169 u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC); 170 IEEE80211_IF_FILE(path_refresh_time, 171 u.mesh.mshcfg.path_refresh_time, DEC); 172 IEEE80211_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 181 static 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 203 static 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 214 static 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 223 static 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 230 static 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 239 static 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 253 static 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 273 static 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 314 static 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 336 static 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 347 static 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 356 static 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 363 static 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 374 static 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 390 static 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 410 static 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 445 static int notif_registered; 446 447 void 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 460 void 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 467 static 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 500 static struct notifier_block mac80211_debugfs_netdev_notifier = { 501 .notifier_call = netdev_notify, 502 }; 503 504 void 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 517 void ieee80211_debugfs_netdev_exit(void) 518 { 519 unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier); 520 notif_registered = 0; 521 } 522