debugfs_key.c 8.9 KB
Newer Older
J
Jiri Benc 已提交
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * Copyright 2003-2005	Devicescape Software, Inc.
 * Copyright (c) 2006	Jiri Benc <jbenc@suse.cz>
 * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/kobject.h>
#include "ieee80211_i.h"
J
Johannes Berg 已提交
13
#include "key.h"
J
Jiri Benc 已提交
14 15 16
#include "debugfs.h"
#include "debugfs_key.h"

17
#define KEY_READ(name, prop, buflen, format_string)			\
J
Jiri Benc 已提交
18 19 20 21 22 23
static ssize_t key_##name##_read(struct file *file,			\
				 char __user *userbuf,			\
				 size_t count, loff_t *ppos)		\
{									\
	char buf[buflen];						\
	struct ieee80211_key *key = file->private_data;			\
24
	int res = scnprintf(buf, buflen, format_string, key->prop);	\
J
Jiri Benc 已提交
25 26
	return simple_read_from_buffer(userbuf, count, ppos, buf, res);	\
}
27
#define KEY_READ_D(name) KEY_READ(name, name, 20, "%d\n")
J
Johannes Berg 已提交
28
#define KEY_READ_X(name) KEY_READ(name, name, 20, "0x%x\n")
J
Jiri Benc 已提交
29 30 31 32 33 34 35 36 37 38 39

#define KEY_OPS(name)							\
static const struct file_operations key_ ##name## _ops = {		\
	.read = key_##name##_read,					\
	.open = mac80211_open_file_generic,				\
}

#define KEY_FILE(name, format)						\
		 KEY_READ_##format(name)				\
		 KEY_OPS(name)

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
#define KEY_CONF_READ(name, buflen, format_string)			\
	KEY_READ(conf_##name, conf.name, buflen, format_string)
#define KEY_CONF_READ_D(name) KEY_CONF_READ(name, 20, "%d\n")

#define KEY_CONF_OPS(name)						\
static const struct file_operations key_ ##name## _ops = {		\
	.read = key_conf_##name##_read,					\
	.open = mac80211_open_file_generic,				\
}

#define KEY_CONF_FILE(name, format)					\
		 KEY_CONF_READ_##format(name)				\
		 KEY_CONF_OPS(name)

KEY_CONF_FILE(keylen, D);
KEY_CONF_FILE(keyidx, D);
KEY_CONF_FILE(hw_key_idx, D);
J
Johannes Berg 已提交
57
KEY_FILE(flags, X);
J
Jiri Benc 已提交
58
KEY_FILE(tx_rx_count, D);
59 60
KEY_READ(ifindex, sdata->dev->ifindex, 20, "%d\n");
KEY_OPS(ifindex);
J
Jiri Benc 已提交
61 62 63 64 65 66 67 68

static ssize_t key_algorithm_read(struct file *file,
				  char __user *userbuf,
				  size_t count, loff_t *ppos)
{
	char *alg;
	struct ieee80211_key *key = file->private_data;

69
	switch (key->conf.alg) {
J
Jiri Benc 已提交
70 71 72 73 74 75 76 77 78
	case ALG_WEP:
		alg = "WEP\n";
		break;
	case ALG_TKIP:
		alg = "TKIP\n";
		break;
	case ALG_CCMP:
		alg = "CCMP\n";
		break;
79 80 81
	case ALG_AES_CMAC:
		alg = "AES-128-CMAC\n";
		break;
J
Jiri Benc 已提交
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
	default:
		return 0;
	}
	return simple_read_from_buffer(userbuf, count, ppos, alg, strlen(alg));
}
KEY_OPS(algorithm);

static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
				size_t count, loff_t *ppos)
{
	const u8 *tpn;
	char buf[20];
	int len;
	struct ieee80211_key *key = file->private_data;

97
	switch (key->conf.alg) {
J
Jiri Benc 已提交
98 99
	case ALG_WEP:
		len = scnprintf(buf, sizeof(buf), "\n");
J
Johannes Berg 已提交
100
		break;
J
Jiri Benc 已提交
101 102
	case ALG_TKIP:
		len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
103 104
				key->u.tkip.tx.iv32,
				key->u.tkip.tx.iv16);
J
Johannes Berg 已提交
105
		break;
J
Jiri Benc 已提交
106 107 108 109
	case ALG_CCMP:
		tpn = key->u.ccmp.tx_pn;
		len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
				tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
J
Johannes Berg 已提交
110
		break;
111 112 113 114 115 116
	case ALG_AES_CMAC:
		tpn = key->u.aes_cmac.tx_pn;
		len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
				tpn[0], tpn[1], tpn[2], tpn[3], tpn[4],
				tpn[5]);
		break;
J
Jiri Benc 已提交
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
	default:
		return 0;
	}
	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
}
KEY_OPS(tx_spec);

static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
				size_t count, loff_t *ppos)
{
	struct ieee80211_key *key = file->private_data;
	char buf[14*NUM_RX_DATA_QUEUES+1], *p = buf;
	int i, len;
	const u8 *rpn;

132
	switch (key->conf.alg) {
J
Jiri Benc 已提交
133 134
	case ALG_WEP:
		len = scnprintf(buf, sizeof(buf), "\n");
J
Johannes Berg 已提交
135
		break;
J
Jiri Benc 已提交
136 137 138 139
	case ALG_TKIP:
		for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
			p += scnprintf(p, sizeof(buf)+buf-p,
				       "%08x %04x\n",
140 141
				       key->u.tkip.rx[i].iv32,
				       key->u.tkip.rx[i].iv16);
J
Jiri Benc 已提交
142
		len = p - buf;
J
Johannes Berg 已提交
143
		break;
J
Jiri Benc 已提交
144 145 146 147 148 149 150 151 152
	case ALG_CCMP:
		for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
			rpn = key->u.ccmp.rx_pn[i];
			p += scnprintf(p, sizeof(buf)+buf-p,
				       "%02x%02x%02x%02x%02x%02x\n",
				       rpn[0], rpn[1], rpn[2],
				       rpn[3], rpn[4], rpn[5]);
		}
		len = p - buf;
J
Johannes Berg 已提交
153
		break;
154 155 156 157 158 159 160 161
	case ALG_AES_CMAC:
		rpn = key->u.aes_cmac.rx_pn;
		p += scnprintf(p, sizeof(buf)+buf-p,
			       "%02x%02x%02x%02x%02x%02x\n",
			       rpn[0], rpn[1], rpn[2],
			       rpn[3], rpn[4], rpn[5]);
		len = p - buf;
		break;
J
Jiri Benc 已提交
162 163 164 165 166 167 168 169 170 171 172 173 174 175
	default:
		return 0;
	}
	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
}
KEY_OPS(rx_spec);

static ssize_t key_replays_read(struct file *file, char __user *userbuf,
				size_t count, loff_t *ppos)
{
	struct ieee80211_key *key = file->private_data;
	char buf[20];
	int len;

176 177 178 179 180 181 182 183 184
	switch (key->conf.alg) {
	case ALG_CCMP:
		len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
		break;
	case ALG_AES_CMAC:
		len = scnprintf(buf, sizeof(buf), "%u\n",
				key->u.aes_cmac.replays);
		break;
	default:
J
Jiri Benc 已提交
185
		return 0;
186
	}
J
Jiri Benc 已提交
187 188 189 190
	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
}
KEY_OPS(replays);

191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
static ssize_t key_icverrors_read(struct file *file, char __user *userbuf,
				  size_t count, loff_t *ppos)
{
	struct ieee80211_key *key = file->private_data;
	char buf[20];
	int len;

	switch (key->conf.alg) {
	case ALG_AES_CMAC:
		len = scnprintf(buf, sizeof(buf), "%u\n",
				key->u.aes_cmac.icverrors);
		break;
	default:
		return 0;
	}
	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
}
KEY_OPS(icverrors);

J
Jiri Benc 已提交
210 211 212 213
static ssize_t key_key_read(struct file *file, char __user *userbuf,
			    size_t count, loff_t *ppos)
{
	struct ieee80211_key *key = file->private_data;
214
	int i, res, bufsize = 2 * key->conf.keylen + 2;
J
Jiri Benc 已提交
215 216 217
	char *buf = kmalloc(bufsize, GFP_KERNEL);
	char *p = buf;

218 219
	for (i = 0; i < key->conf.keylen; i++)
		p += scnprintf(p, bufsize + buf - p, "%02x", key->conf.key[i]);
J
Jiri Benc 已提交
220 221 222 223 224 225 226 227 228 229 230
	p += scnprintf(p, bufsize+buf-p, "\n");
	res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
	kfree(buf);
	return res;
}
KEY_OPS(key);

#define DEBUGFS_ADD(name) \
	key->debugfs.name = debugfs_create_file(#name, 0400,\
				key->debugfs.dir, key, &key_##name##_ops);

231 232
void ieee80211_debugfs_key_add(struct ieee80211_key *key)
  {
J
Johannes Berg 已提交
233
	static int keycount;
234 235
	char buf[50];
	struct sta_info *sta;
J
Jiri Benc 已提交
236

237
	if (!key->local->debugfs.keys)
J
Jiri Benc 已提交
238 239
		return;

J
Johannes Berg 已提交
240
	sprintf(buf, "%d", keycount);
241
	key->debugfs.cnt = keycount;
J
Johannes Berg 已提交
242
	keycount++;
J
Jiri Benc 已提交
243
	key->debugfs.dir = debugfs_create_dir(buf,
244
					key->local->debugfs.keys);
J
Jiri Benc 已提交
245 246 247 248

	if (!key->debugfs.dir)
		return;

249 250 251
	rcu_read_lock();
	sta = rcu_dereference(key->sta);
	if (sta)
252
		sprintf(buf, "../../stations/%pM", sta->sta.addr);
253 254 255 256 257 258 259
	rcu_read_unlock();

	/* using sta as a boolean is fine outside RCU lock */
	if (sta)
		key->debugfs.stalink =
			debugfs_create_symlink("station", key->debugfs.dir, buf);

J
Jiri Benc 已提交
260
	DEBUGFS_ADD(keylen);
261
	DEBUGFS_ADD(flags);
J
Jiri Benc 已提交
262 263 264 265 266 267 268
	DEBUGFS_ADD(keyidx);
	DEBUGFS_ADD(hw_key_idx);
	DEBUGFS_ADD(tx_rx_count);
	DEBUGFS_ADD(algorithm);
	DEBUGFS_ADD(tx_spec);
	DEBUGFS_ADD(rx_spec);
	DEBUGFS_ADD(replays);
269
	DEBUGFS_ADD(icverrors);
J
Jiri Benc 已提交
270
	DEBUGFS_ADD(key);
271
	DEBUGFS_ADD(ifindex);
J
Jiri Benc 已提交
272 273 274 275 276 277 278 279 280 281 282
};

#define DEBUGFS_DEL(name) \
	debugfs_remove(key->debugfs.name); key->debugfs.name = NULL;

void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
{
	if (!key)
		return;

	DEBUGFS_DEL(keylen);
283
	DEBUGFS_DEL(flags);
J
Jiri Benc 已提交
284 285 286 287 288 289 290
	DEBUGFS_DEL(keyidx);
	DEBUGFS_DEL(hw_key_idx);
	DEBUGFS_DEL(tx_rx_count);
	DEBUGFS_DEL(algorithm);
	DEBUGFS_DEL(tx_spec);
	DEBUGFS_DEL(rx_spec);
	DEBUGFS_DEL(replays);
291
	DEBUGFS_DEL(icverrors);
J
Jiri Benc 已提交
292
	DEBUGFS_DEL(key);
293
	DEBUGFS_DEL(ifindex);
J
Jiri Benc 已提交
294 295 296 297 298 299 300 301 302

	debugfs_remove(key->debugfs.stalink);
	key->debugfs.stalink = NULL;
	debugfs_remove(key->debugfs.dir);
	key->debugfs.dir = NULL;
}
void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata)
{
	char buf[50];
303
	struct ieee80211_key *key;
J
Jiri Benc 已提交
304 305 306 307

	if (!sdata->debugfsdir)
		return;

308 309 310 311 312
	/* this is running under the key lock */

	key = sdata->default_key;
	if (key) {
		sprintf(buf, "../keys/%d", key->debugfs.cnt);
313
		sdata->common_debugfs.default_key =
314 315 316 317
			debugfs_create_symlink("default_key",
					       sdata->debugfsdir, buf);
	} else
		ieee80211_debugfs_key_remove_default(sdata);
J
Jiri Benc 已提交
318
}
319

J
Jiri Benc 已提交
320 321 322 323 324
void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata)
{
	if (!sdata)
		return;

325 326
	debugfs_remove(sdata->common_debugfs.default_key);
	sdata->common_debugfs.default_key = NULL;
J
Jiri Benc 已提交
327 328
}

329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata)
{
	char buf[50];
	struct ieee80211_key *key;

	if (!sdata->debugfsdir)
		return;

	/* this is running under the key lock */

	key = sdata->default_mgmt_key;
	if (key) {
		sprintf(buf, "../keys/%d", key->debugfs.cnt);
		sdata->common_debugfs.default_mgmt_key =
			debugfs_create_symlink("default_mgmt_key",
					       sdata->debugfsdir, buf);
	} else
		ieee80211_debugfs_key_remove_mgmt_default(sdata);
}

void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sdata)
{
	if (!sdata)
		return;

	debugfs_remove(sdata->common_debugfs.default_mgmt_key);
	sdata->common_debugfs.default_mgmt_key = NULL;
}

J
Jiri Benc 已提交
358 359 360 361 362 363
void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
				   struct sta_info *sta)
{
	debugfs_remove(key->debugfs.stalink);
	key->debugfs.stalink = NULL;
}