Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/mac80211/debugfs_netdev.c
15109 views
1
/*
2
* Copyright (c) 2006 Jiri Benc <[email protected]>
3
* Copyright 2007 Johannes Berg <[email protected]>
4
*
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License version 2 as
7
* published by the Free Software Foundation.
8
*/
9
10
#include <linux/kernel.h>
11
#include <linux/device.h>
12
#include <linux/if.h>
13
#include <linux/interrupt.h>
14
#include <linux/netdevice.h>
15
#include <linux/rtnetlink.h>
16
#include <linux/slab.h>
17
#include <linux/notifier.h>
18
#include <net/mac80211.h>
19
#include <net/cfg80211.h>
20
#include "ieee80211_i.h"
21
#include "rate.h"
22
#include "debugfs.h"
23
#include "debugfs_netdev.h"
24
25
static ssize_t ieee80211_if_read(
26
struct ieee80211_sub_if_data *sdata,
27
char __user *userbuf,
28
size_t count, loff_t *ppos,
29
ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int))
30
{
31
char buf[70];
32
ssize_t ret = -EINVAL;
33
34
read_lock(&dev_base_lock);
35
if (sdata->dev->reg_state == NETREG_REGISTERED)
36
ret = (*format)(sdata, buf, sizeof(buf));
37
read_unlock(&dev_base_lock);
38
39
if (ret >= 0)
40
ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
41
42
return ret;
43
}
44
45
static ssize_t ieee80211_if_write(
46
struct ieee80211_sub_if_data *sdata,
47
const char __user *userbuf,
48
size_t count, loff_t *ppos,
49
ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int))
50
{
51
u8 *buf;
52
ssize_t ret;
53
54
buf = kmalloc(count, GFP_KERNEL);
55
if (!buf)
56
return -ENOMEM;
57
58
ret = -EFAULT;
59
if (copy_from_user(buf, userbuf, count))
60
goto freebuf;
61
62
ret = -ENODEV;
63
rtnl_lock();
64
if (sdata->dev->reg_state == NETREG_REGISTERED)
65
ret = (*write)(sdata, buf, count);
66
rtnl_unlock();
67
68
freebuf:
69
kfree(buf);
70
return ret;
71
}
72
73
#define IEEE80211_IF_FMT(name, field, format_string) \
74
static ssize_t ieee80211_if_fmt_##name( \
75
const struct ieee80211_sub_if_data *sdata, char *buf, \
76
int buflen) \
77
{ \
78
return scnprintf(buf, buflen, format_string, sdata->field); \
79
}
80
#define IEEE80211_IF_FMT_DEC(name, field) \
81
IEEE80211_IF_FMT(name, field, "%d\n")
82
#define IEEE80211_IF_FMT_HEX(name, field) \
83
IEEE80211_IF_FMT(name, field, "%#x\n")
84
#define IEEE80211_IF_FMT_LHEX(name, field) \
85
IEEE80211_IF_FMT(name, field, "%#lx\n")
86
#define IEEE80211_IF_FMT_SIZE(name, field) \
87
IEEE80211_IF_FMT(name, field, "%zd\n")
88
89
#define IEEE80211_IF_FMT_ATOMIC(name, field) \
90
static ssize_t ieee80211_if_fmt_##name( \
91
const struct ieee80211_sub_if_data *sdata, \
92
char *buf, int buflen) \
93
{ \
94
return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\
95
}
96
97
#define IEEE80211_IF_FMT_MAC(name, field) \
98
static ssize_t ieee80211_if_fmt_##name( \
99
const struct ieee80211_sub_if_data *sdata, char *buf, \
100
int buflen) \
101
{ \
102
return scnprintf(buf, buflen, "%pM\n", sdata->field); \
103
}
104
105
#define IEEE80211_IF_FMT_DEC_DIV_16(name, field) \
106
static ssize_t ieee80211_if_fmt_##name( \
107
const struct ieee80211_sub_if_data *sdata, \
108
char *buf, int buflen) \
109
{ \
110
return scnprintf(buf, buflen, "%d\n", sdata->field / 16); \
111
}
112
113
#define __IEEE80211_IF_FILE(name, _write) \
114
static ssize_t ieee80211_if_read_##name(struct file *file, \
115
char __user *userbuf, \
116
size_t count, loff_t *ppos) \
117
{ \
118
return ieee80211_if_read(file->private_data, \
119
userbuf, count, ppos, \
120
ieee80211_if_fmt_##name); \
121
} \
122
static const struct file_operations name##_ops = { \
123
.read = ieee80211_if_read_##name, \
124
.write = (_write), \
125
.open = mac80211_open_file_generic, \
126
.llseek = generic_file_llseek, \
127
}
128
129
#define __IEEE80211_IF_FILE_W(name) \
130
static ssize_t ieee80211_if_write_##name(struct file *file, \
131
const char __user *userbuf, \
132
size_t count, loff_t *ppos) \
133
{ \
134
return ieee80211_if_write(file->private_data, userbuf, count, \
135
ppos, ieee80211_if_parse_##name); \
136
} \
137
__IEEE80211_IF_FILE(name, ieee80211_if_write_##name)
138
139
140
#define IEEE80211_IF_FILE(name, field, format) \
141
IEEE80211_IF_FMT_##format(name, field) \
142
__IEEE80211_IF_FILE(name, NULL)
143
144
/* common attributes */
145
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
146
IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ],
147
HEX);
148
IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
149
HEX);
150
IEEE80211_IF_FILE(flags, flags, HEX);
151
IEEE80211_IF_FILE(state, state, LHEX);
152
IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC);
153
154
/* STA attributes */
155
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
156
IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
157
IEEE80211_IF_FILE(last_beacon, u.mgd.last_beacon_signal, DEC);
158
IEEE80211_IF_FILE(ave_beacon, u.mgd.ave_beacon_signal, DEC_DIV_16);
159
160
static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
161
enum ieee80211_smps_mode smps_mode)
162
{
163
struct ieee80211_local *local = sdata->local;
164
int err;
165
166
if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) &&
167
smps_mode == IEEE80211_SMPS_STATIC)
168
return -EINVAL;
169
170
/* auto should be dynamic if in PS mode */
171
if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) &&
172
(smps_mode == IEEE80211_SMPS_DYNAMIC ||
173
smps_mode == IEEE80211_SMPS_AUTOMATIC))
174
return -EINVAL;
175
176
/* supported only on managed interfaces for now */
177
if (sdata->vif.type != NL80211_IFTYPE_STATION)
178
return -EOPNOTSUPP;
179
180
mutex_lock(&sdata->u.mgd.mtx);
181
err = __ieee80211_request_smps(sdata, smps_mode);
182
mutex_unlock(&sdata->u.mgd.mtx);
183
184
return err;
185
}
186
187
static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
188
[IEEE80211_SMPS_AUTOMATIC] = "auto",
189
[IEEE80211_SMPS_OFF] = "off",
190
[IEEE80211_SMPS_STATIC] = "static",
191
[IEEE80211_SMPS_DYNAMIC] = "dynamic",
192
};
193
194
static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
195
char *buf, int buflen)
196
{
197
if (sdata->vif.type != NL80211_IFTYPE_STATION)
198
return -EOPNOTSUPP;
199
200
return snprintf(buf, buflen, "request: %s\nused: %s\n",
201
smps_modes[sdata->u.mgd.req_smps],
202
smps_modes[sdata->u.mgd.ap_smps]);
203
}
204
205
static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
206
const char *buf, int buflen)
207
{
208
enum ieee80211_smps_mode mode;
209
210
for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) {
211
if (strncmp(buf, smps_modes[mode], buflen) == 0) {
212
int err = ieee80211_set_smps(sdata, mode);
213
if (!err)
214
return buflen;
215
return err;
216
}
217
}
218
219
return -EINVAL;
220
}
221
222
__IEEE80211_IF_FILE_W(smps);
223
224
static ssize_t ieee80211_if_fmt_tkip_mic_test(
225
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
226
{
227
return -EOPNOTSUPP;
228
}
229
230
static int hwaddr_aton(const char *txt, u8 *addr)
231
{
232
int i;
233
234
for (i = 0; i < ETH_ALEN; i++) {
235
int a, b;
236
237
a = hex_to_bin(*txt++);
238
if (a < 0)
239
return -1;
240
b = hex_to_bin(*txt++);
241
if (b < 0)
242
return -1;
243
*addr++ = (a << 4) | b;
244
if (i < 5 && *txt++ != ':')
245
return -1;
246
}
247
248
return 0;
249
}
250
251
static ssize_t ieee80211_if_parse_tkip_mic_test(
252
struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
253
{
254
struct ieee80211_local *local = sdata->local;
255
u8 addr[ETH_ALEN];
256
struct sk_buff *skb;
257
struct ieee80211_hdr *hdr;
258
__le16 fc;
259
260
/*
261
* Assume colon-delimited MAC address with possible white space
262
* following.
263
*/
264
if (buflen < 3 * ETH_ALEN - 1)
265
return -EINVAL;
266
if (hwaddr_aton(buf, addr) < 0)
267
return -EINVAL;
268
269
if (!ieee80211_sdata_running(sdata))
270
return -ENOTCONN;
271
272
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24 + 100);
273
if (!skb)
274
return -ENOMEM;
275
skb_reserve(skb, local->hw.extra_tx_headroom);
276
277
hdr = (struct ieee80211_hdr *) skb_put(skb, 24);
278
memset(hdr, 0, 24);
279
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
280
281
switch (sdata->vif.type) {
282
case NL80211_IFTYPE_AP:
283
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
284
/* DA BSSID SA */
285
memcpy(hdr->addr1, addr, ETH_ALEN);
286
memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
287
memcpy(hdr->addr3, sdata->vif.addr, ETH_ALEN);
288
break;
289
case NL80211_IFTYPE_STATION:
290
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
291
/* BSSID SA DA */
292
if (sdata->vif.bss_conf.bssid == NULL) {
293
dev_kfree_skb(skb);
294
return -ENOTCONN;
295
}
296
memcpy(hdr->addr1, sdata->vif.bss_conf.bssid, ETH_ALEN);
297
memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
298
memcpy(hdr->addr3, addr, ETH_ALEN);
299
break;
300
default:
301
dev_kfree_skb(skb);
302
return -EOPNOTSUPP;
303
}
304
hdr->frame_control = fc;
305
306
/*
307
* Add some length to the test frame to make it look bit more valid.
308
* The exact contents does not matter since the recipient is required
309
* to drop this because of the Michael MIC failure.
310
*/
311
memset(skb_put(skb, 50), 0, 50);
312
313
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_TKIP_MIC_FAILURE;
314
315
ieee80211_tx_skb(sdata, skb);
316
317
return buflen;
318
}
319
320
__IEEE80211_IF_FILE_W(tkip_mic_test);
321
322
/* AP attributes */
323
IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
324
IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
325
326
static ssize_t ieee80211_if_fmt_num_buffered_multicast(
327
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
328
{
329
return scnprintf(buf, buflen, "%u\n",
330
skb_queue_len(&sdata->u.ap.ps_bc_buf));
331
}
332
__IEEE80211_IF_FILE(num_buffered_multicast, NULL);
333
334
/* WDS attributes */
335
IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
336
337
#ifdef CONFIG_MAC80211_MESH
338
/* Mesh stats attributes */
339
IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC);
340
IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
341
IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
342
IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
343
IEEE80211_IF_FILE(dropped_frames_no_route,
344
u.mesh.mshstats.dropped_frames_no_route, DEC);
345
IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);
346
347
/* Mesh parameters */
348
IEEE80211_IF_FILE(dot11MeshMaxRetries,
349
u.mesh.mshcfg.dot11MeshMaxRetries, DEC);
350
IEEE80211_IF_FILE(dot11MeshRetryTimeout,
351
u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);
352
IEEE80211_IF_FILE(dot11MeshConfirmTimeout,
353
u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);
354
IEEE80211_IF_FILE(dot11MeshHoldingTimeout,
355
u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
356
IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC);
357
IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC);
358
IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC);
359
IEEE80211_IF_FILE(dot11MeshMaxPeerLinks,
360
u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
361
IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout,
362
u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
363
IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval,
364
u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
365
IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime,
366
u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
367
IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries,
368
u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);
369
IEEE80211_IF_FILE(path_refresh_time,
370
u.mesh.mshcfg.path_refresh_time, DEC);
371
IEEE80211_IF_FILE(min_discovery_timeout,
372
u.mesh.mshcfg.min_discovery_timeout, DEC);
373
IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
374
u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
375
#endif
376
377
378
#define DEBUGFS_ADD(name) \
379
debugfs_create_file(#name, 0400, sdata->debugfs.dir, \
380
sdata, &name##_ops);
381
382
#define DEBUGFS_ADD_MODE(name, mode) \
383
debugfs_create_file(#name, mode, sdata->debugfs.dir, \
384
sdata, &name##_ops);
385
386
static void add_sta_files(struct ieee80211_sub_if_data *sdata)
387
{
388
DEBUGFS_ADD(drop_unencrypted);
389
DEBUGFS_ADD(flags);
390
DEBUGFS_ADD(state);
391
DEBUGFS_ADD(channel_type);
392
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
393
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
394
395
DEBUGFS_ADD(bssid);
396
DEBUGFS_ADD(aid);
397
DEBUGFS_ADD(last_beacon);
398
DEBUGFS_ADD(ave_beacon);
399
DEBUGFS_ADD_MODE(smps, 0600);
400
DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
401
}
402
403
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
404
{
405
DEBUGFS_ADD(drop_unencrypted);
406
DEBUGFS_ADD(flags);
407
DEBUGFS_ADD(state);
408
DEBUGFS_ADD(channel_type);
409
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
410
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
411
412
DEBUGFS_ADD(num_sta_ps);
413
DEBUGFS_ADD(dtim_count);
414
DEBUGFS_ADD(num_buffered_multicast);
415
DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
416
}
417
418
static void add_wds_files(struct ieee80211_sub_if_data *sdata)
419
{
420
DEBUGFS_ADD(drop_unencrypted);
421
DEBUGFS_ADD(flags);
422
DEBUGFS_ADD(state);
423
DEBUGFS_ADD(channel_type);
424
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
425
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
426
427
DEBUGFS_ADD(peer);
428
}
429
430
static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
431
{
432
DEBUGFS_ADD(drop_unencrypted);
433
DEBUGFS_ADD(flags);
434
DEBUGFS_ADD(state);
435
DEBUGFS_ADD(channel_type);
436
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
437
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
438
}
439
440
static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
441
{
442
DEBUGFS_ADD(flags);
443
DEBUGFS_ADD(state);
444
DEBUGFS_ADD(channel_type);
445
}
446
447
#ifdef CONFIG_MAC80211_MESH
448
449
static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
450
{
451
struct dentry *dir = debugfs_create_dir("mesh_stats",
452
sdata->debugfs.dir);
453
454
#define MESHSTATS_ADD(name)\
455
debugfs_create_file(#name, 0400, dir, sdata, &name##_ops);
456
457
MESHSTATS_ADD(fwded_mcast);
458
MESHSTATS_ADD(fwded_unicast);
459
MESHSTATS_ADD(fwded_frames);
460
MESHSTATS_ADD(dropped_frames_ttl);
461
MESHSTATS_ADD(dropped_frames_no_route);
462
MESHSTATS_ADD(estab_plinks);
463
#undef MESHSTATS_ADD
464
}
465
466
static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
467
{
468
struct dentry *dir = debugfs_create_dir("mesh_config",
469
sdata->debugfs.dir);
470
471
#define MESHPARAMS_ADD(name) \
472
debugfs_create_file(#name, 0600, dir, sdata, &name##_ops);
473
474
MESHPARAMS_ADD(dot11MeshMaxRetries);
475
MESHPARAMS_ADD(dot11MeshRetryTimeout);
476
MESHPARAMS_ADD(dot11MeshConfirmTimeout);
477
MESHPARAMS_ADD(dot11MeshHoldingTimeout);
478
MESHPARAMS_ADD(dot11MeshTTL);
479
MESHPARAMS_ADD(element_ttl);
480
MESHPARAMS_ADD(auto_open_plinks);
481
MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
482
MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
483
MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval);
484
MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime);
485
MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
486
MESHPARAMS_ADD(path_refresh_time);
487
MESHPARAMS_ADD(min_discovery_timeout);
488
489
#undef MESHPARAMS_ADD
490
}
491
#endif
492
493
static void add_files(struct ieee80211_sub_if_data *sdata)
494
{
495
if (!sdata->debugfs.dir)
496
return;
497
498
switch (sdata->vif.type) {
499
case NL80211_IFTYPE_MESH_POINT:
500
#ifdef CONFIG_MAC80211_MESH
501
add_mesh_stats(sdata);
502
add_mesh_config(sdata);
503
#endif
504
break;
505
case NL80211_IFTYPE_STATION:
506
add_sta_files(sdata);
507
break;
508
case NL80211_IFTYPE_ADHOC:
509
/* XXX */
510
break;
511
case NL80211_IFTYPE_AP:
512
add_ap_files(sdata);
513
break;
514
case NL80211_IFTYPE_WDS:
515
add_wds_files(sdata);
516
break;
517
case NL80211_IFTYPE_MONITOR:
518
add_monitor_files(sdata);
519
break;
520
case NL80211_IFTYPE_AP_VLAN:
521
add_vlan_files(sdata);
522
break;
523
default:
524
break;
525
}
526
}
527
528
void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
529
{
530
char buf[10+IFNAMSIZ];
531
532
sprintf(buf, "netdev:%s", sdata->name);
533
sdata->debugfs.dir = debugfs_create_dir(buf,
534
sdata->local->hw.wiphy->debugfsdir);
535
if (sdata->debugfs.dir)
536
sdata->debugfs.subdir_stations = debugfs_create_dir("stations",
537
sdata->debugfs.dir);
538
add_files(sdata);
539
}
540
541
void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
542
{
543
if (!sdata->debugfs.dir)
544
return;
545
546
debugfs_remove_recursive(sdata->debugfs.dir);
547
sdata->debugfs.dir = NULL;
548
}
549
550
void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
551
{
552
struct dentry *dir;
553
char buf[10 + IFNAMSIZ];
554
555
dir = sdata->debugfs.dir;
556
557
if (!dir)
558
return;
559
560
sprintf(buf, "netdev:%s", sdata->name);
561
if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
562
printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
563
"dir to %s\n", buf);
564
}
565
566