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