1e9f207f0SJiri Benc /* 2e9f207f0SJiri Benc * Copyright 2003-2005 Devicescape Software, Inc. 3e9f207f0SJiri Benc * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> 4e9f207f0SJiri Benc * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> 5d0a77c65SJohannes Berg * Copyright (C) 2015 Intel Deutschland GmbH 6e9f207f0SJiri Benc * 7e9f207f0SJiri Benc * This program is free software; you can redistribute it and/or modify 8e9f207f0SJiri Benc * it under the terms of the GNU General Public License version 2 as 9e9f207f0SJiri Benc * published by the Free Software Foundation. 10e9f207f0SJiri Benc */ 11e9f207f0SJiri Benc 12e9f207f0SJiri Benc #include <linux/kobject.h> 135a0e3ad6STejun Heo #include <linux/slab.h> 14e9f207f0SJiri Benc #include "ieee80211_i.h" 152c8dccc7SJohannes Berg #include "key.h" 16e9f207f0SJiri Benc #include "debugfs.h" 17e9f207f0SJiri Benc #include "debugfs_key.h" 18e9f207f0SJiri Benc 1907caf9d6SEliad Peller #define KEY_READ(name, prop, format_string) \ 20e9f207f0SJiri Benc static ssize_t key_##name##_read(struct file *file, \ 21e9f207f0SJiri Benc char __user *userbuf, \ 22e9f207f0SJiri Benc size_t count, loff_t *ppos) \ 23e9f207f0SJiri Benc { \ 24e9f207f0SJiri Benc struct ieee80211_key *key = file->private_data; \ 2507caf9d6SEliad Peller return mac80211_format_buffer(userbuf, count, ppos, \ 2607caf9d6SEliad Peller format_string, key->prop); \ 27e9f207f0SJiri Benc } 2807caf9d6SEliad Peller #define KEY_READ_D(name) KEY_READ(name, name, "%d\n") 2907caf9d6SEliad Peller #define KEY_READ_X(name) KEY_READ(name, name, "0x%x\n") 30e9f207f0SJiri Benc 31e9f207f0SJiri Benc #define KEY_OPS(name) \ 32e9f207f0SJiri Benc static const struct file_operations key_ ##name## _ops = { \ 33e9f207f0SJiri Benc .read = key_##name##_read, \ 34234e3405SStephen Boyd .open = simple_open, \ 352b18ab36SArnd Bergmann .llseek = generic_file_llseek, \ 36e9f207f0SJiri Benc } 37e9f207f0SJiri Benc 38d0a77c65SJohannes Berg #define KEY_OPS_W(name) \ 39d0a77c65SJohannes Berg static const struct file_operations key_ ##name## _ops = { \ 40d0a77c65SJohannes Berg .read = key_##name##_read, \ 41d0a77c65SJohannes Berg .write = key_##name##_write, \ 42d0a77c65SJohannes Berg .open = simple_open, \ 43d0a77c65SJohannes Berg .llseek = generic_file_llseek, \ 44d0a77c65SJohannes Berg } 45d0a77c65SJohannes Berg 46e9f207f0SJiri Benc #define KEY_FILE(name, format) \ 47e9f207f0SJiri Benc KEY_READ_##format(name) \ 48e9f207f0SJiri Benc KEY_OPS(name) 49e9f207f0SJiri Benc 5007caf9d6SEliad Peller #define KEY_CONF_READ(name, format_string) \ 5107caf9d6SEliad Peller KEY_READ(conf_##name, conf.name, format_string) 5207caf9d6SEliad Peller #define KEY_CONF_READ_D(name) KEY_CONF_READ(name, "%d\n") 538f20fc24SJohannes Berg 548f20fc24SJohannes Berg #define KEY_CONF_OPS(name) \ 558f20fc24SJohannes Berg static const struct file_operations key_ ##name## _ops = { \ 568f20fc24SJohannes Berg .read = key_conf_##name##_read, \ 57234e3405SStephen Boyd .open = simple_open, \ 582b18ab36SArnd Bergmann .llseek = generic_file_llseek, \ 598f20fc24SJohannes Berg } 608f20fc24SJohannes Berg 618f20fc24SJohannes Berg #define KEY_CONF_FILE(name, format) \ 628f20fc24SJohannes Berg KEY_CONF_READ_##format(name) \ 638f20fc24SJohannes Berg KEY_CONF_OPS(name) 648f20fc24SJohannes Berg 658f20fc24SJohannes Berg KEY_CONF_FILE(keylen, D); 668f20fc24SJohannes Berg KEY_CONF_FILE(keyidx, D); 678f20fc24SJohannes Berg KEY_CONF_FILE(hw_key_idx, D); 6811a843b7SJohannes Berg KEY_FILE(flags, X); 6907caf9d6SEliad Peller KEY_READ(ifindex, sdata->name, "%s\n"); 70e7a64f12SJohannes Berg KEY_OPS(ifindex); 71e9f207f0SJiri Benc 72e9f207f0SJiri Benc static ssize_t key_algorithm_read(struct file *file, 73e9f207f0SJiri Benc char __user *userbuf, 74e9f207f0SJiri Benc size_t count, loff_t *ppos) 75e9f207f0SJiri Benc { 7697359d12SJohannes Berg char buf[15]; 77e9f207f0SJiri Benc struct ieee80211_key *key = file->private_data; 7897359d12SJohannes Berg u32 c = key->conf.cipher; 79e9f207f0SJiri Benc 8097359d12SJohannes Berg sprintf(buf, "%.2x-%.2x-%.2x:%d\n", 8197359d12SJohannes Berg c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff); 8297359d12SJohannes Berg return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); 83e9f207f0SJiri Benc } 84e9f207f0SJiri Benc KEY_OPS(algorithm); 85e9f207f0SJiri Benc 86d0a77c65SJohannes Berg static ssize_t key_tx_spec_write(struct file *file, const char __user *userbuf, 87d0a77c65SJohannes Berg size_t count, loff_t *ppos) 88d0a77c65SJohannes Berg { 89d0a77c65SJohannes Berg struct ieee80211_key *key = file->private_data; 90d0a77c65SJohannes Berg u64 pn; 91d0a77c65SJohannes Berg int ret; 92d0a77c65SJohannes Berg 93d0a77c65SJohannes Berg switch (key->conf.cipher) { 94d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_WEP40: 95d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_WEP104: 96d0a77c65SJohannes Berg return -EINVAL; 97d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_TKIP: 98d0a77c65SJohannes Berg /* not supported yet */ 99d0a77c65SJohannes Berg return -EOPNOTSUPP; 100d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_CCMP: 101d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_CCMP_256: 102d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_AES_CMAC: 103d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_BIP_CMAC_256: 104d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_BIP_GMAC_128: 105d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_BIP_GMAC_256: 106d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_GCMP: 107d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_GCMP_256: 108d0a77c65SJohannes Berg ret = kstrtou64_from_user(userbuf, count, 16, &pn); 109d0a77c65SJohannes Berg if (ret) 110d0a77c65SJohannes Berg return ret; 111d0a77c65SJohannes Berg /* PN is a 48-bit counter */ 112d0a77c65SJohannes Berg if (pn >= (1ULL << 48)) 113d0a77c65SJohannes Berg return -ERANGE; 114d0a77c65SJohannes Berg atomic64_set(&key->conf.tx_pn, pn); 115d0a77c65SJohannes Berg return count; 116d0a77c65SJohannes Berg default: 117d0a77c65SJohannes Berg return 0; 118d0a77c65SJohannes Berg } 119d0a77c65SJohannes Berg } 120d0a77c65SJohannes Berg 121e9f207f0SJiri Benc static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, 122e9f207f0SJiri Benc size_t count, loff_t *ppos) 123e9f207f0SJiri Benc { 124aba83a0bSJohannes Berg u64 pn; 125e9f207f0SJiri Benc char buf[20]; 126e9f207f0SJiri Benc int len; 127e9f207f0SJiri Benc struct ieee80211_key *key = file->private_data; 128e9f207f0SJiri Benc 12997359d12SJohannes Berg switch (key->conf.cipher) { 13097359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP40: 13197359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP104: 132e9f207f0SJiri Benc len = scnprintf(buf, sizeof(buf), "\n"); 13350339a67SJohannes Berg break; 13497359d12SJohannes Berg case WLAN_CIPHER_SUITE_TKIP: 135e9f207f0SJiri Benc len = scnprintf(buf, sizeof(buf), "%08x %04x\n", 136b0f76b33SHarvey Harrison key->u.tkip.tx.iv32, 137b0f76b33SHarvey Harrison key->u.tkip.tx.iv16); 13850339a67SJohannes Berg break; 13997359d12SJohannes Berg case WLAN_CIPHER_SUITE_CCMP: 1402b2ba0dbSJouni Malinen case WLAN_CIPHER_SUITE_CCMP_256: 14197359d12SJohannes Berg case WLAN_CIPHER_SUITE_AES_CMAC: 14256c52da2SJouni Malinen case WLAN_CIPHER_SUITE_BIP_CMAC_256: 1438ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_128: 1448ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_256: 14500b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP: 14600b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP_256: 147db388a56SJohannes Berg pn = atomic64_read(&key->conf.tx_pn); 14800b9cfa3SJouni Malinen len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", 14900b9cfa3SJouni Malinen (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), 15000b9cfa3SJouni Malinen (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); 15100b9cfa3SJouni Malinen break; 152e9f207f0SJiri Benc default: 153e9f207f0SJiri Benc return 0; 154e9f207f0SJiri Benc } 155e9f207f0SJiri Benc return simple_read_from_buffer(userbuf, count, ppos, buf, len); 156e9f207f0SJiri Benc } 157d0a77c65SJohannes Berg KEY_OPS_W(tx_spec); 158e9f207f0SJiri Benc 159e9f207f0SJiri Benc static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, 160e9f207f0SJiri Benc size_t count, loff_t *ppos) 161e9f207f0SJiri Benc { 162e9f207f0SJiri Benc struct ieee80211_key *key = file->private_data; 1635a306f58SJohannes Berg char buf[14*IEEE80211_NUM_TIDS+1], *p = buf; 164e9f207f0SJiri Benc int i, len; 165e9f207f0SJiri Benc const u8 *rpn; 166e9f207f0SJiri Benc 16797359d12SJohannes Berg switch (key->conf.cipher) { 16897359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP40: 16997359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP104: 170e9f207f0SJiri Benc len = scnprintf(buf, sizeof(buf), "\n"); 17150339a67SJohannes Berg break; 17297359d12SJohannes Berg case WLAN_CIPHER_SUITE_TKIP: 1735a306f58SJohannes Berg for (i = 0; i < IEEE80211_NUM_TIDS; i++) 174e9f207f0SJiri Benc p += scnprintf(p, sizeof(buf)+buf-p, 175e9f207f0SJiri Benc "%08x %04x\n", 176b0f76b33SHarvey Harrison key->u.tkip.rx[i].iv32, 177b0f76b33SHarvey Harrison key->u.tkip.rx[i].iv16); 178e9f207f0SJiri Benc len = p - buf; 17950339a67SJohannes Berg break; 18097359d12SJohannes Berg case WLAN_CIPHER_SUITE_CCMP: 1812b2ba0dbSJouni Malinen case WLAN_CIPHER_SUITE_CCMP_256: 1825a306f58SJohannes Berg for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { 183e9f207f0SJiri Benc rpn = key->u.ccmp.rx_pn[i]; 184e9f207f0SJiri Benc p += scnprintf(p, sizeof(buf)+buf-p, 185e9f207f0SJiri Benc "%02x%02x%02x%02x%02x%02x\n", 186e9f207f0SJiri Benc rpn[0], rpn[1], rpn[2], 187e9f207f0SJiri Benc rpn[3], rpn[4], rpn[5]); 188e9f207f0SJiri Benc } 189e9f207f0SJiri Benc len = p - buf; 19050339a67SJohannes Berg break; 19197359d12SJohannes Berg case WLAN_CIPHER_SUITE_AES_CMAC: 19256c52da2SJouni Malinen case WLAN_CIPHER_SUITE_BIP_CMAC_256: 1933cfcf6acSJouni Malinen rpn = key->u.aes_cmac.rx_pn; 1943cfcf6acSJouni Malinen p += scnprintf(p, sizeof(buf)+buf-p, 1953cfcf6acSJouni Malinen "%02x%02x%02x%02x%02x%02x\n", 1963cfcf6acSJouni Malinen rpn[0], rpn[1], rpn[2], 1973cfcf6acSJouni Malinen rpn[3], rpn[4], rpn[5]); 1983cfcf6acSJouni Malinen len = p - buf; 1993cfcf6acSJouni Malinen break; 2008ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_128: 2018ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_256: 2028ade538bSJouni Malinen rpn = key->u.aes_gmac.rx_pn; 2038ade538bSJouni Malinen p += scnprintf(p, sizeof(buf)+buf-p, 2048ade538bSJouni Malinen "%02x%02x%02x%02x%02x%02x\n", 2058ade538bSJouni Malinen rpn[0], rpn[1], rpn[2], 2068ade538bSJouni Malinen rpn[3], rpn[4], rpn[5]); 2078ade538bSJouni Malinen len = p - buf; 2088ade538bSJouni Malinen break; 20900b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP: 21000b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP_256: 21100b9cfa3SJouni Malinen for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { 21200b9cfa3SJouni Malinen rpn = key->u.gcmp.rx_pn[i]; 21300b9cfa3SJouni Malinen p += scnprintf(p, sizeof(buf)+buf-p, 21400b9cfa3SJouni Malinen "%02x%02x%02x%02x%02x%02x\n", 21500b9cfa3SJouni Malinen rpn[0], rpn[1], rpn[2], 21600b9cfa3SJouni Malinen rpn[3], rpn[4], rpn[5]); 21700b9cfa3SJouni Malinen } 21800b9cfa3SJouni Malinen len = p - buf; 21900b9cfa3SJouni Malinen break; 220e9f207f0SJiri Benc default: 221e9f207f0SJiri Benc return 0; 222e9f207f0SJiri Benc } 223e9f207f0SJiri Benc return simple_read_from_buffer(userbuf, count, ppos, buf, len); 224e9f207f0SJiri Benc } 225e9f207f0SJiri Benc KEY_OPS(rx_spec); 226e9f207f0SJiri Benc 227e9f207f0SJiri Benc static ssize_t key_replays_read(struct file *file, char __user *userbuf, 228e9f207f0SJiri Benc size_t count, loff_t *ppos) 229e9f207f0SJiri Benc { 230e9f207f0SJiri Benc struct ieee80211_key *key = file->private_data; 231e9f207f0SJiri Benc char buf[20]; 232e9f207f0SJiri Benc int len; 233e9f207f0SJiri Benc 23497359d12SJohannes Berg switch (key->conf.cipher) { 23597359d12SJohannes Berg case WLAN_CIPHER_SUITE_CCMP: 2362b2ba0dbSJouni Malinen case WLAN_CIPHER_SUITE_CCMP_256: 237e9f207f0SJiri Benc len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); 2383cfcf6acSJouni Malinen break; 23997359d12SJohannes Berg case WLAN_CIPHER_SUITE_AES_CMAC: 24056c52da2SJouni Malinen case WLAN_CIPHER_SUITE_BIP_CMAC_256: 2413cfcf6acSJouni Malinen len = scnprintf(buf, sizeof(buf), "%u\n", 2423cfcf6acSJouni Malinen key->u.aes_cmac.replays); 2433cfcf6acSJouni Malinen break; 2448ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_128: 2458ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_256: 2468ade538bSJouni Malinen len = scnprintf(buf, sizeof(buf), "%u\n", 2478ade538bSJouni Malinen key->u.aes_gmac.replays); 2488ade538bSJouni Malinen break; 24900b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP: 25000b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP_256: 25100b9cfa3SJouni Malinen len = scnprintf(buf, sizeof(buf), "%u\n", key->u.gcmp.replays); 25200b9cfa3SJouni Malinen break; 2533cfcf6acSJouni Malinen default: 2543cfcf6acSJouni Malinen return 0; 2553cfcf6acSJouni Malinen } 256e9f207f0SJiri Benc return simple_read_from_buffer(userbuf, count, ppos, buf, len); 257e9f207f0SJiri Benc } 258e9f207f0SJiri Benc KEY_OPS(replays); 259e9f207f0SJiri Benc 2603cfcf6acSJouni Malinen static ssize_t key_icverrors_read(struct file *file, char __user *userbuf, 2613cfcf6acSJouni Malinen size_t count, loff_t *ppos) 2623cfcf6acSJouni Malinen { 2633cfcf6acSJouni Malinen struct ieee80211_key *key = file->private_data; 2643cfcf6acSJouni Malinen char buf[20]; 2653cfcf6acSJouni Malinen int len; 2663cfcf6acSJouni Malinen 26797359d12SJohannes Berg switch (key->conf.cipher) { 26897359d12SJohannes Berg case WLAN_CIPHER_SUITE_AES_CMAC: 26956c52da2SJouni Malinen case WLAN_CIPHER_SUITE_BIP_CMAC_256: 2703cfcf6acSJouni Malinen len = scnprintf(buf, sizeof(buf), "%u\n", 2713cfcf6acSJouni Malinen key->u.aes_cmac.icverrors); 2723cfcf6acSJouni Malinen break; 2738ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_128: 2748ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_256: 2758ade538bSJouni Malinen len = scnprintf(buf, sizeof(buf), "%u\n", 2768ade538bSJouni Malinen key->u.aes_gmac.icverrors); 2778ade538bSJouni Malinen break; 2783cfcf6acSJouni Malinen default: 2793cfcf6acSJouni Malinen return 0; 2803cfcf6acSJouni Malinen } 2813cfcf6acSJouni Malinen return simple_read_from_buffer(userbuf, count, ppos, buf, len); 2823cfcf6acSJouni Malinen } 2833cfcf6acSJouni Malinen KEY_OPS(icverrors); 2843cfcf6acSJouni Malinen 285b98ea058SSaravana static ssize_t key_mic_failures_read(struct file *file, char __user *userbuf, 286b98ea058SSaravana size_t count, loff_t *ppos) 287b98ea058SSaravana { 288b98ea058SSaravana struct ieee80211_key *key = file->private_data; 289b98ea058SSaravana char buf[20]; 290b98ea058SSaravana int len; 291b98ea058SSaravana 292b98ea058SSaravana if (key->conf.cipher != WLAN_CIPHER_SUITE_TKIP) 293b98ea058SSaravana return -EINVAL; 294b98ea058SSaravana 295b98ea058SSaravana len = scnprintf(buf, sizeof(buf), "%u\n", key->u.tkip.mic_failures); 296b98ea058SSaravana 297b98ea058SSaravana return simple_read_from_buffer(userbuf, count, ppos, buf, len); 298b98ea058SSaravana } 299b98ea058SSaravana KEY_OPS(mic_failures); 300b98ea058SSaravana 301e9f207f0SJiri Benc static ssize_t key_key_read(struct file *file, char __user *userbuf, 302e9f207f0SJiri Benc size_t count, loff_t *ppos) 303e9f207f0SJiri Benc { 304e9f207f0SJiri Benc struct ieee80211_key *key = file->private_data; 305520efd1aSJesper Juhl int i, bufsize = 2 * key->conf.keylen + 2; 306e9f207f0SJiri Benc char *buf = kmalloc(bufsize, GFP_KERNEL); 307e9f207f0SJiri Benc char *p = buf; 308520efd1aSJesper Juhl ssize_t res; 309520efd1aSJesper Juhl 310520efd1aSJesper Juhl if (!buf) 311520efd1aSJesper Juhl return -ENOMEM; 312e9f207f0SJiri Benc 3138f20fc24SJohannes Berg for (i = 0; i < key->conf.keylen; i++) 3148f20fc24SJohannes Berg p += scnprintf(p, bufsize + buf - p, "%02x", key->conf.key[i]); 315e9f207f0SJiri Benc p += scnprintf(p, bufsize+buf-p, "\n"); 316e9f207f0SJiri Benc res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); 317e9f207f0SJiri Benc kfree(buf); 318e9f207f0SJiri Benc return res; 319e9f207f0SJiri Benc } 320e9f207f0SJiri Benc KEY_OPS(key); 321e9f207f0SJiri Benc 322e9f207f0SJiri Benc #define DEBUGFS_ADD(name) \ 3237bcfaf2fSJohannes Berg debugfs_create_file(#name, 0400, key->debugfs.dir, \ 3247bcfaf2fSJohannes Berg key, &key_##name##_ops); 325d0a77c65SJohannes Berg #define DEBUGFS_ADD_W(name) \ 326d0a77c65SJohannes Berg debugfs_create_file(#name, 0600, key->debugfs.dir, \ 327d0a77c65SJohannes Berg key, &key_##name##_ops); 328e9f207f0SJiri Benc 3293b96766fSJohannes Berg void ieee80211_debugfs_key_add(struct ieee80211_key *key) 330e9f207f0SJiri Benc { 33150339a67SJohannes Berg static int keycount; 3329446f3efSJohannes Berg char buf[100]; 3333b96766fSJohannes Berg struct sta_info *sta; 334e9f207f0SJiri Benc 3353b96766fSJohannes Berg if (!key->local->debugfs.keys) 336e9f207f0SJiri Benc return; 337e9f207f0SJiri Benc 33850339a67SJohannes Berg sprintf(buf, "%d", keycount); 339d9c58f30SJohannes Berg key->debugfs.cnt = keycount; 34050339a67SJohannes Berg keycount++; 341e9f207f0SJiri Benc key->debugfs.dir = debugfs_create_dir(buf, 3423b96766fSJohannes Berg key->local->debugfs.keys); 343e9f207f0SJiri Benc 344e9f207f0SJiri Benc if (!key->debugfs.dir) 345e9f207f0SJiri Benc return; 346e9f207f0SJiri Benc 34740b275b6SJohannes Berg sta = key->sta; 34840b275b6SJohannes Berg if (sta) { 3499446f3efSJohannes Berg sprintf(buf, "../../netdev:%s/stations/%pM", 3509446f3efSJohannes Berg sta->sdata->name, sta->sta.addr); 3513b96766fSJohannes Berg key->debugfs.stalink = 3523b96766fSJohannes Berg debugfs_create_symlink("station", key->debugfs.dir, buf); 35340b275b6SJohannes Berg } 3543b96766fSJohannes Berg 355e9f207f0SJiri Benc DEBUGFS_ADD(keylen); 3568f20fc24SJohannes Berg DEBUGFS_ADD(flags); 357e9f207f0SJiri Benc DEBUGFS_ADD(keyidx); 358e9f207f0SJiri Benc DEBUGFS_ADD(hw_key_idx); 359e9f207f0SJiri Benc DEBUGFS_ADD(algorithm); 360d0a77c65SJohannes Berg DEBUGFS_ADD_W(tx_spec); 361e9f207f0SJiri Benc DEBUGFS_ADD(rx_spec); 362e9f207f0SJiri Benc DEBUGFS_ADD(replays); 3633cfcf6acSJouni Malinen DEBUGFS_ADD(icverrors); 364b98ea058SSaravana DEBUGFS_ADD(mic_failures); 365e9f207f0SJiri Benc DEBUGFS_ADD(key); 366e7a64f12SJohannes Berg DEBUGFS_ADD(ifindex); 367e9f207f0SJiri Benc }; 368e9f207f0SJiri Benc 369e9f207f0SJiri Benc void ieee80211_debugfs_key_remove(struct ieee80211_key *key) 370e9f207f0SJiri Benc { 371e9f207f0SJiri Benc if (!key) 372e9f207f0SJiri Benc return; 373e9f207f0SJiri Benc 3747bcfaf2fSJohannes Berg debugfs_remove_recursive(key->debugfs.dir); 375e9f207f0SJiri Benc key->debugfs.dir = NULL; 376e9f207f0SJiri Benc } 377f7e0104cSJohannes Berg 378f7e0104cSJohannes Berg void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) 379e9f207f0SJiri Benc { 380e9f207f0SJiri Benc char buf[50]; 38178520cadSJohannes Berg struct ieee80211_key *key; 382e9f207f0SJiri Benc 383ddbfe860SStanislaw Gruszka if (!sdata->vif.debugfs_dir) 384e9f207f0SJiri Benc return; 385e9f207f0SJiri Benc 386f7e0104cSJohannes Berg lockdep_assert_held(&sdata->local->key_mtx); 38778520cadSJohannes Berg 388135792ecSJohannes Berg debugfs_remove(sdata->debugfs.default_unicast_key); 389135792ecSJohannes Berg sdata->debugfs.default_unicast_key = NULL; 390135792ecSJohannes Berg 391f7e0104cSJohannes Berg if (sdata->default_unicast_key) { 39240b275b6SJohannes Berg key = key_mtx_dereference(sdata->local, 39340b275b6SJohannes Berg sdata->default_unicast_key); 39478520cadSJohannes Berg sprintf(buf, "../keys/%d", key->debugfs.cnt); 395f7e0104cSJohannes Berg sdata->debugfs.default_unicast_key = 396f7e0104cSJohannes Berg debugfs_create_symlink("default_unicast_key", 397ddbfe860SStanislaw Gruszka sdata->vif.debugfs_dir, buf); 398135792ecSJohannes Berg } 399135792ecSJohannes Berg 400135792ecSJohannes Berg debugfs_remove(sdata->debugfs.default_multicast_key); 401135792ecSJohannes Berg sdata->debugfs.default_multicast_key = NULL; 40278520cadSJohannes Berg 403f7e0104cSJohannes Berg if (sdata->default_multicast_key) { 40440b275b6SJohannes Berg key = key_mtx_dereference(sdata->local, 40540b275b6SJohannes Berg sdata->default_multicast_key); 406f7e0104cSJohannes Berg sprintf(buf, "../keys/%d", key->debugfs.cnt); 407f7e0104cSJohannes Berg sdata->debugfs.default_multicast_key = 408f7e0104cSJohannes Berg debugfs_create_symlink("default_multicast_key", 409ddbfe860SStanislaw Gruszka sdata->vif.debugfs_dir, buf); 410f7e0104cSJohannes Berg } 411e9f207f0SJiri Benc } 412e9f207f0SJiri Benc 4133cfcf6acSJouni Malinen void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) 4143cfcf6acSJouni Malinen { 4153cfcf6acSJouni Malinen char buf[50]; 4163cfcf6acSJouni Malinen struct ieee80211_key *key; 4173cfcf6acSJouni Malinen 418ddbfe860SStanislaw Gruszka if (!sdata->vif.debugfs_dir) 4193cfcf6acSJouni Malinen return; 4203cfcf6acSJouni Malinen 42140b275b6SJohannes Berg key = key_mtx_dereference(sdata->local, 42240b275b6SJohannes Berg sdata->default_mgmt_key); 4233cfcf6acSJouni Malinen if (key) { 4243cfcf6acSJouni Malinen sprintf(buf, "../keys/%d", key->debugfs.cnt); 4257bcfaf2fSJohannes Berg sdata->debugfs.default_mgmt_key = 4263cfcf6acSJouni Malinen debugfs_create_symlink("default_mgmt_key", 427ddbfe860SStanislaw Gruszka sdata->vif.debugfs_dir, buf); 4283cfcf6acSJouni Malinen } else 4293cfcf6acSJouni Malinen ieee80211_debugfs_key_remove_mgmt_default(sdata); 4303cfcf6acSJouni Malinen } 4313cfcf6acSJouni Malinen 4323cfcf6acSJouni Malinen void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sdata) 4333cfcf6acSJouni Malinen { 4343cfcf6acSJouni Malinen if (!sdata) 4353cfcf6acSJouni Malinen return; 4363cfcf6acSJouni Malinen 4377bcfaf2fSJohannes Berg debugfs_remove(sdata->debugfs.default_mgmt_key); 4387bcfaf2fSJohannes Berg sdata->debugfs.default_mgmt_key = NULL; 4393cfcf6acSJouni Malinen } 4403cfcf6acSJouni Malinen 441e9f207f0SJiri Benc void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, 442e9f207f0SJiri Benc struct sta_info *sta) 443e9f207f0SJiri Benc { 444e9f207f0SJiri Benc debugfs_remove(key->debugfs.stalink); 445e9f207f0SJiri Benc key->debugfs.stalink = NULL; 446e9f207f0SJiri Benc } 447