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 * Copyright (C) 2015   Intel Deutschland GmbH
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11
  12#include <linux/kobject.h>
  13#include <linux/slab.h>
  14#include "ieee80211_i.h"
  15#include "key.h"
  16#include "debugfs.h"
  17#include "debugfs_key.h"
  18
  19#define KEY_READ(name, prop, format_string)                             \
  20static ssize_t key_##name##_read(struct file *file,                     \
  21                                 char __user *userbuf,                  \
  22                                 size_t count, loff_t *ppos)            \
  23{                                                                       \
  24        struct ieee80211_key *key = file->private_data;                 \
  25        return mac80211_format_buffer(userbuf, count, ppos,             \
  26                                      format_string, key->prop);        \
  27}
  28#define KEY_READ_D(name) KEY_READ(name, name, "%d\n")
  29#define KEY_READ_X(name) KEY_READ(name, name, "0x%x\n")
  30
  31#define KEY_OPS(name)                                                   \
  32static const struct file_operations key_ ##name## _ops = {              \
  33        .read = key_##name##_read,                                      \
  34        .open = simple_open,                                            \
  35        .llseek = generic_file_llseek,                                  \
  36}
  37
  38#define KEY_OPS_W(name)                                                 \
  39static const struct file_operations key_ ##name## _ops = {              \
  40        .read = key_##name##_read,                                      \
  41        .write = key_##name##_write,                                    \
  42        .open = simple_open,                                            \
  43        .llseek = generic_file_llseek,                                  \
  44}
  45
  46#define KEY_FILE(name, format)                                          \
  47                 KEY_READ_##format(name)                                \
  48                 KEY_OPS(name)
  49
  50#define KEY_CONF_READ(name, format_string)                              \
  51        KEY_READ(conf_##name, conf.name, format_string)
  52#define KEY_CONF_READ_D(name) KEY_CONF_READ(name, "%d\n")
  53
  54#define KEY_CONF_OPS(name)                                              \
  55static const struct file_operations key_ ##name## _ops = {              \
  56        .read = key_conf_##name##_read,                                 \
  57        .open = simple_open,                                            \
  58        .llseek = generic_file_llseek,                                  \
  59}
  60
  61#define KEY_CONF_FILE(name, format)                                     \
  62                 KEY_CONF_READ_##format(name)                           \
  63                 KEY_CONF_OPS(name)
  64
  65KEY_CONF_FILE(keylen, D);
  66KEY_CONF_FILE(keyidx, D);
  67KEY_CONF_FILE(hw_key_idx, D);
  68KEY_FILE(flags, X);
  69KEY_READ(ifindex, sdata->name, "%s\n");
  70KEY_OPS(ifindex);
  71
  72static ssize_t key_algorithm_read(struct file *file,
  73                                  char __user *userbuf,
  74                                  size_t count, loff_t *ppos)
  75{
  76        char buf[15];
  77        struct ieee80211_key *key = file->private_data;
  78        u32 c = key->conf.cipher;
  79
  80        sprintf(buf, "%.2x-%.2x-%.2x:%d\n",
  81                c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
  82        return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
  83}
  84KEY_OPS(algorithm);
  85
  86static ssize_t key_tx_spec_write(struct file *file, const char __user *userbuf,
  87                                 size_t count, loff_t *ppos)
  88{
  89        struct ieee80211_key *key = file->private_data;
  90        u64 pn;
  91        int ret;
  92
  93        switch (key->conf.cipher) {
  94        case WLAN_CIPHER_SUITE_WEP40:
  95        case WLAN_CIPHER_SUITE_WEP104:
  96                return -EINVAL;
  97        case WLAN_CIPHER_SUITE_TKIP:
  98                /* not supported yet */
  99                return -EOPNOTSUPP;
 100        case WLAN_CIPHER_SUITE_CCMP:
 101        case WLAN_CIPHER_SUITE_CCMP_256:
 102        case WLAN_CIPHER_SUITE_AES_CMAC:
 103        case WLAN_CIPHER_SUITE_BIP_CMAC_256:
 104        case WLAN_CIPHER_SUITE_BIP_GMAC_128:
 105        case WLAN_CIPHER_SUITE_BIP_GMAC_256:
 106        case WLAN_CIPHER_SUITE_GCMP:
 107        case WLAN_CIPHER_SUITE_GCMP_256:
 108                ret = kstrtou64_from_user(userbuf, count, 16, &pn);
 109                if (ret)
 110                        return ret;
 111                /* PN is a 48-bit counter */
 112                if (pn >= (1ULL << 48))
 113                        return -ERANGE;
 114                atomic64_set(&key->conf.tx_pn, pn);
 115                return count;
 116        default:
 117                return 0;
 118        }
 119}
 120
 121static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
 122                                size_t count, loff_t *ppos)
 123{
 124        u64 pn;
 125        char buf[20];
 126        int len;
 127        struct ieee80211_key *key = file->private_data;
 128
 129        switch (key->conf.cipher) {
 130        case WLAN_CIPHER_SUITE_WEP40:
 131        case WLAN_CIPHER_SUITE_WEP104:
 132                len = scnprintf(buf, sizeof(buf), "\n");
 133                break;
 134        case WLAN_CIPHER_SUITE_TKIP:
 135                len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
 136                                key->u.tkip.tx.iv32,
 137                                key->u.tkip.tx.iv16);
 138                break;
 139        case WLAN_CIPHER_SUITE_CCMP:
 140        case WLAN_CIPHER_SUITE_CCMP_256:
 141        case WLAN_CIPHER_SUITE_AES_CMAC:
 142        case WLAN_CIPHER_SUITE_BIP_CMAC_256:
 143        case WLAN_CIPHER_SUITE_BIP_GMAC_128:
 144        case WLAN_CIPHER_SUITE_BIP_GMAC_256:
 145        case WLAN_CIPHER_SUITE_GCMP:
 146        case WLAN_CIPHER_SUITE_GCMP_256:
 147                pn = atomic64_read(&key->conf.tx_pn);
 148                len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
 149                                (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24),
 150                                (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn);
 151                break;
 152        default:
 153                return 0;
 154        }
 155        return simple_read_from_buffer(userbuf, count, ppos, buf, len);
 156}
 157KEY_OPS_W(tx_spec);
 158
 159static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
 160                                size_t count, loff_t *ppos)
 161{
 162        struct ieee80211_key *key = file->private_data;
 163        char buf[14*IEEE80211_NUM_TIDS+1], *p = buf;
 164        int i, len;
 165        const u8 *rpn;
 166
 167        switch (key->conf.cipher) {
 168        case WLAN_CIPHER_SUITE_WEP40:
 169        case WLAN_CIPHER_SUITE_WEP104:
 170                len = scnprintf(buf, sizeof(buf), "\n");
 171                break;
 172        case WLAN_CIPHER_SUITE_TKIP:
 173                for (i = 0; i < IEEE80211_NUM_TIDS; i++)
 174                        p += scnprintf(p, sizeof(buf)+buf-p,
 175                                       "%08x %04x\n",
 176                                       key->u.tkip.rx[i].iv32,
 177                                       key->u.tkip.rx[i].iv16);
 178                len = p - buf;
 179                break;
 180        case WLAN_CIPHER_SUITE_CCMP:
 181        case WLAN_CIPHER_SUITE_CCMP_256:
 182                for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) {
 183                        rpn = key->u.ccmp.rx_pn[i];
 184                        p += scnprintf(p, sizeof(buf)+buf-p,
 185                                       "%02x%02x%02x%02x%02x%02x\n",
 186                                       rpn[0], rpn[1], rpn[2],
 187                                       rpn[3], rpn[4], rpn[5]);
 188                }
 189                len = p - buf;
 190                break;
 191        case WLAN_CIPHER_SUITE_AES_CMAC:
 192        case WLAN_CIPHER_SUITE_BIP_CMAC_256:
 193                rpn = key->u.aes_cmac.rx_pn;
 194                p += scnprintf(p, sizeof(buf)+buf-p,
 195                               "%02x%02x%02x%02x%02x%02x\n",
 196                               rpn[0], rpn[1], rpn[2],
 197                               rpn[3], rpn[4], rpn[5]);
 198                len = p - buf;
 199                break;
 200        case WLAN_CIPHER_SUITE_BIP_GMAC_128:
 201        case WLAN_CIPHER_SUITE_BIP_GMAC_256:
 202                rpn = key->u.aes_gmac.rx_pn;
 203                p += scnprintf(p, sizeof(buf)+buf-p,
 204                               "%02x%02x%02x%02x%02x%02x\n",
 205                               rpn[0], rpn[1], rpn[2],
 206                               rpn[3], rpn[4], rpn[5]);
 207                len = p - buf;
 208                break;
 209        case WLAN_CIPHER_SUITE_GCMP:
 210        case WLAN_CIPHER_SUITE_GCMP_256:
 211                for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) {
 212                        rpn = key->u.gcmp.rx_pn[i];
 213                        p += scnprintf(p, sizeof(buf)+buf-p,
 214                                       "%02x%02x%02x%02x%02x%02x\n",
 215                                       rpn[0], rpn[1], rpn[2],
 216                                       rpn[3], rpn[4], rpn[5]);
 217                }
 218                len = p - buf;
 219                break;
 220        default:
 221                return 0;
 222        }
 223        return simple_read_from_buffer(userbuf, count, ppos, buf, len);
 224}
 225KEY_OPS(rx_spec);
 226
 227static ssize_t key_replays_read(struct file *file, char __user *userbuf,
 228                                size_t count, loff_t *ppos)
 229{
 230        struct ieee80211_key *key = file->private_data;
 231        char buf[20];
 232        int len;
 233
 234        switch (key->conf.cipher) {
 235        case WLAN_CIPHER_SUITE_CCMP:
 236        case WLAN_CIPHER_SUITE_CCMP_256:
 237                len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
 238                break;
 239        case WLAN_CIPHER_SUITE_AES_CMAC:
 240        case WLAN_CIPHER_SUITE_BIP_CMAC_256:
 241                len = scnprintf(buf, sizeof(buf), "%u\n",
 242                                key->u.aes_cmac.replays);
 243                break;
 244        case WLAN_CIPHER_SUITE_BIP_GMAC_128:
 245        case WLAN_CIPHER_SUITE_BIP_GMAC_256:
 246                len = scnprintf(buf, sizeof(buf), "%u\n",
 247                                key->u.aes_gmac.replays);
 248                break;
 249        case WLAN_CIPHER_SUITE_GCMP:
 250        case WLAN_CIPHER_SUITE_GCMP_256:
 251                len = scnprintf(buf, sizeof(buf), "%u\n", key->u.gcmp.replays);
 252                break;
 253        default:
 254                return 0;
 255        }
 256        return simple_read_from_buffer(userbuf, count, ppos, buf, len);
 257}
 258KEY_OPS(replays);
 259
 260static ssize_t key_icverrors_read(struct file *file, char __user *userbuf,
 261                                  size_t count, loff_t *ppos)
 262{
 263        struct ieee80211_key *key = file->private_data;
 264        char buf[20];
 265        int len;
 266
 267        switch (key->conf.cipher) {
 268        case WLAN_CIPHER_SUITE_AES_CMAC:
 269        case WLAN_CIPHER_SUITE_BIP_CMAC_256:
 270                len = scnprintf(buf, sizeof(buf), "%u\n",
 271                                key->u.aes_cmac.icverrors);
 272                break;
 273        case WLAN_CIPHER_SUITE_BIP_GMAC_128:
 274        case WLAN_CIPHER_SUITE_BIP_GMAC_256:
 275                len = scnprintf(buf, sizeof(buf), "%u\n",
 276                                key->u.aes_gmac.icverrors);
 277                break;
 278        default:
 279                return 0;
 280        }
 281        return simple_read_from_buffer(userbuf, count, ppos, buf, len);
 282}
 283KEY_OPS(icverrors);
 284
 285static ssize_t key_mic_failures_read(struct file *file, char __user *userbuf,
 286                                     size_t count, loff_t *ppos)
 287{
 288        struct ieee80211_key *key = file->private_data;
 289        char buf[20];
 290        int len;
 291
 292        if (key->conf.cipher != WLAN_CIPHER_SUITE_TKIP)
 293                return -EINVAL;
 294
 295        len = scnprintf(buf, sizeof(buf), "%u\n", key->u.tkip.mic_failures);
 296
 297        return simple_read_from_buffer(userbuf, count, ppos, buf, len);
 298}
 299KEY_OPS(mic_failures);
 300
 301static ssize_t key_key_read(struct file *file, char __user *userbuf,
 302                            size_t count, loff_t *ppos)
 303{
 304        struct ieee80211_key *key = file->private_data;
 305        int i, bufsize = 2 * key->conf.keylen + 2;
 306        char *buf = kmalloc(bufsize, GFP_KERNEL);
 307        char *p = buf;
 308        ssize_t res;
 309
 310        if (!buf)
 311                return -ENOMEM;
 312
 313        for (i = 0; i < key->conf.keylen; i++)
 314                p += scnprintf(p, bufsize + buf - p, "%02x", key->conf.key[i]);
 315        p += scnprintf(p, bufsize+buf-p, "\n");
 316        res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
 317        kfree(buf);
 318        return res;
 319}
 320KEY_OPS(key);
 321
 322#define DEBUGFS_ADD(name) \
 323        debugfs_create_file(#name, 0400, key->debugfs.dir, \
 324                            key, &key_##name##_ops);
 325#define DEBUGFS_ADD_W(name) \
 326        debugfs_create_file(#name, 0600, key->debugfs.dir, \
 327                            key, &key_##name##_ops);
 328
 329void ieee80211_debugfs_key_add(struct ieee80211_key *key)
 330{
 331        static int keycount;
 332        char buf[100];
 333        struct sta_info *sta;
 334
 335        if (!key->local->debugfs.keys)
 336                return;
 337
 338        sprintf(buf, "%d", keycount);
 339        key->debugfs.cnt = keycount;
 340        keycount++;
 341        key->debugfs.dir = debugfs_create_dir(buf,
 342                                        key->local->debugfs.keys);
 343
 344        if (!key->debugfs.dir)
 345                return;
 346
 347        sta = key->sta;
 348        if (sta) {
 349                sprintf(buf, "../../netdev:%s/stations/%pM",
 350                        sta->sdata->name, sta->sta.addr);
 351                key->debugfs.stalink =
 352                        debugfs_create_symlink("station", key->debugfs.dir, buf);
 353        }
 354
 355        DEBUGFS_ADD(keylen);
 356        DEBUGFS_ADD(flags);
 357        DEBUGFS_ADD(keyidx);
 358        DEBUGFS_ADD(hw_key_idx);
 359        DEBUGFS_ADD(algorithm);
 360        DEBUGFS_ADD_W(tx_spec);
 361        DEBUGFS_ADD(rx_spec);
 362        DEBUGFS_ADD(replays);
 363        DEBUGFS_ADD(icverrors);
 364        DEBUGFS_ADD(mic_failures);
 365        DEBUGFS_ADD(key);
 366        DEBUGFS_ADD(ifindex);
 367};
 368
 369void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
 370{
 371        if (!key)
 372                return;
 373
 374        debugfs_remove_recursive(key->debugfs.dir);
 375        key->debugfs.dir = NULL;
 376}
 377
 378void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
 379{
 380        char buf[50];
 381        struct ieee80211_key *key;
 382
 383        if (!sdata->vif.debugfs_dir)
 384                return;
 385
 386        lockdep_assert_held(&sdata->local->key_mtx);
 387
 388        debugfs_remove(sdata->debugfs.default_unicast_key);
 389        sdata->debugfs.default_unicast_key = NULL;
 390
 391        if (sdata->default_unicast_key) {
 392                key = key_mtx_dereference(sdata->local,
 393                                          sdata->default_unicast_key);
 394                sprintf(buf, "../keys/%d", key->debugfs.cnt);
 395                sdata->debugfs.default_unicast_key =
 396                        debugfs_create_symlink("default_unicast_key",
 397                                               sdata->vif.debugfs_dir, buf);
 398        }
 399
 400        debugfs_remove(sdata->debugfs.default_multicast_key);
 401        sdata->debugfs.default_multicast_key = NULL;
 402
 403        if (sdata->default_multicast_key) {
 404                key = key_mtx_dereference(sdata->local,
 405                                          sdata->default_multicast_key);
 406                sprintf(buf, "../keys/%d", key->debugfs.cnt);
 407                sdata->debugfs.default_multicast_key =
 408                        debugfs_create_symlink("default_multicast_key",
 409                                               sdata->vif.debugfs_dir, buf);
 410        }
 411}
 412
 413void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata)
 414{
 415        char buf[50];
 416        struct ieee80211_key *key;
 417
 418        if (!sdata->vif.debugfs_dir)
 419                return;
 420
 421        key = key_mtx_dereference(sdata->local,
 422                                  sdata->default_mgmt_key);
 423        if (key) {
 424                sprintf(buf, "../keys/%d", key->debugfs.cnt);
 425                sdata->debugfs.default_mgmt_key =
 426                        debugfs_create_symlink("default_mgmt_key",
 427                                               sdata->vif.debugfs_dir, buf);
 428        } else
 429                ieee80211_debugfs_key_remove_mgmt_default(sdata);
 430}
 431
 432void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sdata)
 433{
 434        if (!sdata)
 435                return;
 436
 437        debugfs_remove(sdata->debugfs.default_mgmt_key);
 438        sdata->debugfs.default_mgmt_key = NULL;
 439}
 440
 441void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
 442                                   struct sta_info *sta)
 443{
 444        debugfs_remove(key->debugfs.stalink);
 445        key->debugfs.stalink = NULL;
 446}
 447