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 "ieee80211_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                ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
  37        }
  38        read_unlock(&dev_base_lock);
  39        return ret;
  40}
  41
  42#define IEEE80211_IF_FMT(name, field, format_string)                    \
  43static ssize_t ieee80211_if_fmt_##name(                                 \
  44        const struct ieee80211_sub_if_data *sdata, char *buf,           \
  45        int buflen)                                                     \
  46{                                                                       \
  47        return scnprintf(buf, buflen, format_string, sdata->field);     \
  48}
  49#define IEEE80211_IF_FMT_DEC(name, field)                               \
  50                IEEE80211_IF_FMT(name, field, "%d\n")
  51#define IEEE80211_IF_FMT_HEX(name, field)                               \
  52                IEEE80211_IF_FMT(name, field, "%#x\n")
  53#define IEEE80211_IF_FMT_SIZE(name, field)                              \
  54                IEEE80211_IF_FMT(name, field, "%zd\n")
  55
  56#define IEEE80211_IF_FMT_ATOMIC(name, field)                            \
  57static ssize_t ieee80211_if_fmt_##name(                                 \
  58        const struct ieee80211_sub_if_data *sdata,                      \
  59        char *buf, int buflen)                                          \
  60{                                                                       \
  61        return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\
  62}
  63
  64#define IEEE80211_IF_FMT_MAC(name, field)                               \
  65static ssize_t ieee80211_if_fmt_##name(                                 \
  66        const struct ieee80211_sub_if_data *sdata, char *buf,           \
  67        int buflen)                                                     \
  68{                                                                       \
  69        DECLARE_MAC_BUF(mac);                                           \
  70        return scnprintf(buf, buflen, "%s\n", print_mac(mac, sdata->field));\
  71}
  72
  73#define __IEEE80211_IF_FILE(name)                                       \
  74static ssize_t ieee80211_if_read_##name(struct file *file,              \
  75                                        char __user *userbuf,           \
  76                                        size_t count, loff_t *ppos)     \
  77{                                                                       \
  78        return ieee80211_if_read(file->private_data,                    \
  79                                 userbuf, count, ppos,                  \
  80                                 ieee80211_if_fmt_##name);              \
  81}                                                                       \
  82static const struct file_operations name##_ops = {                      \
  83        .read = ieee80211_if_read_##name,                               \
  84        .open = mac80211_open_file_generic,                             \
  85}
  86
  87#define IEEE80211_IF_FILE(name, field, format)                          \
  88                IEEE80211_IF_FMT_##format(name, field)                  \
  89                __IEEE80211_IF_FILE(name)
  90
  91/* common attributes */
  92IEEE80211_IF_FILE(channel_use, channel_use, DEC);
  93IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
  94IEEE80211_IF_FILE(eapol, eapol, DEC);
  95IEEE80211_IF_FILE(ieee8021_x, ieee802_1x, DEC);
  96
  97/* STA/IBSS attributes */
  98IEEE80211_IF_FILE(state, u.sta.state, DEC);
  99IEEE80211_IF_FILE(bssid, u.sta.bssid, MAC);
 100IEEE80211_IF_FILE(prev_bssid, u.sta.prev_bssid, MAC);
 101IEEE80211_IF_FILE(ssid_len, u.sta.ssid_len, SIZE);
 102IEEE80211_IF_FILE(aid, u.sta.aid, DEC);
 103IEEE80211_IF_FILE(ap_capab, u.sta.ap_capab, HEX);
 104IEEE80211_IF_FILE(capab, u.sta.capab, HEX);
 105IEEE80211_IF_FILE(extra_ie_len, u.sta.extra_ie_len, SIZE);
 106IEEE80211_IF_FILE(auth_tries, u.sta.auth_tries, DEC);
 107IEEE80211_IF_FILE(assoc_tries, u.sta.assoc_tries, DEC);
 108IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX);
 109IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC);
 110IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC);
 111
 112static ssize_t ieee80211_if_fmt_flags(
 113        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 114{
 115        return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n",
 116                 sdata->u.sta.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "",
 117                 sdata->u.sta.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "",
 118                 sdata->u.sta.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "",
 119                 sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
 120                 sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
 121                 sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
 122                 sdata->flags & IEEE80211_SDATA_USE_PROTECTION ? "CTS prot\n" : "");
 123}
 124__IEEE80211_IF_FILE(flags);
 125
 126/* AP attributes */
 127IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
 128IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC);
 129IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
 130IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
 131IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC);
 132IEEE80211_IF_FILE(max_ratectrl_rateidx, u.ap.max_ratectrl_rateidx, DEC);
 133
 134static ssize_t ieee80211_if_fmt_num_buffered_multicast(
 135        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 136{
 137        return scnprintf(buf, buflen, "%u\n",
 138                         skb_queue_len(&sdata->u.ap.ps_bc_buf));
 139}
 140__IEEE80211_IF_FILE(num_buffered_multicast);
 141
 142static ssize_t ieee80211_if_fmt_beacon_head_len(
 143        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 144{
 145        if (sdata->u.ap.beacon_head)
 146                return scnprintf(buf, buflen, "%d\n",
 147                                 sdata->u.ap.beacon_head_len);
 148        return scnprintf(buf, buflen, "\n");
 149}
 150__IEEE80211_IF_FILE(beacon_head_len);
 151
 152static ssize_t ieee80211_if_fmt_beacon_tail_len(
 153        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 154{
 155        if (sdata->u.ap.beacon_tail)
 156                return scnprintf(buf, buflen, "%d\n",
 157                                 sdata->u.ap.beacon_tail_len);
 158        return scnprintf(buf, buflen, "\n");
 159}
 160__IEEE80211_IF_FILE(beacon_tail_len);
 161
 162/* WDS attributes */
 163IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
 164
 165#define DEBUGFS_ADD(name, type)\
 166        sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\
 167                sdata->debugfsdir, sdata, &name##_ops);
 168
 169static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 170{
 171        DEBUGFS_ADD(channel_use, sta);
 172        DEBUGFS_ADD(drop_unencrypted, sta);
 173        DEBUGFS_ADD(eapol, sta);
 174        DEBUGFS_ADD(ieee8021_x, sta);
 175        DEBUGFS_ADD(state, sta);
 176        DEBUGFS_ADD(bssid, sta);
 177        DEBUGFS_ADD(prev_bssid, sta);
 178        DEBUGFS_ADD(ssid_len, sta);
 179        DEBUGFS_ADD(aid, sta);
 180        DEBUGFS_ADD(ap_capab, sta);
 181        DEBUGFS_ADD(capab, sta);
 182        DEBUGFS_ADD(extra_ie_len, sta);
 183        DEBUGFS_ADD(auth_tries, sta);
 184        DEBUGFS_ADD(assoc_tries, sta);
 185        DEBUGFS_ADD(auth_algs, sta);
 186        DEBUGFS_ADD(auth_alg, sta);
 187        DEBUGFS_ADD(auth_transaction, sta);
 188        DEBUGFS_ADD(flags, sta);
 189}
 190
 191static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 192{
 193        DEBUGFS_ADD(channel_use, ap);
 194        DEBUGFS_ADD(drop_unencrypted, ap);
 195        DEBUGFS_ADD(eapol, ap);
 196        DEBUGFS_ADD(ieee8021_x, ap);
 197        DEBUGFS_ADD(num_sta_ps, ap);
 198        DEBUGFS_ADD(dtim_period, ap);
 199        DEBUGFS_ADD(dtim_count, ap);
 200        DEBUGFS_ADD(num_beacons, ap);
 201        DEBUGFS_ADD(force_unicast_rateidx, ap);
 202        DEBUGFS_ADD(max_ratectrl_rateidx, ap);
 203        DEBUGFS_ADD(num_buffered_multicast, ap);
 204        DEBUGFS_ADD(beacon_head_len, ap);
 205        DEBUGFS_ADD(beacon_tail_len, ap);
 206}
 207
 208static void add_wds_files(struct ieee80211_sub_if_data *sdata)
 209{
 210        DEBUGFS_ADD(channel_use, wds);
 211        DEBUGFS_ADD(drop_unencrypted, wds);
 212        DEBUGFS_ADD(eapol, wds);
 213        DEBUGFS_ADD(ieee8021_x, wds);
 214        DEBUGFS_ADD(peer, wds);
 215}
 216
 217static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
 218{
 219        DEBUGFS_ADD(channel_use, vlan);
 220        DEBUGFS_ADD(drop_unencrypted, vlan);
 221        DEBUGFS_ADD(eapol, vlan);
 222        DEBUGFS_ADD(ieee8021_x, vlan);
 223}
 224
 225static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
 226{
 227}
 228
 229static void add_files(struct ieee80211_sub_if_data *sdata)
 230{
 231        if (!sdata->debugfsdir)
 232                return;
 233
 234        switch (sdata->type) {
 235        case IEEE80211_IF_TYPE_STA:
 236        case IEEE80211_IF_TYPE_IBSS:
 237                add_sta_files(sdata);
 238                break;
 239        case IEEE80211_IF_TYPE_AP:
 240                add_ap_files(sdata);
 241                break;
 242        case IEEE80211_IF_TYPE_WDS:
 243                add_wds_files(sdata);
 244                break;
 245        case IEEE80211_IF_TYPE_MNTR:
 246                add_monitor_files(sdata);
 247                break;
 248        case IEEE80211_IF_TYPE_VLAN:
 249                add_vlan_files(sdata);
 250                break;
 251        default:
 252                break;
 253        }
 254}
 255
 256#define DEBUGFS_DEL(name, type)                                 \
 257        do {                                                    \
 258                debugfs_remove(sdata->debugfs.type.name);       \
 259                sdata->debugfs.type.name = NULL;                \
 260        } while (0)
 261
 262static void del_sta_files(struct ieee80211_sub_if_data *sdata)
 263{
 264        DEBUGFS_DEL(channel_use, sta);
 265        DEBUGFS_DEL(drop_unencrypted, sta);
 266        DEBUGFS_DEL(eapol, sta);
 267        DEBUGFS_DEL(ieee8021_x, sta);
 268        DEBUGFS_DEL(state, sta);
 269        DEBUGFS_DEL(bssid, sta);
 270        DEBUGFS_DEL(prev_bssid, sta);
 271        DEBUGFS_DEL(ssid_len, sta);
 272        DEBUGFS_DEL(aid, sta);
 273        DEBUGFS_DEL(ap_capab, sta);
 274        DEBUGFS_DEL(capab, sta);
 275        DEBUGFS_DEL(extra_ie_len, sta);
 276        DEBUGFS_DEL(auth_tries, sta);
 277        DEBUGFS_DEL(assoc_tries, sta);
 278        DEBUGFS_DEL(auth_algs, sta);
 279        DEBUGFS_DEL(auth_alg, sta);
 280        DEBUGFS_DEL(auth_transaction, sta);
 281        DEBUGFS_DEL(flags, sta);
 282}
 283
 284static void del_ap_files(struct ieee80211_sub_if_data *sdata)
 285{
 286        DEBUGFS_DEL(channel_use, ap);
 287        DEBUGFS_DEL(drop_unencrypted, ap);
 288        DEBUGFS_DEL(eapol, ap);
 289        DEBUGFS_DEL(ieee8021_x, ap);
 290        DEBUGFS_DEL(num_sta_ps, ap);
 291        DEBUGFS_DEL(dtim_period, ap);
 292        DEBUGFS_DEL(dtim_count, ap);
 293        DEBUGFS_DEL(num_beacons, ap);
 294        DEBUGFS_DEL(force_unicast_rateidx, ap);
 295        DEBUGFS_DEL(max_ratectrl_rateidx, ap);
 296        DEBUGFS_DEL(num_buffered_multicast, ap);
 297        DEBUGFS_DEL(beacon_head_len, ap);
 298        DEBUGFS_DEL(beacon_tail_len, ap);
 299}
 300
 301static void del_wds_files(struct ieee80211_sub_if_data *sdata)
 302{
 303        DEBUGFS_DEL(channel_use, wds);
 304        DEBUGFS_DEL(drop_unencrypted, wds);
 305        DEBUGFS_DEL(eapol, wds);
 306        DEBUGFS_DEL(ieee8021_x, wds);
 307        DEBUGFS_DEL(peer, wds);
 308}
 309
 310static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
 311{
 312        DEBUGFS_DEL(channel_use, vlan);
 313        DEBUGFS_DEL(drop_unencrypted, vlan);
 314        DEBUGFS_DEL(eapol, vlan);
 315        DEBUGFS_DEL(ieee8021_x, vlan);
 316}
 317
 318static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
 319{
 320}
 321
 322static void del_files(struct ieee80211_sub_if_data *sdata, int type)
 323{
 324        if (!sdata->debugfsdir)
 325                return;
 326
 327        switch (type) {
 328        case IEEE80211_IF_TYPE_STA:
 329        case IEEE80211_IF_TYPE_IBSS:
 330                del_sta_files(sdata);
 331                break;
 332        case IEEE80211_IF_TYPE_AP:
 333                del_ap_files(sdata);
 334                break;
 335        case IEEE80211_IF_TYPE_WDS:
 336                del_wds_files(sdata);
 337                break;
 338        case IEEE80211_IF_TYPE_MNTR:
 339                del_monitor_files(sdata);
 340                break;
 341        case IEEE80211_IF_TYPE_VLAN:
 342                del_vlan_files(sdata);
 343                break;
 344        default:
 345                break;
 346        }
 347}
 348
 349static int notif_registered;
 350
 351void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
 352{
 353        char buf[10+IFNAMSIZ];
 354
 355        if (!notif_registered)
 356                return;
 357
 358        sprintf(buf, "netdev:%s", sdata->dev->name);
 359        sdata->debugfsdir = debugfs_create_dir(buf,
 360                sdata->local->hw.wiphy->debugfsdir);
 361}
 362
 363void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
 364{
 365        del_files(sdata, sdata->type);
 366        debugfs_remove(sdata->debugfsdir);
 367        sdata->debugfsdir = NULL;
 368}
 369
 370void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata,
 371                                      int oldtype)
 372{
 373        del_files(sdata, oldtype);
 374        add_files(sdata);
 375}
 376
 377static int netdev_notify(struct notifier_block * nb,
 378                         unsigned long state,
 379                         void *ndev)
 380{
 381        struct net_device *dev = ndev;
 382        struct dentry *dir;
 383        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 384        char buf[10+IFNAMSIZ];
 385
 386        if (state != NETDEV_CHANGENAME)
 387                return 0;
 388
 389        if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
 390                return 0;
 391
 392        if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
 393                return 0;
 394
 395        sprintf(buf, "netdev:%s", dev->name);
 396        dir = sdata->debugfsdir;
 397        if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
 398                printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
 399                       "dir to %s\n", buf);
 400
 401        return 0;
 402}
 403
 404static struct notifier_block mac80211_debugfs_netdev_notifier = {
 405        .notifier_call = netdev_notify,
 406};
 407
 408void ieee80211_debugfs_netdev_init(void)
 409{
 410        int err;
 411
 412        err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
 413        if (err) {
 414                printk(KERN_ERR
 415                       "mac80211: failed to install netdev notifier,"
 416                       " disabling per-netdev debugfs!\n");
 417        } else
 418                notif_registered = 1;
 419}
 420
 421void ieee80211_debugfs_netdev_exit(void)
 422{
 423        unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
 424        notif_registered = 0;
 425}
 426