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