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