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/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
  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[70];
  31        ssize_t ret = -EINVAL;
  32
  33        read_lock(&dev_base_lock);
  34        if (sdata->dev->reg_state == NETREG_REGISTERED)
  35                ret = (*format)(sdata, buf, sizeof(buf));
  36        read_unlock(&dev_base_lock);
  37
  38        if (ret != -EINVAL)
  39                ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
  40
  41        return ret;
  42}
  43
  44#define IEEE80211_IF_FMT(name, field, format_string)                    \
  45static ssize_t ieee80211_if_fmt_##name(                                 \
  46        const struct ieee80211_sub_if_data *sdata, char *buf,           \
  47        int buflen)                                                     \
  48{                                                                       \
  49        return scnprintf(buf, buflen, format_string, sdata->field);     \
  50}
  51#define IEEE80211_IF_FMT_DEC(name, field)                               \
  52                IEEE80211_IF_FMT(name, field, "%d\n")
  53#define IEEE80211_IF_FMT_HEX(name, field)                               \
  54                IEEE80211_IF_FMT(name, field, "%#x\n")
  55#define IEEE80211_IF_FMT_SIZE(name, field)                              \
  56                IEEE80211_IF_FMT(name, field, "%zd\n")
  57
  58#define IEEE80211_IF_FMT_ATOMIC(name, field)                            \
  59static ssize_t ieee80211_if_fmt_##name(                                 \
  60        const struct ieee80211_sub_if_data *sdata,                      \
  61        char *buf, int buflen)                                          \
  62{                                                                       \
  63        return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\
  64}
  65
  66#define IEEE80211_IF_FMT_MAC(name, field)                               \
  67static ssize_t ieee80211_if_fmt_##name(                                 \
  68        const struct ieee80211_sub_if_data *sdata, char *buf,           \
  69        int buflen)                                                     \
  70{                                                                       \
  71        return scnprintf(buf, buflen, "%pM\n", sdata->field);           \
  72}
  73
  74#define __IEEE80211_IF_FILE(name)                                       \
  75static ssize_t ieee80211_if_read_##name(struct file *file,              \
  76                                        char __user *userbuf,           \
  77                                        size_t count, loff_t *ppos)     \
  78{                                                                       \
  79        return ieee80211_if_read(file->private_data,                    \
  80                                 userbuf, count, ppos,                  \
  81                                 ieee80211_if_fmt_##name);              \
  82}                                                                       \
  83static const struct file_operations name##_ops = {                      \
  84        .read = ieee80211_if_read_##name,                               \
  85        .open = mac80211_open_file_generic,                             \
  86}
  87
  88#define IEEE80211_IF_FILE(name, field, format)                          \
  89                IEEE80211_IF_FMT_##format(name, field)                  \
  90                __IEEE80211_IF_FILE(name)
  91
  92/* common attributes */
  93IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
  94IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
  95IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
  96
  97/* STA attributes */
  98IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
  99IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
 100IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
 101
 102/* AP attributes */
 103IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
 104IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
 105
 106static ssize_t ieee80211_if_fmt_num_buffered_multicast(
 107        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 108{
 109        return scnprintf(buf, buflen, "%u\n",
 110                         skb_queue_len(&sdata->u.ap.ps_bc_buf));
 111}
 112__IEEE80211_IF_FILE(num_buffered_multicast);
 113
 114/* WDS attributes */
 115IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
 116
 117#ifdef CONFIG_MAC80211_MESH
 118/* Mesh stats attributes */
 119IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC);
 120IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
 121IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
 122IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
 123IEEE80211_IF_FILE(dropped_frames_no_route,
 124                u.mesh.mshstats.dropped_frames_no_route, DEC);
 125IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);
 126
 127/* Mesh parameters */
 128IEEE80211_IF_FILE(dot11MeshMaxRetries,
 129                u.mesh.mshcfg.dot11MeshMaxRetries, DEC);
 130IEEE80211_IF_FILE(dot11MeshRetryTimeout,
 131                u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);
 132IEEE80211_IF_FILE(dot11MeshConfirmTimeout,
 133                u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);
 134IEEE80211_IF_FILE(dot11MeshHoldingTimeout,
 135                u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
 136IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC);
 137IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC);
 138IEEE80211_IF_FILE(dot11MeshMaxPeerLinks,
 139                u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
 140IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout,
 141                u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
 142IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval,
 143                u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
 144IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime,
 145                u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
 146IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries,
 147                u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);
 148IEEE80211_IF_FILE(path_refresh_time,
 149                u.mesh.mshcfg.path_refresh_time, DEC);
 150IEEE80211_IF_FILE(min_discovery_timeout,
 151                u.mesh.mshcfg.min_discovery_timeout, DEC);
 152#endif
 153
 154
 155#define DEBUGFS_ADD(name, type)\
 156        sdata->debugfs.type.name = debugfs_create_file(#name, 0400,\
 157                sdata->debugfsdir, sdata, &name##_ops);
 158
 159static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 160{
 161        DEBUGFS_ADD(drop_unencrypted, sta);
 162        DEBUGFS_ADD(force_unicast_rateidx, sta);
 163        DEBUGFS_ADD(max_ratectrl_rateidx, sta);
 164
 165        DEBUGFS_ADD(bssid, sta);
 166        DEBUGFS_ADD(aid, sta);
 167        DEBUGFS_ADD(capab, sta);
 168}
 169
 170static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 171{
 172        DEBUGFS_ADD(drop_unencrypted, ap);
 173        DEBUGFS_ADD(force_unicast_rateidx, ap);
 174        DEBUGFS_ADD(max_ratectrl_rateidx, ap);
 175
 176        DEBUGFS_ADD(num_sta_ps, ap);
 177        DEBUGFS_ADD(dtim_count, ap);
 178        DEBUGFS_ADD(num_buffered_multicast, ap);
 179}
 180
 181static void add_wds_files(struct ieee80211_sub_if_data *sdata)
 182{
 183        DEBUGFS_ADD(drop_unencrypted, wds);
 184        DEBUGFS_ADD(force_unicast_rateidx, wds);
 185        DEBUGFS_ADD(max_ratectrl_rateidx, wds);
 186
 187        DEBUGFS_ADD(peer, wds);
 188}
 189
 190static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
 191{
 192        DEBUGFS_ADD(drop_unencrypted, vlan);
 193        DEBUGFS_ADD(force_unicast_rateidx, vlan);
 194        DEBUGFS_ADD(max_ratectrl_rateidx, vlan);
 195}
 196
 197static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
 198{
 199}
 200
 201#ifdef CONFIG_MAC80211_MESH
 202#define MESHSTATS_ADD(name)\
 203        sdata->mesh_stats.name = debugfs_create_file(#name, 0400,\
 204                sdata->mesh_stats_dir, sdata, &name##_ops);
 205
 206static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
 207{
 208        sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats",
 209                                sdata->debugfsdir);
 210        MESHSTATS_ADD(fwded_mcast);
 211        MESHSTATS_ADD(fwded_unicast);
 212        MESHSTATS_ADD(fwded_frames);
 213        MESHSTATS_ADD(dropped_frames_ttl);
 214        MESHSTATS_ADD(dropped_frames_no_route);
 215        MESHSTATS_ADD(estab_plinks);
 216}
 217
 218#define MESHPARAMS_ADD(name)\
 219        sdata->mesh_config.name = debugfs_create_file(#name, 0600,\
 220                sdata->mesh_config_dir, sdata, &name##_ops);
 221
 222static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
 223{
 224        sdata->mesh_config_dir = debugfs_create_dir("mesh_config",
 225                                sdata->debugfsdir);
 226        MESHPARAMS_ADD(dot11MeshMaxRetries);
 227        MESHPARAMS_ADD(dot11MeshRetryTimeout);
 228        MESHPARAMS_ADD(dot11MeshConfirmTimeout);
 229        MESHPARAMS_ADD(dot11MeshHoldingTimeout);
 230        MESHPARAMS_ADD(dot11MeshTTL);
 231        MESHPARAMS_ADD(auto_open_plinks);
 232        MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
 233        MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
 234        MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval);
 235        MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime);
 236        MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
 237        MESHPARAMS_ADD(path_refresh_time);
 238        MESHPARAMS_ADD(min_discovery_timeout);
 239}
 240#endif
 241
 242static void add_files(struct ieee80211_sub_if_data *sdata)
 243{
 244        if (!sdata->debugfsdir)
 245                return;
 246
 247        switch (sdata->vif.type) {
 248        case NL80211_IFTYPE_MESH_POINT:
 249#ifdef CONFIG_MAC80211_MESH
 250                add_mesh_stats(sdata);
 251                add_mesh_config(sdata);
 252#endif
 253                break;
 254        case NL80211_IFTYPE_STATION:
 255                add_sta_files(sdata);
 256                break;
 257        case NL80211_IFTYPE_ADHOC:
 258                /* XXX */
 259                break;
 260        case NL80211_IFTYPE_AP:
 261                add_ap_files(sdata);
 262                break;
 263        case NL80211_IFTYPE_WDS:
 264                add_wds_files(sdata);
 265                break;
 266        case NL80211_IFTYPE_MONITOR:
 267                add_monitor_files(sdata);
 268                break;
 269        case NL80211_IFTYPE_AP_VLAN:
 270                add_vlan_files(sdata);
 271                break;
 272        default:
 273                break;
 274        }
 275}
 276
 277#define DEBUGFS_DEL(name, type)                                 \
 278        do {                                                    \
 279                debugfs_remove(sdata->debugfs.type.name);       \
 280                sdata->debugfs.type.name = NULL;                \
 281        } while (0)
 282
 283static void del_sta_files(struct ieee80211_sub_if_data *sdata)
 284{
 285        DEBUGFS_DEL(drop_unencrypted, sta);
 286        DEBUGFS_DEL(force_unicast_rateidx, sta);
 287        DEBUGFS_DEL(max_ratectrl_rateidx, sta);
 288
 289        DEBUGFS_DEL(bssid, sta);
 290        DEBUGFS_DEL(aid, sta);
 291        DEBUGFS_DEL(capab, sta);
 292}
 293
 294static void del_ap_files(struct ieee80211_sub_if_data *sdata)
 295{
 296        DEBUGFS_DEL(drop_unencrypted, ap);
 297        DEBUGFS_DEL(force_unicast_rateidx, ap);
 298        DEBUGFS_DEL(max_ratectrl_rateidx, ap);
 299
 300        DEBUGFS_DEL(num_sta_ps, ap);
 301        DEBUGFS_DEL(dtim_count, ap);
 302        DEBUGFS_DEL(num_buffered_multicast, ap);
 303}
 304
 305static void del_wds_files(struct ieee80211_sub_if_data *sdata)
 306{
 307        DEBUGFS_DEL(drop_unencrypted, wds);
 308        DEBUGFS_DEL(force_unicast_rateidx, wds);
 309        DEBUGFS_DEL(max_ratectrl_rateidx, wds);
 310
 311        DEBUGFS_DEL(peer, wds);
 312}
 313
 314static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
 315{
 316        DEBUGFS_DEL(drop_unencrypted, vlan);
 317        DEBUGFS_DEL(force_unicast_rateidx, vlan);
 318        DEBUGFS_DEL(max_ratectrl_rateidx, vlan);
 319}
 320
 321static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
 322{
 323}
 324
 325#ifdef CONFIG_MAC80211_MESH
 326#define MESHSTATS_DEL(name)                     \
 327        do {                                            \
 328                debugfs_remove(sdata->mesh_stats.name); \
 329                sdata->mesh_stats.name = NULL;          \
 330        } while (0)
 331
 332static void del_mesh_stats(struct ieee80211_sub_if_data *sdata)
 333{
 334        MESHSTATS_DEL(fwded_mcast);
 335        MESHSTATS_DEL(fwded_unicast);
 336        MESHSTATS_DEL(fwded_frames);
 337        MESHSTATS_DEL(dropped_frames_ttl);
 338        MESHSTATS_DEL(dropped_frames_no_route);
 339        MESHSTATS_DEL(estab_plinks);
 340        debugfs_remove(sdata->mesh_stats_dir);
 341        sdata->mesh_stats_dir = NULL;
 342}
 343
 344#define MESHPARAMS_DEL(name)                    \
 345        do {                                            \
 346                debugfs_remove(sdata->mesh_config.name);        \
 347                sdata->mesh_config.name = NULL;         \
 348        } while (0)
 349
 350static void del_mesh_config(struct ieee80211_sub_if_data *sdata)
 351{
 352        MESHPARAMS_DEL(dot11MeshMaxRetries);
 353        MESHPARAMS_DEL(dot11MeshRetryTimeout);
 354        MESHPARAMS_DEL(dot11MeshConfirmTimeout);
 355        MESHPARAMS_DEL(dot11MeshHoldingTimeout);
 356        MESHPARAMS_DEL(dot11MeshTTL);
 357        MESHPARAMS_DEL(auto_open_plinks);
 358        MESHPARAMS_DEL(dot11MeshMaxPeerLinks);
 359        MESHPARAMS_DEL(dot11MeshHWMPactivePathTimeout);
 360        MESHPARAMS_DEL(dot11MeshHWMPpreqMinInterval);
 361        MESHPARAMS_DEL(dot11MeshHWMPnetDiameterTraversalTime);
 362        MESHPARAMS_DEL(dot11MeshHWMPmaxPREQretries);
 363        MESHPARAMS_DEL(path_refresh_time);
 364        MESHPARAMS_DEL(min_discovery_timeout);
 365        debugfs_remove(sdata->mesh_config_dir);
 366        sdata->mesh_config_dir = NULL;
 367}
 368#endif
 369
 370static void del_files(struct ieee80211_sub_if_data *sdata)
 371{
 372        if (!sdata->debugfsdir)
 373                return;
 374
 375        switch (sdata->vif.type) {
 376        case NL80211_IFTYPE_MESH_POINT:
 377#ifdef CONFIG_MAC80211_MESH
 378                del_mesh_stats(sdata);
 379                del_mesh_config(sdata);
 380#endif
 381                break;
 382        case NL80211_IFTYPE_STATION:
 383                del_sta_files(sdata);
 384                break;
 385        case NL80211_IFTYPE_ADHOC:
 386                /* XXX */
 387                break;
 388        case NL80211_IFTYPE_AP:
 389                del_ap_files(sdata);
 390                break;
 391        case NL80211_IFTYPE_WDS:
 392                del_wds_files(sdata);
 393                break;
 394        case NL80211_IFTYPE_MONITOR:
 395                del_monitor_files(sdata);
 396                break;
 397        case NL80211_IFTYPE_AP_VLAN:
 398                del_vlan_files(sdata);
 399                break;
 400        default:
 401                break;
 402        }
 403}
 404
 405static int notif_registered;
 406
 407void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
 408{
 409        char buf[10+IFNAMSIZ];
 410
 411        if (!notif_registered)
 412                return;
 413
 414        sprintf(buf, "netdev:%s", sdata->dev->name);
 415        sdata->debugfsdir = debugfs_create_dir(buf,
 416                sdata->local->hw.wiphy->debugfsdir);
 417        add_files(sdata);
 418}
 419
 420void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
 421{
 422        del_files(sdata);
 423        debugfs_remove(sdata->debugfsdir);
 424        sdata->debugfsdir = NULL;
 425}
 426
 427static int netdev_notify(struct notifier_block *nb,
 428                         unsigned long state,
 429                         void *ndev)
 430{
 431        struct net_device *dev = ndev;
 432        struct dentry *dir;
 433        struct ieee80211_sub_if_data *sdata;
 434        char buf[10+IFNAMSIZ];
 435
 436        if (state != NETDEV_CHANGENAME)
 437                return 0;
 438
 439        if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
 440                return 0;
 441
 442        if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
 443                return 0;
 444
 445        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 446
 447        dir = sdata->debugfsdir;
 448
 449        if (!dir)
 450                return 0;
 451
 452        sprintf(buf, "netdev:%s", dev->name);
 453        if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
 454                printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
 455                       "dir to %s\n", buf);
 456
 457        return 0;
 458}
 459
 460static struct notifier_block mac80211_debugfs_netdev_notifier = {
 461        .notifier_call = netdev_notify,
 462};
 463
 464void ieee80211_debugfs_netdev_init(void)
 465{
 466        int err;
 467
 468        err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
 469        if (err) {
 470                printk(KERN_ERR
 471                       "mac80211: failed to install netdev notifier,"
 472                       " disabling per-netdev debugfs!\n");
 473        } else
 474                notif_registered = 1;
 475}
 476
 477void ieee80211_debugfs_netdev_exit(void)
 478{
 479        unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
 480        notif_registered = 0;
 481}
 482