linux/net/mac80211/debugfs_netdev.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2006   Jiri Benc <jbenc@suse.cz>
   3 * Copyright 2007       Johannes Berg <johannes@sipsolutions.net>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 */
   9
  10#include <linux/kernel.h>
  11#include <linux/device.h>
  12#include <linux/if.h>
  13#include <linux/interrupt.h>
  14#include <linux/netdevice.h>
  15#include <linux/rtnetlink.h>
  16#include <linux/slab.h>
  17#include <linux/notifier.h>
  18#include <net/mac80211.h>
  19#include <net/cfg80211.h>
  20#include "ieee80211_i.h"
  21#include "rate.h"
  22#include "debugfs.h"
  23#include "debugfs_netdev.h"
  24#include "driver-ops.h"
  25
  26static ssize_t ieee80211_if_read(
  27        struct ieee80211_sub_if_data *sdata,
  28        char __user *userbuf,
  29        size_t count, loff_t *ppos,
  30        ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int))
  31{
  32        char buf[70];
  33        ssize_t ret = -EINVAL;
  34
  35        read_lock(&dev_base_lock);
  36        if (sdata->dev->reg_state == NETREG_REGISTERED)
  37                ret = (*format)(sdata, buf, sizeof(buf));
  38        read_unlock(&dev_base_lock);
  39
  40        if (ret >= 0)
  41                ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
  42
  43        return ret;
  44}
  45
  46static ssize_t ieee80211_if_write(
  47        struct ieee80211_sub_if_data *sdata,
  48        const char __user *userbuf,
  49        size_t count, loff_t *ppos,
  50        ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int))
  51{
  52        char buf[64];
  53        ssize_t ret;
  54
  55        if (count >= sizeof(buf))
  56                return -E2BIG;
  57
  58        if (copy_from_user(buf, userbuf, count))
  59                return -EFAULT;
  60        buf[count] = '\0';
  61
  62        ret = -ENODEV;
  63        rtnl_lock();
  64        if (sdata->dev->reg_state == NETREG_REGISTERED)
  65                ret = (*write)(sdata, buf, count);
  66        rtnl_unlock();
  67
  68        return ret;
  69}
  70
  71#define IEEE80211_IF_FMT(name, field, format_string)                    \
  72static ssize_t ieee80211_if_fmt_##name(                                 \
  73        const struct ieee80211_sub_if_data *sdata, char *buf,           \
  74        int buflen)                                                     \
  75{                                                                       \
  76        return scnprintf(buf, buflen, format_string, sdata->field);     \
  77}
  78#define IEEE80211_IF_FMT_DEC(name, field)                               \
  79                IEEE80211_IF_FMT(name, field, "%d\n")
  80#define IEEE80211_IF_FMT_HEX(name, field)                               \
  81                IEEE80211_IF_FMT(name, field, "%#x\n")
  82#define IEEE80211_IF_FMT_LHEX(name, field)                              \
  83                IEEE80211_IF_FMT(name, field, "%#lx\n")
  84#define IEEE80211_IF_FMT_SIZE(name, field)                              \
  85                IEEE80211_IF_FMT(name, field, "%zd\n")
  86
  87#define IEEE80211_IF_FMT_HEXARRAY(name, field)                          \
  88static ssize_t ieee80211_if_fmt_##name(                                 \
  89        const struct ieee80211_sub_if_data *sdata,                      \
  90        char *buf, int buflen)                                          \
  91{                                                                       \
  92        char *p = buf;                                                  \
  93        int i;                                                          \
  94        for (i = 0; i < sizeof(sdata->field); i++) {                    \
  95                p += scnprintf(p, buflen + buf - p, "%.2x ",            \
  96                                 sdata->field[i]);                      \
  97        }                                                               \
  98        p += scnprintf(p, buflen + buf - p, "\n");                      \
  99        return p - buf;                                                 \
 100}
 101
 102#define IEEE80211_IF_FMT_ATOMIC(name, field)                            \
 103static ssize_t ieee80211_if_fmt_##name(                                 \
 104        const struct ieee80211_sub_if_data *sdata,                      \
 105        char *buf, int buflen)                                          \
 106{                                                                       \
 107        return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\
 108}
 109
 110#define IEEE80211_IF_FMT_MAC(name, field)                               \
 111static ssize_t ieee80211_if_fmt_##name(                                 \
 112        const struct ieee80211_sub_if_data *sdata, char *buf,           \
 113        int buflen)                                                     \
 114{                                                                       \
 115        return scnprintf(buf, buflen, "%pM\n", sdata->field);           \
 116}
 117
 118#define IEEE80211_IF_FMT_DEC_DIV_16(name, field)                        \
 119static ssize_t ieee80211_if_fmt_##name(                                 \
 120        const struct ieee80211_sub_if_data *sdata,                      \
 121        char *buf, int buflen)                                          \
 122{                                                                       \
 123        return scnprintf(buf, buflen, "%d\n", sdata->field / 16);       \
 124}
 125
 126#define __IEEE80211_IF_FILE(name, _write)                               \
 127static ssize_t ieee80211_if_read_##name(struct file *file,              \
 128                                        char __user *userbuf,           \
 129                                        size_t count, loff_t *ppos)     \
 130{                                                                       \
 131        return ieee80211_if_read(file->private_data,                    \
 132                                 userbuf, count, ppos,                  \
 133                                 ieee80211_if_fmt_##name);              \
 134}                                                                       \
 135static const struct file_operations name##_ops = {                      \
 136        .read = ieee80211_if_read_##name,                               \
 137        .write = (_write),                                              \
 138        .open = simple_open,                                            \
 139        .llseek = generic_file_llseek,                                  \
 140}
 141
 142#define __IEEE80211_IF_FILE_W(name)                                     \
 143static ssize_t ieee80211_if_write_##name(struct file *file,             \
 144                                         const char __user *userbuf,    \
 145                                         size_t count, loff_t *ppos)    \
 146{                                                                       \
 147        return ieee80211_if_write(file->private_data, userbuf, count,   \
 148                                  ppos, ieee80211_if_parse_##name);     \
 149}                                                                       \
 150__IEEE80211_IF_FILE(name, ieee80211_if_write_##name)
 151
 152
 153#define IEEE80211_IF_FILE(name, field, format)                          \
 154                IEEE80211_IF_FMT_##format(name, field)                  \
 155                __IEEE80211_IF_FILE(name, NULL)
 156
 157/* common attributes */
 158IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
 159IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ],
 160                  HEX);
 161IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
 162                  HEX);
 163IEEE80211_IF_FILE(rc_rateidx_mcs_mask_2ghz,
 164                  rc_rateidx_mcs_mask[IEEE80211_BAND_2GHZ], HEXARRAY);
 165IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz,
 166                  rc_rateidx_mcs_mask[IEEE80211_BAND_5GHZ], HEXARRAY);
 167
 168IEEE80211_IF_FILE(flags, flags, HEX);
 169IEEE80211_IF_FILE(state, state, LHEX);
 170IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC);
 171
 172/* STA attributes */
 173IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
 174IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
 175IEEE80211_IF_FILE(last_beacon, u.mgd.last_beacon_signal, DEC);
 176IEEE80211_IF_FILE(ave_beacon, u.mgd.ave_beacon_signal, DEC_DIV_16);
 177
 178static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
 179                              enum ieee80211_smps_mode smps_mode)
 180{
 181        struct ieee80211_local *local = sdata->local;
 182        int err;
 183
 184        if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) &&
 185            smps_mode == IEEE80211_SMPS_STATIC)
 186                return -EINVAL;
 187
 188        /* auto should be dynamic if in PS mode */
 189        if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) &&
 190            (smps_mode == IEEE80211_SMPS_DYNAMIC ||
 191             smps_mode == IEEE80211_SMPS_AUTOMATIC))
 192                return -EINVAL;
 193
 194        /* supported only on managed interfaces for now */
 195        if (sdata->vif.type != NL80211_IFTYPE_STATION)
 196                return -EOPNOTSUPP;
 197
 198        mutex_lock(&sdata->u.mgd.mtx);
 199        err = __ieee80211_request_smps(sdata, smps_mode);
 200        mutex_unlock(&sdata->u.mgd.mtx);
 201
 202        return err;
 203}
 204
 205static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
 206        [IEEE80211_SMPS_AUTOMATIC] = "auto",
 207        [IEEE80211_SMPS_OFF] = "off",
 208        [IEEE80211_SMPS_STATIC] = "static",
 209        [IEEE80211_SMPS_DYNAMIC] = "dynamic",
 210};
 211
 212static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
 213                                     char *buf, int buflen)
 214{
 215        if (sdata->vif.type != NL80211_IFTYPE_STATION)
 216                return -EOPNOTSUPP;
 217
 218        return snprintf(buf, buflen, "request: %s\nused: %s\n",
 219                        smps_modes[sdata->u.mgd.req_smps],
 220                        smps_modes[sdata->u.mgd.ap_smps]);
 221}
 222
 223static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
 224                                       const char *buf, int buflen)
 225{
 226        enum ieee80211_smps_mode mode;
 227
 228        for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) {
 229                if (strncmp(buf, smps_modes[mode], buflen) == 0) {
 230                        int err = ieee80211_set_smps(sdata, mode);
 231                        if (!err)
 232                                return buflen;
 233                        return err;
 234                }
 235        }
 236
 237        return -EINVAL;
 238}
 239
 240__IEEE80211_IF_FILE_W(smps);
 241
 242static ssize_t ieee80211_if_fmt_tkip_mic_test(
 243        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 244{
 245        return -EOPNOTSUPP;
 246}
 247
 248static int hwaddr_aton(const char *txt, u8 *addr)
 249{
 250        int i;
 251
 252        for (i = 0; i < ETH_ALEN; i++) {
 253                int a, b;
 254
 255                a = hex_to_bin(*txt++);
 256                if (a < 0)
 257                        return -1;
 258                b = hex_to_bin(*txt++);
 259                if (b < 0)
 260                        return -1;
 261                *addr++ = (a << 4) | b;
 262                if (i < 5 && *txt++ != ':')
 263                        return -1;
 264        }
 265
 266        return 0;
 267}
 268
 269static ssize_t ieee80211_if_parse_tkip_mic_test(
 270        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 271{
 272        struct ieee80211_local *local = sdata->local;
 273        u8 addr[ETH_ALEN];
 274        struct sk_buff *skb;
 275        struct ieee80211_hdr *hdr;
 276        __le16 fc;
 277
 278        /*
 279         * Assume colon-delimited MAC address with possible white space
 280         * following.
 281         */
 282        if (buflen < 3 * ETH_ALEN - 1)
 283                return -EINVAL;
 284        if (hwaddr_aton(buf, addr) < 0)
 285                return -EINVAL;
 286
 287        if (!ieee80211_sdata_running(sdata))
 288                return -ENOTCONN;
 289
 290        skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24 + 100);
 291        if (!skb)
 292                return -ENOMEM;
 293        skb_reserve(skb, local->hw.extra_tx_headroom);
 294
 295        hdr = (struct ieee80211_hdr *) skb_put(skb, 24);
 296        memset(hdr, 0, 24);
 297        fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
 298
 299        switch (sdata->vif.type) {
 300        case NL80211_IFTYPE_AP:
 301                fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
 302                /* DA BSSID SA */
 303                memcpy(hdr->addr1, addr, ETH_ALEN);
 304                memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
 305                memcpy(hdr->addr3, sdata->vif.addr, ETH_ALEN);
 306                break;
 307        case NL80211_IFTYPE_STATION:
 308                fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
 309                /* BSSID SA DA */
 310                if (sdata->vif.bss_conf.bssid == NULL) {
 311                        dev_kfree_skb(skb);
 312                        return -ENOTCONN;
 313                }
 314                memcpy(hdr->addr1, sdata->vif.bss_conf.bssid, ETH_ALEN);
 315                memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
 316                memcpy(hdr->addr3, addr, ETH_ALEN);
 317                break;
 318        default:
 319                dev_kfree_skb(skb);
 320                return -EOPNOTSUPP;
 321        }
 322        hdr->frame_control = fc;
 323
 324        /*
 325         * Add some length to the test frame to make it look bit more valid.
 326         * The exact contents does not matter since the recipient is required
 327         * to drop this because of the Michael MIC failure.
 328         */
 329        memset(skb_put(skb, 50), 0, 50);
 330
 331        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_TKIP_MIC_FAILURE;
 332
 333        ieee80211_tx_skb(sdata, skb);
 334
 335        return buflen;
 336}
 337
 338__IEEE80211_IF_FILE_W(tkip_mic_test);
 339
 340static ssize_t ieee80211_if_fmt_uapsd_queues(
 341        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 342{
 343        const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 344
 345        return snprintf(buf, buflen, "0x%x\n", ifmgd->uapsd_queues);
 346}
 347
 348static ssize_t ieee80211_if_parse_uapsd_queues(
 349        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 350{
 351        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 352        u8 val;
 353        int ret;
 354
 355        ret = kstrtou8(buf, 0, &val);
 356        if (ret)
 357                return ret;
 358
 359        if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
 360                return -ERANGE;
 361
 362        ifmgd->uapsd_queues = val;
 363
 364        return buflen;
 365}
 366__IEEE80211_IF_FILE_W(uapsd_queues);
 367
 368static ssize_t ieee80211_if_fmt_uapsd_max_sp_len(
 369        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 370{
 371        const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 372
 373        return snprintf(buf, buflen, "0x%x\n", ifmgd->uapsd_max_sp_len);
 374}
 375
 376static ssize_t ieee80211_if_parse_uapsd_max_sp_len(
 377        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 378{
 379        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 380        unsigned long val;
 381        int ret;
 382
 383        ret = kstrtoul(buf, 0, &val);
 384        if (ret)
 385                return -EINVAL;
 386
 387        if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
 388                return -ERANGE;
 389
 390        ifmgd->uapsd_max_sp_len = val;
 391
 392        return buflen;
 393}
 394__IEEE80211_IF_FILE_W(uapsd_max_sp_len);
 395
 396/* AP attributes */
 397IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
 398IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
 399IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
 400
 401static ssize_t ieee80211_if_fmt_num_buffered_multicast(
 402        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 403{
 404        return scnprintf(buf, buflen, "%u\n",
 405                         skb_queue_len(&sdata->u.ap.ps_bc_buf));
 406}
 407__IEEE80211_IF_FILE(num_buffered_multicast, NULL);
 408
 409/* IBSS attributes */
 410static ssize_t ieee80211_if_fmt_tsf(
 411        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 412{
 413        struct ieee80211_local *local = sdata->local;
 414        u64 tsf;
 415
 416        tsf = drv_get_tsf(local, (struct ieee80211_sub_if_data *)sdata);
 417
 418        return scnprintf(buf, buflen, "0x%016llx\n", (unsigned long long) tsf);
 419}
 420
 421static ssize_t ieee80211_if_parse_tsf(
 422        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 423{
 424        struct ieee80211_local *local = sdata->local;
 425        unsigned long long tsf;
 426        int ret;
 427        int tsf_is_delta = 0;
 428
 429        if (strncmp(buf, "reset", 5) == 0) {
 430                if (local->ops->reset_tsf) {
 431                        drv_reset_tsf(local, sdata);
 432                        wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
 433                }
 434        } else {
 435                if (buflen > 10 && buf[1] == '=') {
 436                        if (buf[0] == '+')
 437                                tsf_is_delta = 1;
 438                        else if (buf[0] == '-')
 439                                tsf_is_delta = -1;
 440                        else
 441                                return -EINVAL;
 442                        buf += 2;
 443                }
 444                ret = kstrtoull(buf, 10, &tsf);
 445                if (ret < 0)
 446                        return -EINVAL;
 447                if (tsf_is_delta)
 448                        tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf;
 449                if (local->ops->set_tsf) {
 450                        drv_set_tsf(local, sdata, tsf);
 451                        wiphy_info(local->hw.wiphy,
 452                                   "debugfs set TSF to %#018llx\n", tsf);
 453                }
 454        }
 455
 456        return buflen;
 457}
 458__IEEE80211_IF_FILE_W(tsf);
 459
 460
 461/* WDS attributes */
 462IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
 463
 464#ifdef CONFIG_MAC80211_MESH
 465/* Mesh stats attributes */
 466IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC);
 467IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
 468IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
 469IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
 470IEEE80211_IF_FILE(dropped_frames_congestion,
 471                  u.mesh.mshstats.dropped_frames_congestion, DEC);
 472IEEE80211_IF_FILE(dropped_frames_no_route,
 473                  u.mesh.mshstats.dropped_frames_no_route, DEC);
 474IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);
 475
 476/* Mesh parameters */
 477IEEE80211_IF_FILE(dot11MeshMaxRetries,
 478                  u.mesh.mshcfg.dot11MeshMaxRetries, DEC);
 479IEEE80211_IF_FILE(dot11MeshRetryTimeout,
 480                  u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);
 481IEEE80211_IF_FILE(dot11MeshConfirmTimeout,
 482                  u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);
 483IEEE80211_IF_FILE(dot11MeshHoldingTimeout,
 484                  u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
 485IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC);
 486IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC);
 487IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC);
 488IEEE80211_IF_FILE(dot11MeshMaxPeerLinks,
 489                  u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
 490IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout,
 491                  u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
 492IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval,
 493                  u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
 494IEEE80211_IF_FILE(dot11MeshHWMPperrMinInterval,
 495                  u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC);
 496IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime,
 497                  u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
 498IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries,
 499                  u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);
 500IEEE80211_IF_FILE(path_refresh_time,
 501                  u.mesh.mshcfg.path_refresh_time, DEC);
 502IEEE80211_IF_FILE(min_discovery_timeout,
 503                  u.mesh.mshcfg.min_discovery_timeout, DEC);
 504IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
 505                  u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
 506IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol,
 507                  u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC);
 508IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
 509                  u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
 510IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC);
 511IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC);
 512IEEE80211_IF_FILE(ht_opmode, u.mesh.mshcfg.ht_opmode, DEC);
 513IEEE80211_IF_FILE(dot11MeshHWMPactivePathToRootTimeout,
 514                  u.mesh.mshcfg.dot11MeshHWMPactivePathToRootTimeout, DEC);
 515IEEE80211_IF_FILE(dot11MeshHWMProotInterval,
 516                  u.mesh.mshcfg.dot11MeshHWMProotInterval, DEC);
 517IEEE80211_IF_FILE(dot11MeshHWMPconfirmationInterval,
 518                  u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval, DEC);
 519#endif
 520
 521#define DEBUGFS_ADD_MODE(name, mode) \
 522        debugfs_create_file(#name, mode, sdata->debugfs.dir, \
 523                            sdata, &name##_ops);
 524
 525#define DEBUGFS_ADD(name) DEBUGFS_ADD_MODE(name, 0400)
 526
 527static void add_common_files(struct ieee80211_sub_if_data *sdata)
 528{
 529        DEBUGFS_ADD(drop_unencrypted);
 530        DEBUGFS_ADD(rc_rateidx_mask_2ghz);
 531        DEBUGFS_ADD(rc_rateidx_mask_5ghz);
 532        DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
 533        DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
 534}
 535
 536static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 537{
 538        DEBUGFS_ADD(bssid);
 539        DEBUGFS_ADD(aid);
 540        DEBUGFS_ADD(last_beacon);
 541        DEBUGFS_ADD(ave_beacon);
 542        DEBUGFS_ADD_MODE(smps, 0600);
 543        DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
 544        DEBUGFS_ADD_MODE(uapsd_queues, 0600);
 545        DEBUGFS_ADD_MODE(uapsd_max_sp_len, 0600);
 546}
 547
 548static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 549{
 550        DEBUGFS_ADD(num_mcast_sta);
 551        DEBUGFS_ADD(num_sta_ps);
 552        DEBUGFS_ADD(dtim_count);
 553        DEBUGFS_ADD(num_buffered_multicast);
 554        DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
 555}
 556
 557static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
 558{
 559        DEBUGFS_ADD_MODE(tsf, 0600);
 560}
 561
 562static void add_wds_files(struct ieee80211_sub_if_data *sdata)
 563{
 564        DEBUGFS_ADD(peer);
 565}
 566
 567#ifdef CONFIG_MAC80211_MESH
 568
 569static void add_mesh_files(struct ieee80211_sub_if_data *sdata)
 570{
 571        DEBUGFS_ADD_MODE(tsf, 0600);
 572}
 573
 574static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
 575{
 576        struct dentry *dir = debugfs_create_dir("mesh_stats",
 577                                                sdata->debugfs.dir);
 578#define MESHSTATS_ADD(name)\
 579        debugfs_create_file(#name, 0400, dir, sdata, &name##_ops);
 580
 581        MESHSTATS_ADD(fwded_mcast);
 582        MESHSTATS_ADD(fwded_unicast);
 583        MESHSTATS_ADD(fwded_frames);
 584        MESHSTATS_ADD(dropped_frames_ttl);
 585        MESHSTATS_ADD(dropped_frames_no_route);
 586        MESHSTATS_ADD(dropped_frames_congestion);
 587        MESHSTATS_ADD(estab_plinks);
 588#undef MESHSTATS_ADD
 589}
 590
 591static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
 592{
 593        struct dentry *dir = debugfs_create_dir("mesh_config",
 594                                                sdata->debugfs.dir);
 595
 596#define MESHPARAMS_ADD(name) \
 597        debugfs_create_file(#name, 0600, dir, sdata, &name##_ops);
 598
 599        MESHPARAMS_ADD(dot11MeshMaxRetries);
 600        MESHPARAMS_ADD(dot11MeshRetryTimeout);
 601        MESHPARAMS_ADD(dot11MeshConfirmTimeout);
 602        MESHPARAMS_ADD(dot11MeshHoldingTimeout);
 603        MESHPARAMS_ADD(dot11MeshTTL);
 604        MESHPARAMS_ADD(element_ttl);
 605        MESHPARAMS_ADD(auto_open_plinks);
 606        MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
 607        MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
 608        MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval);
 609        MESHPARAMS_ADD(dot11MeshHWMPperrMinInterval);
 610        MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime);
 611        MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
 612        MESHPARAMS_ADD(path_refresh_time);
 613        MESHPARAMS_ADD(min_discovery_timeout);
 614        MESHPARAMS_ADD(dot11MeshHWMPRootMode);
 615        MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
 616        MESHPARAMS_ADD(dot11MeshForwarding);
 617        MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
 618        MESHPARAMS_ADD(rssi_threshold);
 619        MESHPARAMS_ADD(ht_opmode);
 620        MESHPARAMS_ADD(dot11MeshHWMPactivePathToRootTimeout);
 621        MESHPARAMS_ADD(dot11MeshHWMProotInterval);
 622        MESHPARAMS_ADD(dot11MeshHWMPconfirmationInterval);
 623#undef MESHPARAMS_ADD
 624}
 625#endif
 626
 627static void add_files(struct ieee80211_sub_if_data *sdata)
 628{
 629        if (!sdata->debugfs.dir)
 630                return;
 631
 632        DEBUGFS_ADD(flags);
 633        DEBUGFS_ADD(state);
 634        DEBUGFS_ADD(channel_type);
 635
 636        if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
 637                add_common_files(sdata);
 638
 639        switch (sdata->vif.type) {
 640        case NL80211_IFTYPE_MESH_POINT:
 641#ifdef CONFIG_MAC80211_MESH
 642                add_mesh_files(sdata);
 643                add_mesh_stats(sdata);
 644                add_mesh_config(sdata);
 645#endif
 646                break;
 647        case NL80211_IFTYPE_STATION:
 648                add_sta_files(sdata);
 649                break;
 650        case NL80211_IFTYPE_ADHOC:
 651                add_ibss_files(sdata);
 652                break;
 653        case NL80211_IFTYPE_AP:
 654                add_ap_files(sdata);
 655                break;
 656        case NL80211_IFTYPE_WDS:
 657                add_wds_files(sdata);
 658                break;
 659        default:
 660                break;
 661        }
 662}
 663
 664void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
 665{
 666        char buf[10+IFNAMSIZ];
 667
 668        sprintf(buf, "netdev:%s", sdata->name);
 669        sdata->debugfs.dir = debugfs_create_dir(buf,
 670                sdata->local->hw.wiphy->debugfsdir);
 671        if (sdata->debugfs.dir)
 672                sdata->debugfs.subdir_stations = debugfs_create_dir("stations",
 673                        sdata->debugfs.dir);
 674        add_files(sdata);
 675}
 676
 677void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
 678{
 679        if (!sdata->debugfs.dir)
 680                return;
 681
 682        debugfs_remove_recursive(sdata->debugfs.dir);
 683        sdata->debugfs.dir = NULL;
 684}
 685
 686void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
 687{
 688        struct dentry *dir;
 689        char buf[10 + IFNAMSIZ];
 690
 691        dir = sdata->debugfs.dir;
 692
 693        if (!dir)
 694                return;
 695
 696        sprintf(buf, "netdev:%s", sdata->name);
 697        if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
 698                sdata_err(sdata,
 699                          "debugfs: failed to rename debugfs dir to %s\n",
 700                          buf);
 701}
 702
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.