2
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
3
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
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.
10
#include <linux/kernel.h>
11
#include <linux/device.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"
23
#include "debugfs_netdev.h"
25
static ssize_t ieee80211_if_read(
26
struct ieee80211_sub_if_data *sdata,
28
size_t count, loff_t *ppos,
29
ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int))
32
ssize_t ret = -EINVAL;
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);
40
ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
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))
54
buf = kmalloc(count, GFP_KERNEL);
59
if (copy_from_user(buf, userbuf, count))
64
if (sdata->dev->reg_state == NETREG_REGISTERED)
65
ret = (*write)(sdata, buf, count);
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, \
78
return scnprintf(buf, buflen, format_string, sdata->field); \
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")
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) \
94
return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\
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, \
102
return scnprintf(buf, buflen, "%pM\n", sdata->field); \
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) \
110
return scnprintf(buf, buflen, "%d\n", sdata->field / 16); \
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) \
118
return ieee80211_if_read(file->private_data, \
119
userbuf, count, ppos, \
120
ieee80211_if_fmt_##name); \
122
static const struct file_operations name##_ops = { \
123
.read = ieee80211_if_read_##name, \
125
.open = mac80211_open_file_generic, \
126
.llseek = generic_file_llseek, \
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) \
134
return ieee80211_if_write(file->private_data, userbuf, count, \
135
ppos, ieee80211_if_parse_##name); \
137
__IEEE80211_IF_FILE(name, ieee80211_if_write_##name)
140
#define IEEE80211_IF_FILE(name, field, format) \
141
IEEE80211_IF_FMT_##format(name, field) \
142
__IEEE80211_IF_FILE(name, NULL)
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],
148
IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
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);
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);
160
static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
161
enum ieee80211_smps_mode smps_mode)
163
struct ieee80211_local *local = sdata->local;
166
if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) &&
167
smps_mode == IEEE80211_SMPS_STATIC)
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))
176
/* supported only on managed interfaces for now */
177
if (sdata->vif.type != NL80211_IFTYPE_STATION)
180
mutex_lock(&sdata->u.mgd.mtx);
181
err = __ieee80211_request_smps(sdata, smps_mode);
182
mutex_unlock(&sdata->u.mgd.mtx);
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",
194
static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
195
char *buf, int buflen)
197
if (sdata->vif.type != NL80211_IFTYPE_STATION)
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]);
205
static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
206
const char *buf, int buflen)
208
enum ieee80211_smps_mode mode;
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);
222
__IEEE80211_IF_FILE_W(smps);
224
static ssize_t ieee80211_if_fmt_tkip_mic_test(
225
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
230
static int hwaddr_aton(const char *txt, u8 *addr)
234
for (i = 0; i < ETH_ALEN; i++) {
237
a = hex_to_bin(*txt++);
240
b = hex_to_bin(*txt++);
243
*addr++ = (a << 4) | b;
244
if (i < 5 && *txt++ != ':')
251
static ssize_t ieee80211_if_parse_tkip_mic_test(
252
struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
254
struct ieee80211_local *local = sdata->local;
257
struct ieee80211_hdr *hdr;
261
* Assume colon-delimited MAC address with possible white space
264
if (buflen < 3 * ETH_ALEN - 1)
266
if (hwaddr_aton(buf, addr) < 0)
269
if (!ieee80211_sdata_running(sdata))
272
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24 + 100);
275
skb_reserve(skb, local->hw.extra_tx_headroom);
277
hdr = (struct ieee80211_hdr *) skb_put(skb, 24);
279
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
281
switch (sdata->vif.type) {
282
case NL80211_IFTYPE_AP:
283
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
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);
289
case NL80211_IFTYPE_STATION:
290
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
292
if (sdata->vif.bss_conf.bssid == NULL) {
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);
304
hdr->frame_control = fc;
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.
311
memset(skb_put(skb, 50), 0, 50);
313
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_TKIP_MIC_FAILURE;
315
ieee80211_tx_skb(sdata, skb);
320
__IEEE80211_IF_FILE_W(tkip_mic_test);
323
IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
324
IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
326
static ssize_t ieee80211_if_fmt_num_buffered_multicast(
327
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
329
return scnprintf(buf, buflen, "%u\n",
330
skb_queue_len(&sdata->u.ap.ps_bc_buf));
332
__IEEE80211_IF_FILE(num_buffered_multicast, NULL);
335
IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
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);
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);
378
#define DEBUGFS_ADD(name) \
379
debugfs_create_file(#name, 0400, sdata->debugfs.dir, \
382
#define DEBUGFS_ADD_MODE(name, mode) \
383
debugfs_create_file(#name, mode, sdata->debugfs.dir, \
386
static void add_sta_files(struct ieee80211_sub_if_data *sdata)
388
DEBUGFS_ADD(drop_unencrypted);
391
DEBUGFS_ADD(channel_type);
392
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
393
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
397
DEBUGFS_ADD(last_beacon);
398
DEBUGFS_ADD(ave_beacon);
399
DEBUGFS_ADD_MODE(smps, 0600);
400
DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
403
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
405
DEBUGFS_ADD(drop_unencrypted);
408
DEBUGFS_ADD(channel_type);
409
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
410
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
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);
418
static void add_wds_files(struct ieee80211_sub_if_data *sdata)
420
DEBUGFS_ADD(drop_unencrypted);
423
DEBUGFS_ADD(channel_type);
424
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
425
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
430
static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
432
DEBUGFS_ADD(drop_unencrypted);
435
DEBUGFS_ADD(channel_type);
436
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
437
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
440
static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
444
DEBUGFS_ADD(channel_type);
447
#ifdef CONFIG_MAC80211_MESH
449
static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
451
struct dentry *dir = debugfs_create_dir("mesh_stats",
454
#define MESHSTATS_ADD(name)\
455
debugfs_create_file(#name, 0400, dir, sdata, &name##_ops);
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);
466
static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
468
struct dentry *dir = debugfs_create_dir("mesh_config",
471
#define MESHPARAMS_ADD(name) \
472
debugfs_create_file(#name, 0600, dir, sdata, &name##_ops);
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);
489
#undef MESHPARAMS_ADD
493
static void add_files(struct ieee80211_sub_if_data *sdata)
495
if (!sdata->debugfs.dir)
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);
505
case NL80211_IFTYPE_STATION:
506
add_sta_files(sdata);
508
case NL80211_IFTYPE_ADHOC:
511
case NL80211_IFTYPE_AP:
514
case NL80211_IFTYPE_WDS:
515
add_wds_files(sdata);
517
case NL80211_IFTYPE_MONITOR:
518
add_monitor_files(sdata);
520
case NL80211_IFTYPE_AP_VLAN:
521
add_vlan_files(sdata);
528
void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
530
char buf[10+IFNAMSIZ];
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",
541
void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
543
if (!sdata->debugfs.dir)
546
debugfs_remove_recursive(sdata->debugfs.dir);
547
sdata->debugfs.dir = NULL;
550
void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
553
char buf[10 + IFNAMSIZ];
555
dir = sdata->debugfs.dir;
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 "