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