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 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 104 static 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 111 static 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 124 static const struct file_operations reset_ops = { 125 .write = reset_write, 126 .open = mac80211_open_file_generic, 127 .llseek = noop_llseek, 128 }; 129 130 static 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 142 static 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 160 static 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 167 static 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 179 static 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 207 static 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 214 static 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 226 static 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 254 static 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 261 static 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 288 static const struct file_operations channel_type_ops = { 289 .read = channel_type_read, 290 .open = mac80211_open_file_generic, 291 .llseek = default_llseek, 292 }; 293 294 static 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 312 static 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 320 static 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) \ 340 static 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 } \ 345 static 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 \ 356 static 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 367 DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount); 368 DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount); 369 DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount); 370 DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount); 371 372 void 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 } 456