162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2003-2005	Devicescape Software, Inc.
462306a36Sopenharmony_ci * Copyright (c) 2006	Jiri Benc <jbenc@suse.cz>
562306a36Sopenharmony_ci * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
662306a36Sopenharmony_ci * Copyright (C) 2015	Intel Deutschland GmbH
762306a36Sopenharmony_ci * Copyright (C) 2021-2022   Intel Corporation
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/kobject.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include "ieee80211_i.h"
1362306a36Sopenharmony_ci#include "key.h"
1462306a36Sopenharmony_ci#include "debugfs.h"
1562306a36Sopenharmony_ci#include "debugfs_key.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define KEY_READ(name, prop, format_string)				\
1862306a36Sopenharmony_cistatic ssize_t key_##name##_read(struct file *file,			\
1962306a36Sopenharmony_ci				 char __user *userbuf,			\
2062306a36Sopenharmony_ci				 size_t count, loff_t *ppos)		\
2162306a36Sopenharmony_ci{									\
2262306a36Sopenharmony_ci	struct ieee80211_key *key = file->private_data;			\
2362306a36Sopenharmony_ci	return mac80211_format_buffer(userbuf, count, ppos, 		\
2462306a36Sopenharmony_ci				      format_string, key->prop);	\
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci#define KEY_READ_X(name) KEY_READ(name, name, "0x%x\n")
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define KEY_OPS(name)							\
2962306a36Sopenharmony_cistatic const struct file_operations key_ ##name## _ops = {		\
3062306a36Sopenharmony_ci	.read = key_##name##_read,					\
3162306a36Sopenharmony_ci	.open = simple_open,						\
3262306a36Sopenharmony_ci	.llseek = generic_file_llseek,					\
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define KEY_OPS_W(name)							\
3662306a36Sopenharmony_cistatic const struct file_operations key_ ##name## _ops = {		\
3762306a36Sopenharmony_ci	.read = key_##name##_read,					\
3862306a36Sopenharmony_ci	.write = key_##name##_write,					\
3962306a36Sopenharmony_ci	.open = simple_open,						\
4062306a36Sopenharmony_ci	.llseek = generic_file_llseek,					\
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define KEY_FILE(name, format)						\
4462306a36Sopenharmony_ci		 KEY_READ_##format(name)				\
4562306a36Sopenharmony_ci		 KEY_OPS(name)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define KEY_CONF_READ(name, format_string)				\
4862306a36Sopenharmony_ci	KEY_READ(conf_##name, conf.name, format_string)
4962306a36Sopenharmony_ci#define KEY_CONF_READ_D(name) KEY_CONF_READ(name, "%d\n")
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define KEY_CONF_OPS(name)						\
5262306a36Sopenharmony_cistatic const struct file_operations key_ ##name## _ops = {		\
5362306a36Sopenharmony_ci	.read = key_conf_##name##_read,					\
5462306a36Sopenharmony_ci	.open = simple_open,						\
5562306a36Sopenharmony_ci	.llseek = generic_file_llseek,					\
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define KEY_CONF_FILE(name, format)					\
5962306a36Sopenharmony_ci		 KEY_CONF_READ_##format(name)				\
6062306a36Sopenharmony_ci		 KEY_CONF_OPS(name)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ciKEY_CONF_FILE(keylen, D);
6362306a36Sopenharmony_ciKEY_CONF_FILE(keyidx, D);
6462306a36Sopenharmony_ciKEY_CONF_FILE(hw_key_idx, D);
6562306a36Sopenharmony_ciKEY_FILE(flags, X);
6662306a36Sopenharmony_ciKEY_READ(ifindex, sdata->name, "%s\n");
6762306a36Sopenharmony_ciKEY_OPS(ifindex);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic ssize_t key_algorithm_read(struct file *file,
7062306a36Sopenharmony_ci				  char __user *userbuf,
7162306a36Sopenharmony_ci				  size_t count, loff_t *ppos)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	char buf[15];
7462306a36Sopenharmony_ci	struct ieee80211_key *key = file->private_data;
7562306a36Sopenharmony_ci	u32 c = key->conf.cipher;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	sprintf(buf, "%.2x-%.2x-%.2x:%d\n",
7862306a36Sopenharmony_ci		c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
7962306a36Sopenharmony_ci	return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ciKEY_OPS(algorithm);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic ssize_t key_tx_spec_write(struct file *file, const char __user *userbuf,
8462306a36Sopenharmony_ci				 size_t count, loff_t *ppos)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct ieee80211_key *key = file->private_data;
8762306a36Sopenharmony_ci	u64 pn;
8862306a36Sopenharmony_ci	int ret;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	switch (key->conf.cipher) {
9162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
9262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
9362306a36Sopenharmony_ci		return -EINVAL;
9462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
9562306a36Sopenharmony_ci		/* not supported yet */
9662306a36Sopenharmony_ci		return -EOPNOTSUPP;
9762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
9862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
9962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
10062306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
10162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
10262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
10362306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
10462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
10562306a36Sopenharmony_ci		ret = kstrtou64_from_user(userbuf, count, 16, &pn);
10662306a36Sopenharmony_ci		if (ret)
10762306a36Sopenharmony_ci			return ret;
10862306a36Sopenharmony_ci		/* PN is a 48-bit counter */
10962306a36Sopenharmony_ci		if (pn >= (1ULL << 48))
11062306a36Sopenharmony_ci			return -ERANGE;
11162306a36Sopenharmony_ci		atomic64_set(&key->conf.tx_pn, pn);
11262306a36Sopenharmony_ci		return count;
11362306a36Sopenharmony_ci	default:
11462306a36Sopenharmony_ci		return 0;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
11962306a36Sopenharmony_ci				size_t count, loff_t *ppos)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	u64 pn;
12262306a36Sopenharmony_ci	char buf[20];
12362306a36Sopenharmony_ci	int len;
12462306a36Sopenharmony_ci	struct ieee80211_key *key = file->private_data;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	switch (key->conf.cipher) {
12762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
12862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
12962306a36Sopenharmony_ci		len = scnprintf(buf, sizeof(buf), "\n");
13062306a36Sopenharmony_ci		break;
13162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
13262306a36Sopenharmony_ci		pn = atomic64_read(&key->conf.tx_pn);
13362306a36Sopenharmony_ci		len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
13462306a36Sopenharmony_ci				TKIP_PN_TO_IV32(pn),
13562306a36Sopenharmony_ci				TKIP_PN_TO_IV16(pn));
13662306a36Sopenharmony_ci		break;
13762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
13862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
13962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
14062306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
14162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
14262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
14362306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
14462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
14562306a36Sopenharmony_ci		pn = atomic64_read(&key->conf.tx_pn);
14662306a36Sopenharmony_ci		len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
14762306a36Sopenharmony_ci				(u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24),
14862306a36Sopenharmony_ci				(u8)(pn >> 16), (u8)(pn >> 8), (u8)pn);
14962306a36Sopenharmony_ci		break;
15062306a36Sopenharmony_ci	default:
15162306a36Sopenharmony_ci		return 0;
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ciKEY_OPS_W(tx_spec);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
15862306a36Sopenharmony_ci				size_t count, loff_t *ppos)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	struct ieee80211_key *key = file->private_data;
16162306a36Sopenharmony_ci	char buf[14*IEEE80211_NUM_TIDS+1], *p = buf;
16262306a36Sopenharmony_ci	int i, len;
16362306a36Sopenharmony_ci	const u8 *rpn;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	switch (key->conf.cipher) {
16662306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
16762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
16862306a36Sopenharmony_ci		len = scnprintf(buf, sizeof(buf), "\n");
16962306a36Sopenharmony_ci		break;
17062306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
17162306a36Sopenharmony_ci		for (i = 0; i < IEEE80211_NUM_TIDS; i++)
17262306a36Sopenharmony_ci			p += scnprintf(p, sizeof(buf)+buf-p,
17362306a36Sopenharmony_ci				       "%08x %04x\n",
17462306a36Sopenharmony_ci				       key->u.tkip.rx[i].iv32,
17562306a36Sopenharmony_ci				       key->u.tkip.rx[i].iv16);
17662306a36Sopenharmony_ci		len = p - buf;
17762306a36Sopenharmony_ci		break;
17862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
17962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
18062306a36Sopenharmony_ci		for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) {
18162306a36Sopenharmony_ci			rpn = key->u.ccmp.rx_pn[i];
18262306a36Sopenharmony_ci			p += scnprintf(p, sizeof(buf)+buf-p,
18362306a36Sopenharmony_ci				       "%02x%02x%02x%02x%02x%02x\n",
18462306a36Sopenharmony_ci				       rpn[0], rpn[1], rpn[2],
18562306a36Sopenharmony_ci				       rpn[3], rpn[4], rpn[5]);
18662306a36Sopenharmony_ci		}
18762306a36Sopenharmony_ci		len = p - buf;
18862306a36Sopenharmony_ci		break;
18962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
19062306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
19162306a36Sopenharmony_ci		rpn = key->u.aes_cmac.rx_pn;
19262306a36Sopenharmony_ci		p += scnprintf(p, sizeof(buf)+buf-p,
19362306a36Sopenharmony_ci			       "%02x%02x%02x%02x%02x%02x\n",
19462306a36Sopenharmony_ci			       rpn[0], rpn[1], rpn[2],
19562306a36Sopenharmony_ci			       rpn[3], rpn[4], rpn[5]);
19662306a36Sopenharmony_ci		len = p - buf;
19762306a36Sopenharmony_ci		break;
19862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
19962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
20062306a36Sopenharmony_ci		rpn = key->u.aes_gmac.rx_pn;
20162306a36Sopenharmony_ci		p += scnprintf(p, sizeof(buf)+buf-p,
20262306a36Sopenharmony_ci			       "%02x%02x%02x%02x%02x%02x\n",
20362306a36Sopenharmony_ci			       rpn[0], rpn[1], rpn[2],
20462306a36Sopenharmony_ci			       rpn[3], rpn[4], rpn[5]);
20562306a36Sopenharmony_ci		len = p - buf;
20662306a36Sopenharmony_ci		break;
20762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
20862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
20962306a36Sopenharmony_ci		for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) {
21062306a36Sopenharmony_ci			rpn = key->u.gcmp.rx_pn[i];
21162306a36Sopenharmony_ci			p += scnprintf(p, sizeof(buf)+buf-p,
21262306a36Sopenharmony_ci				       "%02x%02x%02x%02x%02x%02x\n",
21362306a36Sopenharmony_ci				       rpn[0], rpn[1], rpn[2],
21462306a36Sopenharmony_ci				       rpn[3], rpn[4], rpn[5]);
21562306a36Sopenharmony_ci		}
21662306a36Sopenharmony_ci		len = p - buf;
21762306a36Sopenharmony_ci		break;
21862306a36Sopenharmony_ci	default:
21962306a36Sopenharmony_ci		return 0;
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ciKEY_OPS(rx_spec);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic ssize_t key_replays_read(struct file *file, char __user *userbuf,
22662306a36Sopenharmony_ci				size_t count, loff_t *ppos)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	struct ieee80211_key *key = file->private_data;
22962306a36Sopenharmony_ci	char buf[20];
23062306a36Sopenharmony_ci	int len;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	switch (key->conf.cipher) {
23362306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
23462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
23562306a36Sopenharmony_ci		len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
23662306a36Sopenharmony_ci		break;
23762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
23862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
23962306a36Sopenharmony_ci		len = scnprintf(buf, sizeof(buf), "%u\n",
24062306a36Sopenharmony_ci				key->u.aes_cmac.replays);
24162306a36Sopenharmony_ci		break;
24262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
24362306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
24462306a36Sopenharmony_ci		len = scnprintf(buf, sizeof(buf), "%u\n",
24562306a36Sopenharmony_ci				key->u.aes_gmac.replays);
24662306a36Sopenharmony_ci		break;
24762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
24862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
24962306a36Sopenharmony_ci		len = scnprintf(buf, sizeof(buf), "%u\n", key->u.gcmp.replays);
25062306a36Sopenharmony_ci		break;
25162306a36Sopenharmony_ci	default:
25262306a36Sopenharmony_ci		return 0;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ciKEY_OPS(replays);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic ssize_t key_icverrors_read(struct file *file, char __user *userbuf,
25962306a36Sopenharmony_ci				  size_t count, loff_t *ppos)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	struct ieee80211_key *key = file->private_data;
26262306a36Sopenharmony_ci	char buf[20];
26362306a36Sopenharmony_ci	int len;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	switch (key->conf.cipher) {
26662306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
26762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
26862306a36Sopenharmony_ci		len = scnprintf(buf, sizeof(buf), "%u\n",
26962306a36Sopenharmony_ci				key->u.aes_cmac.icverrors);
27062306a36Sopenharmony_ci		break;
27162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
27262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
27362306a36Sopenharmony_ci		len = scnprintf(buf, sizeof(buf), "%u\n",
27462306a36Sopenharmony_ci				key->u.aes_gmac.icverrors);
27562306a36Sopenharmony_ci		break;
27662306a36Sopenharmony_ci	default:
27762306a36Sopenharmony_ci		return 0;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ciKEY_OPS(icverrors);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic ssize_t key_mic_failures_read(struct file *file, char __user *userbuf,
28462306a36Sopenharmony_ci				     size_t count, loff_t *ppos)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	struct ieee80211_key *key = file->private_data;
28762306a36Sopenharmony_ci	char buf[20];
28862306a36Sopenharmony_ci	int len;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (key->conf.cipher != WLAN_CIPHER_SUITE_TKIP)
29162306a36Sopenharmony_ci		return -EINVAL;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	len = scnprintf(buf, sizeof(buf), "%u\n", key->u.tkip.mic_failures);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ciKEY_OPS(mic_failures);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic ssize_t key_key_read(struct file *file, char __user *userbuf,
30062306a36Sopenharmony_ci			    size_t count, loff_t *ppos)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	struct ieee80211_key *key = file->private_data;
30362306a36Sopenharmony_ci	int i, bufsize = 2 * key->conf.keylen + 2;
30462306a36Sopenharmony_ci	char *buf = kmalloc(bufsize, GFP_KERNEL);
30562306a36Sopenharmony_ci	char *p = buf;
30662306a36Sopenharmony_ci	ssize_t res;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (!buf)
30962306a36Sopenharmony_ci		return -ENOMEM;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	for (i = 0; i < key->conf.keylen; i++)
31262306a36Sopenharmony_ci		p += scnprintf(p, bufsize + buf - p, "%02x", key->conf.key[i]);
31362306a36Sopenharmony_ci	p += scnprintf(p, bufsize+buf-p, "\n");
31462306a36Sopenharmony_ci	res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
31562306a36Sopenharmony_ci	kfree(buf);
31662306a36Sopenharmony_ci	return res;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ciKEY_OPS(key);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci#define DEBUGFS_ADD(name) \
32162306a36Sopenharmony_ci	debugfs_create_file(#name, 0400, key->debugfs.dir, \
32262306a36Sopenharmony_ci			    key, &key_##name##_ops)
32362306a36Sopenharmony_ci#define DEBUGFS_ADD_W(name) \
32462306a36Sopenharmony_ci	debugfs_create_file(#name, 0600, key->debugfs.dir, \
32562306a36Sopenharmony_ci			    key, &key_##name##_ops);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_civoid ieee80211_debugfs_key_add(struct ieee80211_key *key)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	static int keycount;
33062306a36Sopenharmony_ci	char buf[100];
33162306a36Sopenharmony_ci	struct sta_info *sta;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (!key->local->debugfs.keys)
33462306a36Sopenharmony_ci		return;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	sprintf(buf, "%d", keycount);
33762306a36Sopenharmony_ci	key->debugfs.cnt = keycount;
33862306a36Sopenharmony_ci	keycount++;
33962306a36Sopenharmony_ci	key->debugfs.dir = debugfs_create_dir(buf,
34062306a36Sopenharmony_ci					key->local->debugfs.keys);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	sta = key->sta;
34362306a36Sopenharmony_ci	if (sta) {
34462306a36Sopenharmony_ci		sprintf(buf, "../../netdev:%s/stations/%pM",
34562306a36Sopenharmony_ci			sta->sdata->name, sta->sta.addr);
34662306a36Sopenharmony_ci		key->debugfs.stalink =
34762306a36Sopenharmony_ci			debugfs_create_symlink("station", key->debugfs.dir, buf);
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	DEBUGFS_ADD(keylen);
35162306a36Sopenharmony_ci	DEBUGFS_ADD(flags);
35262306a36Sopenharmony_ci	DEBUGFS_ADD(keyidx);
35362306a36Sopenharmony_ci	DEBUGFS_ADD(hw_key_idx);
35462306a36Sopenharmony_ci	DEBUGFS_ADD(algorithm);
35562306a36Sopenharmony_ci	DEBUGFS_ADD_W(tx_spec);
35662306a36Sopenharmony_ci	DEBUGFS_ADD(rx_spec);
35762306a36Sopenharmony_ci	DEBUGFS_ADD(replays);
35862306a36Sopenharmony_ci	DEBUGFS_ADD(icverrors);
35962306a36Sopenharmony_ci	DEBUGFS_ADD(mic_failures);
36062306a36Sopenharmony_ci	DEBUGFS_ADD(key);
36162306a36Sopenharmony_ci	DEBUGFS_ADD(ifindex);
36262306a36Sopenharmony_ci};
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_civoid ieee80211_debugfs_key_remove(struct ieee80211_key *key)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	if (!key)
36762306a36Sopenharmony_ci		return;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	debugfs_remove_recursive(key->debugfs.dir);
37062306a36Sopenharmony_ci	key->debugfs.dir = NULL;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_civoid ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	char buf[50];
37662306a36Sopenharmony_ci	struct ieee80211_key *key;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	if (!sdata->vif.debugfs_dir)
37962306a36Sopenharmony_ci		return;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	lockdep_assert_held(&sdata->local->key_mtx);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	debugfs_remove(sdata->debugfs.default_unicast_key);
38462306a36Sopenharmony_ci	sdata->debugfs.default_unicast_key = NULL;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (sdata->default_unicast_key) {
38762306a36Sopenharmony_ci		key = key_mtx_dereference(sdata->local,
38862306a36Sopenharmony_ci					  sdata->default_unicast_key);
38962306a36Sopenharmony_ci		sprintf(buf, "../keys/%d", key->debugfs.cnt);
39062306a36Sopenharmony_ci		sdata->debugfs.default_unicast_key =
39162306a36Sopenharmony_ci			debugfs_create_symlink("default_unicast_key",
39262306a36Sopenharmony_ci					       sdata->vif.debugfs_dir, buf);
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	debugfs_remove(sdata->debugfs.default_multicast_key);
39662306a36Sopenharmony_ci	sdata->debugfs.default_multicast_key = NULL;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (sdata->deflink.default_multicast_key) {
39962306a36Sopenharmony_ci		key = key_mtx_dereference(sdata->local,
40062306a36Sopenharmony_ci					  sdata->deflink.default_multicast_key);
40162306a36Sopenharmony_ci		sprintf(buf, "../keys/%d", key->debugfs.cnt);
40262306a36Sopenharmony_ci		sdata->debugfs.default_multicast_key =
40362306a36Sopenharmony_ci			debugfs_create_symlink("default_multicast_key",
40462306a36Sopenharmony_ci					       sdata->vif.debugfs_dir, buf);
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_civoid ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	char buf[50];
41162306a36Sopenharmony_ci	struct ieee80211_key *key;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (!sdata->vif.debugfs_dir)
41462306a36Sopenharmony_ci		return;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	key = key_mtx_dereference(sdata->local,
41762306a36Sopenharmony_ci				  sdata->deflink.default_mgmt_key);
41862306a36Sopenharmony_ci	if (key) {
41962306a36Sopenharmony_ci		sprintf(buf, "../keys/%d", key->debugfs.cnt);
42062306a36Sopenharmony_ci		sdata->debugfs.default_mgmt_key =
42162306a36Sopenharmony_ci			debugfs_create_symlink("default_mgmt_key",
42262306a36Sopenharmony_ci					       sdata->vif.debugfs_dir, buf);
42362306a36Sopenharmony_ci	} else
42462306a36Sopenharmony_ci		ieee80211_debugfs_key_remove_mgmt_default(sdata);
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_civoid ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sdata)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	if (!sdata)
43062306a36Sopenharmony_ci		return;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	debugfs_remove(sdata->debugfs.default_mgmt_key);
43362306a36Sopenharmony_ci	sdata->debugfs.default_mgmt_key = NULL;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_civoid
43762306a36Sopenharmony_ciieee80211_debugfs_key_add_beacon_default(struct ieee80211_sub_if_data *sdata)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	char buf[50];
44062306a36Sopenharmony_ci	struct ieee80211_key *key;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (!sdata->vif.debugfs_dir)
44362306a36Sopenharmony_ci		return;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	key = key_mtx_dereference(sdata->local,
44662306a36Sopenharmony_ci				  sdata->deflink.default_beacon_key);
44762306a36Sopenharmony_ci	if (key) {
44862306a36Sopenharmony_ci		sprintf(buf, "../keys/%d", key->debugfs.cnt);
44962306a36Sopenharmony_ci		sdata->debugfs.default_beacon_key =
45062306a36Sopenharmony_ci			debugfs_create_symlink("default_beacon_key",
45162306a36Sopenharmony_ci					       sdata->vif.debugfs_dir, buf);
45262306a36Sopenharmony_ci	} else {
45362306a36Sopenharmony_ci		ieee80211_debugfs_key_remove_beacon_default(sdata);
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_civoid
45862306a36Sopenharmony_ciieee80211_debugfs_key_remove_beacon_default(struct ieee80211_sub_if_data *sdata)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	if (!sdata)
46162306a36Sopenharmony_ci		return;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	debugfs_remove(sdata->debugfs.default_beacon_key);
46462306a36Sopenharmony_ci	sdata->debugfs.default_beacon_key = NULL;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_civoid ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
46862306a36Sopenharmony_ci				   struct sta_info *sta)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	debugfs_remove(key->debugfs.stalink);
47162306a36Sopenharmony_ci	key->debugfs.stalink = NULL;
47262306a36Sopenharmony_ci}
473