1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2e9f207f0SJiri Benc /* 3e9f207f0SJiri Benc * Copyright 2003-2005 Devicescape Software, Inc. 4e9f207f0SJiri Benc * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> 5e9f207f0SJiri Benc * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> 6d0a77c65SJohannes Berg * Copyright (C) 2015 Intel Deutschland GmbH 7e9f207f0SJiri Benc */ 8e9f207f0SJiri Benc 9e9f207f0SJiri Benc #include <linux/kobject.h> 105a0e3ad6STejun Heo #include <linux/slab.h> 11e9f207f0SJiri Benc #include "ieee80211_i.h" 122c8dccc7SJohannes Berg #include "key.h" 13e9f207f0SJiri Benc #include "debugfs.h" 14e9f207f0SJiri Benc #include "debugfs_key.h" 15e9f207f0SJiri Benc 1607caf9d6SEliad Peller #define KEY_READ(name, prop, format_string) \ 17e9f207f0SJiri Benc static ssize_t key_##name##_read(struct file *file, \ 18e9f207f0SJiri Benc char __user *userbuf, \ 19e9f207f0SJiri Benc size_t count, loff_t *ppos) \ 20e9f207f0SJiri Benc { \ 21e9f207f0SJiri Benc struct ieee80211_key *key = file->private_data; \ 2207caf9d6SEliad Peller return mac80211_format_buffer(userbuf, count, ppos, \ 2307caf9d6SEliad Peller format_string, key->prop); \ 24e9f207f0SJiri Benc } 2507caf9d6SEliad Peller #define KEY_READ_D(name) KEY_READ(name, name, "%d\n") 2607caf9d6SEliad Peller #define KEY_READ_X(name) KEY_READ(name, name, "0x%x\n") 27e9f207f0SJiri Benc 28e9f207f0SJiri Benc #define KEY_OPS(name) \ 29e9f207f0SJiri Benc static const struct file_operations key_ ##name## _ops = { \ 30e9f207f0SJiri Benc .read = key_##name##_read, \ 31234e3405SStephen Boyd .open = simple_open, \ 322b18ab36SArnd Bergmann .llseek = generic_file_llseek, \ 33e9f207f0SJiri Benc } 34e9f207f0SJiri Benc 35d0a77c65SJohannes Berg #define KEY_OPS_W(name) \ 36d0a77c65SJohannes Berg static const struct file_operations key_ ##name## _ops = { \ 37d0a77c65SJohannes Berg .read = key_##name##_read, \ 38d0a77c65SJohannes Berg .write = key_##name##_write, \ 39d0a77c65SJohannes Berg .open = simple_open, \ 40d0a77c65SJohannes Berg .llseek = generic_file_llseek, \ 41d0a77c65SJohannes Berg } 42d0a77c65SJohannes Berg 43e9f207f0SJiri Benc #define KEY_FILE(name, format) \ 44e9f207f0SJiri Benc KEY_READ_##format(name) \ 45e9f207f0SJiri Benc KEY_OPS(name) 46e9f207f0SJiri Benc 4707caf9d6SEliad Peller #define KEY_CONF_READ(name, format_string) \ 4807caf9d6SEliad Peller KEY_READ(conf_##name, conf.name, format_string) 4907caf9d6SEliad Peller #define KEY_CONF_READ_D(name) KEY_CONF_READ(name, "%d\n") 508f20fc24SJohannes Berg 518f20fc24SJohannes Berg #define KEY_CONF_OPS(name) \ 528f20fc24SJohannes Berg static const struct file_operations key_ ##name## _ops = { \ 538f20fc24SJohannes Berg .read = key_conf_##name##_read, \ 54234e3405SStephen Boyd .open = simple_open, \ 552b18ab36SArnd Bergmann .llseek = generic_file_llseek, \ 568f20fc24SJohannes Berg } 578f20fc24SJohannes Berg 588f20fc24SJohannes Berg #define KEY_CONF_FILE(name, format) \ 598f20fc24SJohannes Berg KEY_CONF_READ_##format(name) \ 608f20fc24SJohannes Berg KEY_CONF_OPS(name) 618f20fc24SJohannes Berg 628f20fc24SJohannes Berg KEY_CONF_FILE(keylen, D); 638f20fc24SJohannes Berg KEY_CONF_FILE(keyidx, D); 648f20fc24SJohannes Berg KEY_CONF_FILE(hw_key_idx, D); 6511a843b7SJohannes Berg KEY_FILE(flags, X); 6607caf9d6SEliad Peller KEY_READ(ifindex, sdata->name, "%s\n"); 67e7a64f12SJohannes Berg KEY_OPS(ifindex); 68e9f207f0SJiri Benc 69e9f207f0SJiri Benc static ssize_t key_algorithm_read(struct file *file, 70e9f207f0SJiri Benc char __user *userbuf, 71e9f207f0SJiri Benc size_t count, loff_t *ppos) 72e9f207f0SJiri Benc { 7397359d12SJohannes Berg char buf[15]; 74e9f207f0SJiri Benc struct ieee80211_key *key = file->private_data; 7597359d12SJohannes Berg u32 c = key->conf.cipher; 76e9f207f0SJiri Benc 7797359d12SJohannes Berg sprintf(buf, "%.2x-%.2x-%.2x:%d\n", 7897359d12SJohannes Berg c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff); 7997359d12SJohannes Berg return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); 80e9f207f0SJiri Benc } 81e9f207f0SJiri Benc KEY_OPS(algorithm); 82e9f207f0SJiri Benc 83d0a77c65SJohannes Berg static ssize_t key_tx_spec_write(struct file *file, const char __user *userbuf, 84d0a77c65SJohannes Berg size_t count, loff_t *ppos) 85d0a77c65SJohannes Berg { 86d0a77c65SJohannes Berg struct ieee80211_key *key = file->private_data; 87d0a77c65SJohannes Berg u64 pn; 88d0a77c65SJohannes Berg int ret; 89d0a77c65SJohannes Berg 90d0a77c65SJohannes Berg switch (key->conf.cipher) { 91d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_WEP40: 92d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_WEP104: 93d0a77c65SJohannes Berg return -EINVAL; 94d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_TKIP: 95d0a77c65SJohannes Berg /* not supported yet */ 96d0a77c65SJohannes Berg return -EOPNOTSUPP; 97d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_CCMP: 98d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_CCMP_256: 99d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_AES_CMAC: 100d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_BIP_CMAC_256: 101d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_BIP_GMAC_128: 102d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_BIP_GMAC_256: 103d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_GCMP: 104d0a77c65SJohannes Berg case WLAN_CIPHER_SUITE_GCMP_256: 105d0a77c65SJohannes Berg ret = kstrtou64_from_user(userbuf, count, 16, &pn); 106d0a77c65SJohannes Berg if (ret) 107d0a77c65SJohannes Berg return ret; 108d0a77c65SJohannes Berg /* PN is a 48-bit counter */ 109d0a77c65SJohannes Berg if (pn >= (1ULL << 48)) 110d0a77c65SJohannes Berg return -ERANGE; 111d0a77c65SJohannes Berg atomic64_set(&key->conf.tx_pn, pn); 112d0a77c65SJohannes Berg return count; 113d0a77c65SJohannes Berg default: 114d0a77c65SJohannes Berg return 0; 115d0a77c65SJohannes Berg } 116d0a77c65SJohannes Berg } 117d0a77c65SJohannes Berg 118e9f207f0SJiri Benc static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, 119e9f207f0SJiri Benc size_t count, loff_t *ppos) 120e9f207f0SJiri Benc { 121aba83a0bSJohannes Berg u64 pn; 122e9f207f0SJiri Benc char buf[20]; 123e9f207f0SJiri Benc int len; 124e9f207f0SJiri Benc struct ieee80211_key *key = file->private_data; 125e9f207f0SJiri Benc 12697359d12SJohannes Berg switch (key->conf.cipher) { 12797359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP40: 12897359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP104: 129e9f207f0SJiri Benc len = scnprintf(buf, sizeof(buf), "\n"); 13050339a67SJohannes Berg break; 13197359d12SJohannes Berg case WLAN_CIPHER_SUITE_TKIP: 132f8079d43SEliad Peller pn = atomic64_read(&key->conf.tx_pn); 133e9f207f0SJiri Benc len = scnprintf(buf, sizeof(buf), "%08x %04x\n", 134f8079d43SEliad Peller TKIP_PN_TO_IV32(pn), 135f8079d43SEliad Peller TKIP_PN_TO_IV16(pn)); 13650339a67SJohannes Berg break; 13797359d12SJohannes Berg case WLAN_CIPHER_SUITE_CCMP: 1382b2ba0dbSJouni Malinen case WLAN_CIPHER_SUITE_CCMP_256: 13997359d12SJohannes Berg case WLAN_CIPHER_SUITE_AES_CMAC: 14056c52da2SJouni Malinen case WLAN_CIPHER_SUITE_BIP_CMAC_256: 1418ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_128: 1428ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_256: 14300b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP: 14400b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP_256: 145db388a56SJohannes Berg pn = atomic64_read(&key->conf.tx_pn); 14600b9cfa3SJouni Malinen len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", 14700b9cfa3SJouni Malinen (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), 14800b9cfa3SJouni Malinen (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); 14900b9cfa3SJouni Malinen break; 150e9f207f0SJiri Benc default: 151e9f207f0SJiri Benc return 0; 152e9f207f0SJiri Benc } 153e9f207f0SJiri Benc return simple_read_from_buffer(userbuf, count, ppos, buf, len); 154e9f207f0SJiri Benc } 155d0a77c65SJohannes Berg KEY_OPS_W(tx_spec); 156e9f207f0SJiri Benc 157e9f207f0SJiri Benc static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, 158e9f207f0SJiri Benc size_t count, loff_t *ppos) 159e9f207f0SJiri Benc { 160e9f207f0SJiri Benc struct ieee80211_key *key = file->private_data; 1615a306f58SJohannes Berg char buf[14*IEEE80211_NUM_TIDS+1], *p = buf; 162e9f207f0SJiri Benc int i, len; 163e9f207f0SJiri Benc const u8 *rpn; 164e9f207f0SJiri Benc 16597359d12SJohannes Berg switch (key->conf.cipher) { 16697359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP40: 16797359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP104: 168e9f207f0SJiri Benc len = scnprintf(buf, sizeof(buf), "\n"); 16950339a67SJohannes Berg break; 17097359d12SJohannes Berg case WLAN_CIPHER_SUITE_TKIP: 1715a306f58SJohannes Berg for (i = 0; i < IEEE80211_NUM_TIDS; i++) 172e9f207f0SJiri Benc p += scnprintf(p, sizeof(buf)+buf-p, 173e9f207f0SJiri Benc "%08x %04x\n", 174b0f76b33SHarvey Harrison key->u.tkip.rx[i].iv32, 175b0f76b33SHarvey Harrison key->u.tkip.rx[i].iv16); 176e9f207f0SJiri Benc len = p - buf; 17750339a67SJohannes Berg break; 17897359d12SJohannes Berg case WLAN_CIPHER_SUITE_CCMP: 1792b2ba0dbSJouni Malinen case WLAN_CIPHER_SUITE_CCMP_256: 1805a306f58SJohannes Berg for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { 181e9f207f0SJiri Benc rpn = key->u.ccmp.rx_pn[i]; 182e9f207f0SJiri Benc p += scnprintf(p, sizeof(buf)+buf-p, 183e9f207f0SJiri Benc "%02x%02x%02x%02x%02x%02x\n", 184e9f207f0SJiri Benc rpn[0], rpn[1], rpn[2], 185e9f207f0SJiri Benc rpn[3], rpn[4], rpn[5]); 186e9f207f0SJiri Benc } 187e9f207f0SJiri Benc len = p - buf; 18850339a67SJohannes Berg break; 18997359d12SJohannes Berg case WLAN_CIPHER_SUITE_AES_CMAC: 19056c52da2SJouni Malinen case WLAN_CIPHER_SUITE_BIP_CMAC_256: 1913cfcf6acSJouni Malinen rpn = key->u.aes_cmac.rx_pn; 1923cfcf6acSJouni Malinen p += scnprintf(p, sizeof(buf)+buf-p, 1933cfcf6acSJouni Malinen "%02x%02x%02x%02x%02x%02x\n", 1943cfcf6acSJouni Malinen rpn[0], rpn[1], rpn[2], 1953cfcf6acSJouni Malinen rpn[3], rpn[4], rpn[5]); 1963cfcf6acSJouni Malinen len = p - buf; 1973cfcf6acSJouni Malinen break; 1988ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_128: 1998ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_256: 2008ade538bSJouni Malinen rpn = key->u.aes_gmac.rx_pn; 2018ade538bSJouni Malinen p += scnprintf(p, sizeof(buf)+buf-p, 2028ade538bSJouni Malinen "%02x%02x%02x%02x%02x%02x\n", 2038ade538bSJouni Malinen rpn[0], rpn[1], rpn[2], 2048ade538bSJouni Malinen rpn[3], rpn[4], rpn[5]); 2058ade538bSJouni Malinen len = p - buf; 2068ade538bSJouni Malinen break; 20700b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP: 20800b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP_256: 20900b9cfa3SJouni Malinen for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { 21000b9cfa3SJouni Malinen rpn = key->u.gcmp.rx_pn[i]; 21100b9cfa3SJouni Malinen p += scnprintf(p, sizeof(buf)+buf-p, 21200b9cfa3SJouni Malinen "%02x%02x%02x%02x%02x%02x\n", 21300b9cfa3SJouni Malinen rpn[0], rpn[1], rpn[2], 21400b9cfa3SJouni Malinen rpn[3], rpn[4], rpn[5]); 21500b9cfa3SJouni Malinen } 21600b9cfa3SJouni Malinen len = p - buf; 21700b9cfa3SJouni Malinen break; 218e9f207f0SJiri Benc default: 219e9f207f0SJiri Benc return 0; 220e9f207f0SJiri Benc } 221e9f207f0SJiri Benc return simple_read_from_buffer(userbuf, count, ppos, buf, len); 222e9f207f0SJiri Benc } 223e9f207f0SJiri Benc KEY_OPS(rx_spec); 224e9f207f0SJiri Benc 225e9f207f0SJiri Benc static ssize_t key_replays_read(struct file *file, char __user *userbuf, 226e9f207f0SJiri Benc size_t count, loff_t *ppos) 227e9f207f0SJiri Benc { 228e9f207f0SJiri Benc struct ieee80211_key *key = file->private_data; 229e9f207f0SJiri Benc char buf[20]; 230e9f207f0SJiri Benc int len; 231e9f207f0SJiri Benc 23297359d12SJohannes Berg switch (key->conf.cipher) { 23397359d12SJohannes Berg case WLAN_CIPHER_SUITE_CCMP: 2342b2ba0dbSJouni Malinen case WLAN_CIPHER_SUITE_CCMP_256: 235e9f207f0SJiri Benc len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); 2363cfcf6acSJouni Malinen break; 23797359d12SJohannes Berg case WLAN_CIPHER_SUITE_AES_CMAC: 23856c52da2SJouni Malinen case WLAN_CIPHER_SUITE_BIP_CMAC_256: 2393cfcf6acSJouni Malinen len = scnprintf(buf, sizeof(buf), "%u\n", 2403cfcf6acSJouni Malinen key->u.aes_cmac.replays); 2413cfcf6acSJouni Malinen break; 2428ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_128: 2438ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_256: 2448ade538bSJouni Malinen len = scnprintf(buf, sizeof(buf), "%u\n", 2458ade538bSJouni Malinen key->u.aes_gmac.replays); 2468ade538bSJouni Malinen break; 24700b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP: 24800b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP_256: 24900b9cfa3SJouni Malinen len = scnprintf(buf, sizeof(buf), "%u\n", key->u.gcmp.replays); 25000b9cfa3SJouni Malinen break; 2513cfcf6acSJouni Malinen default: 2523cfcf6acSJouni Malinen return 0; 2533cfcf6acSJouni Malinen } 254e9f207f0SJiri Benc return simple_read_from_buffer(userbuf, count, ppos, buf, len); 255e9f207f0SJiri Benc } 256e9f207f0SJiri Benc KEY_OPS(replays); 257e9f207f0SJiri Benc 2583cfcf6acSJouni Malinen static ssize_t key_icverrors_read(struct file *file, char __user *userbuf, 2593cfcf6acSJouni Malinen size_t count, loff_t *ppos) 2603cfcf6acSJouni Malinen { 2613cfcf6acSJouni Malinen struct ieee80211_key *key = file->private_data; 2623cfcf6acSJouni Malinen char buf[20]; 2633cfcf6acSJouni Malinen int len; 2643cfcf6acSJouni Malinen 26597359d12SJohannes Berg switch (key->conf.cipher) { 26697359d12SJohannes Berg case WLAN_CIPHER_SUITE_AES_CMAC: 26756c52da2SJouni Malinen case WLAN_CIPHER_SUITE_BIP_CMAC_256: 2683cfcf6acSJouni Malinen len = scnprintf(buf, sizeof(buf), "%u\n", 2693cfcf6acSJouni Malinen key->u.aes_cmac.icverrors); 2703cfcf6acSJouni Malinen break; 2718ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_128: 2728ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_256: 2738ade538bSJouni Malinen len = scnprintf(buf, sizeof(buf), "%u\n", 2748ade538bSJouni Malinen key->u.aes_gmac.icverrors); 2758ade538bSJouni Malinen break; 2763cfcf6acSJouni Malinen default: 2773cfcf6acSJouni Malinen return 0; 2783cfcf6acSJouni Malinen } 2793cfcf6acSJouni Malinen return simple_read_from_buffer(userbuf, count, ppos, buf, len); 2803cfcf6acSJouni Malinen } 2813cfcf6acSJouni Malinen KEY_OPS(icverrors); 2823cfcf6acSJouni Malinen 283b98ea058SSaravana static ssize_t key_mic_failures_read(struct file *file, char __user *userbuf, 284b98ea058SSaravana size_t count, loff_t *ppos) 285b98ea058SSaravana { 286b98ea058SSaravana struct ieee80211_key *key = file->private_data; 287b98ea058SSaravana char buf[20]; 288b98ea058SSaravana int len; 289b98ea058SSaravana 290b98ea058SSaravana if (key->conf.cipher != WLAN_CIPHER_SUITE_TKIP) 291b98ea058SSaravana return -EINVAL; 292b98ea058SSaravana 293b98ea058SSaravana len = scnprintf(buf, sizeof(buf), "%u\n", key->u.tkip.mic_failures); 294b98ea058SSaravana 295b98ea058SSaravana return simple_read_from_buffer(userbuf, count, ppos, buf, len); 296b98ea058SSaravana } 297b98ea058SSaravana KEY_OPS(mic_failures); 298b98ea058SSaravana 299e9f207f0SJiri Benc static ssize_t key_key_read(struct file *file, char __user *userbuf, 300e9f207f0SJiri Benc size_t count, loff_t *ppos) 301e9f207f0SJiri Benc { 302e9f207f0SJiri Benc struct ieee80211_key *key = file->private_data; 303520efd1aSJesper Juhl int i, bufsize = 2 * key->conf.keylen + 2; 304e9f207f0SJiri Benc char *buf = kmalloc(bufsize, GFP_KERNEL); 305e9f207f0SJiri Benc char *p = buf; 306520efd1aSJesper Juhl ssize_t res; 307520efd1aSJesper Juhl 308520efd1aSJesper Juhl if (!buf) 309520efd1aSJesper Juhl return -ENOMEM; 310e9f207f0SJiri Benc 3118f20fc24SJohannes Berg for (i = 0; i < key->conf.keylen; i++) 3128f20fc24SJohannes Berg p += scnprintf(p, bufsize + buf - p, "%02x", key->conf.key[i]); 313e9f207f0SJiri Benc p += scnprintf(p, bufsize+buf-p, "\n"); 314e9f207f0SJiri Benc res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); 315e9f207f0SJiri Benc kfree(buf); 316e9f207f0SJiri Benc return res; 317e9f207f0SJiri Benc } 318e9f207f0SJiri Benc KEY_OPS(key); 319e9f207f0SJiri Benc 320e9f207f0SJiri Benc #define DEBUGFS_ADD(name) \ 3217bcfaf2fSJohannes Berg debugfs_create_file(#name, 0400, key->debugfs.dir, \ 3227bcfaf2fSJohannes Berg key, &key_##name##_ops); 323d0a77c65SJohannes Berg #define DEBUGFS_ADD_W(name) \ 324d0a77c65SJohannes Berg debugfs_create_file(#name, 0600, key->debugfs.dir, \ 325d0a77c65SJohannes Berg key, &key_##name##_ops); 326e9f207f0SJiri Benc 3273b96766fSJohannes Berg void ieee80211_debugfs_key_add(struct ieee80211_key *key) 328e9f207f0SJiri Benc { 32950339a67SJohannes Berg static int keycount; 3309446f3efSJohannes Berg char buf[100]; 3313b96766fSJohannes Berg struct sta_info *sta; 332e9f207f0SJiri Benc 3333b96766fSJohannes Berg if (!key->local->debugfs.keys) 334e9f207f0SJiri Benc return; 335e9f207f0SJiri Benc 33650339a67SJohannes Berg sprintf(buf, "%d", keycount); 337d9c58f30SJohannes Berg key->debugfs.cnt = keycount; 33850339a67SJohannes Berg keycount++; 339e9f207f0SJiri Benc key->debugfs.dir = debugfs_create_dir(buf, 3403b96766fSJohannes Berg key->local->debugfs.keys); 341e9f207f0SJiri Benc 34240b275b6SJohannes Berg sta = key->sta; 34340b275b6SJohannes Berg if (sta) { 3449446f3efSJohannes Berg sprintf(buf, "../../netdev:%s/stations/%pM", 3459446f3efSJohannes Berg sta->sdata->name, sta->sta.addr); 3463b96766fSJohannes Berg key->debugfs.stalink = 3473b96766fSJohannes Berg debugfs_create_symlink("station", key->debugfs.dir, buf); 34840b275b6SJohannes Berg } 3493b96766fSJohannes Berg 350e9f207f0SJiri Benc DEBUGFS_ADD(keylen); 3518f20fc24SJohannes Berg DEBUGFS_ADD(flags); 352e9f207f0SJiri Benc DEBUGFS_ADD(keyidx); 353e9f207f0SJiri Benc DEBUGFS_ADD(hw_key_idx); 354e9f207f0SJiri Benc DEBUGFS_ADD(algorithm); 355d0a77c65SJohannes Berg DEBUGFS_ADD_W(tx_spec); 356e9f207f0SJiri Benc DEBUGFS_ADD(rx_spec); 357e9f207f0SJiri Benc DEBUGFS_ADD(replays); 3583cfcf6acSJouni Malinen DEBUGFS_ADD(icverrors); 359b98ea058SSaravana DEBUGFS_ADD(mic_failures); 360e9f207f0SJiri Benc DEBUGFS_ADD(key); 361e7a64f12SJohannes Berg DEBUGFS_ADD(ifindex); 362e9f207f0SJiri Benc }; 363e9f207f0SJiri Benc 364e9f207f0SJiri Benc void ieee80211_debugfs_key_remove(struct ieee80211_key *key) 365e9f207f0SJiri Benc { 366e9f207f0SJiri Benc if (!key) 367e9f207f0SJiri Benc return; 368e9f207f0SJiri Benc 3697bcfaf2fSJohannes Berg debugfs_remove_recursive(key->debugfs.dir); 370e9f207f0SJiri Benc key->debugfs.dir = NULL; 371e9f207f0SJiri Benc } 372f7e0104cSJohannes Berg 373f7e0104cSJohannes Berg void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) 374e9f207f0SJiri Benc { 375e9f207f0SJiri Benc char buf[50]; 37678520cadSJohannes Berg struct ieee80211_key *key; 377e9f207f0SJiri Benc 378ddbfe860SStanislaw Gruszka if (!sdata->vif.debugfs_dir) 379e9f207f0SJiri Benc return; 380e9f207f0SJiri Benc 381f7e0104cSJohannes Berg lockdep_assert_held(&sdata->local->key_mtx); 38278520cadSJohannes Berg 383135792ecSJohannes Berg debugfs_remove(sdata->debugfs.default_unicast_key); 384135792ecSJohannes Berg sdata->debugfs.default_unicast_key = NULL; 385135792ecSJohannes Berg 386f7e0104cSJohannes Berg if (sdata->default_unicast_key) { 38740b275b6SJohannes Berg key = key_mtx_dereference(sdata->local, 38840b275b6SJohannes Berg sdata->default_unicast_key); 38978520cadSJohannes Berg sprintf(buf, "../keys/%d", key->debugfs.cnt); 390f7e0104cSJohannes Berg sdata->debugfs.default_unicast_key = 391f7e0104cSJohannes Berg debugfs_create_symlink("default_unicast_key", 392ddbfe860SStanislaw Gruszka sdata->vif.debugfs_dir, buf); 393135792ecSJohannes Berg } 394135792ecSJohannes Berg 395135792ecSJohannes Berg debugfs_remove(sdata->debugfs.default_multicast_key); 396135792ecSJohannes Berg sdata->debugfs.default_multicast_key = NULL; 39778520cadSJohannes Berg 398f7e0104cSJohannes Berg if (sdata->default_multicast_key) { 39940b275b6SJohannes Berg key = key_mtx_dereference(sdata->local, 40040b275b6SJohannes Berg sdata->default_multicast_key); 401f7e0104cSJohannes Berg sprintf(buf, "../keys/%d", key->debugfs.cnt); 402f7e0104cSJohannes Berg sdata->debugfs.default_multicast_key = 403f7e0104cSJohannes Berg debugfs_create_symlink("default_multicast_key", 404ddbfe860SStanislaw Gruszka sdata->vif.debugfs_dir, buf); 405f7e0104cSJohannes Berg } 406e9f207f0SJiri Benc } 407e9f207f0SJiri Benc 4083cfcf6acSJouni Malinen void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) 4093cfcf6acSJouni Malinen { 4103cfcf6acSJouni Malinen char buf[50]; 4113cfcf6acSJouni Malinen struct ieee80211_key *key; 4123cfcf6acSJouni Malinen 413ddbfe860SStanislaw Gruszka if (!sdata->vif.debugfs_dir) 4143cfcf6acSJouni Malinen return; 4153cfcf6acSJouni Malinen 41640b275b6SJohannes Berg key = key_mtx_dereference(sdata->local, 41740b275b6SJohannes Berg sdata->default_mgmt_key); 4183cfcf6acSJouni Malinen if (key) { 4193cfcf6acSJouni Malinen sprintf(buf, "../keys/%d", key->debugfs.cnt); 4207bcfaf2fSJohannes Berg sdata->debugfs.default_mgmt_key = 4213cfcf6acSJouni Malinen debugfs_create_symlink("default_mgmt_key", 422ddbfe860SStanislaw Gruszka sdata->vif.debugfs_dir, buf); 4233cfcf6acSJouni Malinen } else 4243cfcf6acSJouni Malinen ieee80211_debugfs_key_remove_mgmt_default(sdata); 4253cfcf6acSJouni Malinen } 4263cfcf6acSJouni Malinen 4273cfcf6acSJouni Malinen void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sdata) 4283cfcf6acSJouni Malinen { 4293cfcf6acSJouni Malinen if (!sdata) 4303cfcf6acSJouni Malinen return; 4313cfcf6acSJouni Malinen 4327bcfaf2fSJohannes Berg debugfs_remove(sdata->debugfs.default_mgmt_key); 4337bcfaf2fSJohannes Berg sdata->debugfs.default_mgmt_key = NULL; 4343cfcf6acSJouni Malinen } 4353cfcf6acSJouni Malinen 436e5473e80SJouni Malinen void 437e5473e80SJouni Malinen ieee80211_debugfs_key_add_beacon_default(struct ieee80211_sub_if_data *sdata) 438e5473e80SJouni Malinen { 439e5473e80SJouni Malinen char buf[50]; 440e5473e80SJouni Malinen struct ieee80211_key *key; 441e5473e80SJouni Malinen 442e5473e80SJouni Malinen if (!sdata->vif.debugfs_dir) 443e5473e80SJouni Malinen return; 444e5473e80SJouni Malinen 445e5473e80SJouni Malinen key = key_mtx_dereference(sdata->local, 446e5473e80SJouni Malinen sdata->default_beacon_key); 447e5473e80SJouni Malinen if (key) { 448e5473e80SJouni Malinen sprintf(buf, "../keys/%d", key->debugfs.cnt); 449e5473e80SJouni Malinen sdata->debugfs.default_beacon_key = 450e5473e80SJouni Malinen debugfs_create_symlink("default_beacon_key", 451e5473e80SJouni Malinen sdata->vif.debugfs_dir, buf); 452e5473e80SJouni Malinen } else { 453e5473e80SJouni Malinen ieee80211_debugfs_key_remove_beacon_default(sdata); 454e5473e80SJouni Malinen } 455e5473e80SJouni Malinen } 456e5473e80SJouni Malinen 457e5473e80SJouni Malinen void 458e5473e80SJouni Malinen ieee80211_debugfs_key_remove_beacon_default(struct ieee80211_sub_if_data *sdata) 459e5473e80SJouni Malinen { 460e5473e80SJouni Malinen if (!sdata) 461e5473e80SJouni Malinen return; 462e5473e80SJouni Malinen 463e5473e80SJouni Malinen debugfs_remove(sdata->debugfs.default_beacon_key); 464e5473e80SJouni Malinen sdata->debugfs.default_beacon_key = NULL; 465e5473e80SJouni Malinen } 466e5473e80SJouni Malinen 467e9f207f0SJiri Benc void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, 468e9f207f0SJiri Benc struct sta_info *sta) 469e9f207f0SJiri Benc { 470e9f207f0SJiri Benc debugfs_remove(key->debugfs.stalink); 471e9f207f0SJiri Benc key->debugfs.stalink = NULL; 472e9f207f0SJiri Benc } 473