at v2.6.37 455 lines 12 kB view raw
1 2/* 3 * mac80211 debugfs for wireless PHYs 4 * 5 * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> 6 * 7 * GPLv2 8 * 9 */ 10 11#include <linux/debugfs.h> 12#include <linux/rtnetlink.h> 13#include "ieee80211_i.h" 14#include "driver-ops.h" 15#include "rate.h" 16#include "debugfs.h" 17 18int mac80211_open_file_generic(struct inode *inode, struct file *file) 19{ 20 file->private_data = inode->i_private; 21 return 0; 22} 23 24#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ 25static ssize_t name## _read(struct file *file, char __user *userbuf, \ 26 size_t count, loff_t *ppos) \ 27{ \ 28 struct ieee80211_local *local = file->private_data; \ 29 char buf[buflen]; \ 30 int res; \ 31 \ 32 res = scnprintf(buf, buflen, fmt "\n", ##value); \ 33 return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ 34} \ 35 \ 36static const struct file_operations name## _ops = { \ 37 .read = name## _read, \ 38 .open = mac80211_open_file_generic, \ 39 .llseek = generic_file_llseek, \ 40}; 41 42#define DEBUGFS_ADD(name) \ 43 debugfs_create_file(#name, 0400, phyd, local, &name## _ops); 44 45#define DEBUGFS_ADD_MODE(name, mode) \ 46 debugfs_create_file(#name, mode, phyd, local, &name## _ops); 47 48 49DEBUGFS_READONLY_FILE(frequency, 20, "%d", 50 local->hw.conf.channel->center_freq); 51DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", 52 local->total_ps_buffered); 53DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x", 54 local->wep_iv & 0xffffff); 55DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s", 56 local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); 57 58static ssize_t tsf_read(struct file *file, char __user *user_buf, 59 size_t count, loff_t *ppos) 60{ 61 struct ieee80211_local *local = file->private_data; 62 u64 tsf; 63 char buf[100]; 64 65 tsf = drv_get_tsf(local); 66 67 snprintf(buf, sizeof(buf), "0x%016llx\n", (unsigned long long) tsf); 68 69 return simple_read_from_buffer(user_buf, count, ppos, buf, 19); 70} 71 72static ssize_t tsf_write(struct file *file, 73 const char __user *user_buf, 74 size_t count, loff_t *ppos) 75{ 76 struct ieee80211_local *local = file->private_data; 77 unsigned long long tsf; 78 char buf[100]; 79 size_t len; 80 81 len = min(count, sizeof(buf) - 1); 82 if (copy_from_user(buf, user_buf, len)) 83 return -EFAULT; 84 buf[len] = '\0'; 85 86 if (strncmp(buf, "reset", 5) == 0) { 87 if (local->ops->reset_tsf) { 88 drv_reset_tsf(local); 89 wiphy_info(local->hw.wiphy, "debugfs reset TSF\n"); 90 } 91 } else { 92 tsf = simple_strtoul(buf, NULL, 0); 93 if (local->ops->set_tsf) { 94 drv_set_tsf(local, tsf); 95 wiphy_info(local->hw.wiphy, 96 "debugfs set TSF to %#018llx\n", tsf); 97 98 } 99 } 100 101 return count; 102} 103 104static const struct file_operations tsf_ops = { 105 .read = tsf_read, 106 .write = tsf_write, 107 .open = mac80211_open_file_generic, 108 .llseek = default_llseek, 109}; 110 111static ssize_t reset_write(struct file *file, const char __user *user_buf, 112 size_t count, loff_t *ppos) 113{ 114 struct ieee80211_local *local = file->private_data; 115 116 rtnl_lock(); 117 __ieee80211_suspend(&local->hw); 118 __ieee80211_resume(&local->hw); 119 rtnl_unlock(); 120 121 return count; 122} 123 124static const struct file_operations reset_ops = { 125 .write = reset_write, 126 .open = mac80211_open_file_generic, 127 .llseek = noop_llseek, 128}; 129 130static ssize_t noack_read(struct file *file, char __user *user_buf, 131 size_t count, loff_t *ppos) 132{ 133 struct ieee80211_local *local = file->private_data; 134 int res; 135 char buf[10]; 136 137 res = scnprintf(buf, sizeof(buf), "%d\n", local->wifi_wme_noack_test); 138 139 return simple_read_from_buffer(user_buf, count, ppos, buf, res); 140} 141 142static ssize_t noack_write(struct file *file, 143 const char __user *user_buf, 144 size_t count, loff_t *ppos) 145{ 146 struct ieee80211_local *local = file->private_data; 147 char buf[10]; 148 size_t len; 149 150 len = min(count, sizeof(buf) - 1); 151 if (copy_from_user(buf, user_buf, len)) 152 return -EFAULT; 153 buf[len] = '\0'; 154 155 local->wifi_wme_noack_test = !!simple_strtoul(buf, NULL, 0); 156 157 return count; 158} 159 160static const struct file_operations noack_ops = { 161 .read = noack_read, 162 .write = noack_write, 163 .open = mac80211_open_file_generic, 164 .llseek = default_llseek, 165}; 166 167static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf, 168 size_t count, loff_t *ppos) 169{ 170 struct ieee80211_local *local = file->private_data; 171 int res; 172 char buf[10]; 173 174 res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_queues); 175 176 return simple_read_from_buffer(user_buf, count, ppos, buf, res); 177} 178 179static ssize_t uapsd_queues_write(struct file *file, 180 const char __user *user_buf, 181 size_t count, loff_t *ppos) 182{ 183 struct ieee80211_local *local = file->private_data; 184 unsigned long val; 185 char buf[10]; 186 size_t len; 187 int ret; 188 189 len = min(count, sizeof(buf) - 1); 190 if (copy_from_user(buf, user_buf, len)) 191 return -EFAULT; 192 buf[len] = '\0'; 193 194 ret = strict_strtoul(buf, 0, &val); 195 196 if (ret) 197 return -EINVAL; 198 199 if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) 200 return -ERANGE; 201 202 local->uapsd_queues = val; 203 204 return count; 205} 206 207static const struct file_operations uapsd_queues_ops = { 208 .read = uapsd_queues_read, 209 .write = uapsd_queues_write, 210 .open = mac80211_open_file_generic, 211 .llseek = default_llseek, 212}; 213 214static ssize_t uapsd_max_sp_len_read(struct file *file, char __user *user_buf, 215 size_t count, loff_t *ppos) 216{ 217 struct ieee80211_local *local = file->private_data; 218 int res; 219 char buf[10]; 220 221 res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_max_sp_len); 222 223 return simple_read_from_buffer(user_buf, count, ppos, buf, res); 224} 225 226static ssize_t uapsd_max_sp_len_write(struct file *file, 227 const char __user *user_buf, 228 size_t count, loff_t *ppos) 229{ 230 struct ieee80211_local *local = file->private_data; 231 unsigned long val; 232 char buf[10]; 233 size_t len; 234 int ret; 235 236 len = min(count, sizeof(buf) - 1); 237 if (copy_from_user(buf, user_buf, len)) 238 return -EFAULT; 239 buf[len] = '\0'; 240 241 ret = strict_strtoul(buf, 0, &val); 242 243 if (ret) 244 return -EINVAL; 245 246 if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) 247 return -ERANGE; 248 249 local->uapsd_max_sp_len = val; 250 251 return count; 252} 253 254static const struct file_operations uapsd_max_sp_len_ops = { 255 .read = uapsd_max_sp_len_read, 256 .write = uapsd_max_sp_len_write, 257 .open = mac80211_open_file_generic, 258 .llseek = default_llseek, 259}; 260 261static ssize_t channel_type_read(struct file *file, char __user *user_buf, 262 size_t count, loff_t *ppos) 263{ 264 struct ieee80211_local *local = file->private_data; 265 const char *buf; 266 267 switch (local->hw.conf.channel_type) { 268 case NL80211_CHAN_NO_HT: 269 buf = "no ht\n"; 270 break; 271 case NL80211_CHAN_HT20: 272 buf = "ht20\n"; 273 break; 274 case NL80211_CHAN_HT40MINUS: 275 buf = "ht40-\n"; 276 break; 277 case NL80211_CHAN_HT40PLUS: 278 buf = "ht40+\n"; 279 break; 280 default: 281 buf = "???"; 282 break; 283 } 284 285 return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); 286} 287 288static const struct file_operations channel_type_ops = { 289 .read = channel_type_read, 290 .open = mac80211_open_file_generic, 291 .llseek = default_llseek, 292}; 293 294static ssize_t queues_read(struct file *file, char __user *user_buf, 295 size_t count, loff_t *ppos) 296{ 297 struct ieee80211_local *local = file->private_data; 298 unsigned long flags; 299 char buf[IEEE80211_MAX_QUEUES * 20]; 300 int q, res = 0; 301 302 spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 303 for (q = 0; q < local->hw.queues; q++) 304 res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q, 305 local->queue_stop_reasons[q], 306 skb_queue_len(&local->pending[q])); 307 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 308 309 return simple_read_from_buffer(user_buf, count, ppos, buf, res); 310} 311 312static const struct file_operations queues_ops = { 313 .read = queues_read, 314 .open = mac80211_open_file_generic, 315 .llseek = default_llseek, 316}; 317 318/* statistics stuff */ 319 320static ssize_t format_devstat_counter(struct ieee80211_local *local, 321 char __user *userbuf, 322 size_t count, loff_t *ppos, 323 int (*printvalue)(struct ieee80211_low_level_stats *stats, char *buf, 324 int buflen)) 325{ 326 struct ieee80211_low_level_stats stats; 327 char buf[20]; 328 int res; 329 330 rtnl_lock(); 331 res = drv_get_stats(local, &stats); 332 rtnl_unlock(); 333 if (res) 334 return res; 335 res = printvalue(&stats, buf, sizeof(buf)); 336 return simple_read_from_buffer(userbuf, count, ppos, buf, res); 337} 338 339#define DEBUGFS_DEVSTATS_FILE(name) \ 340static int print_devstats_##name(struct ieee80211_low_level_stats *stats,\ 341 char *buf, int buflen) \ 342{ \ 343 return scnprintf(buf, buflen, "%u\n", stats->name); \ 344} \ 345static ssize_t stats_ ##name## _read(struct file *file, \ 346 char __user *userbuf, \ 347 size_t count, loff_t *ppos) \ 348{ \ 349 return format_devstat_counter(file->private_data, \ 350 userbuf, \ 351 count, \ 352 ppos, \ 353 print_devstats_##name); \ 354} \ 355 \ 356static const struct file_operations stats_ ##name## _ops = { \ 357 .read = stats_ ##name## _read, \ 358 .open = mac80211_open_file_generic, \ 359 .llseek = generic_file_llseek, \ 360}; 361 362#define DEBUGFS_STATS_ADD(name, field) \ 363 debugfs_create_u32(#name, 0400, statsd, (u32 *) &field); 364#define DEBUGFS_DEVSTATS_ADD(name) \ 365 debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops); 366 367DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount); 368DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount); 369DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount); 370DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount); 371 372void debugfs_hw_add(struct ieee80211_local *local) 373{ 374 struct dentry *phyd = local->hw.wiphy->debugfsdir; 375 struct dentry *statsd; 376 377 if (!phyd) 378 return; 379 380 local->debugfs.keys = debugfs_create_dir("keys", phyd); 381 382 DEBUGFS_ADD(frequency); 383 DEBUGFS_ADD(total_ps_buffered); 384 DEBUGFS_ADD(wep_iv); 385 DEBUGFS_ADD(tsf); 386 DEBUGFS_ADD(queues); 387 DEBUGFS_ADD_MODE(reset, 0200); 388 DEBUGFS_ADD(noack); 389 DEBUGFS_ADD(uapsd_queues); 390 DEBUGFS_ADD(uapsd_max_sp_len); 391 DEBUGFS_ADD(channel_type); 392 393 statsd = debugfs_create_dir("statistics", phyd); 394 395 /* if the dir failed, don't put all the other things into the root! */ 396 if (!statsd) 397 return; 398 399 DEBUGFS_STATS_ADD(transmitted_fragment_count, 400 local->dot11TransmittedFragmentCount); 401 DEBUGFS_STATS_ADD(multicast_transmitted_frame_count, 402 local->dot11MulticastTransmittedFrameCount); 403 DEBUGFS_STATS_ADD(failed_count, local->dot11FailedCount); 404 DEBUGFS_STATS_ADD(retry_count, local->dot11RetryCount); 405 DEBUGFS_STATS_ADD(multiple_retry_count, 406 local->dot11MultipleRetryCount); 407 DEBUGFS_STATS_ADD(frame_duplicate_count, 408 local->dot11FrameDuplicateCount); 409 DEBUGFS_STATS_ADD(received_fragment_count, 410 local->dot11ReceivedFragmentCount); 411 DEBUGFS_STATS_ADD(multicast_received_frame_count, 412 local->dot11MulticastReceivedFrameCount); 413 DEBUGFS_STATS_ADD(transmitted_frame_count, 414 local->dot11TransmittedFrameCount); 415#ifdef CONFIG_MAC80211_DEBUG_COUNTERS 416 DEBUGFS_STATS_ADD(tx_handlers_drop, local->tx_handlers_drop); 417 DEBUGFS_STATS_ADD(tx_handlers_queued, local->tx_handlers_queued); 418 DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted, 419 local->tx_handlers_drop_unencrypted); 420 DEBUGFS_STATS_ADD(tx_handlers_drop_fragment, 421 local->tx_handlers_drop_fragment); 422 DEBUGFS_STATS_ADD(tx_handlers_drop_wep, 423 local->tx_handlers_drop_wep); 424 DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc, 425 local->tx_handlers_drop_not_assoc); 426 DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port, 427 local->tx_handlers_drop_unauth_port); 428 DEBUGFS_STATS_ADD(rx_handlers_drop, local->rx_handlers_drop); 429 DEBUGFS_STATS_ADD(rx_handlers_queued, local->rx_handlers_queued); 430 DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc, 431 local->rx_handlers_drop_nullfunc); 432 DEBUGFS_STATS_ADD(rx_handlers_drop_defrag, 433 local->rx_handlers_drop_defrag); 434 DEBUGFS_STATS_ADD(rx_handlers_drop_short, 435 local->rx_handlers_drop_short); 436 DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan, 437 local->rx_handlers_drop_passive_scan); 438 DEBUGFS_STATS_ADD(tx_expand_skb_head, 439 local->tx_expand_skb_head); 440 DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned, 441 local->tx_expand_skb_head_cloned); 442 DEBUGFS_STATS_ADD(rx_expand_skb_head, 443 local->rx_expand_skb_head); 444 DEBUGFS_STATS_ADD(rx_expand_skb_head2, 445 local->rx_expand_skb_head2); 446 DEBUGFS_STATS_ADD(rx_handlers_fragments, 447 local->rx_handlers_fragments); 448 DEBUGFS_STATS_ADD(tx_status_drop, 449 local->tx_status_drop); 450#endif 451 DEBUGFS_DEVSTATS_ADD(dot11ACKFailureCount); 452 DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount); 453 DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount); 454 DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount); 455}