diff options
| -rw-r--r-- | net/mac80211/Kconfig | 9 | ||||
| -rw-r--r-- | net/mac80211/Makefile | 1 | ||||
| -rw-r--r-- | net/mac80211/debugfs.c | 433 | ||||
| -rw-r--r-- | net/mac80211/debugfs.h | 16 | ||||
| -rw-r--r-- | net/mac80211/debugfs_key.c | 252 | ||||
| -rw-r--r-- | net/mac80211/debugfs_key.h | 34 | ||||
| -rw-r--r-- | net/mac80211/debugfs_netdev.c | 440 | ||||
| -rw-r--r-- | net/mac80211/debugfs_netdev.h | 30 | ||||
| -rw-r--r-- | net/mac80211/debugfs_sta.c | 246 | ||||
| -rw-r--r-- | net/mac80211/debugfs_sta.h | 12 | ||||
| -rw-r--r-- | net/mac80211/ieee80211.c | 14 | ||||
| -rw-r--r-- | net/mac80211/ieee80211_i.h | 127 | ||||
| -rw-r--r-- | net/mac80211/ieee80211_iface.c | 8 | ||||
| -rw-r--r-- | net/mac80211/ieee80211_ioctl.c | 22 | ||||
| -rw-r--r-- | net/mac80211/ieee80211_key.h | 17 | ||||
| -rw-r--r-- | net/mac80211/ieee80211_rate.h | 22 | ||||
| -rw-r--r-- | net/mac80211/rc80211_simple.c | 71 | ||||
| -rw-r--r-- | net/mac80211/sta_info.c | 108 | ||||
| -rw-r--r-- | net/mac80211/sta_info.h | 19 |
19 files changed, 1866 insertions, 15 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index d761b53fb84c..6fffb3845ab6 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
| @@ -20,6 +20,15 @@ config MAC80211_LEDS | |||
| 20 | This option enables a few LED triggers for different | 20 | This option enables a few LED triggers for different |
| 21 | packet receive/transmit events. | 21 | packet receive/transmit events. |
| 22 | 22 | ||
| 23 | config MAC80211_DEBUGFS | ||
| 24 | bool "Export mac80211 internals in DebugFS" | ||
| 25 | depends on MAC80211 && DEBUG_FS | ||
| 26 | ---help--- | ||
| 27 | Select this to see extensive information about | ||
| 28 | the internal state of mac80211 in debugfs. | ||
| 29 | |||
| 30 | Say N unless you know you need this. | ||
| 31 | |||
| 23 | config MAC80211_DEBUG | 32 | config MAC80211_DEBUG |
| 24 | bool "Enable debugging output" | 33 | bool "Enable debugging output" |
| 25 | depends on MAC80211 | 34 | depends on MAC80211 |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 79dea99bb482..e9738dad2d7c 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o | 1 | obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o |
| 2 | 2 | ||
| 3 | mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o | 3 | mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o |
| 4 | mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o | ||
| 4 | 5 | ||
| 5 | mac80211-objs := \ | 6 | mac80211-objs := \ |
| 6 | ieee80211.o \ | 7 | ieee80211.o \ |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c new file mode 100644 index 000000000000..bb6c0feb2d48 --- /dev/null +++ b/net/mac80211/debugfs.c | |||
| @@ -0,0 +1,433 @@ | |||
| 1 | /* | ||
| 2 | * mac80211 debugfs for wireless PHYs | ||
| 3 | * | ||
| 4 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPLv2 | ||
| 7 | * | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/debugfs.h> | ||
| 11 | #include <linux/rtnetlink.h> | ||
| 12 | #include "ieee80211_i.h" | ||
| 13 | #include "ieee80211_rate.h" | ||
| 14 | #include "debugfs.h" | ||
| 15 | |||
| 16 | int mac80211_open_file_generic(struct inode *inode, struct file *file) | ||
| 17 | { | ||
| 18 | file->private_data = inode->i_private; | ||
| 19 | return 0; | ||
| 20 | } | ||
| 21 | |||
| 22 | static const char *ieee80211_mode_str(int mode) | ||
| 23 | { | ||
| 24 | switch (mode) { | ||
| 25 | case MODE_IEEE80211A: | ||
| 26 | return "IEEE 802.11a"; | ||
| 27 | case MODE_IEEE80211B: | ||
| 28 | return "IEEE 802.11b"; | ||
| 29 | case MODE_IEEE80211G: | ||
| 30 | return "IEEE 802.11g"; | ||
| 31 | case MODE_ATHEROS_TURBO: | ||
| 32 | return "Atheros Turbo (5 GHz)"; | ||
| 33 | default: | ||
| 34 | return "UNKNOWN"; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | static ssize_t modes_read(struct file *file, char __user *userbuf, | ||
| 39 | size_t count, loff_t *ppos) | ||
| 40 | { | ||
| 41 | struct ieee80211_local *local = file->private_data; | ||
| 42 | struct ieee80211_hw_mode *mode; | ||
| 43 | char buf[150], *p = buf; | ||
| 44 | |||
| 45 | /* FIXME: locking! */ | ||
| 46 | list_for_each_entry(mode, &local->modes_list, list) { | ||
| 47 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
| 48 | "%s\n", ieee80211_mode_str(mode->mode)); | ||
| 49 | } | ||
| 50 | |||
| 51 | return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); | ||
| 52 | } | ||
| 53 | |||
| 54 | static const struct file_operations modes_ops = { | ||
| 55 | .read = modes_read, | ||
| 56 | .open = mac80211_open_file_generic, | ||
| 57 | }; | ||
| 58 | |||
| 59 | #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ | ||
| 60 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ | ||
| 61 | size_t count, loff_t *ppos) \ | ||
| 62 | { \ | ||
| 63 | struct ieee80211_local *local = file->private_data; \ | ||
| 64 | char buf[buflen]; \ | ||
| 65 | int res; \ | ||
| 66 | \ | ||
| 67 | res = scnprintf(buf, buflen, fmt "\n", ##value); \ | ||
| 68 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
| 69 | } \ | ||
| 70 | \ | ||
| 71 | static const struct file_operations name## _ops = { \ | ||
| 72 | .read = name## _read, \ | ||
| 73 | .open = mac80211_open_file_generic, \ | ||
| 74 | }; | ||
| 75 | |||
| 76 | #define DEBUGFS_ADD(name) \ | ||
| 77 | local->debugfs.name = debugfs_create_file(#name, 0444, phyd, \ | ||
| 78 | local, &name## _ops); | ||
| 79 | |||
| 80 | #define DEBUGFS_DEL(name) \ | ||
| 81 | debugfs_remove(local->debugfs.name); \ | ||
| 82 | local->debugfs.name = NULL; | ||
| 83 | |||
| 84 | |||
| 85 | DEBUGFS_READONLY_FILE(channel, 20, "%d", | ||
| 86 | local->hw.conf.channel); | ||
| 87 | DEBUGFS_READONLY_FILE(frequency, 20, "%d", | ||
| 88 | local->hw.conf.freq); | ||
| 89 | DEBUGFS_READONLY_FILE(radar_detect, 20, "%d", | ||
| 90 | local->hw.conf.radar_detect); | ||
| 91 | DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d", | ||
| 92 | local->hw.conf.antenna_sel_tx); | ||
| 93 | DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d", | ||
| 94 | local->hw.conf.antenna_sel_rx); | ||
| 95 | DEBUGFS_READONLY_FILE(bridge_packets, 20, "%d", | ||
| 96 | local->bridge_packets); | ||
| 97 | DEBUGFS_READONLY_FILE(key_tx_rx_threshold, 20, "%d", | ||
| 98 | local->key_tx_rx_threshold); | ||
| 99 | DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", | ||
| 100 | local->rts_threshold); | ||
| 101 | DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", | ||
| 102 | local->fragmentation_threshold); | ||
| 103 | DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d", | ||
| 104 | local->short_retry_limit); | ||
| 105 | DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", | ||
| 106 | local->long_retry_limit); | ||
| 107 | DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", | ||
| 108 | local->total_ps_buffered); | ||
| 109 | DEBUGFS_READONLY_FILE(mode, 20, "%s", | ||
| 110 | ieee80211_mode_str(local->hw.conf.phymode)); | ||
| 111 | DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x", | ||
| 112 | local->wep_iv & 0xffffff); | ||
| 113 | DEBUGFS_READONLY_FILE(tx_power_reduction, 20, "%d.%d dBm", | ||
| 114 | local->hw.conf.tx_power_reduction / 10, | ||
| 115 | local->hw.conf.tx_power_reduction & 10); | ||
| 116 | DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s", | ||
| 117 | local->rate_ctrl ? local->rate_ctrl->ops->name : "<unset>"); | ||
| 118 | |||
| 119 | /* statistics stuff */ | ||
| 120 | |||
| 121 | static inline int rtnl_lock_local(struct ieee80211_local *local) | ||
| 122 | { | ||
| 123 | rtnl_lock(); | ||
| 124 | if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) { | ||
| 125 | rtnl_unlock(); | ||
| 126 | return -ENODEV; | ||
| 127 | } | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | #define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \ | ||
| 132 | DEBUGFS_READONLY_FILE(stats_ ##name, buflen, fmt, ##value) | ||
| 133 | |||
| 134 | static ssize_t format_devstat_counter(struct ieee80211_local *local, | ||
| 135 | char __user *userbuf, | ||
| 136 | size_t count, loff_t *ppos, | ||
| 137 | int (*printvalue)(struct ieee80211_low_level_stats *stats, char *buf, | ||
| 138 | int buflen)) | ||
| 139 | { | ||
| 140 | struct ieee80211_low_level_stats stats; | ||
| 141 | char buf[20]; | ||
| 142 | int res; | ||
| 143 | |||
| 144 | if (!local->ops->get_stats) | ||
| 145 | return -EOPNOTSUPP; | ||
| 146 | |||
| 147 | res = rtnl_lock_local(local); | ||
| 148 | if (res) | ||
| 149 | return res; | ||
| 150 | |||
| 151 | res = local->ops->get_stats(local_to_hw(local), &stats); | ||
| 152 | rtnl_unlock(); | ||
| 153 | if (!res) | ||
| 154 | res = printvalue(&stats, buf, sizeof(buf)); | ||
| 155 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
| 156 | } | ||
| 157 | |||
| 158 | #define DEBUGFS_DEVSTATS_FILE(name) \ | ||
| 159 | static int print_devstats_##name(struct ieee80211_low_level_stats *stats,\ | ||
| 160 | char *buf, int buflen) \ | ||
| 161 | { \ | ||
| 162 | return scnprintf(buf, buflen, "%u\n", stats->name); \ | ||
| 163 | } \ | ||
| 164 | static ssize_t stats_ ##name## _read(struct file *file, \ | ||
| 165 | char __user *userbuf, \ | ||
| 166 | size_t count, loff_t *ppos) \ | ||
| 167 | { \ | ||
| 168 | return format_devstat_counter(file->private_data, \ | ||
| 169 | userbuf, \ | ||
| 170 | count, \ | ||
| 171 | ppos, \ | ||
| 172 | print_devstats_##name); \ | ||
| 173 | } \ | ||
| 174 | \ | ||
| 175 | static const struct file_operations stats_ ##name## _ops = { \ | ||
| 176 | .read = stats_ ##name## _read, \ | ||
| 177 | .open = mac80211_open_file_generic, \ | ||
| 178 | }; | ||
| 179 | |||
| 180 | #define DEBUGFS_STATS_ADD(name) \ | ||
| 181 | local->debugfs.stats.name = debugfs_create_file(#name, 0444, statsd,\ | ||
| 182 | local, &stats_ ##name## _ops); | ||
| 183 | |||
| 184 | #define DEBUGFS_STATS_DEL(name) \ | ||
| 185 | debugfs_remove(local->debugfs.stats.name); \ | ||
| 186 | local->debugfs.stats.name = NULL; | ||
| 187 | |||
| 188 | DEBUGFS_STATS_FILE(transmitted_fragment_count, 20, "%u", | ||
| 189 | local->dot11TransmittedFragmentCount); | ||
| 190 | DEBUGFS_STATS_FILE(multicast_transmitted_frame_count, 20, "%u", | ||
| 191 | local->dot11MulticastTransmittedFrameCount); | ||
| 192 | DEBUGFS_STATS_FILE(failed_count, 20, "%u", | ||
| 193 | local->dot11FailedCount); | ||
| 194 | DEBUGFS_STATS_FILE(retry_count, 20, "%u", | ||
| 195 | local->dot11RetryCount); | ||
| 196 | DEBUGFS_STATS_FILE(multiple_retry_count, 20, "%u", | ||
| 197 | local->dot11MultipleRetryCount); | ||
| 198 | DEBUGFS_STATS_FILE(frame_duplicate_count, 20, "%u", | ||
| 199 | local->dot11FrameDuplicateCount); | ||
| 200 | DEBUGFS_STATS_FILE(received_fragment_count, 20, "%u", | ||
| 201 | local->dot11ReceivedFragmentCount); | ||
| 202 | DEBUGFS_STATS_FILE(multicast_received_frame_count, 20, "%u", | ||
| 203 | local->dot11MulticastReceivedFrameCount); | ||
| 204 | DEBUGFS_STATS_FILE(transmitted_frame_count, 20, "%u", | ||
| 205 | local->dot11TransmittedFrameCount); | ||
| 206 | DEBUGFS_STATS_FILE(wep_undecryptable_count, 20, "%u", | ||
| 207 | local->dot11WEPUndecryptableCount); | ||
| 208 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
| 209 | DEBUGFS_STATS_FILE(tx_handlers_drop, 20, "%u", | ||
| 210 | local->tx_handlers_drop); | ||
| 211 | DEBUGFS_STATS_FILE(tx_handlers_queued, 20, "%u", | ||
| 212 | local->tx_handlers_queued); | ||
| 213 | DEBUGFS_STATS_FILE(tx_handlers_drop_unencrypted, 20, "%u", | ||
| 214 | local->tx_handlers_drop_unencrypted); | ||
| 215 | DEBUGFS_STATS_FILE(tx_handlers_drop_fragment, 20, "%u", | ||
| 216 | local->tx_handlers_drop_fragment); | ||
| 217 | DEBUGFS_STATS_FILE(tx_handlers_drop_wep, 20, "%u", | ||
| 218 | local->tx_handlers_drop_wep); | ||
| 219 | DEBUGFS_STATS_FILE(tx_handlers_drop_not_assoc, 20, "%u", | ||
| 220 | local->tx_handlers_drop_not_assoc); | ||
| 221 | DEBUGFS_STATS_FILE(tx_handlers_drop_unauth_port, 20, "%u", | ||
| 222 | local->tx_handlers_drop_unauth_port); | ||
| 223 | DEBUGFS_STATS_FILE(rx_handlers_drop, 20, "%u", | ||
| 224 | local->rx_handlers_drop); | ||
| 225 | DEBUGFS_STATS_FILE(rx_handlers_queued, 20, "%u", | ||
| 226 | local->rx_handlers_queued); | ||
| 227 | DEBUGFS_STATS_FILE(rx_handlers_drop_nullfunc, 20, "%u", | ||
| 228 | local->rx_handlers_drop_nullfunc); | ||
| 229 | DEBUGFS_STATS_FILE(rx_handlers_drop_defrag, 20, "%u", | ||
| 230 | local->rx_handlers_drop_defrag); | ||
| 231 | DEBUGFS_STATS_FILE(rx_handlers_drop_short, 20, "%u", | ||
| 232 | local->rx_handlers_drop_short); | ||
| 233 | DEBUGFS_STATS_FILE(rx_handlers_drop_passive_scan, 20, "%u", | ||
| 234 | local->rx_handlers_drop_passive_scan); | ||
| 235 | DEBUGFS_STATS_FILE(tx_expand_skb_head, 20, "%u", | ||
| 236 | local->tx_expand_skb_head); | ||
| 237 | DEBUGFS_STATS_FILE(tx_expand_skb_head_cloned, 20, "%u", | ||
| 238 | local->tx_expand_skb_head_cloned); | ||
| 239 | DEBUGFS_STATS_FILE(rx_expand_skb_head, 20, "%u", | ||
| 240 | local->rx_expand_skb_head); | ||
| 241 | DEBUGFS_STATS_FILE(rx_expand_skb_head2, 20, "%u", | ||
| 242 | local->rx_expand_skb_head2); | ||
| 243 | DEBUGFS_STATS_FILE(rx_handlers_fragments, 20, "%u", | ||
| 244 | local->rx_handlers_fragments); | ||
| 245 | DEBUGFS_STATS_FILE(tx_status_drop, 20, "%u", | ||
| 246 | local->tx_status_drop); | ||
| 247 | |||
| 248 | static ssize_t stats_wme_rx_queue_read(struct file *file, | ||
| 249 | char __user *userbuf, | ||
| 250 | size_t count, loff_t *ppos) | ||
| 251 | { | ||
| 252 | struct ieee80211_local *local = file->private_data; | ||
| 253 | char buf[NUM_RX_DATA_QUEUES*15], *p = buf; | ||
| 254 | int i; | ||
| 255 | |||
| 256 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | ||
| 257 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
| 258 | "%u\n", local->wme_rx_queue[i]); | ||
| 259 | |||
| 260 | return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); | ||
| 261 | } | ||
| 262 | |||
| 263 | static const struct file_operations stats_wme_rx_queue_ops = { | ||
| 264 | .read = stats_wme_rx_queue_read, | ||
| 265 | .open = mac80211_open_file_generic, | ||
| 266 | }; | ||
| 267 | |||
| 268 | static ssize_t stats_wme_tx_queue_read(struct file *file, | ||
| 269 | char __user *userbuf, | ||
| 270 | size_t count, loff_t *ppos) | ||
| 271 | { | ||
| 272 | struct ieee80211_local *local = file->private_data; | ||
| 273 | char buf[NUM_TX_DATA_QUEUES*15], *p = buf; | ||
| 274 | int i; | ||
| 275 | |||
| 276 | for (i = 0; i < NUM_TX_DATA_QUEUES; i++) | ||
| 277 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
| 278 | "%u\n", local->wme_tx_queue[i]); | ||
| 279 | |||
| 280 | return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); | ||
| 281 | } | ||
| 282 | |||
| 283 | static const struct file_operations stats_wme_tx_queue_ops = { | ||
| 284 | .read = stats_wme_tx_queue_read, | ||
| 285 | .open = mac80211_open_file_generic, | ||
| 286 | }; | ||
| 287 | #endif | ||
| 288 | |||
| 289 | DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount); | ||
| 290 | DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount); | ||
| 291 | DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount); | ||
| 292 | DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount); | ||
| 293 | |||
| 294 | |||
| 295 | void debugfs_hw_add(struct ieee80211_local *local) | ||
| 296 | { | ||
| 297 | struct dentry *phyd = local->hw.wiphy->debugfsdir; | ||
| 298 | struct dentry *statsd; | ||
| 299 | |||
| 300 | if (!phyd) | ||
| 301 | return; | ||
| 302 | |||
| 303 | local->debugfs.stations = debugfs_create_dir("stations", phyd); | ||
| 304 | local->debugfs.keys = debugfs_create_dir("keys", phyd); | ||
| 305 | |||
| 306 | DEBUGFS_ADD(channel); | ||
| 307 | DEBUGFS_ADD(frequency); | ||
| 308 | DEBUGFS_ADD(radar_detect); | ||
| 309 | DEBUGFS_ADD(antenna_sel_tx); | ||
| 310 | DEBUGFS_ADD(antenna_sel_rx); | ||
| 311 | DEBUGFS_ADD(bridge_packets); | ||
| 312 | DEBUGFS_ADD(key_tx_rx_threshold); | ||
| 313 | DEBUGFS_ADD(rts_threshold); | ||
| 314 | DEBUGFS_ADD(fragmentation_threshold); | ||
| 315 | DEBUGFS_ADD(short_retry_limit); | ||
| 316 | DEBUGFS_ADD(long_retry_limit); | ||
| 317 | DEBUGFS_ADD(total_ps_buffered); | ||
| 318 | DEBUGFS_ADD(mode); | ||
| 319 | DEBUGFS_ADD(wep_iv); | ||
| 320 | DEBUGFS_ADD(tx_power_reduction); | ||
| 321 | DEBUGFS_ADD(modes); | ||
| 322 | |||
| 323 | statsd = debugfs_create_dir("statistics", phyd); | ||
| 324 | local->debugfs.statistics = statsd; | ||
| 325 | |||
| 326 | /* if the dir failed, don't put all the other things into the root! */ | ||
| 327 | if (!statsd) | ||
| 328 | return; | ||
| 329 | |||
| 330 | DEBUGFS_STATS_ADD(transmitted_fragment_count); | ||
| 331 | DEBUGFS_STATS_ADD(multicast_transmitted_frame_count); | ||
| 332 | DEBUGFS_STATS_ADD(failed_count); | ||
| 333 | DEBUGFS_STATS_ADD(retry_count); | ||
| 334 | DEBUGFS_STATS_ADD(multiple_retry_count); | ||
| 335 | DEBUGFS_STATS_ADD(frame_duplicate_count); | ||
| 336 | DEBUGFS_STATS_ADD(received_fragment_count); | ||
| 337 | DEBUGFS_STATS_ADD(multicast_received_frame_count); | ||
| 338 | DEBUGFS_STATS_ADD(transmitted_frame_count); | ||
| 339 | DEBUGFS_STATS_ADD(wep_undecryptable_count); | ||
| 340 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
| 341 | DEBUGFS_STATS_ADD(tx_handlers_drop); | ||
| 342 | DEBUGFS_STATS_ADD(tx_handlers_queued); | ||
| 343 | DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted); | ||
| 344 | DEBUGFS_STATS_ADD(tx_handlers_drop_fragment); | ||
| 345 | DEBUGFS_STATS_ADD(tx_handlers_drop_wep); | ||
| 346 | DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc); | ||
| 347 | DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port); | ||
| 348 | DEBUGFS_STATS_ADD(rx_handlers_drop); | ||
| 349 | DEBUGFS_STATS_ADD(rx_handlers_queued); | ||
| 350 | DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc); | ||
| 351 | DEBUGFS_STATS_ADD(rx_handlers_drop_defrag); | ||
| 352 | DEBUGFS_STATS_ADD(rx_handlers_drop_short); | ||
| 353 | DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan); | ||
| 354 | DEBUGFS_STATS_ADD(tx_expand_skb_head); | ||
| 355 | DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned); | ||
| 356 | DEBUGFS_STATS_ADD(rx_expand_skb_head); | ||
| 357 | DEBUGFS_STATS_ADD(rx_expand_skb_head2); | ||
| 358 | DEBUGFS_STATS_ADD(rx_handlers_fragments); | ||
| 359 | DEBUGFS_STATS_ADD(tx_status_drop); | ||
| 360 | DEBUGFS_STATS_ADD(wme_tx_queue); | ||
| 361 | DEBUGFS_STATS_ADD(wme_rx_queue); | ||
| 362 | #endif | ||
| 363 | DEBUGFS_STATS_ADD(dot11ACKFailureCount); | ||
| 364 | DEBUGFS_STATS_ADD(dot11RTSFailureCount); | ||
| 365 | DEBUGFS_STATS_ADD(dot11FCSErrorCount); | ||
| 366 | DEBUGFS_STATS_ADD(dot11RTSSuccessCount); | ||
| 367 | } | ||
| 368 | |||
| 369 | void debugfs_hw_del(struct ieee80211_local *local) | ||
| 370 | { | ||
| 371 | DEBUGFS_DEL(channel); | ||
| 372 | DEBUGFS_DEL(frequency); | ||
| 373 | DEBUGFS_DEL(radar_detect); | ||
| 374 | DEBUGFS_DEL(antenna_sel_tx); | ||
| 375 | DEBUGFS_DEL(antenna_sel_rx); | ||
| 376 | DEBUGFS_DEL(bridge_packets); | ||
| 377 | DEBUGFS_DEL(key_tx_rx_threshold); | ||
| 378 | DEBUGFS_DEL(rts_threshold); | ||
| 379 | DEBUGFS_DEL(fragmentation_threshold); | ||
| 380 | DEBUGFS_DEL(short_retry_limit); | ||
| 381 | DEBUGFS_DEL(long_retry_limit); | ||
| 382 | DEBUGFS_DEL(total_ps_buffered); | ||
| 383 | DEBUGFS_DEL(mode); | ||
| 384 | DEBUGFS_DEL(wep_iv); | ||
| 385 | DEBUGFS_DEL(tx_power_reduction); | ||
| 386 | DEBUGFS_DEL(modes); | ||
| 387 | |||
| 388 | DEBUGFS_STATS_DEL(transmitted_fragment_count); | ||
| 389 | DEBUGFS_STATS_DEL(multicast_transmitted_frame_count); | ||
| 390 | DEBUGFS_STATS_DEL(failed_count); | ||
| 391 | DEBUGFS_STATS_DEL(retry_count); | ||
| 392 | DEBUGFS_STATS_DEL(multiple_retry_count); | ||
| 393 | DEBUGFS_STATS_DEL(frame_duplicate_count); | ||
| 394 | DEBUGFS_STATS_DEL(received_fragment_count); | ||
| 395 | DEBUGFS_STATS_DEL(multicast_received_frame_count); | ||
| 396 | DEBUGFS_STATS_DEL(transmitted_frame_count); | ||
| 397 | DEBUGFS_STATS_DEL(wep_undecryptable_count); | ||
| 398 | DEBUGFS_STATS_DEL(num_scans); | ||
| 399 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
| 400 | DEBUGFS_STATS_DEL(tx_handlers_drop); | ||
| 401 | DEBUGFS_STATS_DEL(tx_handlers_queued); | ||
| 402 | DEBUGFS_STATS_DEL(tx_handlers_drop_unencrypted); | ||
| 403 | DEBUGFS_STATS_DEL(tx_handlers_drop_fragment); | ||
| 404 | DEBUGFS_STATS_DEL(tx_handlers_drop_wep); | ||
| 405 | DEBUGFS_STATS_DEL(tx_handlers_drop_not_assoc); | ||
| 406 | DEBUGFS_STATS_DEL(tx_handlers_drop_unauth_port); | ||
| 407 | DEBUGFS_STATS_DEL(rx_handlers_drop); | ||
| 408 | DEBUGFS_STATS_DEL(rx_handlers_queued); | ||
| 409 | DEBUGFS_STATS_DEL(rx_handlers_drop_nullfunc); | ||
| 410 | DEBUGFS_STATS_DEL(rx_handlers_drop_defrag); | ||
| 411 | DEBUGFS_STATS_DEL(rx_handlers_drop_short); | ||
| 412 | DEBUGFS_STATS_DEL(rx_handlers_drop_passive_scan); | ||
| 413 | DEBUGFS_STATS_DEL(tx_expand_skb_head); | ||
| 414 | DEBUGFS_STATS_DEL(tx_expand_skb_head_cloned); | ||
| 415 | DEBUGFS_STATS_DEL(rx_expand_skb_head); | ||
| 416 | DEBUGFS_STATS_DEL(rx_expand_skb_head2); | ||
| 417 | DEBUGFS_STATS_DEL(rx_handlers_fragments); | ||
| 418 | DEBUGFS_STATS_DEL(tx_status_drop); | ||
| 419 | DEBUGFS_STATS_DEL(wme_tx_queue); | ||
| 420 | DEBUGFS_STATS_DEL(wme_rx_queue); | ||
| 421 | #endif | ||
| 422 | DEBUGFS_STATS_DEL(dot11ACKFailureCount); | ||
| 423 | DEBUGFS_STATS_DEL(dot11RTSFailureCount); | ||
| 424 | DEBUGFS_STATS_DEL(dot11FCSErrorCount); | ||
| 425 | DEBUGFS_STATS_DEL(dot11RTSSuccessCount); | ||
| 426 | |||
| 427 | debugfs_remove(local->debugfs.statistics); | ||
| 428 | local->debugfs.statistics = NULL; | ||
| 429 | debugfs_remove(local->debugfs.stations); | ||
| 430 | local->debugfs.stations = NULL; | ||
| 431 | debugfs_remove(local->debugfs.keys); | ||
| 432 | local->debugfs.keys = NULL; | ||
| 433 | } | ||
diff --git a/net/mac80211/debugfs.h b/net/mac80211/debugfs.h new file mode 100644 index 000000000000..dd2541935c27 --- /dev/null +++ b/net/mac80211/debugfs.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #ifndef __MAC80211_DEBUGFS_H | ||
| 2 | #define __MAC80211_DEBUGFS_H | ||
| 3 | |||
| 4 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 5 | extern void debugfs_hw_add(struct ieee80211_local *local); | ||
| 6 | extern void debugfs_hw_del(struct ieee80211_local *local); | ||
| 7 | extern int mac80211_open_file_generic(struct inode *inode, struct file *file); | ||
| 8 | #else | ||
| 9 | static inline void debugfs_hw_add(struct ieee80211_local *local) | ||
| 10 | { | ||
| 11 | return; | ||
| 12 | } | ||
| 13 | static inline void debugfs_hw_del(struct ieee80211_local *local) {} | ||
| 14 | #endif | ||
| 15 | |||
| 16 | #endif /* __MAC80211_DEBUGFS_H */ | ||
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c new file mode 100644 index 000000000000..7d56dc9e7326 --- /dev/null +++ b/net/mac80211/debugfs_key.c | |||
| @@ -0,0 +1,252 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2003-2005 Devicescape Software, Inc. | ||
| 3 | * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> | ||
| 4 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/kobject.h> | ||
| 12 | #include "ieee80211_i.h" | ||
| 13 | #include "ieee80211_key.h" | ||
| 14 | #include "debugfs.h" | ||
| 15 | #include "debugfs_key.h" | ||
| 16 | |||
| 17 | #define KEY_READ(name, buflen, format_string) \ | ||
| 18 | static ssize_t key_##name##_read(struct file *file, \ | ||
| 19 | char __user *userbuf, \ | ||
| 20 | size_t count, loff_t *ppos) \ | ||
| 21 | { \ | ||
| 22 | char buf[buflen]; \ | ||
| 23 | struct ieee80211_key *key = file->private_data; \ | ||
| 24 | int res = scnprintf(buf, buflen, format_string, key->name); \ | ||
| 25 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
| 26 | } | ||
| 27 | #define KEY_READ_D(name) KEY_READ(name, 20, "%d\n") | ||
| 28 | |||
| 29 | #define KEY_OPS(name) \ | ||
| 30 | static const struct file_operations key_ ##name## _ops = { \ | ||
| 31 | .read = key_##name##_read, \ | ||
| 32 | .open = mac80211_open_file_generic, \ | ||
| 33 | } | ||
| 34 | |||
| 35 | #define KEY_FILE(name, format) \ | ||
| 36 | KEY_READ_##format(name) \ | ||
| 37 | KEY_OPS(name) | ||
| 38 | |||
| 39 | KEY_FILE(keylen, D); | ||
| 40 | KEY_FILE(force_sw_encrypt, D); | ||
| 41 | KEY_FILE(keyidx, D); | ||
| 42 | KEY_FILE(hw_key_idx, D); | ||
| 43 | KEY_FILE(tx_rx_count, D); | ||
| 44 | |||
| 45 | static ssize_t key_algorithm_read(struct file *file, | ||
| 46 | char __user *userbuf, | ||
| 47 | size_t count, loff_t *ppos) | ||
| 48 | { | ||
| 49 | char *alg; | ||
| 50 | struct ieee80211_key *key = file->private_data; | ||
| 51 | |||
| 52 | switch (key->alg) { | ||
| 53 | case ALG_WEP: | ||
| 54 | alg = "WEP\n"; | ||
| 55 | break; | ||
| 56 | case ALG_TKIP: | ||
| 57 | alg = "TKIP\n"; | ||
| 58 | break; | ||
| 59 | case ALG_CCMP: | ||
| 60 | alg = "CCMP\n"; | ||
| 61 | break; | ||
| 62 | default: | ||
| 63 | return 0; | ||
| 64 | } | ||
| 65 | return simple_read_from_buffer(userbuf, count, ppos, alg, strlen(alg)); | ||
| 66 | } | ||
| 67 | KEY_OPS(algorithm); | ||
| 68 | |||
| 69 | static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, | ||
| 70 | size_t count, loff_t *ppos) | ||
| 71 | { | ||
| 72 | const u8 *tpn; | ||
| 73 | char buf[20]; | ||
| 74 | int len; | ||
| 75 | struct ieee80211_key *key = file->private_data; | ||
| 76 | |||
| 77 | switch (key->alg) { | ||
| 78 | case ALG_WEP: | ||
| 79 | len = scnprintf(buf, sizeof(buf), "\n"); | ||
| 80 | case ALG_TKIP: | ||
| 81 | len = scnprintf(buf, sizeof(buf), "%08x %04x\n", | ||
| 82 | key->u.tkip.iv32, | ||
| 83 | key->u.tkip.iv16); | ||
| 84 | case ALG_CCMP: | ||
| 85 | tpn = key->u.ccmp.tx_pn; | ||
| 86 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", | ||
| 87 | tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]); | ||
| 88 | default: | ||
| 89 | return 0; | ||
| 90 | } | ||
| 91 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | ||
| 92 | } | ||
| 93 | KEY_OPS(tx_spec); | ||
| 94 | |||
| 95 | static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | ||
| 96 | size_t count, loff_t *ppos) | ||
| 97 | { | ||
| 98 | struct ieee80211_key *key = file->private_data; | ||
| 99 | char buf[14*NUM_RX_DATA_QUEUES+1], *p = buf; | ||
| 100 | int i, len; | ||
| 101 | const u8 *rpn; | ||
| 102 | |||
| 103 | switch (key->alg) { | ||
| 104 | case ALG_WEP: | ||
| 105 | len = scnprintf(buf, sizeof(buf), "\n"); | ||
| 106 | case ALG_TKIP: | ||
| 107 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | ||
| 108 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
| 109 | "%08x %04x\n", | ||
| 110 | key->u.tkip.iv32_rx[i], | ||
| 111 | key->u.tkip.iv16_rx[i]); | ||
| 112 | len = p - buf; | ||
| 113 | case ALG_CCMP: | ||
| 114 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) { | ||
| 115 | rpn = key->u.ccmp.rx_pn[i]; | ||
| 116 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
| 117 | "%02x%02x%02x%02x%02x%02x\n", | ||
| 118 | rpn[0], rpn[1], rpn[2], | ||
| 119 | rpn[3], rpn[4], rpn[5]); | ||
| 120 | } | ||
| 121 | len = p - buf; | ||
| 122 | default: | ||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | ||
| 126 | } | ||
| 127 | KEY_OPS(rx_spec); | ||
| 128 | |||
| 129 | static ssize_t key_replays_read(struct file *file, char __user *userbuf, | ||
| 130 | size_t count, loff_t *ppos) | ||
| 131 | { | ||
| 132 | struct ieee80211_key *key = file->private_data; | ||
| 133 | char buf[20]; | ||
| 134 | int len; | ||
| 135 | |||
| 136 | if (key->alg != ALG_CCMP) | ||
| 137 | return 0; | ||
| 138 | len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); | ||
| 139 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | ||
| 140 | } | ||
| 141 | KEY_OPS(replays); | ||
| 142 | |||
| 143 | static ssize_t key_key_read(struct file *file, char __user *userbuf, | ||
| 144 | size_t count, loff_t *ppos) | ||
| 145 | { | ||
| 146 | struct ieee80211_key *key = file->private_data; | ||
| 147 | int i, res, bufsize = 2*key->keylen+2; | ||
| 148 | char *buf = kmalloc(bufsize, GFP_KERNEL); | ||
| 149 | char *p = buf; | ||
| 150 | |||
| 151 | for (i = 0; i < key->keylen; i++) | ||
| 152 | p += scnprintf(p, bufsize+buf-p, "%02x", key->key[i]); | ||
| 153 | p += scnprintf(p, bufsize+buf-p, "\n"); | ||
| 154 | res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); | ||
| 155 | kfree(buf); | ||
| 156 | return res; | ||
| 157 | } | ||
| 158 | KEY_OPS(key); | ||
| 159 | |||
| 160 | #define DEBUGFS_ADD(name) \ | ||
| 161 | key->debugfs.name = debugfs_create_file(#name, 0400,\ | ||
| 162 | key->debugfs.dir, key, &key_##name##_ops); | ||
| 163 | |||
| 164 | void ieee80211_debugfs_key_add(struct ieee80211_local *local, | ||
| 165 | struct ieee80211_key *key) | ||
| 166 | { | ||
| 167 | char buf[20]; | ||
| 168 | |||
| 169 | if (!local->debugfs.keys) | ||
| 170 | return; | ||
| 171 | |||
| 172 | sprintf(buf, "%d", key->keyidx); | ||
| 173 | key->debugfs.dir = debugfs_create_dir(buf, | ||
| 174 | local->debugfs.keys); | ||
| 175 | |||
| 176 | if (!key->debugfs.dir) | ||
| 177 | return; | ||
| 178 | |||
| 179 | DEBUGFS_ADD(keylen); | ||
| 180 | DEBUGFS_ADD(force_sw_encrypt); | ||
| 181 | DEBUGFS_ADD(keyidx); | ||
| 182 | DEBUGFS_ADD(hw_key_idx); | ||
| 183 | DEBUGFS_ADD(tx_rx_count); | ||
| 184 | DEBUGFS_ADD(algorithm); | ||
| 185 | DEBUGFS_ADD(tx_spec); | ||
| 186 | DEBUGFS_ADD(rx_spec); | ||
| 187 | DEBUGFS_ADD(replays); | ||
| 188 | DEBUGFS_ADD(key); | ||
| 189 | }; | ||
| 190 | |||
| 191 | #define DEBUGFS_DEL(name) \ | ||
| 192 | debugfs_remove(key->debugfs.name); key->debugfs.name = NULL; | ||
| 193 | |||
| 194 | void ieee80211_debugfs_key_remove(struct ieee80211_key *key) | ||
| 195 | { | ||
| 196 | if (!key) | ||
| 197 | return; | ||
| 198 | |||
| 199 | DEBUGFS_DEL(keylen); | ||
| 200 | DEBUGFS_DEL(force_sw_encrypt); | ||
| 201 | DEBUGFS_DEL(keyidx); | ||
| 202 | DEBUGFS_DEL(hw_key_idx); | ||
| 203 | DEBUGFS_DEL(tx_rx_count); | ||
| 204 | DEBUGFS_DEL(algorithm); | ||
| 205 | DEBUGFS_DEL(tx_spec); | ||
| 206 | DEBUGFS_DEL(rx_spec); | ||
| 207 | DEBUGFS_DEL(replays); | ||
| 208 | DEBUGFS_DEL(key); | ||
| 209 | |||
| 210 | debugfs_remove(key->debugfs.stalink); | ||
| 211 | key->debugfs.stalink = NULL; | ||
| 212 | debugfs_remove(key->debugfs.dir); | ||
| 213 | key->debugfs.dir = NULL; | ||
| 214 | } | ||
| 215 | void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) | ||
| 216 | { | ||
| 217 | char buf[50]; | ||
| 218 | |||
| 219 | if (!sdata->debugfsdir) | ||
| 220 | return; | ||
| 221 | |||
| 222 | sprintf(buf, "../keys/%d", sdata->default_key->keyidx); | ||
| 223 | sdata->debugfs.default_key = | ||
| 224 | debugfs_create_symlink("default_key", sdata->debugfsdir, buf); | ||
| 225 | } | ||
| 226 | void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata) | ||
| 227 | { | ||
| 228 | if (!sdata) | ||
| 229 | return; | ||
| 230 | |||
| 231 | debugfs_remove(sdata->debugfs.default_key); | ||
| 232 | sdata->debugfs.default_key = NULL; | ||
| 233 | } | ||
| 234 | void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key, | ||
| 235 | struct sta_info *sta) | ||
| 236 | { | ||
| 237 | char buf[50]; | ||
| 238 | |||
| 239 | if (!key->debugfs.dir) | ||
| 240 | return; | ||
| 241 | |||
| 242 | sprintf(buf, "../sta/" MAC_FMT, MAC_ARG(sta->addr)); | ||
| 243 | key->debugfs.stalink = | ||
| 244 | debugfs_create_symlink("station", key->debugfs.dir, buf); | ||
| 245 | } | ||
| 246 | |||
| 247 | void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, | ||
| 248 | struct sta_info *sta) | ||
| 249 | { | ||
| 250 | debugfs_remove(key->debugfs.stalink); | ||
| 251 | key->debugfs.stalink = NULL; | ||
| 252 | } | ||
diff --git a/net/mac80211/debugfs_key.h b/net/mac80211/debugfs_key.h new file mode 100644 index 000000000000..aecfce395da6 --- /dev/null +++ b/net/mac80211/debugfs_key.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | #ifndef __MAC80211_DEBUGFS_KEY_H | ||
| 2 | #define __MAC80211_DEBUGFS_KEY_H | ||
| 3 | |||
| 4 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 5 | void ieee80211_debugfs_key_add(struct ieee80211_local *local, | ||
| 6 | struct ieee80211_key *key); | ||
| 7 | void ieee80211_debugfs_key_remove(struct ieee80211_key *key); | ||
| 8 | void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata); | ||
| 9 | void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata); | ||
| 10 | void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key, | ||
| 11 | struct sta_info *sta); | ||
| 12 | void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, | ||
| 13 | struct sta_info *sta); | ||
| 14 | #else | ||
| 15 | static inline void ieee80211_debugfs_key_add(struct ieee80211_local *local, | ||
| 16 | struct ieee80211_key *key) | ||
| 17 | {} | ||
| 18 | static inline void ieee80211_debugfs_key_remove(struct ieee80211_key *key) | ||
| 19 | {} | ||
| 20 | static inline void ieee80211_debugfs_key_add_default( | ||
| 21 | struct ieee80211_sub_if_data *sdata) | ||
| 22 | {} | ||
| 23 | static inline void ieee80211_debugfs_key_remove_default( | ||
| 24 | struct ieee80211_sub_if_data *sdata) | ||
| 25 | {} | ||
| 26 | static inline void ieee80211_debugfs_key_sta_link( | ||
| 27 | struct ieee80211_key *key, struct sta_info *sta) | ||
| 28 | {} | ||
| 29 | static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, | ||
| 30 | struct sta_info *sta) | ||
| 31 | {} | ||
| 32 | #endif | ||
| 33 | |||
| 34 | #endif /* __MAC80211_DEBUGFS_KEY_H */ | ||
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c new file mode 100644 index 000000000000..9e3964638bad --- /dev/null +++ b/net/mac80211/debugfs_netdev.c | |||
| @@ -0,0 +1,440 @@ | |||
| 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 | return scnprintf(buf, buflen, MAC_FMT "\n", MAC_ARG(sdata->field));\ | ||
| 70 | } | ||
| 71 | |||
| 72 | #define __IEEE80211_IF_FILE(name) \ | ||
| 73 | static ssize_t ieee80211_if_read_##name(struct file *file, \ | ||
| 74 | char __user *userbuf, \ | ||
| 75 | size_t count, loff_t *ppos) \ | ||
| 76 | { \ | ||
| 77 | return ieee80211_if_read(file->private_data, \ | ||
| 78 | userbuf, count, ppos, \ | ||
| 79 | ieee80211_if_fmt_##name); \ | ||
| 80 | } \ | ||
| 81 | static const struct file_operations name##_ops = { \ | ||
| 82 | .read = ieee80211_if_read_##name, \ | ||
| 83 | .open = mac80211_open_file_generic, \ | ||
| 84 | } | ||
| 85 | |||
| 86 | #define IEEE80211_IF_FILE(name, field, format) \ | ||
| 87 | IEEE80211_IF_FMT_##format(name, field) \ | ||
| 88 | __IEEE80211_IF_FILE(name) | ||
| 89 | |||
| 90 | /* common attributes */ | ||
| 91 | IEEE80211_IF_FILE(channel_use, channel_use, DEC); | ||
| 92 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); | ||
| 93 | IEEE80211_IF_FILE(eapol, eapol, DEC); | ||
| 94 | IEEE80211_IF_FILE(ieee8021_x, ieee802_1x, 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.ssid_set ? "SSID\n" : "", | ||
| 116 | sdata->u.sta.bssid_set ? "BSSID\n" : "", | ||
| 117 | sdata->u.sta.prev_bssid_set ? "prev BSSID\n" : "", | ||
| 118 | sdata->u.sta.authenticated ? "AUTH\n" : "", | ||
| 119 | sdata->u.sta.associated ? "ASSOC\n" : "", | ||
| 120 | sdata->u.sta.probereq_poll ? "PROBEREQ POLL\n" : "", | ||
| 121 | sdata->u.sta.use_protection ? "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_period, u.ap.dtim_period, DEC); | ||
| 128 | IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); | ||
| 129 | IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC); | ||
| 130 | IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC); | ||
| 131 | IEEE80211_IF_FILE(max_ratectrl_rateidx, u.ap.max_ratectrl_rateidx, DEC); | ||
| 132 | |||
| 133 | static ssize_t ieee80211_if_fmt_num_buffered_multicast( | ||
| 134 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
| 135 | { | ||
| 136 | return scnprintf(buf, buflen, "%u\n", | ||
| 137 | skb_queue_len(&sdata->u.ap.ps_bc_buf)); | ||
| 138 | } | ||
| 139 | __IEEE80211_IF_FILE(num_buffered_multicast); | ||
| 140 | |||
| 141 | static ssize_t ieee80211_if_fmt_beacon_head_len( | ||
| 142 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
| 143 | { | ||
| 144 | if (sdata->u.ap.beacon_head) | ||
| 145 | return scnprintf(buf, buflen, "%d\n", | ||
| 146 | sdata->u.ap.beacon_head_len); | ||
| 147 | return scnprintf(buf, buflen, "\n"); | ||
| 148 | } | ||
| 149 | __IEEE80211_IF_FILE(beacon_head_len); | ||
| 150 | |||
| 151 | static ssize_t ieee80211_if_fmt_beacon_tail_len( | ||
| 152 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
| 153 | { | ||
| 154 | if (sdata->u.ap.beacon_tail) | ||
| 155 | return scnprintf(buf, buflen, "%d\n", | ||
| 156 | sdata->u.ap.beacon_tail_len); | ||
| 157 | return scnprintf(buf, buflen, "\n"); | ||
| 158 | } | ||
| 159 | __IEEE80211_IF_FILE(beacon_tail_len); | ||
| 160 | |||
| 161 | /* WDS attributes */ | ||
| 162 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); | ||
| 163 | |||
| 164 | /* VLAN attributes */ | ||
| 165 | IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC); | ||
| 166 | |||
| 167 | /* MONITOR attributes */ | ||
| 168 | static ssize_t ieee80211_if_fmt_mode( | ||
| 169 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
| 170 | { | ||
| 171 | struct ieee80211_local *local = sdata->local; | ||
| 172 | |||
| 173 | return scnprintf(buf, buflen, "%s\n", | ||
| 174 | ((local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) || | ||
| 175 | local->open_count == local->monitors) ? | ||
| 176 | "hard" : "soft"); | ||
| 177 | } | ||
| 178 | __IEEE80211_IF_FILE(mode); | ||
| 179 | |||
| 180 | |||
| 181 | #define DEBUGFS_ADD(name, type)\ | ||
| 182 | sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\ | ||
| 183 | sdata->debugfsdir, sdata, &name##_ops); | ||
| 184 | |||
| 185 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) | ||
| 186 | { | ||
| 187 | DEBUGFS_ADD(channel_use, sta); | ||
| 188 | DEBUGFS_ADD(drop_unencrypted, sta); | ||
| 189 | DEBUGFS_ADD(eapol, sta); | ||
| 190 | DEBUGFS_ADD(ieee8021_x, sta); | ||
| 191 | DEBUGFS_ADD(state, sta); | ||
| 192 | DEBUGFS_ADD(bssid, sta); | ||
| 193 | DEBUGFS_ADD(prev_bssid, sta); | ||
| 194 | DEBUGFS_ADD(ssid_len, sta); | ||
| 195 | DEBUGFS_ADD(aid, sta); | ||
| 196 | DEBUGFS_ADD(ap_capab, sta); | ||
| 197 | DEBUGFS_ADD(capab, sta); | ||
| 198 | DEBUGFS_ADD(extra_ie_len, sta); | ||
| 199 | DEBUGFS_ADD(auth_tries, sta); | ||
| 200 | DEBUGFS_ADD(assoc_tries, sta); | ||
| 201 | DEBUGFS_ADD(auth_algs, sta); | ||
| 202 | DEBUGFS_ADD(auth_alg, sta); | ||
| 203 | DEBUGFS_ADD(auth_transaction, sta); | ||
| 204 | DEBUGFS_ADD(flags, sta); | ||
| 205 | } | ||
| 206 | |||
| 207 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) | ||
| 208 | { | ||
| 209 | DEBUGFS_ADD(channel_use, ap); | ||
| 210 | DEBUGFS_ADD(drop_unencrypted, ap); | ||
| 211 | DEBUGFS_ADD(eapol, ap); | ||
| 212 | DEBUGFS_ADD(ieee8021_x, ap); | ||
| 213 | DEBUGFS_ADD(num_sta_ps, ap); | ||
| 214 | DEBUGFS_ADD(dtim_period, ap); | ||
| 215 | DEBUGFS_ADD(dtim_count, ap); | ||
| 216 | DEBUGFS_ADD(num_beacons, ap); | ||
| 217 | DEBUGFS_ADD(force_unicast_rateidx, ap); | ||
| 218 | DEBUGFS_ADD(max_ratectrl_rateidx, ap); | ||
| 219 | DEBUGFS_ADD(num_buffered_multicast, ap); | ||
| 220 | DEBUGFS_ADD(beacon_head_len, ap); | ||
| 221 | DEBUGFS_ADD(beacon_tail_len, ap); | ||
| 222 | } | ||
| 223 | |||
| 224 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) | ||
| 225 | { | ||
| 226 | DEBUGFS_ADD(channel_use, wds); | ||
| 227 | DEBUGFS_ADD(drop_unencrypted, wds); | ||
| 228 | DEBUGFS_ADD(eapol, wds); | ||
| 229 | DEBUGFS_ADD(ieee8021_x, wds); | ||
| 230 | DEBUGFS_ADD(peer, wds); | ||
| 231 | } | ||
| 232 | |||
| 233 | static void add_vlan_files(struct ieee80211_sub_if_data *sdata) | ||
| 234 | { | ||
| 235 | DEBUGFS_ADD(channel_use, vlan); | ||
| 236 | DEBUGFS_ADD(drop_unencrypted, vlan); | ||
| 237 | DEBUGFS_ADD(eapol, vlan); | ||
| 238 | DEBUGFS_ADD(ieee8021_x, vlan); | ||
| 239 | DEBUGFS_ADD(vlan_id, vlan); | ||
| 240 | } | ||
| 241 | |||
| 242 | static void add_monitor_files(struct ieee80211_sub_if_data *sdata) | ||
| 243 | { | ||
| 244 | DEBUGFS_ADD(mode, monitor); | ||
| 245 | } | ||
| 246 | |||
| 247 | static void add_files(struct ieee80211_sub_if_data *sdata) | ||
| 248 | { | ||
| 249 | if (!sdata->debugfsdir) | ||
| 250 | return; | ||
| 251 | |||
| 252 | switch (sdata->type) { | ||
| 253 | case IEEE80211_IF_TYPE_STA: | ||
| 254 | case IEEE80211_IF_TYPE_IBSS: | ||
| 255 | add_sta_files(sdata); | ||
| 256 | break; | ||
| 257 | case IEEE80211_IF_TYPE_AP: | ||
| 258 | add_ap_files(sdata); | ||
| 259 | break; | ||
| 260 | case IEEE80211_IF_TYPE_WDS: | ||
| 261 | add_wds_files(sdata); | ||
| 262 | break; | ||
| 263 | case IEEE80211_IF_TYPE_MNTR: | ||
| 264 | add_monitor_files(sdata); | ||
| 265 | break; | ||
| 266 | case IEEE80211_IF_TYPE_VLAN: | ||
| 267 | add_vlan_files(sdata); | ||
| 268 | break; | ||
| 269 | default: | ||
| 270 | break; | ||
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 274 | #define DEBUGFS_DEL(name, type)\ | ||
| 275 | debugfs_remove(sdata->debugfs.type.name);\ | ||
| 276 | sdata->debugfs.type.name = NULL; | ||
| 277 | |||
| 278 | static void del_sta_files(struct ieee80211_sub_if_data *sdata) | ||
| 279 | { | ||
| 280 | DEBUGFS_DEL(channel_use, sta); | ||
| 281 | DEBUGFS_DEL(drop_unencrypted, sta); | ||
| 282 | DEBUGFS_DEL(eapol, sta); | ||
| 283 | DEBUGFS_DEL(ieee8021_x, sta); | ||
| 284 | DEBUGFS_DEL(state, sta); | ||
| 285 | DEBUGFS_DEL(bssid, sta); | ||
| 286 | DEBUGFS_DEL(prev_bssid, sta); | ||
| 287 | DEBUGFS_DEL(ssid_len, sta); | ||
| 288 | DEBUGFS_DEL(aid, sta); | ||
| 289 | DEBUGFS_DEL(ap_capab, sta); | ||
| 290 | DEBUGFS_DEL(capab, sta); | ||
| 291 | DEBUGFS_DEL(extra_ie_len, sta); | ||
| 292 | DEBUGFS_DEL(auth_tries, sta); | ||
| 293 | DEBUGFS_DEL(assoc_tries, sta); | ||
| 294 | DEBUGFS_DEL(auth_algs, sta); | ||
| 295 | DEBUGFS_DEL(auth_alg, sta); | ||
| 296 | DEBUGFS_DEL(auth_transaction, sta); | ||
| 297 | DEBUGFS_DEL(flags, sta); | ||
| 298 | } | ||
| 299 | |||
| 300 | static void del_ap_files(struct ieee80211_sub_if_data *sdata) | ||
| 301 | { | ||
| 302 | DEBUGFS_DEL(channel_use, ap); | ||
| 303 | DEBUGFS_DEL(drop_unencrypted, ap); | ||
| 304 | DEBUGFS_DEL(eapol, ap); | ||
| 305 | DEBUGFS_DEL(ieee8021_x, ap); | ||
| 306 | DEBUGFS_DEL(num_sta_ps, ap); | ||
| 307 | DEBUGFS_DEL(dtim_period, ap); | ||
| 308 | DEBUGFS_DEL(dtim_count, ap); | ||
| 309 | DEBUGFS_DEL(num_beacons, ap); | ||
| 310 | DEBUGFS_DEL(force_unicast_rateidx, ap); | ||
| 311 | DEBUGFS_DEL(max_ratectrl_rateidx, ap); | ||
| 312 | DEBUGFS_DEL(num_buffered_multicast, ap); | ||
| 313 | DEBUGFS_DEL(beacon_head_len, ap); | ||
| 314 | DEBUGFS_DEL(beacon_tail_len, ap); | ||
| 315 | } | ||
| 316 | |||
| 317 | static void del_wds_files(struct ieee80211_sub_if_data *sdata) | ||
| 318 | { | ||
| 319 | DEBUGFS_DEL(channel_use, wds); | ||
| 320 | DEBUGFS_DEL(drop_unencrypted, wds); | ||
| 321 | DEBUGFS_DEL(eapol, wds); | ||
| 322 | DEBUGFS_DEL(ieee8021_x, wds); | ||
| 323 | DEBUGFS_DEL(peer, wds); | ||
| 324 | } | ||
| 325 | |||
| 326 | static void del_vlan_files(struct ieee80211_sub_if_data *sdata) | ||
| 327 | { | ||
| 328 | DEBUGFS_DEL(channel_use, vlan); | ||
| 329 | DEBUGFS_DEL(drop_unencrypted, vlan); | ||
| 330 | DEBUGFS_DEL(eapol, vlan); | ||
| 331 | DEBUGFS_DEL(ieee8021_x, vlan); | ||
| 332 | DEBUGFS_DEL(vlan_id, vlan); | ||
| 333 | } | ||
| 334 | |||
| 335 | static void del_monitor_files(struct ieee80211_sub_if_data *sdata) | ||
| 336 | { | ||
| 337 | DEBUGFS_DEL(mode, monitor); | ||
| 338 | } | ||
| 339 | |||
| 340 | static void del_files(struct ieee80211_sub_if_data *sdata, int type) | ||
| 341 | { | ||
| 342 | if (!sdata->debugfsdir) | ||
| 343 | return; | ||
| 344 | |||
| 345 | switch (type) { | ||
| 346 | case IEEE80211_IF_TYPE_STA: | ||
| 347 | case IEEE80211_IF_TYPE_IBSS: | ||
| 348 | del_sta_files(sdata); | ||
| 349 | break; | ||
| 350 | case IEEE80211_IF_TYPE_AP: | ||
| 351 | del_ap_files(sdata); | ||
| 352 | break; | ||
| 353 | case IEEE80211_IF_TYPE_WDS: | ||
| 354 | del_wds_files(sdata); | ||
| 355 | break; | ||
| 356 | case IEEE80211_IF_TYPE_MNTR: | ||
| 357 | del_monitor_files(sdata); | ||
| 358 | break; | ||
| 359 | case IEEE80211_IF_TYPE_VLAN: | ||
| 360 | del_vlan_files(sdata); | ||
| 361 | break; | ||
| 362 | default: | ||
| 363 | break; | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | static int notif_registered; | ||
| 368 | |||
| 369 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) | ||
| 370 | { | ||
| 371 | char buf[10+IFNAMSIZ]; | ||
| 372 | |||
| 373 | if (!notif_registered) | ||
| 374 | return; | ||
| 375 | |||
| 376 | sprintf(buf, "netdev:%s", sdata->dev->name); | ||
| 377 | sdata->debugfsdir = debugfs_create_dir(buf, | ||
| 378 | sdata->local->hw.wiphy->debugfsdir); | ||
| 379 | } | ||
| 380 | |||
| 381 | void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) | ||
| 382 | { | ||
| 383 | del_files(sdata, sdata->type); | ||
| 384 | debugfs_remove(sdata->debugfsdir); | ||
| 385 | sdata->debugfsdir = NULL; | ||
| 386 | } | ||
| 387 | |||
| 388 | void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata, | ||
| 389 | int oldtype) | ||
| 390 | { | ||
| 391 | del_files(sdata, oldtype); | ||
| 392 | add_files(sdata); | ||
| 393 | } | ||
| 394 | |||
| 395 | static int netdev_notify(struct notifier_block * nb, | ||
| 396 | unsigned long state, | ||
| 397 | void *ndev) | ||
| 398 | { | ||
| 399 | struct net_device *dev = ndev; | ||
| 400 | char buf[10+IFNAMSIZ]; | ||
| 401 | |||
| 402 | if (state != NETDEV_CHANGENAME) | ||
| 403 | return 0; | ||
| 404 | |||
| 405 | if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) | ||
| 406 | return 0; | ||
| 407 | |||
| 408 | if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) | ||
| 409 | return 0; | ||
| 410 | |||
| 411 | /* TODO | ||
| 412 | sprintf(buf, "netdev:%s", dev->name); | ||
| 413 | debugfs_rename(IEEE80211_DEV_TO_SUB_IF(dev)->debugfsdir, buf); | ||
| 414 | */ | ||
| 415 | |||
| 416 | return 0; | ||
| 417 | } | ||
| 418 | |||
| 419 | static struct notifier_block mac80211_debugfs_netdev_notifier = { | ||
| 420 | .notifier_call = netdev_notify, | ||
| 421 | }; | ||
| 422 | |||
| 423 | void ieee80211_debugfs_netdev_init(void) | ||
| 424 | { | ||
| 425 | int err; | ||
| 426 | |||
| 427 | err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier); | ||
| 428 | if (err) { | ||
| 429 | printk(KERN_ERR | ||
| 430 | "mac80211: failed to install netdev notifier," | ||
| 431 | " disabling per-netdev debugfs!\n"); | ||
| 432 | } else | ||
| 433 | notif_registered = 1; | ||
| 434 | } | ||
| 435 | |||
| 436 | void ieee80211_debugfs_netdev_exit(void) | ||
| 437 | { | ||
| 438 | unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier); | ||
| 439 | notif_registered = 0; | ||
| 440 | } | ||
diff --git a/net/mac80211/debugfs_netdev.h b/net/mac80211/debugfs_netdev.h new file mode 100644 index 000000000000..a690071fde8a --- /dev/null +++ b/net/mac80211/debugfs_netdev.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* routines exported for debugfs handling */ | ||
| 2 | |||
| 3 | #ifndef __IEEE80211_DEBUGFS_NETDEV_H | ||
| 4 | #define __IEEE80211_DEBUGFS_NETDEV_H | ||
| 5 | |||
| 6 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 7 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata); | ||
| 8 | void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata); | ||
| 9 | void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata, | ||
| 10 | int oldtype); | ||
| 11 | void ieee80211_debugfs_netdev_init(void); | ||
| 12 | void ieee80211_debugfs_netdev_exit(void); | ||
| 13 | #else | ||
| 14 | static inline void ieee80211_debugfs_add_netdev( | ||
| 15 | struct ieee80211_sub_if_data *sdata) | ||
| 16 | {} | ||
| 17 | static inline void ieee80211_debugfs_remove_netdev( | ||
| 18 | struct ieee80211_sub_if_data *sdata) | ||
| 19 | {} | ||
| 20 | static inline void ieee80211_debugfs_change_if_type( | ||
| 21 | struct ieee80211_sub_if_data *sdata, int oldtype) | ||
| 22 | {} | ||
| 23 | static inline void ieee80211_debugfs_netdev_init(void) | ||
| 24 | {} | ||
| 25 | |||
| 26 | static inline void ieee80211_debugfs_netdev_exit(void) | ||
| 27 | {} | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #endif /* __IEEE80211_DEBUGFS_NETDEV_H */ | ||
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c new file mode 100644 index 000000000000..d41e696f3980 --- /dev/null +++ b/net/mac80211/debugfs_sta.c | |||
| @@ -0,0 +1,246 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2003-2005 Devicescape Software, Inc. | ||
| 3 | * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> | ||
| 4 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/debugfs.h> | ||
| 12 | #include <linux/ieee80211.h> | ||
| 13 | #include "ieee80211_i.h" | ||
| 14 | #include "debugfs.h" | ||
| 15 | #include "debugfs_sta.h" | ||
| 16 | #include "sta_info.h" | ||
| 17 | |||
| 18 | /* sta attributtes */ | ||
| 19 | |||
| 20 | #define STA_READ(name, buflen, field, format_string) \ | ||
| 21 | static ssize_t sta_ ##name## _read(struct file *file, \ | ||
| 22 | char __user *userbuf, \ | ||
| 23 | size_t count, loff_t *ppos) \ | ||
| 24 | { \ | ||
| 25 | int res; \ | ||
| 26 | struct sta_info *sta = file->private_data; \ | ||
| 27 | char buf[buflen]; \ | ||
| 28 | res = scnprintf(buf, buflen, format_string, sta->field); \ | ||
| 29 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
| 30 | } | ||
| 31 | #define STA_READ_D(name, field) STA_READ(name, 20, field, "%d\n") | ||
| 32 | #define STA_READ_U(name, field) STA_READ(name, 20, field, "%u\n") | ||
| 33 | #define STA_READ_LU(name, field) STA_READ(name, 20, field, "%lu\n") | ||
| 34 | #define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n") | ||
| 35 | |||
| 36 | #define STA_READ_RATE(name, field) \ | ||
| 37 | static ssize_t sta_##name##_read(struct file *file, \ | ||
| 38 | char __user *userbuf, \ | ||
| 39 | size_t count, loff_t *ppos) \ | ||
| 40 | { \ | ||
| 41 | struct sta_info *sta = file->private_data; \ | ||
| 42 | struct ieee80211_local *local = wdev_priv(sta->dev->ieee80211_ptr);\ | ||
| 43 | struct ieee80211_hw_mode *mode = local->oper_hw_mode; \ | ||
| 44 | char buf[20]; \ | ||
| 45 | int res = scnprintf(buf, sizeof(buf), "%d\n", \ | ||
| 46 | (sta->field >= 0 && \ | ||
| 47 | sta->field < mode->num_rates) ? \ | ||
| 48 | mode->rates[sta->field].rate : -1); \ | ||
| 49 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
| 50 | } | ||
| 51 | |||
| 52 | #define STA_OPS(name) \ | ||
| 53 | static const struct file_operations sta_ ##name## _ops = { \ | ||
| 54 | .read = sta_##name##_read, \ | ||
| 55 | .open = mac80211_open_file_generic, \ | ||
| 56 | } | ||
| 57 | |||
| 58 | #define STA_FILE(name, field, format) \ | ||
| 59 | STA_READ_##format(name, field) \ | ||
| 60 | STA_OPS(name) | ||
| 61 | |||
| 62 | STA_FILE(aid, aid, D); | ||
| 63 | STA_FILE(key_idx_compression, key_idx_compression, D); | ||
| 64 | STA_FILE(dev, dev->name, S); | ||
| 65 | STA_FILE(vlan_id, vlan_id, D); | ||
| 66 | STA_FILE(rx_packets, rx_packets, LU); | ||
| 67 | STA_FILE(tx_packets, tx_packets, LU); | ||
| 68 | STA_FILE(rx_bytes, rx_bytes, LU); | ||
| 69 | STA_FILE(tx_bytes, tx_bytes, LU); | ||
| 70 | STA_FILE(rx_duplicates, num_duplicates, LU); | ||
| 71 | STA_FILE(rx_fragments, rx_fragments, LU); | ||
| 72 | STA_FILE(rx_dropped, rx_dropped, LU); | ||
| 73 | STA_FILE(tx_fragments, tx_fragments, LU); | ||
| 74 | STA_FILE(tx_filtered, tx_filtered_count, LU); | ||
| 75 | STA_FILE(txrate, txrate, RATE); | ||
| 76 | STA_FILE(last_txrate, last_txrate, RATE); | ||
| 77 | STA_FILE(tx_retry_failed, tx_retry_failed, LU); | ||
| 78 | STA_FILE(tx_retry_count, tx_retry_count, LU); | ||
| 79 | STA_FILE(last_rssi, last_rssi, D); | ||
| 80 | STA_FILE(last_signal, last_signal, D); | ||
| 81 | STA_FILE(last_noise, last_noise, D); | ||
| 82 | STA_FILE(channel_use, channel_use, D); | ||
| 83 | STA_FILE(wep_weak_iv_count, wep_weak_iv_count, D); | ||
| 84 | |||
| 85 | static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | ||
| 86 | size_t count, loff_t *ppos) | ||
| 87 | { | ||
| 88 | char buf[100]; | ||
| 89 | struct sta_info *sta = file->private_data; | ||
| 90 | int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s", | ||
| 91 | sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "", | ||
| 92 | sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "", | ||
| 93 | sta->flags & WLAN_STA_PS ? "PS\n" : "", | ||
| 94 | sta->flags & WLAN_STA_TIM ? "TIM\n" : "", | ||
| 95 | sta->flags & WLAN_STA_PERM ? "PERM\n" : "", | ||
| 96 | sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", | ||
| 97 | sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", | ||
| 98 | sta->flags & WLAN_STA_WME ? "WME\n" : "", | ||
| 99 | sta->flags & WLAN_STA_WDS ? "WDS\n" : ""); | ||
| 100 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
| 101 | } | ||
| 102 | STA_OPS(flags); | ||
| 103 | |||
| 104 | static ssize_t sta_num_ps_buf_frames_read(struct file *file, | ||
| 105 | char __user *userbuf, | ||
| 106 | size_t count, loff_t *ppos) | ||
| 107 | { | ||
| 108 | char buf[20]; | ||
| 109 | struct sta_info *sta = file->private_data; | ||
| 110 | int res = scnprintf(buf, sizeof(buf), "%u\n", | ||
| 111 | skb_queue_len(&sta->ps_tx_buf)); | ||
| 112 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
| 113 | } | ||
| 114 | STA_OPS(num_ps_buf_frames); | ||
| 115 | |||
| 116 | static ssize_t sta_last_ack_rssi_read(struct file *file, char __user *userbuf, | ||
| 117 | size_t count, loff_t *ppos) | ||
| 118 | { | ||
| 119 | char buf[100]; | ||
| 120 | struct sta_info *sta = file->private_data; | ||
| 121 | int res = scnprintf(buf, sizeof(buf), "%d %d %d\n", | ||
| 122 | sta->last_ack_rssi[0], | ||
| 123 | sta->last_ack_rssi[1], | ||
| 124 | sta->last_ack_rssi[2]); | ||
| 125 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
| 126 | } | ||
| 127 | STA_OPS(last_ack_rssi); | ||
| 128 | |||
| 129 | static ssize_t sta_last_ack_ms_read(struct file *file, char __user *userbuf, | ||
| 130 | size_t count, loff_t *ppos) | ||
| 131 | { | ||
| 132 | char buf[20]; | ||
| 133 | struct sta_info *sta = file->private_data; | ||
| 134 | int res = scnprintf(buf, sizeof(buf), "%d\n", | ||
| 135 | sta->last_ack ? | ||
| 136 | jiffies_to_msecs(jiffies - sta->last_ack) : -1); | ||
| 137 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
| 138 | } | ||
| 139 | STA_OPS(last_ack_ms); | ||
| 140 | |||
| 141 | static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf, | ||
| 142 | size_t count, loff_t *ppos) | ||
| 143 | { | ||
| 144 | char buf[20]; | ||
| 145 | struct sta_info *sta = file->private_data; | ||
| 146 | int res = scnprintf(buf, sizeof(buf), "%d\n", | ||
| 147 | jiffies_to_msecs(jiffies - sta->last_rx)); | ||
| 148 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
| 149 | } | ||
| 150 | STA_OPS(inactive_ms); | ||
| 151 | |||
| 152 | static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, | ||
| 153 | size_t count, loff_t *ppos) | ||
| 154 | { | ||
| 155 | char buf[15*NUM_RX_DATA_QUEUES], *p = buf; | ||
| 156 | int i; | ||
| 157 | struct sta_info *sta = file->private_data; | ||
| 158 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | ||
| 159 | p += scnprintf(p, sizeof(buf)+buf-p, "%x ", | ||
| 160 | sta->last_seq_ctrl[i]); | ||
| 161 | p += scnprintf(p, sizeof(buf)+buf-p, "\n"); | ||
| 162 | return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); | ||
| 163 | } | ||
| 164 | STA_OPS(last_seq_ctrl); | ||
| 165 | |||
| 166 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
| 167 | static ssize_t sta_wme_rx_queue_read(struct file *file, char __user *userbuf, | ||
| 168 | size_t count, loff_t *ppos) | ||
| 169 | { | ||
| 170 | char buf[15*NUM_RX_DATA_QUEUES], *p = buf; | ||
| 171 | int i; | ||
| 172 | struct sta_info *sta = file->private_data; | ||
| 173 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | ||
| 174 | p += scnprintf(p, sizeof(buf)+buf-p, "%u ", | ||
| 175 | sta->wme_rx_queue[i]); | ||
| 176 | p += scnprintf(p, sizeof(buf)+buf-p, "\n"); | ||
| 177 | return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); | ||
| 178 | } | ||
| 179 | STA_OPS(wme_rx_queue); | ||
| 180 | |||
| 181 | static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf, | ||
| 182 | size_t count, loff_t *ppos) | ||
| 183 | { | ||
| 184 | char buf[15*NUM_TX_DATA_QUEUES], *p = buf; | ||
| 185 | int i; | ||
| 186 | struct sta_info *sta = file->private_data; | ||
| 187 | for (i = 0; i < NUM_TX_DATA_QUEUES; i++) | ||
| 188 | p += scnprintf(p, sizeof(buf)+buf-p, "%u ", | ||
| 189 | sta->wme_tx_queue[i]); | ||
| 190 | p += scnprintf(p, sizeof(buf)+buf-p, "\n"); | ||
| 191 | return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); | ||
| 192 | } | ||
| 193 | STA_OPS(wme_tx_queue); | ||
| 194 | #endif | ||
| 195 | |||
| 196 | #define DEBUGFS_ADD(name) \ | ||
| 197 | sta->debugfs.name = debugfs_create_file(#name, 0444, \ | ||
| 198 | sta->debugfs.dir, sta, &sta_ ##name## _ops); | ||
| 199 | |||
| 200 | #define DEBUGFS_DEL(name) \ | ||
| 201 | debugfs_remove(sta->debugfs.name);\ | ||
| 202 | sta->debugfs.name = NULL; | ||
| 203 | |||
| 204 | |||
| 205 | void ieee80211_sta_debugfs_add(struct sta_info *sta) | ||
| 206 | { | ||
| 207 | char buf[3*6]; | ||
| 208 | struct dentry *stations_dir = sta->local->debugfs.stations; | ||
| 209 | |||
| 210 | if (!stations_dir) | ||
| 211 | return; | ||
| 212 | |||
| 213 | sprintf(buf, MAC_FMT, MAC_ARG(sta->addr)); | ||
| 214 | |||
| 215 | sta->debugfs.dir = debugfs_create_dir(buf, stations_dir); | ||
| 216 | if (!sta->debugfs.dir) | ||
| 217 | return; | ||
| 218 | |||
| 219 | DEBUGFS_ADD(flags); | ||
| 220 | DEBUGFS_ADD(num_ps_buf_frames); | ||
| 221 | DEBUGFS_ADD(last_ack_rssi); | ||
| 222 | DEBUGFS_ADD(last_ack_ms); | ||
| 223 | DEBUGFS_ADD(inactive_ms); | ||
| 224 | DEBUGFS_ADD(last_seq_ctrl); | ||
| 225 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
| 226 | DEBUGFS_ADD(wme_rx_queue); | ||
| 227 | DEBUGFS_ADD(wme_tx_queue); | ||
| 228 | #endif | ||
| 229 | } | ||
| 230 | |||
| 231 | void ieee80211_sta_debugfs_remove(struct sta_info *sta) | ||
| 232 | { | ||
| 233 | DEBUGFS_DEL(flags); | ||
| 234 | DEBUGFS_DEL(num_ps_buf_frames); | ||
| 235 | DEBUGFS_DEL(last_ack_rssi); | ||
| 236 | DEBUGFS_DEL(last_ack_ms); | ||
| 237 | DEBUGFS_DEL(inactive_ms); | ||
| 238 | DEBUGFS_DEL(last_seq_ctrl); | ||
| 239 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
| 240 | DEBUGFS_DEL(wme_rx_queue); | ||
| 241 | DEBUGFS_DEL(wme_tx_queue); | ||
| 242 | #endif | ||
| 243 | |||
| 244 | debugfs_remove(sta->debugfs.dir); | ||
| 245 | sta->debugfs.dir = NULL; | ||
| 246 | } | ||
diff --git a/net/mac80211/debugfs_sta.h b/net/mac80211/debugfs_sta.h new file mode 100644 index 000000000000..574a1cd54b96 --- /dev/null +++ b/net/mac80211/debugfs_sta.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef __MAC80211_DEBUGFS_STA_H | ||
| 2 | #define __MAC80211_DEBUGFS_STA_H | ||
| 3 | |||
| 4 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 5 | void ieee80211_sta_debugfs_add(struct sta_info *sta); | ||
| 6 | void ieee80211_sta_debugfs_remove(struct sta_info *sta); | ||
| 7 | #else | ||
| 8 | static inline void ieee80211_sta_debugfs_add(struct sta_info *sta) {} | ||
| 9 | static inline void ieee80211_sta_debugfs_remove(struct sta_info *sta) {} | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #endif /* __MAC80211_DEBUGFS_STA_H */ | ||
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 48a832d4e175..6e36df67f8d5 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c | |||
| @@ -35,6 +35,9 @@ | |||
| 35 | #include "aes_ccm.h" | 35 | #include "aes_ccm.h" |
| 36 | #include "ieee80211_led.h" | 36 | #include "ieee80211_led.h" |
| 37 | #include "ieee80211_cfg.h" | 37 | #include "ieee80211_cfg.h" |
| 38 | #include "debugfs.h" | ||
| 39 | #include "debugfs_netdev.h" | ||
| 40 | #include "debugfs_key.h" | ||
| 38 | 41 | ||
| 39 | /* privid for wiphys to determine whether they belong to us or not */ | 42 | /* privid for wiphys to determine whether they belong to us or not */ |
| 40 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; | 43 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; |
| @@ -108,6 +111,7 @@ static void ieee80211_key_release(struct kref *kref) | |||
| 108 | key = container_of(kref, struct ieee80211_key, kref); | 111 | key = container_of(kref, struct ieee80211_key, kref); |
| 109 | if (key->alg == ALG_CCMP) | 112 | if (key->alg == ALG_CCMP) |
| 110 | ieee80211_aes_key_free(key->u.ccmp.tfm); | 113 | ieee80211_aes_key_free(key->u.ccmp.tfm); |
| 114 | ieee80211_debugfs_key_remove(key); | ||
| 111 | kfree(key); | 115 | kfree(key); |
| 112 | } | 116 | } |
| 113 | 117 | ||
| @@ -4704,6 +4708,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 4704 | goto fail_workqueue; | 4708 | goto fail_workqueue; |
| 4705 | } | 4709 | } |
| 4706 | 4710 | ||
| 4711 | debugfs_hw_add(local); | ||
| 4712 | |||
| 4707 | local->hw.conf.beacon_int = 1000; | 4713 | local->hw.conf.beacon_int = 1000; |
| 4708 | 4714 | ||
| 4709 | local->wstats_flags |= local->hw.max_rssi ? | 4715 | local->wstats_flags |= local->hw.max_rssi ? |
| @@ -4731,6 +4737,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 4731 | if (result < 0) | 4737 | if (result < 0) |
| 4732 | goto fail_dev; | 4738 | goto fail_dev; |
| 4733 | 4739 | ||
| 4740 | ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); | ||
| 4741 | |||
| 4734 | result = ieee80211_init_rate_ctrl_alg(local, NULL); | 4742 | result = ieee80211_init_rate_ctrl_alg(local, NULL); |
| 4735 | if (result < 0) { | 4743 | if (result < 0) { |
| 4736 | printk(KERN_DEBUG "%s: Failed to initialize rate control " | 4744 | printk(KERN_DEBUG "%s: Failed to initialize rate control " |
| @@ -4765,11 +4773,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 4765 | fail_wep: | 4773 | fail_wep: |
| 4766 | rate_control_deinitialize(local); | 4774 | rate_control_deinitialize(local); |
| 4767 | fail_rate: | 4775 | fail_rate: |
| 4776 | ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); | ||
| 4768 | unregister_netdevice(local->mdev); | 4777 | unregister_netdevice(local->mdev); |
| 4769 | fail_dev: | 4778 | fail_dev: |
| 4770 | rtnl_unlock(); | 4779 | rtnl_unlock(); |
| 4771 | sta_info_stop(local); | 4780 | sta_info_stop(local); |
| 4772 | fail_sta_info: | 4781 | fail_sta_info: |
| 4782 | debugfs_hw_del(local); | ||
| 4773 | destroy_workqueue(local->hw.workqueue); | 4783 | destroy_workqueue(local->hw.workqueue); |
| 4774 | fail_workqueue: | 4784 | fail_workqueue: |
| 4775 | wiphy_unregister(local->hw.wiphy); | 4785 | wiphy_unregister(local->hw.wiphy); |
| @@ -4844,6 +4854,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
| 4844 | ieee80211_clear_tx_pending(local); | 4854 | ieee80211_clear_tx_pending(local); |
| 4845 | sta_info_stop(local); | 4855 | sta_info_stop(local); |
| 4846 | rate_control_deinitialize(local); | 4856 | rate_control_deinitialize(local); |
| 4857 | debugfs_hw_del(local); | ||
| 4847 | 4858 | ||
| 4848 | for (i = 0; i < NUM_IEEE80211_MODES; i++) { | 4859 | for (i = 0; i < NUM_IEEE80211_MODES; i++) { |
| 4849 | kfree(local->supp_rates[i]); | 4860 | kfree(local->supp_rates[i]); |
| @@ -4953,6 +4964,8 @@ static int __init ieee80211_init(void) | |||
| 4953 | return ret; | 4964 | return ret; |
| 4954 | } | 4965 | } |
| 4955 | 4966 | ||
| 4967 | ieee80211_debugfs_netdev_init(); | ||
| 4968 | |||
| 4956 | return 0; | 4969 | return 0; |
| 4957 | } | 4970 | } |
| 4958 | 4971 | ||
| @@ -4960,6 +4973,7 @@ static int __init ieee80211_init(void) | |||
| 4960 | static void __exit ieee80211_exit(void) | 4973 | static void __exit ieee80211_exit(void) |
| 4961 | { | 4974 | { |
| 4962 | ieee80211_wme_unregister(); | 4975 | ieee80211_wme_unregister(); |
| 4976 | ieee80211_debugfs_netdev_exit(); | ||
| 4963 | } | 4977 | } |
| 4964 | 4978 | ||
| 4965 | 4979 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ae94d6461798..af4d14d0b969 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -307,6 +307,65 @@ struct ieee80211_sub_if_data { | |||
| 307 | } u; | 307 | } u; |
| 308 | int channel_use; | 308 | int channel_use; |
| 309 | int channel_use_raw; | 309 | int channel_use_raw; |
| 310 | |||
| 311 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 312 | struct dentry *debugfsdir; | ||
| 313 | union { | ||
| 314 | struct { | ||
| 315 | struct dentry *channel_use; | ||
| 316 | struct dentry *drop_unencrypted; | ||
| 317 | struct dentry *eapol; | ||
| 318 | struct dentry *ieee8021_x; | ||
| 319 | struct dentry *state; | ||
| 320 | struct dentry *bssid; | ||
| 321 | struct dentry *prev_bssid; | ||
| 322 | struct dentry *ssid_len; | ||
| 323 | struct dentry *aid; | ||
| 324 | struct dentry *ap_capab; | ||
| 325 | struct dentry *capab; | ||
| 326 | struct dentry *extra_ie_len; | ||
| 327 | struct dentry *auth_tries; | ||
| 328 | struct dentry *assoc_tries; | ||
| 329 | struct dentry *auth_algs; | ||
| 330 | struct dentry *auth_alg; | ||
| 331 | struct dentry *auth_transaction; | ||
| 332 | struct dentry *flags; | ||
| 333 | } sta; | ||
| 334 | struct { | ||
| 335 | struct dentry *channel_use; | ||
| 336 | struct dentry *drop_unencrypted; | ||
| 337 | struct dentry *eapol; | ||
| 338 | struct dentry *ieee8021_x; | ||
| 339 | struct dentry *num_sta_ps; | ||
| 340 | struct dentry *dtim_period; | ||
| 341 | struct dentry *dtim_count; | ||
| 342 | struct dentry *num_beacons; | ||
| 343 | struct dentry *force_unicast_rateidx; | ||
| 344 | struct dentry *max_ratectrl_rateidx; | ||
| 345 | struct dentry *num_buffered_multicast; | ||
| 346 | struct dentry *beacon_head_len; | ||
| 347 | struct dentry *beacon_tail_len; | ||
| 348 | } ap; | ||
| 349 | struct { | ||
| 350 | struct dentry *channel_use; | ||
| 351 | struct dentry *drop_unencrypted; | ||
| 352 | struct dentry *eapol; | ||
| 353 | struct dentry *ieee8021_x; | ||
| 354 | struct dentry *peer; | ||
| 355 | } wds; | ||
| 356 | struct { | ||
| 357 | struct dentry *channel_use; | ||
| 358 | struct dentry *drop_unencrypted; | ||
| 359 | struct dentry *eapol; | ||
| 360 | struct dentry *ieee8021_x; | ||
| 361 | struct dentry *vlan_id; | ||
| 362 | } vlan; | ||
| 363 | struct { | ||
| 364 | struct dentry *mode; | ||
| 365 | } monitor; | ||
| 366 | struct dentry *default_key; | ||
| 367 | } debugfs; | ||
| 368 | #endif | ||
| 310 | }; | 369 | }; |
| 311 | 370 | ||
| 312 | #define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev) | 371 | #define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev) |
| @@ -444,6 +503,10 @@ struct ieee80211_local { | |||
| 444 | u32 stat_time; | 503 | u32 stat_time; |
| 445 | struct timer_list stat_timer; | 504 | struct timer_list stat_timer; |
| 446 | 505 | ||
| 506 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 507 | struct work_struct sta_debugfs_add; | ||
| 508 | #endif | ||
| 509 | |||
| 447 | enum { | 510 | enum { |
| 448 | STA_ANTENNA_SEL_AUTO = 0, | 511 | STA_ANTENNA_SEL_AUTO = 0, |
| 449 | STA_ANTENNA_SEL_SW_CTRL = 1, | 512 | STA_ANTENNA_SEL_SW_CTRL = 1, |
| @@ -500,6 +563,70 @@ struct ieee80211_local { | |||
| 500 | * (1 << MODE_*) */ | 563 | * (1 << MODE_*) */ |
| 501 | 564 | ||
| 502 | int user_space_mlme; | 565 | int user_space_mlme; |
| 566 | |||
| 567 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 568 | struct local_debugfsdentries { | ||
| 569 | struct dentry *channel; | ||
| 570 | struct dentry *frequency; | ||
| 571 | struct dentry *radar_detect; | ||
| 572 | struct dentry *antenna_sel_tx; | ||
| 573 | struct dentry *antenna_sel_rx; | ||
| 574 | struct dentry *bridge_packets; | ||
| 575 | struct dentry *key_tx_rx_threshold; | ||
| 576 | struct dentry *rts_threshold; | ||
| 577 | struct dentry *fragmentation_threshold; | ||
| 578 | struct dentry *short_retry_limit; | ||
| 579 | struct dentry *long_retry_limit; | ||
| 580 | struct dentry *total_ps_buffered; | ||
| 581 | struct dentry *mode; | ||
| 582 | struct dentry *wep_iv; | ||
| 583 | struct dentry *tx_power_reduction; | ||
| 584 | struct dentry *modes; | ||
| 585 | struct dentry *statistics; | ||
| 586 | struct local_debugfsdentries_statsdentries { | ||
| 587 | struct dentry *transmitted_fragment_count; | ||
| 588 | struct dentry *multicast_transmitted_frame_count; | ||
| 589 | struct dentry *failed_count; | ||
| 590 | struct dentry *retry_count; | ||
| 591 | struct dentry *multiple_retry_count; | ||
| 592 | struct dentry *frame_duplicate_count; | ||
| 593 | struct dentry *received_fragment_count; | ||
| 594 | struct dentry *multicast_received_frame_count; | ||
| 595 | struct dentry *transmitted_frame_count; | ||
| 596 | struct dentry *wep_undecryptable_count; | ||
| 597 | struct dentry *num_scans; | ||
| 598 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
| 599 | struct dentry *tx_handlers_drop; | ||
| 600 | struct dentry *tx_handlers_queued; | ||
| 601 | struct dentry *tx_handlers_drop_unencrypted; | ||
| 602 | struct dentry *tx_handlers_drop_fragment; | ||
| 603 | struct dentry *tx_handlers_drop_wep; | ||
| 604 | struct dentry *tx_handlers_drop_not_assoc; | ||
| 605 | struct dentry *tx_handlers_drop_unauth_port; | ||
| 606 | struct dentry *rx_handlers_drop; | ||
| 607 | struct dentry *rx_handlers_queued; | ||
| 608 | struct dentry *rx_handlers_drop_nullfunc; | ||
| 609 | struct dentry *rx_handlers_drop_defrag; | ||
| 610 | struct dentry *rx_handlers_drop_short; | ||
| 611 | struct dentry *rx_handlers_drop_passive_scan; | ||
| 612 | struct dentry *tx_expand_skb_head; | ||
| 613 | struct dentry *tx_expand_skb_head_cloned; | ||
| 614 | struct dentry *rx_expand_skb_head; | ||
| 615 | struct dentry *rx_expand_skb_head2; | ||
| 616 | struct dentry *rx_handlers_fragments; | ||
| 617 | struct dentry *tx_status_drop; | ||
| 618 | struct dentry *wme_tx_queue; | ||
| 619 | struct dentry *wme_rx_queue; | ||
| 620 | #endif | ||
| 621 | struct dentry *dot11ACKFailureCount; | ||
| 622 | struct dentry *dot11RTSFailureCount; | ||
| 623 | struct dentry *dot11FCSErrorCount; | ||
| 624 | struct dentry *dot11RTSSuccessCount; | ||
| 625 | } stats; | ||
| 626 | struct dentry *stations; | ||
| 627 | struct dentry *keys; | ||
| 628 | } debugfs; | ||
| 629 | #endif | ||
| 503 | }; | 630 | }; |
| 504 | 631 | ||
| 505 | static inline struct ieee80211_local *hw_to_local( | 632 | static inline struct ieee80211_local *hw_to_local( |
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 64267d4b31a4..cf0f32e8c2a2 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <net/mac80211.h> | 14 | #include <net/mac80211.h> |
| 15 | #include "ieee80211_i.h" | 15 | #include "ieee80211_i.h" |
| 16 | #include "sta_info.h" | 16 | #include "sta_info.h" |
| 17 | #include "debugfs_netdev.h" | ||
| 17 | 18 | ||
| 18 | void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) | 19 | void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) |
| 19 | { | 20 | { |
| @@ -73,6 +74,7 @@ int ieee80211_if_add(struct net_device *dev, const char *name, | |||
| 73 | if (ret) | 74 | if (ret) |
| 74 | goto fail; | 75 | goto fail; |
| 75 | 76 | ||
| 77 | ieee80211_debugfs_add_netdev(sdata); | ||
| 76 | ieee80211_if_set_type(ndev, type); | 78 | ieee80211_if_set_type(ndev, type); |
| 77 | 79 | ||
| 78 | write_lock_bh(&local->sub_if_lock); | 80 | write_lock_bh(&local->sub_if_lock); |
| @@ -126,6 +128,8 @@ int ieee80211_if_add_mgmt(struct ieee80211_local *local) | |||
| 126 | if (ret) | 128 | if (ret) |
| 127 | goto fail; | 129 | goto fail; |
| 128 | 130 | ||
| 131 | ieee80211_debugfs_add_netdev(nsdata); | ||
| 132 | |||
| 129 | if (local->open_count > 0) | 133 | if (local->open_count > 0) |
| 130 | dev_open(ndev); | 134 | dev_open(ndev); |
| 131 | local->apdev = ndev; | 135 | local->apdev = ndev; |
| @@ -142,6 +146,7 @@ void ieee80211_if_del_mgmt(struct ieee80211_local *local) | |||
| 142 | 146 | ||
| 143 | ASSERT_RTNL(); | 147 | ASSERT_RTNL(); |
| 144 | apdev = local->apdev; | 148 | apdev = local->apdev; |
| 149 | ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(apdev)); | ||
| 145 | local->apdev = NULL; | 150 | local->apdev = NULL; |
| 146 | unregister_netdevice(apdev); | 151 | unregister_netdevice(apdev); |
| 147 | } | 152 | } |
| @@ -150,6 +155,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) | |||
| 150 | { | 155 | { |
| 151 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 156 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 152 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 157 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
| 158 | int oldtype = sdata->type; | ||
| 153 | 159 | ||
| 154 | sdata->type = type; | 160 | sdata->type = type; |
| 155 | switch (type) { | 161 | switch (type) { |
| @@ -195,6 +201,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) | |||
| 195 | printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x", | 201 | printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x", |
| 196 | dev->name, __FUNCTION__, type); | 202 | dev->name, __FUNCTION__, type); |
| 197 | } | 203 | } |
| 204 | ieee80211_debugfs_change_if_type(sdata, oldtype); | ||
| 198 | ieee80211_update_default_wep_only(local); | 205 | ieee80211_update_default_wep_only(local); |
| 199 | } | 206 | } |
| 200 | 207 | ||
| @@ -303,6 +310,7 @@ void __ieee80211_if_del(struct ieee80211_local *local, | |||
| 303 | { | 310 | { |
| 304 | struct net_device *dev = sdata->dev; | 311 | struct net_device *dev = sdata->dev; |
| 305 | 312 | ||
| 313 | ieee80211_debugfs_remove_netdev(sdata); | ||
| 306 | unregister_netdevice(dev); | 314 | unregister_netdevice(dev); |
| 307 | /* Except master interface, the net_device will be freed by | 315 | /* Except master interface, the net_device will be freed by |
| 308 | * net_device->destructor (i. e. ieee80211_if_free). */ | 316 | * net_device->destructor (i. e. ieee80211_if_free). */ |
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 73909ec85f2a..352f03bd8a3a 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include "ieee80211_rate.h" | 25 | #include "ieee80211_rate.h" |
| 26 | #include "wpa.h" | 26 | #include "wpa.h" |
| 27 | #include "aes_ccm.h" | 27 | #include "aes_ccm.h" |
| 28 | #include "debugfs_key.h" | ||
| 28 | 29 | ||
| 29 | static int ieee80211_regdom = 0x10; /* FCC */ | 30 | static int ieee80211_regdom = 0x10; /* FCC */ |
| 30 | module_param(ieee80211_regdom, int, 0444); | 31 | module_param(ieee80211_regdom, int, 0444); |
| @@ -180,8 +181,11 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
| 180 | } | 181 | } |
| 181 | kfree(keyconf); | 182 | kfree(keyconf); |
| 182 | 183 | ||
| 183 | if (set_tx_key || sdata->default_key == key) | 184 | if (set_tx_key || sdata->default_key == key) { |
| 185 | ieee80211_debugfs_key_remove_default(sdata); | ||
| 184 | sdata->default_key = NULL; | 186 | sdata->default_key = NULL; |
| 187 | } | ||
| 188 | ieee80211_debugfs_key_remove(key); | ||
| 185 | if (sta) | 189 | if (sta) |
| 186 | sta->key = NULL; | 190 | sta->key = NULL; |
| 187 | else | 191 | else |
| @@ -221,13 +225,19 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
| 221 | } | 225 | } |
| 222 | } | 226 | } |
| 223 | 227 | ||
| 224 | if (set_tx_key || sdata->default_key == old_key) | 228 | if (set_tx_key || sdata->default_key == old_key) { |
| 229 | ieee80211_debugfs_key_remove_default(sdata); | ||
| 225 | sdata->default_key = NULL; | 230 | sdata->default_key = NULL; |
| 231 | } | ||
| 232 | ieee80211_debugfs_key_remove(old_key); | ||
| 226 | if (sta) | 233 | if (sta) |
| 227 | sta->key = key; | 234 | sta->key = key; |
| 228 | else | 235 | else |
| 229 | sdata->keys[idx] = key; | 236 | sdata->keys[idx] = key; |
| 230 | ieee80211_key_free(old_key); | 237 | ieee80211_key_free(old_key); |
| 238 | ieee80211_debugfs_key_add(local, key); | ||
| 239 | if (sta) | ||
| 240 | ieee80211_debugfs_key_sta_link(key, sta); | ||
| 231 | 241 | ||
| 232 | if (try_hwaccel && | 242 | if (try_hwaccel && |
| 233 | (alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP)) | 243 | (alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP)) |
| @@ -236,6 +246,8 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
| 236 | 246 | ||
| 237 | if (set_tx_key || (!sta && !sdata->default_key && key)) { | 247 | if (set_tx_key || (!sta && !sdata->default_key && key)) { |
| 238 | sdata->default_key = key; | 248 | sdata->default_key = key; |
| 249 | if (key) | ||
| 250 | ieee80211_debugfs_key_add_default(sdata); | ||
| 239 | 251 | ||
| 240 | if (local->ops->set_key_idx && | 252 | if (local->ops->set_key_idx && |
| 241 | local->ops->set_key_idx(local_to_hw(local), idx)) | 253 | local->ops->set_key_idx(local_to_hw(local), idx)) |
| @@ -1505,8 +1517,12 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev, | |||
| 1505 | alg = ALG_NONE; | 1517 | alg = ALG_NONE; |
| 1506 | else if (erq->length == 0) { | 1518 | else if (erq->length == 0) { |
| 1507 | /* No key data - just set the default TX key index */ | 1519 | /* No key data - just set the default TX key index */ |
| 1508 | if (sdata->default_key != sdata->keys[idx]) | 1520 | if (sdata->default_key != sdata->keys[idx]) { |
| 1521 | ieee80211_debugfs_key_remove_default(sdata); | ||
| 1509 | sdata->default_key = sdata->keys[idx]; | 1522 | sdata->default_key = sdata->keys[idx]; |
| 1523 | if (sdata->default_key) | ||
| 1524 | ieee80211_debugfs_key_add_default(sdata); | ||
| 1525 | } | ||
| 1510 | return 0; | 1526 | return 0; |
| 1511 | } | 1527 | } |
| 1512 | 1528 | ||
diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h index da67d87705d7..c33384912782 100644 --- a/net/mac80211/ieee80211_key.h +++ b/net/mac80211/ieee80211_key.h | |||
| @@ -83,6 +83,23 @@ struct ieee80211_key { | |||
| 83 | * (used only for broadcast keys). */ | 83 | * (used only for broadcast keys). */ |
| 84 | s8 keyidx; /* WEP key index */ | 84 | s8 keyidx; /* WEP key index */ |
| 85 | 85 | ||
| 86 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 87 | struct { | ||
| 88 | struct dentry *stalink; | ||
| 89 | struct dentry *dir; | ||
| 90 | struct dentry *keylen; | ||
| 91 | struct dentry *force_sw_encrypt; | ||
| 92 | struct dentry *keyidx; | ||
| 93 | struct dentry *hw_key_idx; | ||
| 94 | struct dentry *tx_rx_count; | ||
| 95 | struct dentry *algorithm; | ||
| 96 | struct dentry *tx_spec; | ||
| 97 | struct dentry *rx_spec; | ||
| 98 | struct dentry *replays; | ||
| 99 | struct dentry *key; | ||
| 100 | } debugfs; | ||
| 101 | #endif | ||
| 102 | |||
| 86 | u8 key[0]; | 103 | u8 key[0]; |
| 87 | }; | 104 | }; |
| 88 | 105 | ||
diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h index 710f5685cedd..f021a028d9d0 100644 --- a/net/mac80211/ieee80211_rate.h +++ b/net/mac80211/ieee80211_rate.h | |||
| @@ -56,6 +56,9 @@ struct rate_control_ops { | |||
| 56 | 56 | ||
| 57 | int (*add_attrs)(void *priv, struct kobject *kobj); | 57 | int (*add_attrs)(void *priv, struct kobject *kobj); |
| 58 | void (*remove_attrs)(void *priv, struct kobject *kobj); | 58 | void (*remove_attrs)(void *priv, struct kobject *kobj); |
| 59 | void (*add_sta_debugfs)(void *priv, void *priv_sta, | ||
| 60 | struct dentry *dir); | ||
| 61 | void (*remove_sta_debugfs)(void *priv, void *priv_sta); | ||
| 59 | }; | 62 | }; |
| 60 | 63 | ||
| 61 | struct rate_control_ref { | 64 | struct rate_control_ref { |
| @@ -119,4 +122,23 @@ static inline void rate_control_free_sta(struct rate_control_ref *ref, | |||
| 119 | ref->ops->free_sta(ref->priv, priv); | 122 | ref->ops->free_sta(ref->priv, priv); |
| 120 | } | 123 | } |
| 121 | 124 | ||
| 125 | static inline void rate_control_add_sta_debugfs(struct sta_info *sta) | ||
| 126 | { | ||
| 127 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 128 | struct rate_control_ref *ref = sta->rate_ctrl; | ||
| 129 | if (sta->debugfs.dir && ref->ops->add_sta_debugfs) | ||
| 130 | ref->ops->add_sta_debugfs(ref->priv, sta->rate_ctrl_priv, | ||
| 131 | sta->debugfs.dir); | ||
| 132 | #endif | ||
| 133 | } | ||
| 134 | |||
| 135 | static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) | ||
| 136 | { | ||
| 137 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 138 | struct rate_control_ref *ref = sta->rate_ctrl; | ||
| 139 | if (ref->ops->remove_sta_debugfs) | ||
| 140 | ref->ops->remove_sta_debugfs(ref->priv, sta->rate_ctrl_priv); | ||
| 141 | #endif | ||
| 142 | } | ||
| 143 | |||
| 122 | #endif /* IEEE80211_RATE_H */ | 144 | #endif /* IEEE80211_RATE_H */ |
diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index 68bddaeee005..2048cfd1ca70 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <net/mac80211.h> | 18 | #include <net/mac80211.h> |
| 19 | #include "ieee80211_i.h" | 19 | #include "ieee80211_i.h" |
| 20 | #include "ieee80211_rate.h" | 20 | #include "ieee80211_rate.h" |
| 21 | #include "debugfs.h" | ||
| 21 | 22 | ||
| 22 | 23 | ||
| 23 | /* This is a minimal implementation of TX rate controlling that can be used | 24 | /* This is a minimal implementation of TX rate controlling that can be used |
| @@ -121,6 +122,11 @@ struct sta_rate_control { | |||
| 121 | unsigned long avg_rate_update; | 122 | unsigned long avg_rate_update; |
| 122 | u32 tx_avg_rate_sum; | 123 | u32 tx_avg_rate_sum; |
| 123 | u32 tx_avg_rate_num; | 124 | u32 tx_avg_rate_num; |
| 125 | |||
| 126 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 127 | struct dentry *tx_avg_rate_sum_dentry; | ||
| 128 | struct dentry *tx_avg_rate_num_dentry; | ||
| 129 | #endif | ||
| 124 | }; | 130 | }; |
| 125 | 131 | ||
| 126 | 132 | ||
| @@ -327,6 +333,67 @@ static void rate_control_simple_free_sta(void *priv, void *priv_sta) | |||
| 327 | kfree(rctrl); | 333 | kfree(rctrl); |
| 328 | } | 334 | } |
| 329 | 335 | ||
| 336 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 337 | |||
| 338 | static int open_file_generic(struct inode *inode, struct file *file) | ||
| 339 | { | ||
| 340 | file->private_data = inode->i_private; | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | |||
| 344 | static ssize_t sta_tx_avg_rate_sum_read(struct file *file, | ||
| 345 | char __user *userbuf, | ||
| 346 | size_t count, loff_t *ppos) | ||
| 347 | { | ||
| 348 | struct sta_rate_control *srctrl = file->private_data; | ||
| 349 | char buf[20]; | ||
| 350 | |||
| 351 | sprintf(buf, "%d\n", srctrl->tx_avg_rate_sum); | ||
| 352 | return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); | ||
| 353 | } | ||
| 354 | |||
| 355 | static const struct file_operations sta_tx_avg_rate_sum_ops = { | ||
| 356 | .read = sta_tx_avg_rate_sum_read, | ||
| 357 | .open = open_file_generic, | ||
| 358 | }; | ||
| 359 | |||
| 360 | static ssize_t sta_tx_avg_rate_num_read(struct file *file, | ||
| 361 | char __user *userbuf, | ||
| 362 | size_t count, loff_t *ppos) | ||
| 363 | { | ||
| 364 | struct sta_rate_control *srctrl = file->private_data; | ||
| 365 | char buf[20]; | ||
| 366 | |||
| 367 | sprintf(buf, "%d\n", srctrl->tx_avg_rate_num); | ||
| 368 | return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); | ||
| 369 | } | ||
| 370 | |||
| 371 | static const struct file_operations sta_tx_avg_rate_num_ops = { | ||
| 372 | .read = sta_tx_avg_rate_num_read, | ||
| 373 | .open = open_file_generic, | ||
| 374 | }; | ||
| 375 | |||
| 376 | static void rate_control_simple_add_sta_debugfs(void *priv, void *priv_sta, | ||
| 377 | struct dentry *dir) | ||
| 378 | { | ||
| 379 | struct sta_rate_control *srctrl = priv_sta; | ||
| 380 | |||
| 381 | srctrl->tx_avg_rate_num_dentry = | ||
| 382 | debugfs_create_file("rc_simple_sta_tx_avg_rate_num", 0400, | ||
| 383 | dir, srctrl, &sta_tx_avg_rate_num_ops); | ||
| 384 | srctrl->tx_avg_rate_sum_dentry = | ||
| 385 | debugfs_create_file("rc_simple_sta_tx_avg_rate_sum", 0400, | ||
| 386 | dir, srctrl, &sta_tx_avg_rate_sum_ops); | ||
| 387 | } | ||
| 388 | |||
| 389 | static void rate_control_simple_remove_sta_debugfs(void *priv, void *priv_sta) | ||
| 390 | { | ||
| 391 | struct sta_rate_control *srctrl = priv_sta; | ||
| 392 | |||
| 393 | debugfs_remove(srctrl->tx_avg_rate_sum_dentry); | ||
| 394 | debugfs_remove(srctrl->tx_avg_rate_num_dentry); | ||
| 395 | } | ||
| 396 | #endif | ||
| 330 | 397 | ||
| 331 | static struct rate_control_ops rate_control_simple = { | 398 | static struct rate_control_ops rate_control_simple = { |
| 332 | .module = THIS_MODULE, | 399 | .module = THIS_MODULE, |
| @@ -339,6 +406,10 @@ static struct rate_control_ops rate_control_simple = { | |||
| 339 | .free = rate_control_simple_free, | 406 | .free = rate_control_simple_free, |
| 340 | .alloc_sta = rate_control_simple_alloc_sta, | 407 | .alloc_sta = rate_control_simple_alloc_sta, |
| 341 | .free_sta = rate_control_simple_free_sta, | 408 | .free_sta = rate_control_simple_free_sta, |
| 409 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 410 | .add_sta_debugfs = rate_control_simple_add_sta_debugfs, | ||
| 411 | .remove_sta_debugfs = rate_control_simple_remove_sta_debugfs, | ||
| 412 | #endif | ||
| 342 | }; | 413 | }; |
| 343 | 414 | ||
| 344 | 415 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index cddaf578dc8f..ab7b1f067c6e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
| @@ -19,6 +19,8 @@ | |||
| 19 | #include "ieee80211_i.h" | 19 | #include "ieee80211_i.h" |
| 20 | #include "ieee80211_rate.h" | 20 | #include "ieee80211_rate.h" |
| 21 | #include "sta_info.h" | 21 | #include "sta_info.h" |
| 22 | #include "debugfs_key.h" | ||
| 23 | #include "debugfs_sta.h" | ||
| 22 | 24 | ||
| 23 | /* Caller must hold local->sta_lock */ | 25 | /* Caller must hold local->sta_lock */ |
| 24 | static void sta_info_hash_add(struct ieee80211_local *local, | 26 | static void sta_info_hash_add(struct ieee80211_local *local, |
| @@ -120,6 +122,8 @@ static void sta_info_release(struct kref *kref) | |||
| 120 | } | 122 | } |
| 121 | rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); | 123 | rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); |
| 122 | rate_control_put(sta->rate_ctrl); | 124 | rate_control_put(sta->rate_ctrl); |
| 125 | if (sta->key) | ||
| 126 | ieee80211_debugfs_key_sta_del(sta->key, sta); | ||
| 123 | kfree(sta); | 127 | kfree(sta); |
| 124 | } | 128 | } |
| 125 | 129 | ||
| @@ -173,9 +177,42 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, | |||
| 173 | local->mdev->name, MAC_ARG(addr)); | 177 | local->mdev->name, MAC_ARG(addr)); |
| 174 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 178 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
| 175 | 179 | ||
| 180 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 181 | if (!in_interrupt()) { | ||
| 182 | sta->debugfs_registered = 1; | ||
| 183 | ieee80211_sta_debugfs_add(sta); | ||
| 184 | rate_control_add_sta_debugfs(sta); | ||
| 185 | } else { | ||
| 186 | /* debugfs entry adding might sleep, so schedule process | ||
| 187 | * context task for adding entry for STAs that do not yet | ||
| 188 | * have one. */ | ||
| 189 | queue_work(local->hw.workqueue, &local->sta_debugfs_add); | ||
| 190 | } | ||
| 191 | #endif | ||
| 192 | |||
| 176 | return sta; | 193 | return sta; |
| 177 | } | 194 | } |
| 178 | 195 | ||
| 196 | static void finish_sta_info_free(struct ieee80211_local *local, | ||
| 197 | struct sta_info *sta) | ||
| 198 | { | ||
| 199 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
| 200 | printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n", | ||
| 201 | local->mdev->name, MAC_ARG(sta->addr)); | ||
| 202 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
| 203 | |||
| 204 | if (sta->key) { | ||
| 205 | ieee80211_debugfs_key_remove(sta->key); | ||
| 206 | ieee80211_key_free(sta->key); | ||
| 207 | sta->key = NULL; | ||
| 208 | } | ||
| 209 | |||
| 210 | rate_control_remove_sta_debugfs(sta); | ||
| 211 | ieee80211_sta_debugfs_remove(sta); | ||
| 212 | |||
| 213 | sta_info_put(sta); | ||
| 214 | } | ||
| 215 | |||
| 179 | static void sta_info_remove(struct sta_info *sta) | 216 | static void sta_info_remove(struct sta_info *sta) |
| 180 | { | 217 | { |
| 181 | struct ieee80211_local *local = sta->local; | 218 | struct ieee80211_local *local = sta->local; |
| @@ -239,17 +276,13 @@ void sta_info_free(struct sta_info *sta, int locked) | |||
| 239 | sta->key_idx_compression = HW_KEY_IDX_INVALID; | 276 | sta->key_idx_compression = HW_KEY_IDX_INVALID; |
| 240 | } | 277 | } |
| 241 | 278 | ||
| 242 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 279 | #ifdef CONFIG_MAC80211_DEBUGFS |
| 243 | printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n", | 280 | if (in_atomic()) { |
| 244 | local->mdev->name, MAC_ARG(sta->addr)); | 281 | list_add(&sta->list, &local->deleted_sta_list); |
| 245 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 282 | queue_work(local->hw.workqueue, &local->sta_debugfs_add); |
| 246 | 283 | } else | |
| 247 | if (sta->key) { | 284 | #endif |
| 248 | ieee80211_key_free(sta->key); | 285 | finish_sta_info_free(local, sta); |
| 249 | sta->key = NULL; | ||
| 250 | } | ||
| 251 | |||
| 252 | sta_info_put(sta); | ||
| 253 | } | 286 | } |
| 254 | 287 | ||
| 255 | 288 | ||
| @@ -322,6 +355,50 @@ static void sta_info_cleanup(unsigned long data) | |||
| 322 | add_timer(&local->sta_cleanup); | 355 | add_timer(&local->sta_cleanup); |
| 323 | } | 356 | } |
| 324 | 357 | ||
| 358 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 359 | static void sta_info_debugfs_add_task(struct work_struct *work) | ||
| 360 | { | ||
| 361 | struct ieee80211_local *local = | ||
| 362 | container_of(work, struct ieee80211_local, sta_debugfs_add); | ||
| 363 | struct sta_info *sta, *tmp; | ||
| 364 | |||
| 365 | while (1) { | ||
| 366 | spin_lock_bh(&local->sta_lock); | ||
| 367 | if (!list_empty(&local->deleted_sta_list)) { | ||
| 368 | sta = list_entry(local->deleted_sta_list.next, | ||
| 369 | struct sta_info, list); | ||
| 370 | list_del(local->deleted_sta_list.next); | ||
| 371 | } else | ||
| 372 | sta = NULL; | ||
| 373 | spin_unlock_bh(&local->sta_lock); | ||
| 374 | if (!sta) | ||
| 375 | break; | ||
| 376 | finish_sta_info_free(local, sta); | ||
| 377 | } | ||
| 378 | |||
| 379 | while (1) { | ||
| 380 | sta = NULL; | ||
| 381 | spin_lock_bh(&local->sta_lock); | ||
| 382 | list_for_each_entry(tmp, &local->sta_list, list) { | ||
| 383 | if (!tmp->debugfs_registered) { | ||
| 384 | sta = tmp; | ||
| 385 | __sta_info_get(sta); | ||
| 386 | break; | ||
| 387 | } | ||
| 388 | } | ||
| 389 | spin_unlock_bh(&local->sta_lock); | ||
| 390 | |||
| 391 | if (!sta) | ||
| 392 | break; | ||
| 393 | |||
| 394 | sta->debugfs_registered = 1; | ||
| 395 | ieee80211_sta_debugfs_add(sta); | ||
| 396 | rate_control_add_sta_debugfs(sta); | ||
| 397 | sta_info_put(sta); | ||
| 398 | } | ||
| 399 | } | ||
| 400 | #endif | ||
| 401 | |||
| 325 | void sta_info_init(struct ieee80211_local *local) | 402 | void sta_info_init(struct ieee80211_local *local) |
| 326 | { | 403 | { |
| 327 | spin_lock_init(&local->sta_lock); | 404 | spin_lock_init(&local->sta_lock); |
| @@ -332,6 +409,10 @@ void sta_info_init(struct ieee80211_local *local) | |||
| 332 | local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; | 409 | local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; |
| 333 | local->sta_cleanup.data = (unsigned long) local; | 410 | local->sta_cleanup.data = (unsigned long) local; |
| 334 | local->sta_cleanup.function = sta_info_cleanup; | 411 | local->sta_cleanup.function = sta_info_cleanup; |
| 412 | |||
| 413 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 414 | INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_task); | ||
| 415 | #endif | ||
| 335 | } | 416 | } |
| 336 | 417 | ||
| 337 | int sta_info_start(struct ieee80211_local *local) | 418 | int sta_info_start(struct ieee80211_local *local) |
| @@ -347,7 +428,10 @@ void sta_info_stop(struct ieee80211_local *local) | |||
| 347 | del_timer(&local->sta_cleanup); | 428 | del_timer(&local->sta_cleanup); |
| 348 | 429 | ||
| 349 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { | 430 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { |
| 350 | /* We don't need locking at this point. */ | 431 | /* sta_info_free must be called with 0 as the last |
| 432 | * parameter to ensure all debugfs sta entries are | ||
| 433 | * unregistered. We don't need locking at this | ||
| 434 | * point. */ | ||
| 351 | sta_info_free(sta, 0); | 435 | sta_info_free(sta, 0); |
| 352 | } | 436 | } |
| 353 | } | 437 | } |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index f26e1c294395..b5591d2f60a4 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
| @@ -98,6 +98,9 @@ struct sta_info { | |||
| 98 | * filtering; used only if sta->key is not | 98 | * filtering; used only if sta->key is not |
| 99 | * set */ | 99 | * set */ |
| 100 | 100 | ||
| 101 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 102 | int debugfs_registered; | ||
| 103 | #endif | ||
| 101 | int assoc_ap; /* whether this is an AP that we are | 104 | int assoc_ap; /* whether this is an AP that we are |
| 102 | * associated with as a client */ | 105 | * associated with as a client */ |
| 103 | 106 | ||
| @@ -109,6 +112,22 @@ struct sta_info { | |||
| 109 | int vlan_id; | 112 | int vlan_id; |
| 110 | 113 | ||
| 111 | u16 listen_interval; | 114 | u16 listen_interval; |
| 115 | |||
| 116 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 117 | struct sta_info_debugfsdentries { | ||
| 118 | struct dentry *dir; | ||
| 119 | struct dentry *flags; | ||
| 120 | struct dentry *num_ps_buf_frames; | ||
| 121 | struct dentry *last_ack_rssi; | ||
| 122 | struct dentry *last_ack_ms; | ||
| 123 | struct dentry *inactive_ms; | ||
| 124 | struct dentry *last_seq_ctrl; | ||
| 125 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | ||
| 126 | struct dentry *wme_rx_queue; | ||
| 127 | struct dentry *wme_tx_queue; | ||
| 128 | #endif | ||
| 129 | } debugfs; | ||
| 130 | #endif | ||
| 112 | }; | 131 | }; |
| 113 | 132 | ||
| 114 | 133 | ||
