linux/net/mac80211/debugfs_key.c
<<
>>
Prefs
   1/*
   2 * Copyright 2003-2005  Devicescape Software, Inc.
   3 * Copyright (c) 2006   Jiri Benc <jbenc@suse.cz>
   4 * Copyright 2007       Johannes Berg <johannes@sipsolutions.net>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/kobject.h>
  12#include <linux/slab.h>
  13#include "ieee80211_i.h"
  14#include "key.h"
  15#include "debugfs.h"
  16#include "debugfs_key.h"
  17
  18#define KEY_READ(name, prop, buflen, format_string)                     \
  19static ssize_t key_##name##_read(struct file *file,                     \
  20                                 char __user *userbuf,                  \
  21                                 size_t count, loff_t *ppos)            \
  22{                                                                       \
  23        char buf[buflen];                                               \
  24        struct ieee80211_key *key = file->private_data;                 \
  25        int res = scnprintf(buf, buflen, format_string, key->prop);     \
  26        return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
  27}
  28#define KEY_READ_D(name) KEY_READ(name, name, 20, "%d\n")
  29#define KEY_READ_X(name) KEY_READ(name, name, 20, "0x%x\n")
  30
  31#define KEY_OPS(name)                                                   \
  32static const struct file_operations key_ ##name## _ops = {              \
  33        .read = key_##name##_read,                                      \
  34        .open = mac80211_open_file_generic,                             \
  35}
  36
  37#define KEY_FILE(name, format)                                          \
  38                 KEY_READ_##format(name)                                \
  39                 KEY_OPS(name)
  40
  41#define KEY_CONF_READ(name, buflen, format_string)                      \
  42        KEY_READ(conf_##name, conf.name, buflen, format_string)
  43#define KEY_CONF_READ_D(name) KEY_CONF_READ(name, 20, "%d\n")
  44
  45#define KEY_CONF_OPS(name)                                              \
  46static const struct file_operations key_ ##name## _ops = {              \
  47        .read = key_conf_##name##_read,                                 \
  48        .open = mac80211_open_file_generic,                             \
  49}
  50
  51#define KEY_CONF_FILE(name, format)                                     \
  52                 KEY_CONF_READ_##format(name)                           \
  53                 KEY_CONF_OPS(name)
  54
  55KEY_CONF_FILE(keylen, D);
  56KEY_CONF_FILE(keyidx, D);
  57KEY_CONF_FILE(hw_key_idx, D);
  58KEY_FILE(flags, X);
  59KEY_FILE(tx_rx_count, D);
  60KEY_READ(ifindex, sdata->name, IFNAMSIZ + 2, "%s\n");
  61KEY_OPS(ifindex);
  62
  63static ssize_t key_algorithm_read(struct file *file,
  64                                  char __user *userbuf,
  65                                  size_t count, loff_t *ppos)
  66{
  67        char *alg;
  68        struct ieee80211_key *key = file->private_data;
  69
  70        switch (key->conf.alg) {
  71        case ALG_WEP:
  72                alg = "WEP\n";
  73                break;
  74        case ALG_TKIP:
  75                alg = "TKIP\n";
  76                break;
  77        case ALG_CCMP:
  78                alg = "CCMP\n";
  79                break;
  80        case ALG_AES_CMAC:
  81                alg = "AES-128-CMAC\n";
  82                break;
  83        default:
  84                return 0;
  85        }
  86        return simple_read_from_buffer(userbuf, count, ppos, alg, strlen(alg));
  87}
  88KEY_OPS(algorithm);
  89
  90static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
  91                                size_t count, loff_t *ppos)
  92{
  93        const u8 *tpn;
  94        char buf[20];
  95        int len;
  96        struct ieee80211_key *key = file->private_data;
  97
  98        switch (key->conf.alg) {
  99        case ALG_WEP:
 100                len = scnprintf(buf, sizeof(buf), "\n");
 101                break;
 102        case ALG_TKIP:
 103                len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
 104                                key->u.tkip.tx.iv32,
 105                                key->u.tkip.tx.iv16);
 106                break;
 107        case ALG_CCMP:
 108                tpn = key->u.ccmp.tx_pn;
 109                len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
 110                                tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
 111                break;
 112        case ALG_AES_CMAC:
 113                tpn = key->u.aes_cmac.tx_pn;
 114                len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
 115                                tpn[0], tpn[1], tpn[2], tpn[3], tpn[4],
 116                                tpn[5]);
 117                break;
 118        default:
 119                return 0;
 120        }
 121        return simple_read_from_buffer(userbuf, count, ppos, buf, len);
 122}
 123KEY_OPS(tx_spec);
 124
 125static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
 126                                size_t count, loff_t *ppos)
 127{
 128        struct ieee80211_key *key = file->private_data;
 129        char buf[14*NUM_RX_DATA_QUEUES+1], *p = buf;
 130        int i, len;
 131        const u8 *rpn;
 132
 133        switch (key->conf.alg) {
 134        case ALG_WEP:
 135                len = scnprintf(buf, sizeof(buf), "\n");
 136                break;
 137        case ALG_TKIP:
 138                for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
 139                        p += scnprintf(p, sizeof(buf)+buf-p,
 140                                       "%08x %04x\n",
 141                                       key->u.tkip.rx[i].iv32,
 142                                       key->u.tkip.rx[i].iv16);
 143                len = p - buf;
 144                break;
 145        case ALG_CCMP:
 146                for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
 147                        rpn = key->u.ccmp.rx_pn[i];
 148                        p += scnprintf(p, sizeof(buf)+buf-p,
 149                                       "%02x%02x%02x%02x%02x%02x\n",
 150                                       rpn[0], rpn[1], rpn[2],
 151                                       rpn[3], rpn[4], rpn[5]);
 152                }
 153                len = p - buf;
 154                break;
 155        case ALG_AES_CMAC:
 156                rpn = key->u.aes_cmac.rx_pn;
 157                p += scnprintf(p, sizeof(buf)+buf-p,
 158                               "%02x%02x%02x%02x%02x%02x\n",
 159                               rpn[0], rpn[1], rpn[2],
 160                               rpn[3], rpn[4], rpn[5]);
 161                len = p - buf;
 162                break;
 163        default:
 164                return 0;
 165        }
 166        return simple_read_from_buffer(userbuf, count, ppos, buf, len);
 167}
 168KEY_OPS(rx_spec);
 169
 170static ssize_t key_replays_read(struct file *file, char __user *userbuf,
 171                                size_t count, loff_t *ppos)
 172{
 173        struct ieee80211_key *key = file->private_data;
 174        char buf[20];
 175        int len;
 176
 177        switch (key->conf.alg) {
 178        case ALG_CCMP:
 179                len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
 180                break;
 181        case ALG_AES_CMAC:
 182                len = scnprintf(buf, sizeof(buf), "%u\n",
 183                                key->u.aes_cmac.replays);
 184                break;
 185        default:
 186                return 0;
 187        }
 188        return simple_read_from_buffer(userbuf, count, ppos, buf, len);
 189}
 190KEY_OPS(replays);
 191
 192static ssize_t key_icverrors_read(struct file *file, char __user *userbuf,
 193                                  size_t count, loff_t *ppos)
 194{
 195        struct ieee80211_key *key = file->private_data;
 196        char buf[20];
 197        int len;
 198
 199        switch (key->conf.alg) {
 200        case ALG_AES_CMAC:
 201                len = scnprintf(buf, sizeof(buf), "%u\n",
 202                                key->u.aes_cmac.icverrors);
 203                break;
 204        default:
 205                return 0;
 206        }
 207        return simple_read_from_buffer(userbuf, count, ppos, buf, len);
 208}
 209KEY_OPS(icverrors);
 210
 211static ssize_t key_key_read(struct file *file, char __user *userbuf,
 212                            size_t count, loff_t *ppos)
 213{
 214        struct ieee80211_key *key = file->private_data;
 215        int i, res, bufsize = 2 * key->conf.keylen + 2;
 216        char *buf = kmalloc(bufsize, GFP_KERNEL);
 217        char *p = buf;
 218
 219        for (i = 0; i < key->conf.keylen; i++)
 220                p += scnprintf(p, bufsize + buf - p, "%02x", key->conf.key[i]);
 221        p += scnprintf(p, bufsize+buf-p, "\n");
 222        res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
 223        kfree(buf);
 224        return res;
 225}
 226KEY_OPS(key);
 227
 228#define DEBUGFS_ADD(name) \
 229        debugfs_create_file(#name, 0400, key->debugfs.dir, \
 230                            key, &key_##name##_ops);
 231
 232void ieee80211_debugfs_key_add(struct ieee80211_key *key)
 233  {
 234        static int keycount;
 235        char buf[50];
 236        struct sta_info *sta;
 237
 238        if (!key->local->debugfs.keys)
 239                return;
 240
 241        sprintf(buf, "%d", keycount);
 242        key->debugfs.cnt = keycount;
 243        keycount++;
 244        key->debugfs.dir = debugfs_create_dir(buf,
 245                                        key->local->debugfs.keys);
 246
 247        if (!key->debugfs.dir)
 248                return;
 249
 250        rcu_read_lock();
 251        sta = rcu_dereference(key->sta);
 252        if (sta)
 253                sprintf(buf, "../../stations/%pM", sta->sta.addr);
 254        rcu_read_unlock();
 255
 256        /* using sta as a boolean is fine outside RCU lock */
 257        if (sta)
 258                key->debugfs.stalink =
 259                        debugfs_create_symlink("station", key->debugfs.dir, buf);
 260
 261        DEBUGFS_ADD(keylen);
 262        DEBUGFS_ADD(flags);
 263        DEBUGFS_ADD(keyidx);
 264        DEBUGFS_ADD(hw_key_idx);
 265        DEBUGFS_ADD(tx_rx_count);
 266        DEBUGFS_ADD(algorithm);
 267        DEBUGFS_ADD(tx_spec);
 268        DEBUGFS_ADD(rx_spec);
 269        DEBUGFS_ADD(replays);
 270        DEBUGFS_ADD(icverrors);
 271        DEBUGFS_ADD(key);
 272        DEBUGFS_ADD(ifindex);
 273};
 274
 275void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
 276{
 277        if (!key)
 278                return;
 279
 280        debugfs_remove_recursive(key->debugfs.dir);
 281        key->debugfs.dir = NULL;
 282}
 283void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata)
 284{
 285        char buf[50];
 286        struct ieee80211_key *key;
 287
 288        if (!sdata->debugfs.dir)
 289                return;
 290
 291        /* this is running under the key lock */
 292
 293        key = sdata->default_key;
 294        if (key) {
 295                sprintf(buf, "../keys/%d", key->debugfs.cnt);
 296                sdata->debugfs.default_key =
 297                        debugfs_create_symlink("default_key",
 298                                               sdata->debugfs.dir, buf);
 299        } else
 300                ieee80211_debugfs_key_remove_default(sdata);
 301}
 302
 303void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata)
 304{
 305        if (!sdata)
 306                return;
 307
 308        debugfs_remove(sdata->debugfs.default_key);
 309        sdata->debugfs.default_key = NULL;
 310}
 311
 312void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata)
 313{
 314        char buf[50];
 315        struct ieee80211_key *key;
 316
 317        if (!sdata->debugfs.dir)
 318                return;
 319
 320        /* this is running under the key lock */
 321
 322        key = sdata->default_mgmt_key;
 323        if (key) {
 324                sprintf(buf, "../keys/%d", key->debugfs.cnt);
 325                sdata->debugfs.default_mgmt_key =
 326                        debugfs_create_symlink("default_mgmt_key",
 327                                               sdata->debugfs.dir, buf);
 328        } else
 329                ieee80211_debugfs_key_remove_mgmt_default(sdata);
 330}
 331
 332void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sdata)
 333{
 334        if (!sdata)
 335                return;
 336
 337        debugfs_remove(sdata->debugfs.default_mgmt_key);
 338        sdata->debugfs.default_mgmt_key = NULL;
 339}
 340
 341void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
 342                                   struct sta_info *sta)
 343{
 344        debugfs_remove(key->debugfs.stalink);
 345        key->debugfs.stalink = NULL;
 346}
 347
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.