linux/net/mac80211/debugfs_netdev.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2006   Jiri Benc <jbenc@suse.cz>
   4 * Copyright 2007       Johannes Berg <johannes@sipsolutions.net>
   5 * Copyright (C) 2020 Intel Corporation
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/device.h>
  10#include <linux/if.h>
  11#include <linux/if_ether.h>
  12#include <linux/interrupt.h>
  13#include <linux/netdevice.h>
  14#include <linux/rtnetlink.h>
  15#include <linux/slab.h>
  16#include <linux/notifier.h>
  17#include <net/mac80211.h>
  18#include <net/cfg80211.h>
  19#include "ieee80211_i.h"
  20#include "rate.h"
  21#include "debugfs.h"
  22#include "debugfs_netdev.h"
  23#include "driver-ops.h"
  24
  25static ssize_t ieee80211_if_read(
  26        struct ieee80211_sub_if_data *sdata,
  27        char __user *userbuf,
  28        size_t count, loff_t *ppos,
  29        ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int))
  30{
  31        char buf[200];
  32        ssize_t ret = -EINVAL;
  33
  34        read_lock(&dev_base_lock);
  35        ret = (*format)(sdata, buf, sizeof(buf));
  36        read_unlock(&dev_base_lock);
  37
  38        if (ret >= 0)
  39                ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
  40
  41        return ret;
  42}
  43
  44static ssize_t ieee80211_if_write(
  45        struct ieee80211_sub_if_data *sdata,
  46        const char __user *userbuf,
  47        size_t count, loff_t *ppos,
  48        ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int))
  49{
  50        char buf[64];
  51        ssize_t ret;
  52
  53        if (count >= sizeof(buf))
  54                return -E2BIG;
  55
  56        if (copy_from_user(buf, userbuf, count))
  57                return -EFAULT;
  58        buf[count] = '\0';
  59
  60        rtnl_lock();
  61        ret = (*write)(sdata, buf, count);
  62        rtnl_unlock();
  63
  64        return ret;
  65}
  66
  67#define IEEE80211_IF_FMT(name, field, format_string)                    \
  68static ssize_t ieee80211_if_fmt_##name(                                 \
  69        const struct ieee80211_sub_if_data *sdata, char *buf,           \
  70        int buflen)                                                     \
  71{                                                                       \
  72        return scnprintf(buf, buflen, format_string, sdata->field);     \
  73}
  74#define IEEE80211_IF_FMT_DEC(name, field)                               \
  75                IEEE80211_IF_FMT(name, field, "%d\n")
  76#define IEEE80211_IF_FMT_HEX(name, field)                               \
  77                IEEE80211_IF_FMT(name, field, "%#x\n")
  78#define IEEE80211_IF_FMT_LHEX(name, field)                              \
  79                IEEE80211_IF_FMT(name, field, "%#lx\n")
  80#define IEEE80211_IF_FMT_SIZE(name, field)                              \
  81                IEEE80211_IF_FMT(name, field, "%zd\n")
  82
  83#define IEEE80211_IF_FMT_HEXARRAY(name, field)                          \
  84static ssize_t ieee80211_if_fmt_##name(                                 \
  85        const struct ieee80211_sub_if_data *sdata,                      \
  86        char *buf, int buflen)                                          \
  87{                                                                       \
  88        char *p = buf;                                                  \
  89        int i;                                                          \
  90        for (i = 0; i < sizeof(sdata->field); i++) {                    \
  91                p += scnprintf(p, buflen + buf - p, "%.2x ",            \
  92                                 sdata->field[i]);                      \
  93        }                                                               \
  94        p += scnprintf(p, buflen + buf - p, "\n");                      \
  95        return p - buf;                                                 \
  96}
  97
  98#define IEEE80211_IF_FMT_ATOMIC(name, field)                            \
  99static ssize_t ieee80211_if_fmt_##name(                                 \
 100        const struct ieee80211_sub_if_data *sdata,                      \
 101        char *buf, int buflen)                                          \
 102{                                                                       \
 103        return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\
 104}
 105
 106#define IEEE80211_IF_FMT_MAC(name, field)                               \
 107static ssize_t ieee80211_if_fmt_##name(                                 \
 108        const struct ieee80211_sub_if_data *sdata, char *buf,           \
 109        int buflen)                                                     \
 110{                                                                       \
 111        return scnprintf(buf, buflen, "%pM\n", sdata->field);           \
 112}
 113
 114#define IEEE80211_IF_FMT_JIFFIES_TO_MS(name, field)                     \
 115static ssize_t ieee80211_if_fmt_##name(                                 \
 116        const struct ieee80211_sub_if_data *sdata,                      \
 117        char *buf, int buflen)                                          \
 118{                                                                       \
 119        return scnprintf(buf, buflen, "%d\n",                           \
 120                         jiffies_to_msecs(sdata->field));               \
 121}
 122
 123#define _IEEE80211_IF_FILE_OPS(name, _read, _write)                     \
 124static const struct file_operations name##_ops = {                      \
 125        .read = (_read),                                                \
 126        .write = (_write),                                              \
 127        .open = simple_open,                                            \
 128        .llseek = generic_file_llseek,                                  \
 129}
 130
 131#define _IEEE80211_IF_FILE_R_FN(name)                                   \
 132static ssize_t ieee80211_if_read_##name(struct file *file,              \
 133                                        char __user *userbuf,           \
 134                                        size_t count, loff_t *ppos)     \
 135{                                                                       \
 136        return ieee80211_if_read(file->private_data,                    \
 137                                 userbuf, count, ppos,                  \
 138                                 ieee80211_if_fmt_##name);              \
 139}
 140
 141#define _IEEE80211_IF_FILE_W_FN(name)                                   \
 142static ssize_t ieee80211_if_write_##name(struct file *file,             \
 143                                         const char __user *userbuf,    \
 144                                         size_t count, loff_t *ppos)    \
 145{                                                                       \
 146        return ieee80211_if_write(file->private_data, userbuf, count,   \
 147                                  ppos, ieee80211_if_parse_##name);     \
 148}
 149
 150#define IEEE80211_IF_FILE_R(name)                                       \
 151        _IEEE80211_IF_FILE_R_FN(name)                                   \
 152        _IEEE80211_IF_FILE_OPS(name, ieee80211_if_read_##name, NULL)
 153
 154#define IEEE80211_IF_FILE_W(name)                                       \
 155        _IEEE80211_IF_FILE_W_FN(name)                                   \
 156        _IEEE80211_IF_FILE_OPS(name, NULL, ieee80211_if_write_##name)
 157
 158#define IEEE80211_IF_FILE_RW(name)                                      \
 159        _IEEE80211_IF_FILE_R_FN(name)                                   \
 160        _IEEE80211_IF_FILE_W_FN(name)                                   \
 161        _IEEE80211_IF_FILE_OPS(name, ieee80211_if_read_##name,          \
 162                               ieee80211_if_write_##name)
 163
 164#define IEEE80211_IF_FILE(name, field, format)                          \
 165        IEEE80211_IF_FMT_##format(name, field)                          \
 166        IEEE80211_IF_FILE_R(name)
 167
 168/* common attributes */
 169IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[NL80211_BAND_2GHZ],
 170                  HEX);
 171IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[NL80211_BAND_5GHZ],
 172                  HEX);
 173IEEE80211_IF_FILE(rc_rateidx_mcs_mask_2ghz,
 174                  rc_rateidx_mcs_mask[NL80211_BAND_2GHZ], HEXARRAY);
 175IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz,
 176                  rc_rateidx_mcs_mask[NL80211_BAND_5GHZ], HEXARRAY);
 177
 178static ssize_t ieee80211_if_fmt_rc_rateidx_vht_mcs_mask_2ghz(
 179                                const struct ieee80211_sub_if_data *sdata,
 180                                char *buf, int buflen)
 181{
 182        int i, len = 0;
 183        const u16 *mask = sdata->rc_rateidx_vht_mcs_mask[NL80211_BAND_2GHZ];
 184
 185        for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
 186                len += scnprintf(buf + len, buflen - len, "%04x ", mask[i]);
 187        len += scnprintf(buf + len, buflen - len, "\n");
 188
 189        return len;
 190}
 191
 192IEEE80211_IF_FILE_R(rc_rateidx_vht_mcs_mask_2ghz);
 193
 194static ssize_t ieee80211_if_fmt_rc_rateidx_vht_mcs_mask_5ghz(
 195                                const struct ieee80211_sub_if_data *sdata,
 196                                char *buf, int buflen)
 197{
 198        int i, len = 0;
 199        const u16 *mask = sdata->rc_rateidx_vht_mcs_mask[NL80211_BAND_5GHZ];
 200
 201        for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
 202                len += scnprintf(buf + len, buflen - len, "%04x ", mask[i]);
 203        len += scnprintf(buf + len, buflen - len, "\n");
 204
 205        return len;
 206}
 207
 208IEEE80211_IF_FILE_R(rc_rateidx_vht_mcs_mask_5ghz);
 209
 210IEEE80211_IF_FILE(flags, flags, HEX);
 211IEEE80211_IF_FILE(state, state, LHEX);
 212IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC);
 213IEEE80211_IF_FILE(ap_power_level, ap_power_level, DEC);
 214IEEE80211_IF_FILE(user_power_level, user_power_level, DEC);
 215
 216static ssize_t
 217ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata,
 218                           char *buf, int buflen)
 219{
 220        int len;
 221
 222        len = scnprintf(buf, buflen, "AC queues: VO:%d VI:%d BE:%d BK:%d\n",
 223                        sdata->vif.hw_queue[IEEE80211_AC_VO],
 224                        sdata->vif.hw_queue[IEEE80211_AC_VI],
 225                        sdata->vif.hw_queue[IEEE80211_AC_BE],
 226                        sdata->vif.hw_queue[IEEE80211_AC_BK]);
 227
 228        if (sdata->vif.type == NL80211_IFTYPE_AP)
 229                len += scnprintf(buf + len, buflen - len, "cab queue: %d\n",
 230                                 sdata->vif.cab_queue);
 231
 232        return len;
 233}
 234IEEE80211_IF_FILE_R(hw_queues);
 235
 236/* STA attributes */
 237IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
 238IEEE80211_IF_FILE(aid, vif.bss_conf.aid, DEC);
 239IEEE80211_IF_FILE(beacon_timeout, u.mgd.beacon_timeout, JIFFIES_TO_MS);
 240
 241static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
 242                              enum ieee80211_smps_mode smps_mode)
 243{
 244        struct ieee80211_local *local = sdata->local;
 245        int err;
 246
 247        if (!(local->hw.wiphy->features & NL80211_FEATURE_STATIC_SMPS) &&
 248            smps_mode == IEEE80211_SMPS_STATIC)
 249                return -EINVAL;
 250
 251        /* auto should be dynamic if in PS mode */
 252        if (!(local->hw.wiphy->features & NL80211_FEATURE_DYNAMIC_SMPS) &&
 253            (smps_mode == IEEE80211_SMPS_DYNAMIC ||
 254             smps_mode == IEEE80211_SMPS_AUTOMATIC))
 255                return -EINVAL;
 256
 257        if (sdata->vif.type != NL80211_IFTYPE_STATION)
 258                return -EOPNOTSUPP;
 259
 260        sdata_lock(sdata);
 261        err = __ieee80211_request_smps_mgd(sdata, smps_mode);
 262        sdata_unlock(sdata);
 263
 264        return err;
 265}
 266
 267static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
 268        [IEEE80211_SMPS_AUTOMATIC] = "auto",
 269        [IEEE80211_SMPS_OFF] = "off",
 270        [IEEE80211_SMPS_STATIC] = "static",
 271        [IEEE80211_SMPS_DYNAMIC] = "dynamic",
 272};
 273
 274static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
 275                                     char *buf, int buflen)
 276{
 277        if (sdata->vif.type == NL80211_IFTYPE_STATION)
 278                return snprintf(buf, buflen, "request: %s\nused: %s\n",
 279                                smps_modes[sdata->u.mgd.req_smps],
 280                                smps_modes[sdata->smps_mode]);
 281        return -EINVAL;
 282}
 283
 284static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
 285                                       const char *buf, int buflen)
 286{
 287        enum ieee80211_smps_mode mode;
 288
 289        for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) {
 290                if (strncmp(buf, smps_modes[mode], buflen) == 0) {
 291                        int err = ieee80211_set_smps(sdata, mode);
 292                        if (!err)
 293                                return buflen;
 294                        return err;
 295                }
 296        }
 297
 298        return -EINVAL;
 299}
 300IEEE80211_IF_FILE_RW(smps);
 301
 302static ssize_t ieee80211_if_parse_tkip_mic_test(
 303        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 304{
 305        struct ieee80211_local *local = sdata->local;
 306        u8 addr[ETH_ALEN];
 307        struct sk_buff *skb;
 308        struct ieee80211_hdr *hdr;
 309        __le16 fc;
 310
 311        if (!mac_pton(buf, addr))
 312                return -EINVAL;
 313
 314        if (!ieee80211_sdata_running(sdata))
 315                return -ENOTCONN;
 316
 317        skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24 + 100);
 318        if (!skb)
 319                return -ENOMEM;
 320        skb_reserve(skb, local->hw.extra_tx_headroom);
 321
 322        hdr = skb_put_zero(skb, 24);
 323        fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
 324
 325        switch (sdata->vif.type) {
 326        case NL80211_IFTYPE_AP:
 327                fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
 328                /* DA BSSID SA */
 329                memcpy(hdr->addr1, addr, ETH_ALEN);
 330                memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
 331                memcpy(hdr->addr3, sdata->vif.addr, ETH_ALEN);
 332                break;
 333        case NL80211_IFTYPE_STATION:
 334                fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
 335                /* BSSID SA DA */
 336                sdata_lock(sdata);
 337                if (!sdata->u.mgd.associated) {
 338                        sdata_unlock(sdata);
 339                        dev_kfree_skb(skb);
 340                        return -ENOTCONN;
 341                }
 342                memcpy(hdr->addr1, sdata->u.mgd.associated->bssid, ETH_ALEN);
 343                memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
 344                memcpy(hdr->addr3, addr, ETH_ALEN);
 345                sdata_unlock(sdata);
 346                break;
 347        default:
 348                dev_kfree_skb(skb);
 349                return -EOPNOTSUPP;
 350        }
 351        hdr->frame_control = fc;
 352
 353        /*
 354         * Add some length to the test frame to make it look bit more valid.
 355         * The exact contents does not matter since the recipient is required
 356         * to drop this because of the Michael MIC failure.
 357         */
 358        skb_put_zero(skb, 50);
 359
 360        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_TKIP_MIC_FAILURE;
 361
 362        ieee80211_tx_skb(sdata, skb);
 363
 364        return buflen;
 365}
 366IEEE80211_IF_FILE_W(tkip_mic_test);
 367
 368static ssize_t ieee80211_if_parse_beacon_loss(
 369        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 370{
 371        if (!ieee80211_sdata_running(sdata) || !sdata->vif.bss_conf.assoc)
 372                return -ENOTCONN;
 373
 374        ieee80211_beacon_loss(&sdata->vif);
 375
 376        return buflen;
 377}
 378IEEE80211_IF_FILE_W(beacon_loss);
 379
 380static ssize_t ieee80211_if_fmt_uapsd_queues(
 381        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 382{
 383        const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 384
 385        return snprintf(buf, buflen, "0x%x\n", ifmgd->uapsd_queues);
 386}
 387
 388static ssize_t ieee80211_if_parse_uapsd_queues(
 389        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 390{
 391        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 392        u8 val;
 393        int ret;
 394
 395        ret = kstrtou8(buf, 0, &val);
 396        if (ret)
 397                return ret;
 398
 399        if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
 400                return -ERANGE;
 401
 402        ifmgd->uapsd_queues = val;
 403
 404        return buflen;
 405}
 406IEEE80211_IF_FILE_RW(uapsd_queues);
 407
 408static ssize_t ieee80211_if_fmt_uapsd_max_sp_len(
 409        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 410{
 411        const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 412
 413        return snprintf(buf, buflen, "0x%x\n", ifmgd->uapsd_max_sp_len);
 414}
 415
 416static ssize_t ieee80211_if_parse_uapsd_max_sp_len(
 417        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 418{
 419        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 420        unsigned long val;
 421        int ret;
 422
 423        ret = kstrtoul(buf, 0, &val);
 424        if (ret)
 425                return -EINVAL;
 426
 427        if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
 428                return -ERANGE;
 429
 430        ifmgd->uapsd_max_sp_len = val;
 431
 432        return buflen;
 433}
 434IEEE80211_IF_FILE_RW(uapsd_max_sp_len);
 435
 436static ssize_t ieee80211_if_fmt_tdls_wider_bw(
 437        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 438{
 439        const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 440        bool tdls_wider_bw;
 441
 442        tdls_wider_bw = ieee80211_hw_check(&sdata->local->hw, TDLS_WIDER_BW) &&
 443                        !ifmgd->tdls_wider_bw_prohibited;
 444
 445        return snprintf(buf, buflen, "%d\n", tdls_wider_bw);
 446}
 447
 448static ssize_t ieee80211_if_parse_tdls_wider_bw(
 449        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 450{
 451        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 452        u8 val;
 453        int ret;
 454
 455        ret = kstrtou8(buf, 0, &val);
 456        if (ret)
 457                return ret;
 458
 459        ifmgd->tdls_wider_bw_prohibited = !val;
 460        return buflen;
 461}
 462IEEE80211_IF_FILE_RW(tdls_wider_bw);
 463
 464/* AP attributes */
 465IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
 466IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC);
 467IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC);
 468IEEE80211_IF_FILE(num_mcast_sta_vlan, u.vlan.num_mcast_sta, ATOMIC);
 469
 470static ssize_t ieee80211_if_fmt_num_buffered_multicast(
 471        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 472{
 473        return scnprintf(buf, buflen, "%u\n",
 474                         skb_queue_len(&sdata->u.ap.ps.bc_buf));
 475}
 476IEEE80211_IF_FILE_R(num_buffered_multicast);
 477
 478static ssize_t ieee80211_if_fmt_aqm(
 479        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 480{
 481        struct ieee80211_local *local = sdata->local;
 482        struct txq_info *txqi;
 483        int len;
 484
 485        if (!sdata->vif.txq)
 486                return 0;
 487
 488        txqi = to_txq_info(sdata->vif.txq);
 489
 490        spin_lock_bh(&local->fq.lock);
 491        rcu_read_lock();
 492
 493        len = scnprintf(buf,
 494                        buflen,
 495                        "ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n"
 496                        "%u %u %u %u %u %u %u %u %u %u\n",
 497                        txqi->txq.ac,
 498                        txqi->tin.backlog_bytes,
 499                        txqi->tin.backlog_packets,
 500                        txqi->tin.flows,
 501                        txqi->cstats.drop_count,
 502                        txqi->cstats.ecn_mark,
 503                        txqi->tin.overlimit,
 504                        txqi->tin.collisions,
 505                        txqi->tin.tx_bytes,
 506                        txqi->tin.tx_packets);
 507
 508        rcu_read_unlock();
 509        spin_unlock_bh(&local->fq.lock);
 510
 511        return len;
 512}
 513IEEE80211_IF_FILE_R(aqm);
 514
 515static ssize_t ieee80211_if_fmt_airtime(
 516        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 517{
 518        struct ieee80211_local *local = sdata->local;
 519        struct ieee80211_txq *txq = sdata->vif.txq;
 520        struct airtime_info *air_info;
 521        int len;
 522
 523        if (!txq)
 524                return 0;
 525
 526        spin_lock_bh(&local->airtime[txq->ac].lock);
 527        air_info = to_airtime_info(txq);
 528        len = scnprintf(buf,
 529                        buflen,
 530                        "RX: %llu us\nTX: %llu us\nWeight: %u\n"
 531                        "Virt-T: %lld us\n",
 532                        air_info->rx_airtime,
 533                        air_info->tx_airtime,
 534                        air_info->weight,
 535                        air_info->v_t);
 536        spin_unlock_bh(&local->airtime[txq->ac].lock);
 537
 538        return len;
 539}
 540
 541IEEE80211_IF_FILE_R(airtime);
 542
 543IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX);
 544
 545/* IBSS attributes */
 546static ssize_t ieee80211_if_fmt_tsf(
 547        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 548{
 549        struct ieee80211_local *local = sdata->local;
 550        u64 tsf;
 551
 552        tsf = drv_get_tsf(local, (struct ieee80211_sub_if_data *)sdata);
 553
 554        return scnprintf(buf, buflen, "0x%016llx\n", (unsigned long long) tsf);
 555}
 556
 557static ssize_t ieee80211_if_parse_tsf(
 558        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 559{
 560        struct ieee80211_local *local = sdata->local;
 561        unsigned long long tsf;
 562        int ret;
 563        int tsf_is_delta = 0;
 564
 565        if (strncmp(buf, "reset", 5) == 0) {
 566                if (local->ops->reset_tsf) {
 567                        drv_reset_tsf(local, sdata);
 568                        wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
 569                }
 570        } else {
 571                if (buflen > 10 && buf[1] == '=') {
 572                        if (buf[0] == '+')
 573                                tsf_is_delta = 1;
 574                        else if (buf[0] == '-')
 575                                tsf_is_delta = -1;
 576                        else
 577                                return -EINVAL;
 578                        buf += 2;
 579                }
 580                ret = kstrtoull(buf, 10, &tsf);
 581                if (ret < 0)
 582                        return ret;
 583                if (tsf_is_delta && local->ops->offset_tsf) {
 584                        drv_offset_tsf(local, sdata, tsf_is_delta * tsf);
 585                        wiphy_info(local->hw.wiphy,
 586                                   "debugfs offset TSF by %018lld\n",
 587                                   tsf_is_delta * tsf);
 588                } else if (local->ops->set_tsf) {
 589                        if (tsf_is_delta)
 590                                tsf = drv_get_tsf(local, sdata) +
 591                                      tsf_is_delta * tsf;
 592                        drv_set_tsf(local, sdata, tsf);
 593                        wiphy_info(local->hw.wiphy,
 594                                   "debugfs set TSF to %#018llx\n", tsf);
 595                }
 596        }
 597
 598        ieee80211_recalc_dtim(local, sdata);
 599        return buflen;
 600}
 601IEEE80211_IF_FILE_RW(tsf);
 602
 603
 604#ifdef CONFIG_MAC80211_MESH
 605IEEE80211_IF_FILE(estab_plinks, u.mesh.estab_plinks, ATOMIC);
 606
 607/* Mesh stats attributes */
 608IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC);
 609IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
 610IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
 611IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
 612IEEE80211_IF_FILE(dropped_frames_congestion,
 613                  u.mesh.mshstats.dropped_frames_congestion, DEC);
 614IEEE80211_IF_FILE(dropped_frames_no_route,
 615                  u.mesh.mshstats.dropped_frames_no_route, DEC);
 616
 617/* Mesh parameters */
 618IEEE80211_IF_FILE(dot11MeshMaxRetries,
 619                  u.mesh.mshcfg.dot11MeshMaxRetries, DEC);
 620IEEE80211_IF_FILE(dot11MeshRetryTimeout,
 621                  u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);
 622IEEE80211_IF_FILE(dot11MeshConfirmTimeout,
 623                  u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);
 624IEEE80211_IF_FILE(dot11MeshHoldingTimeout,
 625                  u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
 626IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC);
 627IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC);
 628IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC);
 629IEEE80211_IF_FILE(dot11MeshMaxPeerLinks,
 630                  u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
 631IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout,
 632                  u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
 633IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval,
 634                  u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
 635IEEE80211_IF_FILE(dot11MeshHWMPperrMinInterval,
 636                  u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC);
 637IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime,
 638                  u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
 639IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries,
 640                  u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);
 641IEEE80211_IF_FILE(path_refresh_time,
 642                  u.mesh.mshcfg.path_refresh_time, DEC);
 643IEEE80211_IF_FILE(min_discovery_timeout,
 644                  u.mesh.mshcfg.min_discovery_timeout, DEC);
 645IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
 646                  u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
 647IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol,
 648                  u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC);
 649IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
 650                  u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
 651IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC);
 652IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC);
 653IEEE80211_IF_FILE(ht_opmode, u.mesh.mshcfg.ht_opmode, DEC);
 654IEEE80211_IF_FILE(dot11MeshHWMPactivePathToRootTimeout,
 655                  u.mesh.mshcfg.dot11MeshHWMPactivePathToRootTimeout, DEC);
 656IEEE80211_IF_FILE(dot11MeshHWMProotInterval,
 657                  u.mesh.mshcfg.dot11MeshHWMProotInterval, DEC);
 658IEEE80211_IF_FILE(dot11MeshHWMPconfirmationInterval,
 659                  u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval, DEC);
 660IEEE80211_IF_FILE(power_mode, u.mesh.mshcfg.power_mode, DEC);
 661IEEE80211_IF_FILE(dot11MeshAwakeWindowDuration,
 662                  u.mesh.mshcfg.dot11MeshAwakeWindowDuration, DEC);
 663IEEE80211_IF_FILE(dot11MeshConnectedToMeshGate,
 664                  u.mesh.mshcfg.dot11MeshConnectedToMeshGate, DEC);
 665IEEE80211_IF_FILE(dot11MeshNolearn, u.mesh.mshcfg.dot11MeshNolearn, DEC);
 666IEEE80211_IF_FILE(dot11MeshConnectedToAuthServer,
 667                  u.mesh.mshcfg.dot11MeshConnectedToAuthServer, DEC);
 668#endif
 669
 670#define DEBUGFS_ADD_MODE(name, mode) \
 671        debugfs_create_file(#name, mode, sdata->vif.debugfs_dir, \
 672                            sdata, &name##_ops)
 673
 674#define DEBUGFS_ADD(name) DEBUGFS_ADD_MODE(name, 0400)
 675
 676static void add_common_files(struct ieee80211_sub_if_data *sdata)
 677{
 678        DEBUGFS_ADD(rc_rateidx_mask_2ghz);
 679        DEBUGFS_ADD(rc_rateidx_mask_5ghz);
 680        DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
 681        DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
 682        DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_2ghz);
 683        DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz);
 684        DEBUGFS_ADD(hw_queues);
 685
 686        if (sdata->local->ops->wake_tx_queue &&
 687            sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
 688            sdata->vif.type != NL80211_IFTYPE_NAN) {
 689                DEBUGFS_ADD(aqm);
 690                DEBUGFS_ADD(airtime);
 691        }
 692}
 693
 694static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 695{
 696        DEBUGFS_ADD(bssid);
 697        DEBUGFS_ADD(aid);
 698        DEBUGFS_ADD(beacon_timeout);
 699        DEBUGFS_ADD_MODE(smps, 0600);
 700        DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
 701        DEBUGFS_ADD_MODE(beacon_loss, 0200);
 702        DEBUGFS_ADD_MODE(uapsd_queues, 0600);
 703        DEBUGFS_ADD_MODE(uapsd_max_sp_len, 0600);
 704        DEBUGFS_ADD_MODE(tdls_wider_bw, 0600);
 705}
 706
 707static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 708{
 709        DEBUGFS_ADD(num_mcast_sta);
 710        DEBUGFS_ADD_MODE(smps, 0600);
 711        DEBUGFS_ADD(num_sta_ps);
 712        DEBUGFS_ADD(dtim_count);
 713        DEBUGFS_ADD(num_buffered_multicast);
 714        DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
 715        DEBUGFS_ADD_MODE(multicast_to_unicast, 0600);
 716}
 717
 718static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
 719{
 720        /* add num_mcast_sta_vlan using name num_mcast_sta */
 721        debugfs_create_file("num_mcast_sta", 0400, sdata->vif.debugfs_dir,
 722                            sdata, &num_mcast_sta_vlan_ops);
 723}
 724
 725static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
 726{
 727        DEBUGFS_ADD_MODE(tsf, 0600);
 728}
 729
 730#ifdef CONFIG_MAC80211_MESH
 731
 732static void add_mesh_files(struct ieee80211_sub_if_data *sdata)
 733{
 734        DEBUGFS_ADD_MODE(tsf, 0600);
 735        DEBUGFS_ADD_MODE(estab_plinks, 0400);
 736}
 737
 738static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
 739{
 740        struct dentry *dir = debugfs_create_dir("mesh_stats",
 741                                                sdata->vif.debugfs_dir);
 742#define MESHSTATS_ADD(name)\
 743        debugfs_create_file(#name, 0400, dir, sdata, &name##_ops)
 744
 745        MESHSTATS_ADD(fwded_mcast);
 746        MESHSTATS_ADD(fwded_unicast);
 747        MESHSTATS_ADD(fwded_frames);
 748        MESHSTATS_ADD(dropped_frames_ttl);
 749        MESHSTATS_ADD(dropped_frames_no_route);
 750        MESHSTATS_ADD(dropped_frames_congestion);
 751#undef MESHSTATS_ADD
 752}
 753
 754static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
 755{
 756        struct dentry *dir = debugfs_create_dir("mesh_config",
 757                                                sdata->vif.debugfs_dir);
 758
 759#define MESHPARAMS_ADD(name) \
 760        debugfs_create_file(#name, 0600, dir, sdata, &name##_ops)
 761
 762        MESHPARAMS_ADD(dot11MeshMaxRetries);
 763        MESHPARAMS_ADD(dot11MeshRetryTimeout);
 764        MESHPARAMS_ADD(dot11MeshConfirmTimeout);
 765        MESHPARAMS_ADD(dot11MeshHoldingTimeout);
 766        MESHPARAMS_ADD(dot11MeshTTL);
 767        MESHPARAMS_ADD(element_ttl);
 768        MESHPARAMS_ADD(auto_open_plinks);
 769        MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
 770        MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
 771        MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval);
 772        MESHPARAMS_ADD(dot11MeshHWMPperrMinInterval);
 773        MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime);
 774        MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
 775        MESHPARAMS_ADD(path_refresh_time);
 776        MESHPARAMS_ADD(min_discovery_timeout);
 777        MESHPARAMS_ADD(dot11MeshHWMPRootMode);
 778        MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
 779        MESHPARAMS_ADD(dot11MeshForwarding);
 780        MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
 781        MESHPARAMS_ADD(rssi_threshold);
 782        MESHPARAMS_ADD(ht_opmode);
 783        MESHPARAMS_ADD(dot11MeshHWMPactivePathToRootTimeout);
 784        MESHPARAMS_ADD(dot11MeshHWMProotInterval);
 785        MESHPARAMS_ADD(dot11MeshHWMPconfirmationInterval);
 786        MESHPARAMS_ADD(power_mode);
 787        MESHPARAMS_ADD(dot11MeshAwakeWindowDuration);
 788        MESHPARAMS_ADD(dot11MeshConnectedToMeshGate);
 789        MESHPARAMS_ADD(dot11MeshNolearn);
 790        MESHPARAMS_ADD(dot11MeshConnectedToAuthServer);
 791#undef MESHPARAMS_ADD
 792}
 793#endif
 794
 795static void add_files(struct ieee80211_sub_if_data *sdata)
 796{
 797        if (!sdata->vif.debugfs_dir)
 798                return;
 799
 800        DEBUGFS_ADD(flags);
 801        DEBUGFS_ADD(state);
 802        DEBUGFS_ADD(txpower);
 803        DEBUGFS_ADD(user_power_level);
 804        DEBUGFS_ADD(ap_power_level);
 805
 806        if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
 807                add_common_files(sdata);
 808
 809        switch (sdata->vif.type) {
 810        case NL80211_IFTYPE_MESH_POINT:
 811#ifdef CONFIG_MAC80211_MESH
 812                add_mesh_files(sdata);
 813                add_mesh_stats(sdata);
 814                add_mesh_config(sdata);
 815#endif
 816                break;
 817        case NL80211_IFTYPE_STATION:
 818                add_sta_files(sdata);
 819                break;
 820        case NL80211_IFTYPE_ADHOC:
 821                add_ibss_files(sdata);
 822                break;
 823        case NL80211_IFTYPE_AP:
 824                add_ap_files(sdata);
 825                break;
 826        case NL80211_IFTYPE_AP_VLAN:
 827                add_vlan_files(sdata);
 828                break;
 829        default:
 830                break;
 831        }
 832}
 833
 834void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
 835{
 836        char buf[10+IFNAMSIZ];
 837
 838        sprintf(buf, "netdev:%s", sdata->name);
 839        sdata->vif.debugfs_dir = debugfs_create_dir(buf,
 840                sdata->local->hw.wiphy->debugfsdir);
 841        sdata->debugfs.subdir_stations = debugfs_create_dir("stations",
 842                                                        sdata->vif.debugfs_dir);
 843        add_files(sdata);
 844}
 845
 846void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
 847{
 848        if (!sdata->vif.debugfs_dir)
 849                return;
 850
 851        debugfs_remove_recursive(sdata->vif.debugfs_dir);
 852        sdata->vif.debugfs_dir = NULL;
 853        sdata->debugfs.subdir_stations = NULL;
 854}
 855
 856void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
 857{
 858        struct dentry *dir;
 859        char buf[10 + IFNAMSIZ];
 860
 861        dir = sdata->vif.debugfs_dir;
 862
 863        if (IS_ERR_OR_NULL(dir))
 864                return;
 865
 866        sprintf(buf, "netdev:%s", sdata->name);
 867        debugfs_rename(dir->d_parent, dir, dir->d_parent, buf);
 868}
 869