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 "ieee80211_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 ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret); 37 } 38 read_unlock(&dev_base_lock); 39 return ret; 40 } 41 42 #define IEEE80211_IF_FMT(name, field, format_string) \ 43 static ssize_t ieee80211_if_fmt_##name( \ 44 const struct ieee80211_sub_if_data *sdata, char *buf, \ 45 int buflen) \ 46 { \ 47 return scnprintf(buf, buflen, format_string, sdata->field); \ 48 } 49 #define IEEE80211_IF_FMT_DEC(name, field) \ 50 IEEE80211_IF_FMT(name, field, "%d\n") 51 #define IEEE80211_IF_FMT_HEX(name, field) \ 52 IEEE80211_IF_FMT(name, field, "%#x\n") 53 #define IEEE80211_IF_FMT_SIZE(name, field) \ 54 IEEE80211_IF_FMT(name, field, "%zd\n") 55 56 #define IEEE80211_IF_FMT_ATOMIC(name, field) \ 57 static ssize_t ieee80211_if_fmt_##name( \ 58 const struct ieee80211_sub_if_data *sdata, \ 59 char *buf, int buflen) \ 60 { \ 61 return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\ 62 } 63 64 #define IEEE80211_IF_FMT_MAC(name, field) \ 65 static ssize_t ieee80211_if_fmt_##name( \ 66 const struct ieee80211_sub_if_data *sdata, char *buf, \ 67 int buflen) \ 68 { \ 69 DECLARE_MAC_BUF(mac); \ 70 return scnprintf(buf, buflen, "%s\n", print_mac(mac, sdata->field));\ 71 } 72 73 #define __IEEE80211_IF_FILE(name) \ 74 static ssize_t ieee80211_if_read_##name(struct file *file, \ 75 char __user *userbuf, \ 76 size_t count, loff_t *ppos) \ 77 { \ 78 return ieee80211_if_read(file->private_data, \ 79 userbuf, count, ppos, \ 80 ieee80211_if_fmt_##name); \ 81 } \ 82 static const struct file_operations name##_ops = { \ 83 .read = ieee80211_if_read_##name, \ 84 .open = mac80211_open_file_generic, \ 85 } 86 87 #define IEEE80211_IF_FILE(name, field, format) \ 88 IEEE80211_IF_FMT_##format(name, field) \ 89 __IEEE80211_IF_FILE(name) 90 91 /* common attributes */ 92 IEEE80211_IF_FILE(channel_use, channel_use, DEC); 93 IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); 94 IEEE80211_IF_FILE(ieee802_1x_pac, ieee802_1x_pac, DEC); 95 96 /* STA/IBSS attributes */ 97 IEEE80211_IF_FILE(state, u.sta.state, DEC); 98 IEEE80211_IF_FILE(bssid, u.sta.bssid, MAC); 99 IEEE80211_IF_FILE(prev_bssid, u.sta.prev_bssid, MAC); 100 IEEE80211_IF_FILE(ssid_len, u.sta.ssid_len, SIZE); 101 IEEE80211_IF_FILE(aid, u.sta.aid, DEC); 102 IEEE80211_IF_FILE(ap_capab, u.sta.ap_capab, HEX); 103 IEEE80211_IF_FILE(capab, u.sta.capab, HEX); 104 IEEE80211_IF_FILE(extra_ie_len, u.sta.extra_ie_len, SIZE); 105 IEEE80211_IF_FILE(auth_tries, u.sta.auth_tries, DEC); 106 IEEE80211_IF_FILE(assoc_tries, u.sta.assoc_tries, DEC); 107 IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX); 108 IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC); 109 IEEE80211_IF_FILE(auth_transaction, u.sta.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%s%s\n", 115 sdata->u.sta.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "", 116 sdata->u.sta.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "", 117 sdata->u.sta.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "", 118 sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", 119 sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", 120 sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "", 121 sdata->bss_conf.use_cts_prot ? "CTS prot\n" : ""); 122 } 123 __IEEE80211_IF_FILE(flags); 124 125 /* AP attributes */ 126 IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); 127 IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); 128 IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC); 129 IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC); 130 IEEE80211_IF_FILE(max_ratectrl_rateidx, u.ap.max_ratectrl_rateidx, DEC); 131 132 static ssize_t ieee80211_if_fmt_num_buffered_multicast( 133 const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) 134 { 135 return scnprintf(buf, buflen, "%u\n", 136 skb_queue_len(&sdata->u.ap.ps_bc_buf)); 137 } 138 __IEEE80211_IF_FILE(num_buffered_multicast); 139 140 /* WDS attributes */ 141 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); 142 143 #define DEBUGFS_ADD(name, type)\ 144 sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\ 145 sdata->debugfsdir, sdata, &name##_ops); 146 147 static void add_sta_files(struct ieee80211_sub_if_data *sdata) 148 { 149 DEBUGFS_ADD(channel_use, sta); 150 DEBUGFS_ADD(drop_unencrypted, sta); 151 DEBUGFS_ADD(ieee802_1x_pac, sta); 152 DEBUGFS_ADD(state, sta); 153 DEBUGFS_ADD(bssid, sta); 154 DEBUGFS_ADD(prev_bssid, sta); 155 DEBUGFS_ADD(ssid_len, sta); 156 DEBUGFS_ADD(aid, sta); 157 DEBUGFS_ADD(ap_capab, sta); 158 DEBUGFS_ADD(capab, sta); 159 DEBUGFS_ADD(extra_ie_len, sta); 160 DEBUGFS_ADD(auth_tries, sta); 161 DEBUGFS_ADD(assoc_tries, sta); 162 DEBUGFS_ADD(auth_algs, sta); 163 DEBUGFS_ADD(auth_alg, sta); 164 DEBUGFS_ADD(auth_transaction, sta); 165 DEBUGFS_ADD(flags, sta); 166 } 167 168 static void add_ap_files(struct ieee80211_sub_if_data *sdata) 169 { 170 DEBUGFS_ADD(channel_use, ap); 171 DEBUGFS_ADD(drop_unencrypted, ap); 172 DEBUGFS_ADD(ieee802_1x_pac, ap); 173 DEBUGFS_ADD(num_sta_ps, ap); 174 DEBUGFS_ADD(dtim_count, ap); 175 DEBUGFS_ADD(num_beacons, ap); 176 DEBUGFS_ADD(force_unicast_rateidx, ap); 177 DEBUGFS_ADD(max_ratectrl_rateidx, 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(channel_use, wds); 184 DEBUGFS_ADD(drop_unencrypted, wds); 185 DEBUGFS_ADD(ieee802_1x_pac, wds); 186 DEBUGFS_ADD(peer, wds); 187 } 188 189 static void add_vlan_files(struct ieee80211_sub_if_data *sdata) 190 { 191 DEBUGFS_ADD(channel_use, vlan); 192 DEBUGFS_ADD(drop_unencrypted, vlan); 193 DEBUGFS_ADD(ieee802_1x_pac, vlan); 194 } 195 196 static void add_monitor_files(struct ieee80211_sub_if_data *sdata) 197 { 198 } 199 200 static void add_files(struct ieee80211_sub_if_data *sdata) 201 { 202 if (!sdata->debugfsdir) 203 return; 204 205 switch (sdata->vif.type) { 206 case IEEE80211_IF_TYPE_STA: 207 case IEEE80211_IF_TYPE_IBSS: 208 add_sta_files(sdata); 209 break; 210 case IEEE80211_IF_TYPE_AP: 211 add_ap_files(sdata); 212 break; 213 case IEEE80211_IF_TYPE_WDS: 214 add_wds_files(sdata); 215 break; 216 case IEEE80211_IF_TYPE_MNTR: 217 add_monitor_files(sdata); 218 break; 219 case IEEE80211_IF_TYPE_VLAN: 220 add_vlan_files(sdata); 221 break; 222 default: 223 break; 224 } 225 } 226 227 #define DEBUGFS_DEL(name, type) \ 228 do { \ 229 debugfs_remove(sdata->debugfs.type.name); \ 230 sdata->debugfs.type.name = NULL; \ 231 } while (0) 232 233 static void del_sta_files(struct ieee80211_sub_if_data *sdata) 234 { 235 DEBUGFS_DEL(channel_use, sta); 236 DEBUGFS_DEL(drop_unencrypted, sta); 237 DEBUGFS_DEL(ieee802_1x_pac, sta); 238 DEBUGFS_DEL(state, sta); 239 DEBUGFS_DEL(bssid, sta); 240 DEBUGFS_DEL(prev_bssid, sta); 241 DEBUGFS_DEL(ssid_len, sta); 242 DEBUGFS_DEL(aid, sta); 243 DEBUGFS_DEL(ap_capab, sta); 244 DEBUGFS_DEL(capab, sta); 245 DEBUGFS_DEL(extra_ie_len, sta); 246 DEBUGFS_DEL(auth_tries, sta); 247 DEBUGFS_DEL(assoc_tries, sta); 248 DEBUGFS_DEL(auth_algs, sta); 249 DEBUGFS_DEL(auth_alg, sta); 250 DEBUGFS_DEL(auth_transaction, sta); 251 DEBUGFS_DEL(flags, sta); 252 } 253 254 static void del_ap_files(struct ieee80211_sub_if_data *sdata) 255 { 256 DEBUGFS_DEL(channel_use, ap); 257 DEBUGFS_DEL(drop_unencrypted, ap); 258 DEBUGFS_DEL(ieee802_1x_pac, ap); 259 DEBUGFS_DEL(num_sta_ps, ap); 260 DEBUGFS_DEL(dtim_count, ap); 261 DEBUGFS_DEL(num_beacons, ap); 262 DEBUGFS_DEL(force_unicast_rateidx, ap); 263 DEBUGFS_DEL(max_ratectrl_rateidx, ap); 264 DEBUGFS_DEL(num_buffered_multicast, ap); 265 } 266 267 static void del_wds_files(struct ieee80211_sub_if_data *sdata) 268 { 269 DEBUGFS_DEL(channel_use, wds); 270 DEBUGFS_DEL(drop_unencrypted, wds); 271 DEBUGFS_DEL(ieee802_1x_pac, wds); 272 DEBUGFS_DEL(peer, wds); 273 } 274 275 static void del_vlan_files(struct ieee80211_sub_if_data *sdata) 276 { 277 DEBUGFS_DEL(channel_use, vlan); 278 DEBUGFS_DEL(drop_unencrypted, vlan); 279 DEBUGFS_DEL(ieee802_1x_pac, vlan); 280 } 281 282 static void del_monitor_files(struct ieee80211_sub_if_data *sdata) 283 { 284 } 285 286 static void del_files(struct ieee80211_sub_if_data *sdata, int type) 287 { 288 if (!sdata->debugfsdir) 289 return; 290 291 switch (type) { 292 case IEEE80211_IF_TYPE_STA: 293 case IEEE80211_IF_TYPE_IBSS: 294 del_sta_files(sdata); 295 break; 296 case IEEE80211_IF_TYPE_AP: 297 del_ap_files(sdata); 298 break; 299 case IEEE80211_IF_TYPE_WDS: 300 del_wds_files(sdata); 301 break; 302 case IEEE80211_IF_TYPE_MNTR: 303 del_monitor_files(sdata); 304 break; 305 case IEEE80211_IF_TYPE_VLAN: 306 del_vlan_files(sdata); 307 break; 308 default: 309 break; 310 } 311 } 312 313 static int notif_registered; 314 315 void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) 316 { 317 char buf[10+IFNAMSIZ]; 318 319 if (!notif_registered) 320 return; 321 322 sprintf(buf, "netdev:%s", sdata->dev->name); 323 sdata->debugfsdir = debugfs_create_dir(buf, 324 sdata->local->hw.wiphy->debugfsdir); 325 } 326 327 void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) 328 { 329 del_files(sdata, sdata->vif.type); 330 debugfs_remove(sdata->debugfsdir); 331 sdata->debugfsdir = NULL; 332 } 333 334 void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata, 335 int oldtype) 336 { 337 del_files(sdata, oldtype); 338 add_files(sdata); 339 } 340 341 static int netdev_notify(struct notifier_block * nb, 342 unsigned long state, 343 void *ndev) 344 { 345 struct net_device *dev = ndev; 346 struct dentry *dir; 347 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 348 char buf[10+IFNAMSIZ]; 349 350 if (state != NETDEV_CHANGENAME) 351 return 0; 352 353 if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) 354 return 0; 355 356 if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) 357 return 0; 358 359 sprintf(buf, "netdev:%s", dev->name); 360 dir = sdata->debugfsdir; 361 if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) 362 printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " 363 "dir to %s\n", buf); 364 365 return 0; 366 } 367 368 static struct notifier_block mac80211_debugfs_netdev_notifier = { 369 .notifier_call = netdev_notify, 370 }; 371 372 void ieee80211_debugfs_netdev_init(void) 373 { 374 int err; 375 376 err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier); 377 if (err) { 378 printk(KERN_ERR 379 "mac80211: failed to install netdev notifier," 380 " disabling per-netdev debugfs!\n"); 381 } else 382 notif_registered = 1; 383 } 384 385 void ieee80211_debugfs_netdev_exit(void) 386 { 387 unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier); 388 notif_registered = 0; 389 } 390