Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * Copyright 2003-2005 Devicescape Software, Inc.
4 : : * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
5 : : * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
6 : : * Copyright (C) 2015 Intel Deutschland GmbH
7 : : */
8 : :
9 : : #include <linux/kobject.h>
10 : : #include <linux/slab.h>
11 : : #include "ieee80211_i.h"
12 : : #include "key.h"
13 : : #include "debugfs.h"
14 : : #include "debugfs_key.h"
15 : :
16 : : #define KEY_READ(name, prop, format_string) \
17 : : static ssize_t key_##name##_read(struct file *file, \
18 : : char __user *userbuf, \
19 : : size_t count, loff_t *ppos) \
20 : : { \
21 : : struct ieee80211_key *key = file->private_data; \
22 : : return mac80211_format_buffer(userbuf, count, ppos, \
23 : : format_string, key->prop); \
24 : : }
25 : : #define KEY_READ_D(name) KEY_READ(name, name, "%d\n")
26 : : #define KEY_READ_X(name) KEY_READ(name, name, "0x%x\n")
27 : :
28 : : #define KEY_OPS(name) \
29 : : static const struct file_operations key_ ##name## _ops = { \
30 : : .read = key_##name##_read, \
31 : : .open = simple_open, \
32 : : .llseek = generic_file_llseek, \
33 : : }
34 : :
35 : : #define KEY_OPS_W(name) \
36 : : static const struct file_operations key_ ##name## _ops = { \
37 : : .read = key_##name##_read, \
38 : : .write = key_##name##_write, \
39 : : .open = simple_open, \
40 : : .llseek = generic_file_llseek, \
41 : : }
42 : :
43 : : #define KEY_FILE(name, format) \
44 : : KEY_READ_##format(name) \
45 : : KEY_OPS(name)
46 : :
47 : : #define KEY_CONF_READ(name, format_string) \
48 : : KEY_READ(conf_##name, conf.name, format_string)
49 : : #define KEY_CONF_READ_D(name) KEY_CONF_READ(name, "%d\n")
50 : :
51 : : #define KEY_CONF_OPS(name) \
52 : : static const struct file_operations key_ ##name## _ops = { \
53 : : .read = key_conf_##name##_read, \
54 : : .open = simple_open, \
55 : : .llseek = generic_file_llseek, \
56 : : }
57 : :
58 : : #define KEY_CONF_FILE(name, format) \
59 : : KEY_CONF_READ_##format(name) \
60 : : KEY_CONF_OPS(name)
61 : :
62 : 0 : KEY_CONF_FILE(keylen, D);
63 : 0 : KEY_CONF_FILE(keyidx, D);
64 : 0 : KEY_CONF_FILE(hw_key_idx, D);
65 : 0 : KEY_FILE(flags, X);
66 : 0 : KEY_READ(ifindex, sdata->name, "%s\n");
67 : : KEY_OPS(ifindex);
68 : :
69 : 0 : static ssize_t key_algorithm_read(struct file *file,
70 : : char __user *userbuf,
71 : : size_t count, loff_t *ppos)
72 : : {
73 : 0 : char buf[15];
74 : 0 : struct ieee80211_key *key = file->private_data;
75 : 0 : u32 c = key->conf.cipher;
76 : :
77 : 0 : sprintf(buf, "%.2x-%.2x-%.2x:%d\n",
78 : 0 : c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
79 : 0 : return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
80 : : }
81 : : KEY_OPS(algorithm);
82 : :
83 : 0 : static ssize_t key_tx_spec_write(struct file *file, const char __user *userbuf,
84 : : size_t count, loff_t *ppos)
85 : : {
86 : 0 : struct ieee80211_key *key = file->private_data;
87 : 0 : u64 pn;
88 : 0 : int ret;
89 : :
90 [ # # # # ]: 0 : switch (key->conf.cipher) {
91 : : case WLAN_CIPHER_SUITE_WEP40:
92 : : case WLAN_CIPHER_SUITE_WEP104:
93 : : return -EINVAL;
94 : 0 : case WLAN_CIPHER_SUITE_TKIP:
95 : : /* not supported yet */
96 : 0 : return -EOPNOTSUPP;
97 : : case WLAN_CIPHER_SUITE_CCMP:
98 : : case WLAN_CIPHER_SUITE_CCMP_256:
99 : : case WLAN_CIPHER_SUITE_AES_CMAC:
100 : : case WLAN_CIPHER_SUITE_BIP_CMAC_256:
101 : : case WLAN_CIPHER_SUITE_BIP_GMAC_128:
102 : : case WLAN_CIPHER_SUITE_BIP_GMAC_256:
103 : : case WLAN_CIPHER_SUITE_GCMP:
104 : : case WLAN_CIPHER_SUITE_GCMP_256:
105 : 0 : ret = kstrtou64_from_user(userbuf, count, 16, &pn);
106 [ # # ]: 0 : if (ret)
107 : 0 : return ret;
108 : : /* PN is a 48-bit counter */
109 [ # # ]: 0 : if (pn >= (1ULL << 48))
110 : : return -ERANGE;
111 : 0 : atomic64_set(&key->conf.tx_pn, pn);
112 : 0 : return count;
113 : 0 : default:
114 : 0 : return 0;
115 : : }
116 : : }
117 : :
118 : 0 : static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
119 : : size_t count, loff_t *ppos)
120 : : {
121 : 0 : u64 pn;
122 : 0 : char buf[20];
123 : 0 : int len;
124 : 0 : struct ieee80211_key *key = file->private_data;
125 : :
126 [ # # # # ]: 0 : switch (key->conf.cipher) {
127 : 0 : case WLAN_CIPHER_SUITE_WEP40:
128 : : case WLAN_CIPHER_SUITE_WEP104:
129 : 0 : len = scnprintf(buf, sizeof(buf), "\n");
130 : 0 : break;
131 : 0 : case WLAN_CIPHER_SUITE_TKIP:
132 : 0 : pn = atomic64_read(&key->conf.tx_pn);
133 : 0 : len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
134 : 0 : TKIP_PN_TO_IV32(pn),
135 : 0 : TKIP_PN_TO_IV16(pn));
136 : 0 : break;
137 : 0 : case WLAN_CIPHER_SUITE_CCMP:
138 : : case WLAN_CIPHER_SUITE_CCMP_256:
139 : : case WLAN_CIPHER_SUITE_AES_CMAC:
140 : : case WLAN_CIPHER_SUITE_BIP_CMAC_256:
141 : : case WLAN_CIPHER_SUITE_BIP_GMAC_128:
142 : : case WLAN_CIPHER_SUITE_BIP_GMAC_256:
143 : : case WLAN_CIPHER_SUITE_GCMP:
144 : : case WLAN_CIPHER_SUITE_GCMP_256:
145 : 0 : pn = atomic64_read(&key->conf.tx_pn);
146 : 0 : len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
147 : 0 : (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24),
148 : 0 : (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn);
149 : 0 : break;
150 : : default:
151 : : return 0;
152 : : }
153 : 0 : return simple_read_from_buffer(userbuf, count, ppos, buf, len);
154 : : }
155 : : KEY_OPS_W(tx_spec);
156 : :
157 : 0 : static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
158 : : size_t count, loff_t *ppos)
159 : : {
160 : 0 : struct ieee80211_key *key = file->private_data;
161 : 0 : char buf[14*IEEE80211_NUM_TIDS+1], *p = buf;
162 : 0 : int i, len;
163 : 0 : const u8 *rpn;
164 : :
165 [ # # # # : 0 : switch (key->conf.cipher) {
# # # ]
166 : 0 : case WLAN_CIPHER_SUITE_WEP40:
167 : : case WLAN_CIPHER_SUITE_WEP104:
168 : 0 : len = scnprintf(buf, sizeof(buf), "\n");
169 : 0 : break;
170 : : case WLAN_CIPHER_SUITE_TKIP:
171 [ # # ]: 0 : for (i = 0; i < IEEE80211_NUM_TIDS; i++)
172 : 0 : p += scnprintf(p, sizeof(buf)+buf-p,
173 : : "%08x %04x\n",
174 : : key->u.tkip.rx[i].iv32,
175 : 0 : key->u.tkip.rx[i].iv16);
176 : 0 : len = p - buf;
177 : 0 : break;
178 : : case WLAN_CIPHER_SUITE_CCMP:
179 : : case WLAN_CIPHER_SUITE_CCMP_256:
180 [ # # ]: 0 : for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) {
181 : 0 : rpn = key->u.ccmp.rx_pn[i];
182 : 0 : p += scnprintf(p, sizeof(buf)+buf-p,
183 : : "%02x%02x%02x%02x%02x%02x\n",
184 : 0 : rpn[0], rpn[1], rpn[2],
185 : 0 : rpn[3], rpn[4], rpn[5]);
186 : : }
187 : 0 : len = p - buf;
188 : 0 : break;
189 : 0 : case WLAN_CIPHER_SUITE_AES_CMAC:
190 : : case WLAN_CIPHER_SUITE_BIP_CMAC_256:
191 : 0 : rpn = key->u.aes_cmac.rx_pn;
192 : 0 : p += scnprintf(p, sizeof(buf)+buf-p,
193 : : "%02x%02x%02x%02x%02x%02x\n",
194 : 0 : rpn[0], rpn[1], rpn[2],
195 : 0 : rpn[3], rpn[4], rpn[5]);
196 : 0 : len = p - buf;
197 : 0 : break;
198 : 0 : case WLAN_CIPHER_SUITE_BIP_GMAC_128:
199 : : case WLAN_CIPHER_SUITE_BIP_GMAC_256:
200 : 0 : rpn = key->u.aes_gmac.rx_pn;
201 : 0 : p += scnprintf(p, sizeof(buf)+buf-p,
202 : : "%02x%02x%02x%02x%02x%02x\n",
203 : 0 : rpn[0], rpn[1], rpn[2],
204 : 0 : rpn[3], rpn[4], rpn[5]);
205 : 0 : len = p - buf;
206 : 0 : break;
207 : : case WLAN_CIPHER_SUITE_GCMP:
208 : : case WLAN_CIPHER_SUITE_GCMP_256:
209 [ # # ]: 0 : for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) {
210 : 0 : rpn = key->u.gcmp.rx_pn[i];
211 : 0 : p += scnprintf(p, sizeof(buf)+buf-p,
212 : : "%02x%02x%02x%02x%02x%02x\n",
213 : 0 : rpn[0], rpn[1], rpn[2],
214 : 0 : rpn[3], rpn[4], rpn[5]);
215 : : }
216 : 0 : len = p - buf;
217 : 0 : break;
218 : : default:
219 : : return 0;
220 : : }
221 : 0 : return simple_read_from_buffer(userbuf, count, ppos, buf, len);
222 : : }
223 : : KEY_OPS(rx_spec);
224 : :
225 : 0 : static ssize_t key_replays_read(struct file *file, char __user *userbuf,
226 : : size_t count, loff_t *ppos)
227 : : {
228 : 0 : struct ieee80211_key *key = file->private_data;
229 : 0 : char buf[20];
230 : 0 : int len;
231 : :
232 [ # # # # : 0 : switch (key->conf.cipher) {
# ]
233 : 0 : case WLAN_CIPHER_SUITE_CCMP:
234 : : case WLAN_CIPHER_SUITE_CCMP_256:
235 : 0 : len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
236 : 0 : break;
237 : 0 : case WLAN_CIPHER_SUITE_AES_CMAC:
238 : : case WLAN_CIPHER_SUITE_BIP_CMAC_256:
239 : 0 : len = scnprintf(buf, sizeof(buf), "%u\n",
240 : : key->u.aes_cmac.replays);
241 : 0 : break;
242 : 0 : case WLAN_CIPHER_SUITE_BIP_GMAC_128:
243 : : case WLAN_CIPHER_SUITE_BIP_GMAC_256:
244 : 0 : len = scnprintf(buf, sizeof(buf), "%u\n",
245 : : key->u.aes_gmac.replays);
246 : 0 : break;
247 : 0 : case WLAN_CIPHER_SUITE_GCMP:
248 : : case WLAN_CIPHER_SUITE_GCMP_256:
249 : 0 : len = scnprintf(buf, sizeof(buf), "%u\n", key->u.gcmp.replays);
250 : 0 : break;
251 : : default:
252 : : return 0;
253 : : }
254 : 0 : return simple_read_from_buffer(userbuf, count, ppos, buf, len);
255 : : }
256 : : KEY_OPS(replays);
257 : :
258 : 0 : static ssize_t key_icverrors_read(struct file *file, char __user *userbuf,
259 : : size_t count, loff_t *ppos)
260 : : {
261 : 0 : struct ieee80211_key *key = file->private_data;
262 : 0 : char buf[20];
263 : 0 : int len;
264 : :
265 [ # # # ]: 0 : switch (key->conf.cipher) {
266 : 0 : case WLAN_CIPHER_SUITE_AES_CMAC:
267 : : case WLAN_CIPHER_SUITE_BIP_CMAC_256:
268 : 0 : len = scnprintf(buf, sizeof(buf), "%u\n",
269 : : key->u.aes_cmac.icverrors);
270 : 0 : break;
271 : 0 : case WLAN_CIPHER_SUITE_BIP_GMAC_128:
272 : : case WLAN_CIPHER_SUITE_BIP_GMAC_256:
273 : 0 : len = scnprintf(buf, sizeof(buf), "%u\n",
274 : : key->u.aes_gmac.icverrors);
275 : 0 : break;
276 : : default:
277 : : return 0;
278 : : }
279 : 0 : return simple_read_from_buffer(userbuf, count, ppos, buf, len);
280 : : }
281 : : KEY_OPS(icverrors);
282 : :
283 : 0 : static ssize_t key_mic_failures_read(struct file *file, char __user *userbuf,
284 : : size_t count, loff_t *ppos)
285 : : {
286 : 0 : struct ieee80211_key *key = file->private_data;
287 : 0 : char buf[20];
288 : 0 : int len;
289 : :
290 [ # # ]: 0 : if (key->conf.cipher != WLAN_CIPHER_SUITE_TKIP)
291 : : return -EINVAL;
292 : :
293 : 0 : len = scnprintf(buf, sizeof(buf), "%u\n", key->u.tkip.mic_failures);
294 : :
295 : 0 : return simple_read_from_buffer(userbuf, count, ppos, buf, len);
296 : : }
297 : : KEY_OPS(mic_failures);
298 : :
299 : 0 : static ssize_t key_key_read(struct file *file, char __user *userbuf,
300 : : size_t count, loff_t *ppos)
301 : : {
302 : 0 : struct ieee80211_key *key = file->private_data;
303 : 0 : int i, bufsize = 2 * key->conf.keylen + 2;
304 [ # # ]: 0 : char *buf = kmalloc(bufsize, GFP_KERNEL);
305 : 0 : char *p = buf;
306 : 0 : ssize_t res;
307 : :
308 [ # # ]: 0 : if (!buf)
309 : : return -ENOMEM;
310 : :
311 [ # # ]: 0 : for (i = 0; i < key->conf.keylen; i++)
312 : 0 : p += scnprintf(p, bufsize + buf - p, "%02x", key->conf.key[i]);
313 : 0 : p += scnprintf(p, bufsize+buf-p, "\n");
314 : 0 : res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
315 : 0 : kfree(buf);
316 : 0 : return res;
317 : : }
318 : : KEY_OPS(key);
319 : :
320 : : #define DEBUGFS_ADD(name) \
321 : : debugfs_create_file(#name, 0400, key->debugfs.dir, \
322 : : key, &key_##name##_ops);
323 : : #define DEBUGFS_ADD_W(name) \
324 : : debugfs_create_file(#name, 0600, key->debugfs.dir, \
325 : : key, &key_##name##_ops);
326 : :
327 : 0 : void ieee80211_debugfs_key_add(struct ieee80211_key *key)
328 : : {
329 : 0 : static int keycount;
330 : 0 : char buf[100];
331 : 0 : struct sta_info *sta;
332 : :
333 [ # # ]: 0 : if (!key->local->debugfs.keys)
334 : 0 : return;
335 : :
336 : 0 : sprintf(buf, "%d", keycount);
337 : 0 : key->debugfs.cnt = keycount;
338 : 0 : keycount++;
339 : 0 : key->debugfs.dir = debugfs_create_dir(buf,
340 : 0 : key->local->debugfs.keys);
341 : :
342 : 0 : sta = key->sta;
343 [ # # ]: 0 : if (sta) {
344 : 0 : sprintf(buf, "../../netdev:%s/stations/%pM",
345 : 0 : sta->sdata->name, sta->sta.addr);
346 : 0 : key->debugfs.stalink =
347 : 0 : debugfs_create_symlink("station", key->debugfs.dir, buf);
348 : : }
349 : :
350 : 0 : DEBUGFS_ADD(keylen);
351 : 0 : DEBUGFS_ADD(flags);
352 : 0 : DEBUGFS_ADD(keyidx);
353 : 0 : DEBUGFS_ADD(hw_key_idx);
354 : 0 : DEBUGFS_ADD(algorithm);
355 : 0 : DEBUGFS_ADD_W(tx_spec);
356 : 0 : DEBUGFS_ADD(rx_spec);
357 : 0 : DEBUGFS_ADD(replays);
358 : 0 : DEBUGFS_ADD(icverrors);
359 : 0 : DEBUGFS_ADD(mic_failures);
360 : 0 : DEBUGFS_ADD(key);
361 : 0 : DEBUGFS_ADD(ifindex);
362 : : };
363 : :
364 : 0 : void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
365 : : {
366 [ # # ]: 0 : if (!key)
367 : : return;
368 : :
369 : 0 : debugfs_remove_recursive(key->debugfs.dir);
370 : 0 : key->debugfs.dir = NULL;
371 : : }
372 : :
373 : 0 : void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
374 : : {
375 : 0 : char buf[50];
376 : 0 : struct ieee80211_key *key;
377 : :
378 [ # # ]: 0 : if (!sdata->vif.debugfs_dir)
379 : 0 : return;
380 : :
381 : 0 : lockdep_assert_held(&sdata->local->key_mtx);
382 : :
383 : 0 : debugfs_remove(sdata->debugfs.default_unicast_key);
384 : 0 : sdata->debugfs.default_unicast_key = NULL;
385 : :
386 [ # # ]: 0 : if (sdata->default_unicast_key) {
387 : 0 : key = key_mtx_dereference(sdata->local,
388 : : sdata->default_unicast_key);
389 : 0 : sprintf(buf, "../keys/%d", key->debugfs.cnt);
390 : 0 : sdata->debugfs.default_unicast_key =
391 : 0 : debugfs_create_symlink("default_unicast_key",
392 : : sdata->vif.debugfs_dir, buf);
393 : : }
394 : :
395 : 0 : debugfs_remove(sdata->debugfs.default_multicast_key);
396 : 0 : sdata->debugfs.default_multicast_key = NULL;
397 : :
398 [ # # ]: 0 : if (sdata->default_multicast_key) {
399 : 0 : key = key_mtx_dereference(sdata->local,
400 : : sdata->default_multicast_key);
401 : 0 : sprintf(buf, "../keys/%d", key->debugfs.cnt);
402 : 0 : sdata->debugfs.default_multicast_key =
403 : 0 : debugfs_create_symlink("default_multicast_key",
404 : : sdata->vif.debugfs_dir, buf);
405 : : }
406 : : }
407 : :
408 : 0 : void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata)
409 : : {
410 : 0 : char buf[50];
411 : 0 : struct ieee80211_key *key;
412 : :
413 [ # # ]: 0 : if (!sdata->vif.debugfs_dir)
414 : 0 : return;
415 : :
416 : 0 : key = key_mtx_dereference(sdata->local,
417 : : sdata->default_mgmt_key);
418 [ # # ]: 0 : if (key) {
419 : 0 : sprintf(buf, "../keys/%d", key->debugfs.cnt);
420 : 0 : sdata->debugfs.default_mgmt_key =
421 : 0 : debugfs_create_symlink("default_mgmt_key",
422 : : sdata->vif.debugfs_dir, buf);
423 : : } else
424 : 0 : ieee80211_debugfs_key_remove_mgmt_default(sdata);
425 : : }
426 : :
427 : 0 : void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sdata)
428 : : {
429 [ # # # # ]: 0 : if (!sdata)
430 : : return;
431 : :
432 : 0 : debugfs_remove(sdata->debugfs.default_mgmt_key);
433 : 0 : sdata->debugfs.default_mgmt_key = NULL;
434 : : }
435 : :
436 : 0 : void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
437 : : struct sta_info *sta)
438 : : {
439 : 0 : debugfs_remove(key->debugfs.stalink);
440 : 0 : key->debugfs.stalink = NULL;
441 : 0 : }
|