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 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/kobject.h>
12#include "ieee80211_i.h"
13#include "ieee80211_key.h"
14#include "debugfs.h"
15#include "debugfs_key.h"
16
17#define KEY_READ(name, buflen, format_string)				\
18static ssize_t key_##name##_read(struct file *file,			\
19				 char __user *userbuf,			\
20				 size_t count, loff_t *ppos)		\
21{									\
22	char buf[buflen];						\
23	struct ieee80211_key *key = file->private_data;			\
24	int res = scnprintf(buf, buflen, format_string, key->name);	\
25	return simple_read_from_buffer(userbuf, count, ppos, buf, res);	\
26}
27#define KEY_READ_D(name) KEY_READ(name, 20, "%d\n")
28
29#define KEY_OPS(name)							\
30static const struct file_operations key_ ##name## _ops = {		\
31	.read = key_##name##_read,					\
32	.open = mac80211_open_file_generic,				\
33}
34
35#define KEY_FILE(name, format)						\
36		 KEY_READ_##format(name)				\
37		 KEY_OPS(name)
38
39KEY_FILE(keylen, D);
40KEY_FILE(force_sw_encrypt, D);
41KEY_FILE(keyidx, D);
42KEY_FILE(hw_key_idx, D);
43KEY_FILE(tx_rx_count, D);
44
45static ssize_t key_algorithm_read(struct file *file,
46				  char __user *userbuf,
47				  size_t count, loff_t *ppos)
48{
49	char *alg;
50	struct ieee80211_key *key = file->private_data;
51
52	switch (key->alg) {
53	case ALG_WEP:
54		alg = "WEP\n";
55		break;
56	case ALG_TKIP:
57		alg = "TKIP\n";
58		break;
59	case ALG_CCMP:
60		alg = "CCMP\n";
61		break;
62	default:
63		return 0;
64	}
65	return simple_read_from_buffer(userbuf, count, ppos, alg, strlen(alg));
66}
67KEY_OPS(algorithm);
68
69static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
70				size_t count, loff_t *ppos)
71{
72	const u8 *tpn;
73	char buf[20];
74	int len;
75	struct ieee80211_key *key = file->private_data;
76
77	switch (key->alg) {
78	case ALG_WEP:
79		len = scnprintf(buf, sizeof(buf), "\n");
80	case ALG_TKIP:
81		len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
82				key->u.tkip.iv32,
83				key->u.tkip.iv16);
84	case ALG_CCMP:
85		tpn = key->u.ccmp.tx_pn;
86		len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
87				tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
88	default:
89		return 0;
90	}
91	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
92}
93KEY_OPS(tx_spec);
94
95static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
96				size_t count, loff_t *ppos)
97{
98	struct ieee80211_key *key = file->private_data;
99	char buf[14*NUM_RX_DATA_QUEUES+1], *p = buf;
100	int i, len;
101	const u8 *rpn;
102
103	switch (key->alg) {
104	case ALG_WEP:
105		len = scnprintf(buf, sizeof(buf), "\n");
106	case ALG_TKIP:
107		for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
108			p += scnprintf(p, sizeof(buf)+buf-p,
109				       "%08x %04x\n",
110				       key->u.tkip.iv32_rx[i],
111				       key->u.tkip.iv16_rx[i]);
112		len = p - buf;
113	case ALG_CCMP:
114		for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
115			rpn = key->u.ccmp.rx_pn[i];
116			p += scnprintf(p, sizeof(buf)+buf-p,
117				       "%02x%02x%02x%02x%02x%02x\n",
118				       rpn[0], rpn[1], rpn[2],
119				       rpn[3], rpn[4], rpn[5]);
120		}
121		len = p - buf;
122	default:
123		return 0;
124	}
125	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
126}
127KEY_OPS(rx_spec);
128
129static ssize_t key_replays_read(struct file *file, char __user *userbuf,
130				size_t count, loff_t *ppos)
131{
132	struct ieee80211_key *key = file->private_data;
133	char buf[20];
134	int len;
135
136	if (key->alg != ALG_CCMP)
137		return 0;
138	len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
139	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
140}
141KEY_OPS(replays);
142
143static ssize_t key_key_read(struct file *file, char __user *userbuf,
144			    size_t count, loff_t *ppos)
145{
146	struct ieee80211_key *key = file->private_data;
147	int i, res, bufsize = 2*key->keylen+2;
148	char *buf = kmalloc(bufsize, GFP_KERNEL);
149	char *p = buf;
150
151	for (i = 0; i < key->keylen; i++)
152		p += scnprintf(p, bufsize+buf-p, "%02x", key->key[i]);
153	p += scnprintf(p, bufsize+buf-p, "\n");
154	res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
155	kfree(buf);
156	return res;
157}
158KEY_OPS(key);
159
160#define DEBUGFS_ADD(name) \
161	key->debugfs.name = debugfs_create_file(#name, 0400,\
162				key->debugfs.dir, key, &key_##name##_ops);
163
164void ieee80211_debugfs_key_add(struct ieee80211_local *local,
165			       struct ieee80211_key *key)
166{
167	char buf[20];
168
169	if (!local->debugfs.keys)
170		return;
171
172	sprintf(buf, "%d", key->keyidx);
173	key->debugfs.dir = debugfs_create_dir(buf,
174					local->debugfs.keys);
175
176	if (!key->debugfs.dir)
177		return;
178
179	DEBUGFS_ADD(keylen);
180	DEBUGFS_ADD(force_sw_encrypt);
181	DEBUGFS_ADD(keyidx);
182	DEBUGFS_ADD(hw_key_idx);
183	DEBUGFS_ADD(tx_rx_count);
184	DEBUGFS_ADD(algorithm);
185	DEBUGFS_ADD(tx_spec);
186	DEBUGFS_ADD(rx_spec);
187	DEBUGFS_ADD(replays);
188	DEBUGFS_ADD(key);
189};
190
191#define DEBUGFS_DEL(name) \
192	debugfs_remove(key->debugfs.name); key->debugfs.name = NULL;
193
194void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
195{
196	if (!key)
197		return;
198
199	DEBUGFS_DEL(keylen);
200	DEBUGFS_DEL(force_sw_encrypt);
201	DEBUGFS_DEL(keyidx);
202	DEBUGFS_DEL(hw_key_idx);
203	DEBUGFS_DEL(tx_rx_count);
204	DEBUGFS_DEL(algorithm);
205	DEBUGFS_DEL(tx_spec);
206	DEBUGFS_DEL(rx_spec);
207	DEBUGFS_DEL(replays);
208	DEBUGFS_DEL(key);
209
210	debugfs_remove(key->debugfs.stalink);
211	key->debugfs.stalink = NULL;
212	debugfs_remove(key->debugfs.dir);
213	key->debugfs.dir = NULL;
214}
215void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata)
216{
217	char buf[50];
218
219	if (!sdata->debugfsdir)
220		return;
221
222	sprintf(buf, "../keys/%d", sdata->default_key->keyidx);
223	sdata->debugfs.default_key =
224		debugfs_create_symlink("default_key", sdata->debugfsdir, buf);
225}
226void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata)
227{
228	if (!sdata)
229		return;
230
231	debugfs_remove(sdata->debugfs.default_key);
232	sdata->debugfs.default_key = NULL;
233}
234void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key,
235				    struct sta_info *sta)
236{
237	char buf[50];
238
239	if (!key->debugfs.dir)
240		return;
241
242	sprintf(buf, "../sta/" MAC_FMT, MAC_ARG(sta->addr));
243	key->debugfs.stalink =
244		debugfs_create_symlink("station", key->debugfs.dir, buf);
245}
246
247void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
248				   struct sta_info *sta)
249{
250	debugfs_remove(key->debugfs.stalink);
251	key->debugfs.stalink = NULL;
252}
253