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 */
   6
   7#include <linux/kernel.h>
   8#include <linux/device.h>
   9#include <linux/if.h>
  10#include <linux/if_ether.h>
  11#include <linux/interrupt.h>
  12#include <linux/netdevice.h>
  13#include <linux/rtnetlink.h>
  14#include <linux/slab.h>
  15#include <linux/notifier.h>
  16#include <net/mac80211.h>
  17#include <net/cfg80211.h>
  18#include "ieee80211_i.h"
  19#include "rate.h"
  20#include "debugfs.h"
  21#include "debugfs_netdev.h"
  22#include "driver-ops.h"
  23
  24static ssize_t ieee80211_if_read(
  25        struct ieee80211_sub_if_data *sdata,
  26        char __user *userbuf,
  27        size_t count, loff_t *ppos,
  28        ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int))
  29{
  30        char buf[200];
  31        ssize_t ret = -EINVAL;
  32
  33        read_lock(&dev_base_lock);
  34        ret = (*format)(sdata, buf, sizeof(buf));
  35        read_unlock(&dev_base_lock);
  36
  37        if (ret >= 0)
  38                ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
  39
  40        return ret;
  41}
  42
  43static ssize_t ieee80211_if_write(
  44        struct ieee80211_sub_if_data *sdata,
  45        const char __user *userbuf,
  46        size_t count, loff_t *ppos,
  47        ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int))
  48{
  49        char buf[64];
  50        ssize_t ret;
  51
  52        if (count >= sizeof(buf))
  53                return -E2BIG;
  54
  55        if (copy_from_user(buf, userbuf, count))
  56                return -EFAULT;
  57        buf[count] = '\0';
  58
  59        ret = -ENODEV;
  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, u.mgd.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            sdata->vif.type != NL80211_IFTYPE_AP)
 259                return -EOPNOTSUPP;
 260
 261        sdata_lock(sdata);
 262        if (sdata->vif.type == NL80211_IFTYPE_STATION)
 263                err = __ieee80211_request_smps_mgd(sdata, smps_mode);
 264        else
 265                err = __ieee80211_request_smps_ap(sdata, smps_mode);
 266        sdata_unlock(sdata);
 267
 268        return err;
 269}
 270
 271static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
 272        [IEEE80211_SMPS_AUTOMATIC] = "auto",
 273        [IEEE80211_SMPS_OFF] = "off",
 274        [IEEE80211_SMPS_STATIC] = "static",
 275        [IEEE80211_SMPS_DYNAMIC] = "dynamic",
 276};
 277
 278static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
 279                                     char *buf, int buflen)
 280{
 281        if (sdata->vif.type == NL80211_IFTYPE_STATION)
 282                return snprintf(buf, buflen, "request: %s\nused: %s\n",
 283                                smps_modes[sdata->u.mgd.req_smps],
 284                                smps_modes[sdata->smps_mode]);
 285        if (sdata->vif.type == NL80211_IFTYPE_AP)
 286                return snprintf(buf, buflen, "request: %s\nused: %s\n",
 287                                smps_modes[sdata->u.ap.req_smps],
 288                                smps_modes[sdata->smps_mode]);
 289        return -EINVAL;
 290}
 291
 292static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
 293                                       const char *buf, int buflen)
 294{
 295        enum ieee80211_smps_mode mode;
 296
 297        for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) {
 298                if (strncmp(buf, smps_modes[mode], buflen) == 0) {
 299                        int err = ieee80211_set_smps(sdata, mode);
 300                        if (!err)
 301                                return buflen;
 302                        return err;
 303                }
 304        }
 305
 306        return -EINVAL;
 307}
 308IEEE80211_IF_FILE_RW(smps);
 309
 310static ssize_t ieee80211_if_parse_tkip_mic_test(
 311        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 312{
 313        struct ieee80211_local *local = sdata->local;
 314        u8 addr[ETH_ALEN];
 315        struct sk_buff *skb;
 316        struct ieee80211_hdr *hdr;
 317        __le16 fc;
 318
 319        if (!mac_pton(buf, addr))
 320                return -EINVAL;
 321
 322        if (!ieee80211_sdata_running(sdata))
 323                return -ENOTCONN;
 324
 325        skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24 + 100);
 326        if (!skb)
 327                return -ENOMEM;
 328        skb_reserve(skb, local->hw.extra_tx_headroom);
 329
 330        hdr = skb_put_zero(skb, 24);
 331        fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
 332
 333        switch (sdata->vif.type) {
 334        case NL80211_IFTYPE_AP:
 335                fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
 336                /* DA BSSID SA */
 337                memcpy(hdr->addr1, addr, ETH_ALEN);
 338                memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
 339                memcpy(hdr->addr3, sdata->vif.addr, ETH_ALEN);
 340                break;
 341        case NL80211_IFTYPE_STATION:
 342                fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
 343                /* BSSID SA DA */
 344                sdata_lock(sdata);
 345                if (!sdata->u.mgd.associated) {
 346                        sdata_unlock(sdata);
 347                        dev_kfree_skb(skb);
 348                        return -ENOTCONN;
 349                }
 350                memcpy(hdr->addr1, sdata->u.mgd.associated->bssid, ETH_ALEN);
 351                memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
 352                memcpy(hdr->addr3, addr, ETH_ALEN);
 353                sdata_unlock(sdata);
 354                break;
 355        default:
 356                dev_kfree_skb(skb);
 357                return -EOPNOTSUPP;
 358        }
 359        hdr->frame_control = fc;
 360
 361        /*
 362         * Add some length to the test frame to make it look bit more valid.
 363         * The exact contents does not matter since the recipient is required
 364         * to drop this because of the Michael MIC failure.
 365         */
 366        skb_put_zero(skb, 50);
 367
 368        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_TKIP_MIC_FAILURE;
 369
 370        ieee80211_tx_skb(sdata, skb);
 371
 372        return buflen;
 373}
 374IEEE80211_IF_FILE_W(tkip_mic_test);
 375
 376static ssize_t ieee80211_if_parse_beacon_loss(
 377        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 378{
 379        if (!ieee80211_sdata_running(sdata) || !sdata->vif.bss_conf.assoc)
 380                return -ENOTCONN;
 381
 382        ieee80211_beacon_loss(&sdata->vif);
 383
 384        return buflen;
 385}
 386IEEE80211_IF_FILE_W(beacon_loss);
 387
 388static ssize_t ieee80211_if_fmt_uapsd_queues(
 389        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 390{
 391        const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 392
 393        return snprintf(buf, buflen, "0x%x\n", ifmgd->uapsd_queues);
 394}
 395
 396static ssize_t ieee80211_if_parse_uapsd_queues(
 397        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 398{
 399        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 400        u8 val;
 401        int ret;
 402
 403        ret = kstrtou8(buf, 0, &val);
 404        if (ret)
 405                return ret;
 406
 407        if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
 408                return -ERANGE;
 409
 410        ifmgd->uapsd_queues = val;
 411
 412        return buflen;
 413}
 414IEEE80211_IF_FILE_RW(uapsd_queues);
 415
 416static ssize_t ieee80211_if_fmt_uapsd_max_sp_len(
 417        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 418{
 419        const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 420
 421        return snprintf(buf, buflen, "0x%x\n", ifmgd->uapsd_max_sp_len);
 422}
 423
 424static ssize_t ieee80211_if_parse_uapsd_max_sp_len(
 425        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 426{
 427        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 428        unsigned long val;
 429        int ret;
 430
 431        ret = kstrtoul(buf, 0, &val);
 432        if (ret)
 433                return -EINVAL;
 434
 435        if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
 436                return -ERANGE;
 437
 438        ifmgd->uapsd_max_sp_len = val;
 439
 440        return buflen;
 441}
 442IEEE80211_IF_FILE_RW(uapsd_max_sp_len);
 443
 444static ssize_t ieee80211_if_fmt_tdls_wider_bw(
 445        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 446{
 447        const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 448        bool tdls_wider_bw;
 449
 450        tdls_wider_bw = ieee80211_hw_check(&sdata->local->hw, TDLS_WIDER_BW) &&
 451                        !ifmgd->tdls_wider_bw_prohibited;
 452
 453        return snprintf(buf, buflen, "%d\n", tdls_wider_bw);
 454}
 455
 456static ssize_t ieee80211_if_parse_tdls_wider_bw(
 457        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 458{
 459        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 460        u8 val;
 461        int ret;
 462
 463        ret = kstrtou8(buf, 0, &val);
 464        if (ret)
 465                return ret;
 466
 467        ifmgd->tdls_wider_bw_prohibited = !val;
 468        return buflen;
 469}
 470IEEE80211_IF_FILE_RW(tdls_wider_bw);
 471
 472/* AP attributes */
 473IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
 474IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC);
 475IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC);
 476IEEE80211_IF_FILE(num_mcast_sta_vlan, u.vlan.num_mcast_sta, ATOMIC);
 477
 478static ssize_t ieee80211_if_fmt_num_buffered_multicast(
 479        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 480{
 481        return scnprintf(buf, buflen, "%u\n",
 482                         skb_queue_len(&sdata->u.ap.ps.bc_buf));
 483}
 484IEEE80211_IF_FILE_R(num_buffered_multicast);
 485
 486static ssize_t ieee80211_if_fmt_aqm(
 487        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 488{
 489        struct ieee80211_local *local = sdata->local;
 490        struct txq_info *txqi;
 491        int len;
 492
 493        if (!sdata->vif.txq)
 494                return 0;
 495
 496        txqi = to_txq_info(sdata->vif.txq);
 497
 498        spin_lock_bh(&local->fq.lock);
 499        rcu_read_lock();
 500
 501        len = scnprintf(buf,
 502                        buflen,
 503                        "ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n"
 504                        "%u %u %u %u %u %u %u %u %u %u\n",
 505                        txqi->txq.ac,
 506                        txqi->tin.backlog_bytes,
 507                        txqi->tin.backlog_packets,
 508                        txqi->tin.flows,
 509                        txqi->cstats.drop_count,
 510                        txqi->cstats.ecn_mark,
 511                        txqi->tin.overlimit,
 512                        txqi->tin.collisions,
 513                        txqi->tin.tx_bytes,
 514                        txqi->tin.tx_packets);
 515
 516        rcu_read_unlock();
 517        spin_unlock_bh(&local->fq.lock);
 518
 519        return len;
 520}
 521IEEE80211_IF_FILE_R(aqm);
 522
 523IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX);
 524
 525/* IBSS attributes */
 526static ssize_t ieee80211_if_fmt_tsf(
 527        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 528{
 529        struct ieee80211_local *local = sdata->local;
 530        u64 tsf;
 531
 532        tsf = drv_get_tsf(local, (struct ieee80211_sub_if_data *)sdata);
 533
 534        return scnprintf(buf, buflen, "0x%016llx\n", (unsigned long long) tsf);
 535}
 536
 537static ssize_t ieee80211_if_parse_tsf(
 538        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 539{
 540        struct ieee80211_local *local = sdata->local;
 541        unsigned long long tsf;
 542        int ret;
 543        int tsf_is_delta = 0;
 544
 545        if (strncmp(buf, "reset", 5) == 0) {
 546                if (local->ops->reset_tsf) {
 547                        drv_reset_tsf(local, sdata);
 548                        wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
 549                }
 550        } else {
 551                if (buflen > 10 && buf[1] == '=') {
 552                        if (buf[0] == '+')
 553                                tsf_is_delta = 1;
 554                        else if (buf[0] == '-')
 555                                tsf_is_delta = -1;
 556                        else
 557                                return -EINVAL;
 558                        buf += 2;
 559                }
 560                ret = kstrtoull(buf, 10, &tsf);
 561                if (ret < 0)
 562                        return ret;
 563                if (tsf_is_delta && local->ops->offset_tsf) {
 564                        drv_offset_tsf(local, sdata, tsf_is_delta * tsf);
 565                        wiphy_info(local->hw.wiphy,
 566                                   "debugfs offset TSF by %018lld\n",
 567                                   tsf_is_delta * tsf);
 568                } else if (local->ops->set_tsf) {
 569                        if (tsf_is_delta)
 570                                tsf = drv_get_tsf(local, sdata) +
 571                                      tsf_is_delta * tsf;
 572                        drv_set_tsf(local, sdata, tsf);
 573                        wiphy_info(local->hw.wiphy,
 574                                   "debugfs set TSF to %#018llx\n", tsf);
 575                }
 576        }
 577
 578        ieee80211_recalc_dtim(local, sdata);
 579        return buflen;
 580}
 581IEEE80211_IF_FILE_RW(tsf);
 582
 583
 584/* WDS attributes */
 585IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
 586
 587#ifdef CONFIG_MAC80211_MESH
 588IEEE80211_IF_FILE(estab_plinks, u.mesh.estab_plinks, ATOMIC);
 589
 590/* Mesh stats attributes */
 591IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC);
 592IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
 593IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
 594IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
 595IEEE80211_IF_FILE(dropped_frames_congestion,
 596                  u.mesh.mshstats.dropped_frames_congestion, DEC);
 597IEEE80211_IF_FILE(dropped_frames_no_route,
 598                  u.mesh.mshstats.dropped_frames_no_route, DEC);
 599
 600/* Mesh parameters */
 601IEEE80211_IF_FILE(dot11MeshMaxRetries,
 602                  u.mesh.mshcfg.dot11MeshMaxRetries, DEC);
 603IEEE80211_IF_FILE(dot11MeshRetryTimeout,
 604                  u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);
 605IEEE80211_IF_FILE(dot11MeshConfirmTimeout,
 606                  u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);
 607IEEE80211_IF_FILE(dot11MeshHoldingTimeout,
 608                  u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
 609IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC);
 610IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC);
 611IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC);
 612IEEE80211_IF_FILE(dot11MeshMaxPeerLinks,
 613                  u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
 614IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout,
 615                  u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
 616IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval,
 617                  u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
 618IEEE80211_IF_FILE(dot11MeshHWMPperrMinInterval,
 619                  u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC);
 620IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime,
 621                  u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
 622IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries,
 623                  u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);
 624IEEE80211_IF_FILE(path_refresh_time,
 625                  u.mesh.mshcfg.path_refresh_time, DEC);
 626IEEE80211_IF_FILE(min_discovery_timeout,
 627                  u.mesh.mshcfg.min_discovery_timeout, DEC);
 628IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
 629                  u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
 630IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol,
 631                  u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC);
 632IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
 633                  u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
 634IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC);
 635IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC);
 636IEEE80211_IF_FILE(ht_opmode, u.mesh.mshcfg.ht_opmode, DEC);
 637IEEE80211_IF_FILE(dot11MeshHWMPactivePathToRootTimeout,
 638                  u.mesh.mshcfg.dot11MeshHWMPactivePathToRootTimeout, DEC);
 639IEEE80211_IF_FILE(dot11MeshHWMProotInterval,
 640                  u.mesh.mshcfg.dot11MeshHWMProotInterval, DEC);
 641IEEE80211_IF_FILE(dot11MeshHWMPconfirmationInterval,
 642                  u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval, DEC);
 643IEEE80211_IF_FILE(power_mode, u.mesh.mshcfg.power_mode, DEC);
 644IEEE80211_IF_FILE(dot11MeshAwakeWindowDuration,
 645                  u.mesh.mshcfg.dot11MeshAwakeWindowDuration, DEC);
 646IEEE80211_IF_FILE(dot11MeshConnectedToMeshGate,
 647                  u.mesh.mshcfg.dot11MeshConnectedToMeshGate, DEC);
 648#endif
 649
 650#define DEBUGFS_ADD_MODE(name, mode) \
 651        debugfs_create_file(#name, mode, sdata->vif.debugfs_dir, \
 652                            sdata, &name##_ops);
 653
 654#define DEBUGFS_ADD(name) DEBUGFS_ADD_MODE(name, 0400)
 655
 656static void add_common_files(struct ieee80211_sub_if_data *sdata)
 657{
 658        DEBUGFS_ADD(rc_rateidx_mask_2ghz);
 659        DEBUGFS_ADD(rc_rateidx_mask_5ghz);
 660        DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
 661        DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
 662        DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_2ghz);
 663        DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz);
 664        DEBUGFS_ADD(hw_queues);
 665
 666        if (sdata->local->ops->wake_tx_queue &&
 667            sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
 668            sdata->vif.type != NL80211_IFTYPE_NAN)
 669                DEBUGFS_ADD(aqm);
 670}
 671
 672static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 673{
 674        DEBUGFS_ADD(bssid);
 675        DEBUGFS_ADD(aid);
 676        DEBUGFS_ADD(beacon_timeout);
 677        DEBUGFS_ADD_MODE(smps, 0600);
 678        DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
 679        DEBUGFS_ADD_MODE(beacon_loss, 0200);
 680        DEBUGFS_ADD_MODE(uapsd_queues, 0600);
 681        DEBUGFS_ADD_MODE(uapsd_max_sp_len, 0600);
 682        DEBUGFS_ADD_MODE(tdls_wider_bw, 0600);
 683}
 684
 685static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 686{
 687        DEBUGFS_ADD(num_mcast_sta);
 688        DEBUGFS_ADD_MODE(smps, 0600);
 689        DEBUGFS_ADD(num_sta_ps);
 690        DEBUGFS_ADD(dtim_count);
 691        DEBUGFS_ADD(num_buffered_multicast);
 692        DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
 693        DEBUGFS_ADD_MODE(multicast_to_unicast, 0600);
 694}
 695
 696static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
 697{
 698        /* add num_mcast_sta_vlan using name num_mcast_sta */
 699        debugfs_create_file("num_mcast_sta", 0400, sdata->vif.debugfs_dir,
 700                            sdata, &num_mcast_sta_vlan_ops);
 701}
 702
 703static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
 704{
 705        DEBUGFS_ADD_MODE(tsf, 0600);
 706}
 707
 708static void add_wds_files(struct ieee80211_sub_if_data *sdata)
 709{
 710        DEBUGFS_ADD(peer);
 711}
 712
 713#ifdef CONFIG_MAC80211_MESH
 714
 715static void add_mesh_files(struct ieee80211_sub_if_data *sdata)
 716{
 717        DEBUGFS_ADD_MODE(tsf, 0600);
 718        DEBUGFS_ADD_MODE(estab_plinks, 0400);
 719}
 720
 721static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
 722{
 723        struct dentry *dir = debugfs_create_dir("mesh_stats",
 724                                                sdata->vif.debugfs_dir);
 725#define MESHSTATS_ADD(name)\
 726        debugfs_create_file(#name, 0400, dir, sdata, &name##_ops);
 727
 728        MESHSTATS_ADD(fwded_mcast);
 729        MESHSTATS_ADD(fwded_unicast);
 730        MESHSTATS_ADD(fwded_frames);
 731        MESHSTATS_ADD(dropped_frames_ttl);
 732        MESHSTATS_ADD(dropped_frames_no_route);
 733        MESHSTATS_ADD(dropped_frames_congestion);
 734#undef MESHSTATS_ADD
 735}
 736
 737static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
 738{
 739        struct dentry *dir = debugfs_create_dir("mesh_config",
 740                                                sdata->vif.debugfs_dir);
 741
 742#define MESHPARAMS_ADD(name) \
 743        debugfs_create_file(#name, 0600, dir, sdata, &name##_ops);
 744
 745        MESHPARAMS_ADD(dot11MeshMaxRetries);
 746        MESHPARAMS_ADD(dot11MeshRetryTimeout);
 747        MESHPARAMS_ADD(dot11MeshConfirmTimeout);
 748        MESHPARAMS_ADD(dot11MeshHoldingTimeout);
 749        MESHPARAMS_ADD(dot11MeshTTL);
 750        MESHPARAMS_ADD(element_ttl);
 751        MESHPARAMS_ADD(auto_open_plinks);
 752        MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
 753        MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
 754        MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval);
 755        MESHPARAMS_ADD(dot11MeshHWMPperrMinInterval);
 756        MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime);
 757        MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
 758        MESHPARAMS_ADD(path_refresh_time);
 759        MESHPARAMS_ADD(min_discovery_timeout);
 760        MESHPARAMS_ADD(dot11MeshHWMPRootMode);
 761        MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
 762        MESHPARAMS_ADD(dot11MeshForwarding);
 763        MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
 764        MESHPARAMS_ADD(rssi_threshold);
 765        MESHPARAMS_ADD(ht_opmode);
 766        MESHPARAMS_ADD(dot11MeshHWMPactivePathToRootTimeout);
 767        MESHPARAMS_ADD(dot11MeshHWMProotInterval);
 768        MESHPARAMS_ADD(dot11MeshHWMPconfirmationInterval);
 769        MESHPARAMS_ADD(power_mode);
 770        MESHPARAMS_ADD(dot11MeshAwakeWindowDuration);
 771        MESHPARAMS_ADD(dot11MeshConnectedToMeshGate);
 772#undef MESHPARAMS_ADD
 773}
 774#endif
 775
 776static void add_files(struct ieee80211_sub_if_data *sdata)
 777{
 778        if (!sdata->vif.debugfs_dir)
 779                return;
 780
 781        DEBUGFS_ADD(flags);
 782        DEBUGFS_ADD(state);
 783        DEBUGFS_ADD(txpower);
 784        DEBUGFS_ADD(user_power_level);
 785        DEBUGFS_ADD(ap_power_level);
 786
 787        if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
 788                add_common_files(sdata);
 789
 790        switch (sdata->vif.type) {
 791        case NL80211_IFTYPE_MESH_POINT:
 792#ifdef CONFIG_MAC80211_MESH
 793                add_mesh_files(sdata);
 794                add_mesh_stats(sdata);
 795                add_mesh_config(sdata);
 796#endif
 797                break;
 798        case NL80211_IFTYPE_STATION:
 799                add_sta_files(sdata);
 800                break;
 801        case NL80211_IFTYPE_ADHOC:
 802                add_ibss_files(sdata);
 803                break;
 804        case NL80211_IFTYPE_AP:
 805                add_ap_files(sdata);
 806                break;
 807        case NL80211_IFTYPE_AP_VLAN:
 808                add_vlan_files(sdata);
 809                break;
 810        case NL80211_IFTYPE_WDS:
 811                add_wds_files(sdata);
 812                break;
 813        default:
 814                break;
 815        }
 816}
 817
 818void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
 819{
 820        char buf[10+IFNAMSIZ];
 821
 822        sprintf(buf, "netdev:%s", sdata->name);
 823        sdata->vif.debugfs_dir = debugfs_create_dir(buf,
 824                sdata->local->hw.wiphy->debugfsdir);
 825        sdata->debugfs.subdir_stations = debugfs_create_dir("stations",
 826                                                        sdata->vif.debugfs_dir);
 827        add_files(sdata);
 828}
 829
 830void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
 831{
 832        if (!sdata->vif.debugfs_dir)
 833                return;
 834
 835        debugfs_remove_recursive(sdata->vif.debugfs_dir);
 836        sdata->vif.debugfs_dir = NULL;
 837        sdata->debugfs.subdir_stations = NULL;
 838}
 839
 840void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
 841{
 842        struct dentry *dir;
 843        char buf[10 + IFNAMSIZ];
 844
 845        dir = sdata->vif.debugfs_dir;
 846
 847        if (IS_ERR_OR_NULL(dir))
 848                return;
 849
 850        sprintf(buf, "netdev:%s", sdata->name);
 851        debugfs_rename(dir->d_parent, dir, dir->d_parent, buf);
 852}
 853