xref: /OK3568_Linux_fs/kernel/net/mac80211/debugfs_netdev.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2006	Jiri Benc <jbenc@suse.cz>
4*4882a593Smuzhiyun  * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
5*4882a593Smuzhiyun  * Copyright (C) 2020 Intel Corporation
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/kernel.h>
9*4882a593Smuzhiyun #include <linux/device.h>
10*4882a593Smuzhiyun #include <linux/if.h>
11*4882a593Smuzhiyun #include <linux/if_ether.h>
12*4882a593Smuzhiyun #include <linux/interrupt.h>
13*4882a593Smuzhiyun #include <linux/netdevice.h>
14*4882a593Smuzhiyun #include <linux/rtnetlink.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/notifier.h>
17*4882a593Smuzhiyun #include <net/mac80211.h>
18*4882a593Smuzhiyun #include <net/cfg80211.h>
19*4882a593Smuzhiyun #include "ieee80211_i.h"
20*4882a593Smuzhiyun #include "rate.h"
21*4882a593Smuzhiyun #include "debugfs.h"
22*4882a593Smuzhiyun #include "debugfs_netdev.h"
23*4882a593Smuzhiyun #include "driver-ops.h"
24*4882a593Smuzhiyun 
ieee80211_if_read(struct ieee80211_sub_if_data * sdata,char __user * userbuf,size_t count,loff_t * ppos,ssize_t (* format)(const struct ieee80211_sub_if_data *,char *,int))25*4882a593Smuzhiyun static ssize_t ieee80211_if_read(
26*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata,
27*4882a593Smuzhiyun 	char __user *userbuf,
28*4882a593Smuzhiyun 	size_t count, loff_t *ppos,
29*4882a593Smuzhiyun 	ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int))
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun 	char buf[200];
32*4882a593Smuzhiyun 	ssize_t ret = -EINVAL;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	read_lock(&dev_base_lock);
35*4882a593Smuzhiyun 	ret = (*format)(sdata, buf, sizeof(buf));
36*4882a593Smuzhiyun 	read_unlock(&dev_base_lock);
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	if (ret >= 0)
39*4882a593Smuzhiyun 		ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	return ret;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
ieee80211_if_write(struct ieee80211_sub_if_data * sdata,const char __user * userbuf,size_t count,loff_t * ppos,ssize_t (* write)(struct ieee80211_sub_if_data *,const char *,int))44*4882a593Smuzhiyun static ssize_t ieee80211_if_write(
45*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata,
46*4882a593Smuzhiyun 	const char __user *userbuf,
47*4882a593Smuzhiyun 	size_t count, loff_t *ppos,
48*4882a593Smuzhiyun 	ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int))
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	char buf[64];
51*4882a593Smuzhiyun 	ssize_t ret;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	if (count >= sizeof(buf))
54*4882a593Smuzhiyun 		return -E2BIG;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	if (copy_from_user(buf, userbuf, count))
57*4882a593Smuzhiyun 		return -EFAULT;
58*4882a593Smuzhiyun 	buf[count] = '\0';
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	ret = -ENODEV;
61*4882a593Smuzhiyun 	rtnl_lock();
62*4882a593Smuzhiyun 	ret = (*write)(sdata, buf, count);
63*4882a593Smuzhiyun 	rtnl_unlock();
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	return ret;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun #define IEEE80211_IF_FMT(name, field, format_string)			\
69*4882a593Smuzhiyun static ssize_t ieee80211_if_fmt_##name(					\
70*4882a593Smuzhiyun 	const struct ieee80211_sub_if_data *sdata, char *buf,		\
71*4882a593Smuzhiyun 	int buflen)							\
72*4882a593Smuzhiyun {									\
73*4882a593Smuzhiyun 	return scnprintf(buf, buflen, format_string, sdata->field);	\
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun #define IEEE80211_IF_FMT_DEC(name, field)				\
76*4882a593Smuzhiyun 		IEEE80211_IF_FMT(name, field, "%d\n")
77*4882a593Smuzhiyun #define IEEE80211_IF_FMT_HEX(name, field)				\
78*4882a593Smuzhiyun 		IEEE80211_IF_FMT(name, field, "%#x\n")
79*4882a593Smuzhiyun #define IEEE80211_IF_FMT_LHEX(name, field)				\
80*4882a593Smuzhiyun 		IEEE80211_IF_FMT(name, field, "%#lx\n")
81*4882a593Smuzhiyun #define IEEE80211_IF_FMT_SIZE(name, field)				\
82*4882a593Smuzhiyun 		IEEE80211_IF_FMT(name, field, "%zd\n")
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun #define IEEE80211_IF_FMT_HEXARRAY(name, field)				\
85*4882a593Smuzhiyun static ssize_t ieee80211_if_fmt_##name(					\
86*4882a593Smuzhiyun 	const struct ieee80211_sub_if_data *sdata,			\
87*4882a593Smuzhiyun 	char *buf, int buflen)						\
88*4882a593Smuzhiyun {									\
89*4882a593Smuzhiyun 	char *p = buf;							\
90*4882a593Smuzhiyun 	int i;								\
91*4882a593Smuzhiyun 	for (i = 0; i < sizeof(sdata->field); i++) {			\
92*4882a593Smuzhiyun 		p += scnprintf(p, buflen + buf - p, "%.2x ",		\
93*4882a593Smuzhiyun 				 sdata->field[i]);			\
94*4882a593Smuzhiyun 	}								\
95*4882a593Smuzhiyun 	p += scnprintf(p, buflen + buf - p, "\n");			\
96*4882a593Smuzhiyun 	return p - buf;							\
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun #define IEEE80211_IF_FMT_ATOMIC(name, field)				\
100*4882a593Smuzhiyun static ssize_t ieee80211_if_fmt_##name(					\
101*4882a593Smuzhiyun 	const struct ieee80211_sub_if_data *sdata,			\
102*4882a593Smuzhiyun 	char *buf, int buflen)						\
103*4882a593Smuzhiyun {									\
104*4882a593Smuzhiyun 	return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun #define IEEE80211_IF_FMT_MAC(name, field)				\
108*4882a593Smuzhiyun static ssize_t ieee80211_if_fmt_##name(					\
109*4882a593Smuzhiyun 	const struct ieee80211_sub_if_data *sdata, char *buf,		\
110*4882a593Smuzhiyun 	int buflen)							\
111*4882a593Smuzhiyun {									\
112*4882a593Smuzhiyun 	return scnprintf(buf, buflen, "%pM\n", sdata->field);		\
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun #define IEEE80211_IF_FMT_JIFFIES_TO_MS(name, field)			\
116*4882a593Smuzhiyun static ssize_t ieee80211_if_fmt_##name(					\
117*4882a593Smuzhiyun 	const struct ieee80211_sub_if_data *sdata,			\
118*4882a593Smuzhiyun 	char *buf, int buflen)						\
119*4882a593Smuzhiyun {									\
120*4882a593Smuzhiyun 	return scnprintf(buf, buflen, "%d\n",				\
121*4882a593Smuzhiyun 			 jiffies_to_msecs(sdata->field));		\
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun #define _IEEE80211_IF_FILE_OPS(name, _read, _write)			\
125*4882a593Smuzhiyun static const struct file_operations name##_ops = {			\
126*4882a593Smuzhiyun 	.read = (_read),						\
127*4882a593Smuzhiyun 	.write = (_write),						\
128*4882a593Smuzhiyun 	.open = simple_open,						\
129*4882a593Smuzhiyun 	.llseek = generic_file_llseek,					\
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun #define _IEEE80211_IF_FILE_R_FN(name)					\
133*4882a593Smuzhiyun static ssize_t ieee80211_if_read_##name(struct file *file,		\
134*4882a593Smuzhiyun 					char __user *userbuf,		\
135*4882a593Smuzhiyun 					size_t count, loff_t *ppos)	\
136*4882a593Smuzhiyun {									\
137*4882a593Smuzhiyun 	return ieee80211_if_read(file->private_data,			\
138*4882a593Smuzhiyun 				 userbuf, count, ppos,			\
139*4882a593Smuzhiyun 				 ieee80211_if_fmt_##name);		\
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun #define _IEEE80211_IF_FILE_W_FN(name)					\
143*4882a593Smuzhiyun static ssize_t ieee80211_if_write_##name(struct file *file,		\
144*4882a593Smuzhiyun 					 const char __user *userbuf,	\
145*4882a593Smuzhiyun 					 size_t count, loff_t *ppos)	\
146*4882a593Smuzhiyun {									\
147*4882a593Smuzhiyun 	return ieee80211_if_write(file->private_data, userbuf, count,	\
148*4882a593Smuzhiyun 				  ppos, ieee80211_if_parse_##name);	\
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun #define IEEE80211_IF_FILE_R(name)					\
152*4882a593Smuzhiyun 	_IEEE80211_IF_FILE_R_FN(name)					\
153*4882a593Smuzhiyun 	_IEEE80211_IF_FILE_OPS(name, ieee80211_if_read_##name, NULL)
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun #define IEEE80211_IF_FILE_W(name)					\
156*4882a593Smuzhiyun 	_IEEE80211_IF_FILE_W_FN(name)					\
157*4882a593Smuzhiyun 	_IEEE80211_IF_FILE_OPS(name, NULL, ieee80211_if_write_##name)
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun #define IEEE80211_IF_FILE_RW(name)					\
160*4882a593Smuzhiyun 	_IEEE80211_IF_FILE_R_FN(name)					\
161*4882a593Smuzhiyun 	_IEEE80211_IF_FILE_W_FN(name)					\
162*4882a593Smuzhiyun 	_IEEE80211_IF_FILE_OPS(name, ieee80211_if_read_##name,		\
163*4882a593Smuzhiyun 			       ieee80211_if_write_##name)
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun #define IEEE80211_IF_FILE(name, field, format)				\
166*4882a593Smuzhiyun 	IEEE80211_IF_FMT_##format(name, field)				\
167*4882a593Smuzhiyun 	IEEE80211_IF_FILE_R(name)
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun /* common attributes */
170*4882a593Smuzhiyun IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[NL80211_BAND_2GHZ],
171*4882a593Smuzhiyun 		  HEX);
172*4882a593Smuzhiyun IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[NL80211_BAND_5GHZ],
173*4882a593Smuzhiyun 		  HEX);
174*4882a593Smuzhiyun IEEE80211_IF_FILE(rc_rateidx_mcs_mask_2ghz,
175*4882a593Smuzhiyun 		  rc_rateidx_mcs_mask[NL80211_BAND_2GHZ], HEXARRAY);
176*4882a593Smuzhiyun IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz,
177*4882a593Smuzhiyun 		  rc_rateidx_mcs_mask[NL80211_BAND_5GHZ], HEXARRAY);
178*4882a593Smuzhiyun 
ieee80211_if_fmt_rc_rateidx_vht_mcs_mask_2ghz(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)179*4882a593Smuzhiyun static ssize_t ieee80211_if_fmt_rc_rateidx_vht_mcs_mask_2ghz(
180*4882a593Smuzhiyun 				const struct ieee80211_sub_if_data *sdata,
181*4882a593Smuzhiyun 				char *buf, int buflen)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	int i, len = 0;
184*4882a593Smuzhiyun 	const u16 *mask = sdata->rc_rateidx_vht_mcs_mask[NL80211_BAND_2GHZ];
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
187*4882a593Smuzhiyun 		len += scnprintf(buf + len, buflen - len, "%04x ", mask[i]);
188*4882a593Smuzhiyun 	len += scnprintf(buf + len, buflen - len, "\n");
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	return len;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun IEEE80211_IF_FILE_R(rc_rateidx_vht_mcs_mask_2ghz);
194*4882a593Smuzhiyun 
ieee80211_if_fmt_rc_rateidx_vht_mcs_mask_5ghz(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)195*4882a593Smuzhiyun static ssize_t ieee80211_if_fmt_rc_rateidx_vht_mcs_mask_5ghz(
196*4882a593Smuzhiyun 				const struct ieee80211_sub_if_data *sdata,
197*4882a593Smuzhiyun 				char *buf, int buflen)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	int i, len = 0;
200*4882a593Smuzhiyun 	const u16 *mask = sdata->rc_rateidx_vht_mcs_mask[NL80211_BAND_5GHZ];
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
203*4882a593Smuzhiyun 		len += scnprintf(buf + len, buflen - len, "%04x ", mask[i]);
204*4882a593Smuzhiyun 	len += scnprintf(buf + len, buflen - len, "\n");
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	return len;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun IEEE80211_IF_FILE_R(rc_rateidx_vht_mcs_mask_5ghz);
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun IEEE80211_IF_FILE(flags, flags, HEX);
212*4882a593Smuzhiyun IEEE80211_IF_FILE(state, state, LHEX);
213*4882a593Smuzhiyun IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC);
214*4882a593Smuzhiyun IEEE80211_IF_FILE(ap_power_level, ap_power_level, DEC);
215*4882a593Smuzhiyun IEEE80211_IF_FILE(user_power_level, user_power_level, DEC);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun static ssize_t
ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)218*4882a593Smuzhiyun ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata,
219*4882a593Smuzhiyun 			   char *buf, int buflen)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun 	int len;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	len = scnprintf(buf, buflen, "AC queues: VO:%d VI:%d BE:%d BK:%d\n",
224*4882a593Smuzhiyun 			sdata->vif.hw_queue[IEEE80211_AC_VO],
225*4882a593Smuzhiyun 			sdata->vif.hw_queue[IEEE80211_AC_VI],
226*4882a593Smuzhiyun 			sdata->vif.hw_queue[IEEE80211_AC_BE],
227*4882a593Smuzhiyun 			sdata->vif.hw_queue[IEEE80211_AC_BK]);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	if (sdata->vif.type == NL80211_IFTYPE_AP)
230*4882a593Smuzhiyun 		len += scnprintf(buf + len, buflen - len, "cab queue: %d\n",
231*4882a593Smuzhiyun 				 sdata->vif.cab_queue);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	return len;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun IEEE80211_IF_FILE_R(hw_queues);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun /* STA attributes */
238*4882a593Smuzhiyun IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
239*4882a593Smuzhiyun IEEE80211_IF_FILE(aid, vif.bss_conf.aid, DEC);
240*4882a593Smuzhiyun IEEE80211_IF_FILE(beacon_timeout, u.mgd.beacon_timeout, JIFFIES_TO_MS);
241*4882a593Smuzhiyun 
ieee80211_set_smps(struct ieee80211_sub_if_data * sdata,enum ieee80211_smps_mode smps_mode)242*4882a593Smuzhiyun static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
243*4882a593Smuzhiyun 			      enum ieee80211_smps_mode smps_mode)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
246*4882a593Smuzhiyun 	int err;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	if (!(local->hw.wiphy->features & NL80211_FEATURE_STATIC_SMPS) &&
249*4882a593Smuzhiyun 	    smps_mode == IEEE80211_SMPS_STATIC)
250*4882a593Smuzhiyun 		return -EINVAL;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	/* auto should be dynamic if in PS mode */
253*4882a593Smuzhiyun 	if (!(local->hw.wiphy->features & NL80211_FEATURE_DYNAMIC_SMPS) &&
254*4882a593Smuzhiyun 	    (smps_mode == IEEE80211_SMPS_DYNAMIC ||
255*4882a593Smuzhiyun 	     smps_mode == IEEE80211_SMPS_AUTOMATIC))
256*4882a593Smuzhiyun 		return -EINVAL;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	if (sdata->vif.type != NL80211_IFTYPE_STATION)
259*4882a593Smuzhiyun 		return -EOPNOTSUPP;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	sdata_lock(sdata);
262*4882a593Smuzhiyun 	err = __ieee80211_request_smps_mgd(sdata, smps_mode);
263*4882a593Smuzhiyun 	sdata_unlock(sdata);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	return err;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
269*4882a593Smuzhiyun 	[IEEE80211_SMPS_AUTOMATIC] = "auto",
270*4882a593Smuzhiyun 	[IEEE80211_SMPS_OFF] = "off",
271*4882a593Smuzhiyun 	[IEEE80211_SMPS_STATIC] = "static",
272*4882a593Smuzhiyun 	[IEEE80211_SMPS_DYNAMIC] = "dynamic",
273*4882a593Smuzhiyun };
274*4882a593Smuzhiyun 
ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)275*4882a593Smuzhiyun static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
276*4882a593Smuzhiyun 				     char *buf, int buflen)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun 	if (sdata->vif.type == NL80211_IFTYPE_STATION)
279*4882a593Smuzhiyun 		return snprintf(buf, buflen, "request: %s\nused: %s\n",
280*4882a593Smuzhiyun 				smps_modes[sdata->u.mgd.req_smps],
281*4882a593Smuzhiyun 				smps_modes[sdata->smps_mode]);
282*4882a593Smuzhiyun 	return -EINVAL;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun 
ieee80211_if_parse_smps(struct ieee80211_sub_if_data * sdata,const char * buf,int buflen)285*4882a593Smuzhiyun static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
286*4882a593Smuzhiyun 				       const char *buf, int buflen)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun 	enum ieee80211_smps_mode mode;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) {
291*4882a593Smuzhiyun 		if (strncmp(buf, smps_modes[mode], buflen) == 0) {
292*4882a593Smuzhiyun 			int err = ieee80211_set_smps(sdata, mode);
293*4882a593Smuzhiyun 			if (!err)
294*4882a593Smuzhiyun 				return buflen;
295*4882a593Smuzhiyun 			return err;
296*4882a593Smuzhiyun 		}
297*4882a593Smuzhiyun 	}
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	return -EINVAL;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun IEEE80211_IF_FILE_RW(smps);
302*4882a593Smuzhiyun 
ieee80211_if_parse_tkip_mic_test(struct ieee80211_sub_if_data * sdata,const char * buf,int buflen)303*4882a593Smuzhiyun static ssize_t ieee80211_if_parse_tkip_mic_test(
304*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
307*4882a593Smuzhiyun 	u8 addr[ETH_ALEN];
308*4882a593Smuzhiyun 	struct sk_buff *skb;
309*4882a593Smuzhiyun 	struct ieee80211_hdr *hdr;
310*4882a593Smuzhiyun 	__le16 fc;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	if (!mac_pton(buf, addr))
313*4882a593Smuzhiyun 		return -EINVAL;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	if (!ieee80211_sdata_running(sdata))
316*4882a593Smuzhiyun 		return -ENOTCONN;
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24 + 100);
319*4882a593Smuzhiyun 	if (!skb)
320*4882a593Smuzhiyun 		return -ENOMEM;
321*4882a593Smuzhiyun 	skb_reserve(skb, local->hw.extra_tx_headroom);
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	hdr = skb_put_zero(skb, 24);
324*4882a593Smuzhiyun 	fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	switch (sdata->vif.type) {
327*4882a593Smuzhiyun 	case NL80211_IFTYPE_AP:
328*4882a593Smuzhiyun 		fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
329*4882a593Smuzhiyun 		/* DA BSSID SA */
330*4882a593Smuzhiyun 		memcpy(hdr->addr1, addr, ETH_ALEN);
331*4882a593Smuzhiyun 		memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
332*4882a593Smuzhiyun 		memcpy(hdr->addr3, sdata->vif.addr, ETH_ALEN);
333*4882a593Smuzhiyun 		break;
334*4882a593Smuzhiyun 	case NL80211_IFTYPE_STATION:
335*4882a593Smuzhiyun 		fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
336*4882a593Smuzhiyun 		/* BSSID SA DA */
337*4882a593Smuzhiyun 		sdata_lock(sdata);
338*4882a593Smuzhiyun 		if (!sdata->u.mgd.associated) {
339*4882a593Smuzhiyun 			sdata_unlock(sdata);
340*4882a593Smuzhiyun 			dev_kfree_skb(skb);
341*4882a593Smuzhiyun 			return -ENOTCONN;
342*4882a593Smuzhiyun 		}
343*4882a593Smuzhiyun 		memcpy(hdr->addr1, sdata->u.mgd.associated->bssid, ETH_ALEN);
344*4882a593Smuzhiyun 		memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
345*4882a593Smuzhiyun 		memcpy(hdr->addr3, addr, ETH_ALEN);
346*4882a593Smuzhiyun 		sdata_unlock(sdata);
347*4882a593Smuzhiyun 		break;
348*4882a593Smuzhiyun 	default:
349*4882a593Smuzhiyun 		dev_kfree_skb(skb);
350*4882a593Smuzhiyun 		return -EOPNOTSUPP;
351*4882a593Smuzhiyun 	}
352*4882a593Smuzhiyun 	hdr->frame_control = fc;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	/*
355*4882a593Smuzhiyun 	 * Add some length to the test frame to make it look bit more valid.
356*4882a593Smuzhiyun 	 * The exact contents does not matter since the recipient is required
357*4882a593Smuzhiyun 	 * to drop this because of the Michael MIC failure.
358*4882a593Smuzhiyun 	 */
359*4882a593Smuzhiyun 	skb_put_zero(skb, 50);
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_TKIP_MIC_FAILURE;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	ieee80211_tx_skb(sdata, skb);
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	return buflen;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun IEEE80211_IF_FILE_W(tkip_mic_test);
368*4882a593Smuzhiyun 
ieee80211_if_parse_beacon_loss(struct ieee80211_sub_if_data * sdata,const char * buf,int buflen)369*4882a593Smuzhiyun static ssize_t ieee80211_if_parse_beacon_loss(
370*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	if (!ieee80211_sdata_running(sdata) || !sdata->vif.bss_conf.assoc)
373*4882a593Smuzhiyun 		return -ENOTCONN;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	ieee80211_beacon_loss(&sdata->vif);
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	return buflen;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun IEEE80211_IF_FILE_W(beacon_loss);
380*4882a593Smuzhiyun 
ieee80211_if_fmt_uapsd_queues(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)381*4882a593Smuzhiyun static ssize_t ieee80211_if_fmt_uapsd_queues(
382*4882a593Smuzhiyun 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun 	const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	return snprintf(buf, buflen, "0x%x\n", ifmgd->uapsd_queues);
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun 
ieee80211_if_parse_uapsd_queues(struct ieee80211_sub_if_data * sdata,const char * buf,int buflen)389*4882a593Smuzhiyun static ssize_t ieee80211_if_parse_uapsd_queues(
390*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
393*4882a593Smuzhiyun 	u8 val;
394*4882a593Smuzhiyun 	int ret;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	ret = kstrtou8(buf, 0, &val);
397*4882a593Smuzhiyun 	if (ret)
398*4882a593Smuzhiyun 		return ret;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
401*4882a593Smuzhiyun 		return -ERANGE;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	ifmgd->uapsd_queues = val;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	return buflen;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun IEEE80211_IF_FILE_RW(uapsd_queues);
408*4882a593Smuzhiyun 
ieee80211_if_fmt_uapsd_max_sp_len(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)409*4882a593Smuzhiyun static ssize_t ieee80211_if_fmt_uapsd_max_sp_len(
410*4882a593Smuzhiyun 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun 	const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	return snprintf(buf, buflen, "0x%x\n", ifmgd->uapsd_max_sp_len);
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun 
ieee80211_if_parse_uapsd_max_sp_len(struct ieee80211_sub_if_data * sdata,const char * buf,int buflen)417*4882a593Smuzhiyun static ssize_t ieee80211_if_parse_uapsd_max_sp_len(
418*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
421*4882a593Smuzhiyun 	unsigned long val;
422*4882a593Smuzhiyun 	int ret;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	ret = kstrtoul(buf, 0, &val);
425*4882a593Smuzhiyun 	if (ret)
426*4882a593Smuzhiyun 		return -EINVAL;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
429*4882a593Smuzhiyun 		return -ERANGE;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	ifmgd->uapsd_max_sp_len = val;
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	return buflen;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun IEEE80211_IF_FILE_RW(uapsd_max_sp_len);
436*4882a593Smuzhiyun 
ieee80211_if_fmt_tdls_wider_bw(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)437*4882a593Smuzhiyun static ssize_t ieee80211_if_fmt_tdls_wider_bw(
438*4882a593Smuzhiyun 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun 	const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
441*4882a593Smuzhiyun 	bool tdls_wider_bw;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	tdls_wider_bw = ieee80211_hw_check(&sdata->local->hw, TDLS_WIDER_BW) &&
444*4882a593Smuzhiyun 			!ifmgd->tdls_wider_bw_prohibited;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	return snprintf(buf, buflen, "%d\n", tdls_wider_bw);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun 
ieee80211_if_parse_tdls_wider_bw(struct ieee80211_sub_if_data * sdata,const char * buf,int buflen)449*4882a593Smuzhiyun static ssize_t ieee80211_if_parse_tdls_wider_bw(
450*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
453*4882a593Smuzhiyun 	u8 val;
454*4882a593Smuzhiyun 	int ret;
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	ret = kstrtou8(buf, 0, &val);
457*4882a593Smuzhiyun 	if (ret)
458*4882a593Smuzhiyun 		return ret;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	ifmgd->tdls_wider_bw_prohibited = !val;
461*4882a593Smuzhiyun 	return buflen;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun IEEE80211_IF_FILE_RW(tdls_wider_bw);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun /* AP attributes */
466*4882a593Smuzhiyun IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
467*4882a593Smuzhiyun IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC);
468*4882a593Smuzhiyun IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC);
469*4882a593Smuzhiyun IEEE80211_IF_FILE(num_mcast_sta_vlan, u.vlan.num_mcast_sta, ATOMIC);
470*4882a593Smuzhiyun 
ieee80211_if_fmt_num_buffered_multicast(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)471*4882a593Smuzhiyun static ssize_t ieee80211_if_fmt_num_buffered_multicast(
472*4882a593Smuzhiyun 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun 	return scnprintf(buf, buflen, "%u\n",
475*4882a593Smuzhiyun 			 skb_queue_len(&sdata->u.ap.ps.bc_buf));
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun IEEE80211_IF_FILE_R(num_buffered_multicast);
478*4882a593Smuzhiyun 
ieee80211_if_fmt_aqm(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)479*4882a593Smuzhiyun static ssize_t ieee80211_if_fmt_aqm(
480*4882a593Smuzhiyun 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
483*4882a593Smuzhiyun 	struct txq_info *txqi;
484*4882a593Smuzhiyun 	int len;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	if (!sdata->vif.txq)
487*4882a593Smuzhiyun 		return 0;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	txqi = to_txq_info(sdata->vif.txq);
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	spin_lock_bh(&local->fq.lock);
492*4882a593Smuzhiyun 	rcu_read_lock();
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	len = scnprintf(buf,
495*4882a593Smuzhiyun 			buflen,
496*4882a593Smuzhiyun 			"ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n"
497*4882a593Smuzhiyun 			"%u %u %u %u %u %u %u %u %u %u\n",
498*4882a593Smuzhiyun 			txqi->txq.ac,
499*4882a593Smuzhiyun 			txqi->tin.backlog_bytes,
500*4882a593Smuzhiyun 			txqi->tin.backlog_packets,
501*4882a593Smuzhiyun 			txqi->tin.flows,
502*4882a593Smuzhiyun 			txqi->cstats.drop_count,
503*4882a593Smuzhiyun 			txqi->cstats.ecn_mark,
504*4882a593Smuzhiyun 			txqi->tin.overlimit,
505*4882a593Smuzhiyun 			txqi->tin.collisions,
506*4882a593Smuzhiyun 			txqi->tin.tx_bytes,
507*4882a593Smuzhiyun 			txqi->tin.tx_packets);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	rcu_read_unlock();
510*4882a593Smuzhiyun 	spin_unlock_bh(&local->fq.lock);
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	return len;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun IEEE80211_IF_FILE_R(aqm);
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX);
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun /* IBSS attributes */
ieee80211_if_fmt_tsf(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)519*4882a593Smuzhiyun static ssize_t ieee80211_if_fmt_tsf(
520*4882a593Smuzhiyun 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
521*4882a593Smuzhiyun {
522*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
523*4882a593Smuzhiyun 	u64 tsf;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	tsf = drv_get_tsf(local, (struct ieee80211_sub_if_data *)sdata);
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	return scnprintf(buf, buflen, "0x%016llx\n", (unsigned long long) tsf);
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun 
ieee80211_if_parse_tsf(struct ieee80211_sub_if_data * sdata,const char * buf,int buflen)530*4882a593Smuzhiyun static ssize_t ieee80211_if_parse_tsf(
531*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
534*4882a593Smuzhiyun 	unsigned long long tsf;
535*4882a593Smuzhiyun 	int ret;
536*4882a593Smuzhiyun 	int tsf_is_delta = 0;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	if (strncmp(buf, "reset", 5) == 0) {
539*4882a593Smuzhiyun 		if (local->ops->reset_tsf) {
540*4882a593Smuzhiyun 			drv_reset_tsf(local, sdata);
541*4882a593Smuzhiyun 			wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
542*4882a593Smuzhiyun 		}
543*4882a593Smuzhiyun 	} else {
544*4882a593Smuzhiyun 		if (buflen > 10 && buf[1] == '=') {
545*4882a593Smuzhiyun 			if (buf[0] == '+')
546*4882a593Smuzhiyun 				tsf_is_delta = 1;
547*4882a593Smuzhiyun 			else if (buf[0] == '-')
548*4882a593Smuzhiyun 				tsf_is_delta = -1;
549*4882a593Smuzhiyun 			else
550*4882a593Smuzhiyun 				return -EINVAL;
551*4882a593Smuzhiyun 			buf += 2;
552*4882a593Smuzhiyun 		}
553*4882a593Smuzhiyun 		ret = kstrtoull(buf, 10, &tsf);
554*4882a593Smuzhiyun 		if (ret < 0)
555*4882a593Smuzhiyun 			return ret;
556*4882a593Smuzhiyun 		if (tsf_is_delta && local->ops->offset_tsf) {
557*4882a593Smuzhiyun 			drv_offset_tsf(local, sdata, tsf_is_delta * tsf);
558*4882a593Smuzhiyun 			wiphy_info(local->hw.wiphy,
559*4882a593Smuzhiyun 				   "debugfs offset TSF by %018lld\n",
560*4882a593Smuzhiyun 				   tsf_is_delta * tsf);
561*4882a593Smuzhiyun 		} else if (local->ops->set_tsf) {
562*4882a593Smuzhiyun 			if (tsf_is_delta)
563*4882a593Smuzhiyun 				tsf = drv_get_tsf(local, sdata) +
564*4882a593Smuzhiyun 				      tsf_is_delta * tsf;
565*4882a593Smuzhiyun 			drv_set_tsf(local, sdata, tsf);
566*4882a593Smuzhiyun 			wiphy_info(local->hw.wiphy,
567*4882a593Smuzhiyun 				   "debugfs set TSF to %#018llx\n", tsf);
568*4882a593Smuzhiyun 		}
569*4882a593Smuzhiyun 	}
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	ieee80211_recalc_dtim(local, sdata);
572*4882a593Smuzhiyun 	return buflen;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun IEEE80211_IF_FILE_RW(tsf);
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun /* WDS attributes */
578*4882a593Smuzhiyun IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun #ifdef CONFIG_MAC80211_MESH
581*4882a593Smuzhiyun IEEE80211_IF_FILE(estab_plinks, u.mesh.estab_plinks, ATOMIC);
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun /* Mesh stats attributes */
584*4882a593Smuzhiyun IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC);
585*4882a593Smuzhiyun IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
586*4882a593Smuzhiyun IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
587*4882a593Smuzhiyun IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
588*4882a593Smuzhiyun IEEE80211_IF_FILE(dropped_frames_congestion,
589*4882a593Smuzhiyun 		  u.mesh.mshstats.dropped_frames_congestion, DEC);
590*4882a593Smuzhiyun IEEE80211_IF_FILE(dropped_frames_no_route,
591*4882a593Smuzhiyun 		  u.mesh.mshstats.dropped_frames_no_route, DEC);
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun /* Mesh parameters */
594*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshMaxRetries,
595*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshMaxRetries, DEC);
596*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshRetryTimeout,
597*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);
598*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshConfirmTimeout,
599*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);
600*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshHoldingTimeout,
601*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
602*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC);
603*4882a593Smuzhiyun IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC);
604*4882a593Smuzhiyun IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC);
605*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshMaxPeerLinks,
606*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
607*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout,
608*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
609*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval,
610*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
611*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshHWMPperrMinInterval,
612*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC);
613*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime,
614*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
615*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries,
616*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);
617*4882a593Smuzhiyun IEEE80211_IF_FILE(path_refresh_time,
618*4882a593Smuzhiyun 		  u.mesh.mshcfg.path_refresh_time, DEC);
619*4882a593Smuzhiyun IEEE80211_IF_FILE(min_discovery_timeout,
620*4882a593Smuzhiyun 		  u.mesh.mshcfg.min_discovery_timeout, DEC);
621*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
622*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
623*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol,
624*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC);
625*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
626*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
627*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC);
628*4882a593Smuzhiyun IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC);
629*4882a593Smuzhiyun IEEE80211_IF_FILE(ht_opmode, u.mesh.mshcfg.ht_opmode, DEC);
630*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshHWMPactivePathToRootTimeout,
631*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshHWMPactivePathToRootTimeout, DEC);
632*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshHWMProotInterval,
633*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshHWMProotInterval, DEC);
634*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshHWMPconfirmationInterval,
635*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval, DEC);
636*4882a593Smuzhiyun IEEE80211_IF_FILE(power_mode, u.mesh.mshcfg.power_mode, DEC);
637*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshAwakeWindowDuration,
638*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshAwakeWindowDuration, DEC);
639*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshConnectedToMeshGate,
640*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshConnectedToMeshGate, DEC);
641*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshNolearn, u.mesh.mshcfg.dot11MeshNolearn, DEC);
642*4882a593Smuzhiyun IEEE80211_IF_FILE(dot11MeshConnectedToAuthServer,
643*4882a593Smuzhiyun 		  u.mesh.mshcfg.dot11MeshConnectedToAuthServer, DEC);
644*4882a593Smuzhiyun #endif
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun #define DEBUGFS_ADD_MODE(name, mode) \
647*4882a593Smuzhiyun 	debugfs_create_file(#name, mode, sdata->vif.debugfs_dir, \
648*4882a593Smuzhiyun 			    sdata, &name##_ops);
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun #define DEBUGFS_ADD(name) DEBUGFS_ADD_MODE(name, 0400)
651*4882a593Smuzhiyun 
add_common_files(struct ieee80211_sub_if_data * sdata)652*4882a593Smuzhiyun static void add_common_files(struct ieee80211_sub_if_data *sdata)
653*4882a593Smuzhiyun {
654*4882a593Smuzhiyun 	DEBUGFS_ADD(rc_rateidx_mask_2ghz);
655*4882a593Smuzhiyun 	DEBUGFS_ADD(rc_rateidx_mask_5ghz);
656*4882a593Smuzhiyun 	DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
657*4882a593Smuzhiyun 	DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
658*4882a593Smuzhiyun 	DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_2ghz);
659*4882a593Smuzhiyun 	DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz);
660*4882a593Smuzhiyun 	DEBUGFS_ADD(hw_queues);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	if (sdata->local->ops->wake_tx_queue &&
663*4882a593Smuzhiyun 	    sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
664*4882a593Smuzhiyun 	    sdata->vif.type != NL80211_IFTYPE_NAN)
665*4882a593Smuzhiyun 		DEBUGFS_ADD(aqm);
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun 
add_sta_files(struct ieee80211_sub_if_data * sdata)668*4882a593Smuzhiyun static void add_sta_files(struct ieee80211_sub_if_data *sdata)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun 	DEBUGFS_ADD(bssid);
671*4882a593Smuzhiyun 	DEBUGFS_ADD(aid);
672*4882a593Smuzhiyun 	DEBUGFS_ADD(beacon_timeout);
673*4882a593Smuzhiyun 	DEBUGFS_ADD_MODE(smps, 0600);
674*4882a593Smuzhiyun 	DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
675*4882a593Smuzhiyun 	DEBUGFS_ADD_MODE(beacon_loss, 0200);
676*4882a593Smuzhiyun 	DEBUGFS_ADD_MODE(uapsd_queues, 0600);
677*4882a593Smuzhiyun 	DEBUGFS_ADD_MODE(uapsd_max_sp_len, 0600);
678*4882a593Smuzhiyun 	DEBUGFS_ADD_MODE(tdls_wider_bw, 0600);
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun 
add_ap_files(struct ieee80211_sub_if_data * sdata)681*4882a593Smuzhiyun static void add_ap_files(struct ieee80211_sub_if_data *sdata)
682*4882a593Smuzhiyun {
683*4882a593Smuzhiyun 	DEBUGFS_ADD(num_mcast_sta);
684*4882a593Smuzhiyun 	DEBUGFS_ADD_MODE(smps, 0600);
685*4882a593Smuzhiyun 	DEBUGFS_ADD(num_sta_ps);
686*4882a593Smuzhiyun 	DEBUGFS_ADD(dtim_count);
687*4882a593Smuzhiyun 	DEBUGFS_ADD(num_buffered_multicast);
688*4882a593Smuzhiyun 	DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
689*4882a593Smuzhiyun 	DEBUGFS_ADD_MODE(multicast_to_unicast, 0600);
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun 
add_vlan_files(struct ieee80211_sub_if_data * sdata)692*4882a593Smuzhiyun static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
693*4882a593Smuzhiyun {
694*4882a593Smuzhiyun 	/* add num_mcast_sta_vlan using name num_mcast_sta */
695*4882a593Smuzhiyun 	debugfs_create_file("num_mcast_sta", 0400, sdata->vif.debugfs_dir,
696*4882a593Smuzhiyun 			    sdata, &num_mcast_sta_vlan_ops);
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun 
add_ibss_files(struct ieee80211_sub_if_data * sdata)699*4882a593Smuzhiyun static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
700*4882a593Smuzhiyun {
701*4882a593Smuzhiyun 	DEBUGFS_ADD_MODE(tsf, 0600);
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun 
add_wds_files(struct ieee80211_sub_if_data * sdata)704*4882a593Smuzhiyun static void add_wds_files(struct ieee80211_sub_if_data *sdata)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun 	DEBUGFS_ADD(peer);
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun #ifdef CONFIG_MAC80211_MESH
710*4882a593Smuzhiyun 
add_mesh_files(struct ieee80211_sub_if_data * sdata)711*4882a593Smuzhiyun static void add_mesh_files(struct ieee80211_sub_if_data *sdata)
712*4882a593Smuzhiyun {
713*4882a593Smuzhiyun 	DEBUGFS_ADD_MODE(tsf, 0600);
714*4882a593Smuzhiyun 	DEBUGFS_ADD_MODE(estab_plinks, 0400);
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun 
add_mesh_stats(struct ieee80211_sub_if_data * sdata)717*4882a593Smuzhiyun static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
718*4882a593Smuzhiyun {
719*4882a593Smuzhiyun 	struct dentry *dir = debugfs_create_dir("mesh_stats",
720*4882a593Smuzhiyun 						sdata->vif.debugfs_dir);
721*4882a593Smuzhiyun #define MESHSTATS_ADD(name)\
722*4882a593Smuzhiyun 	debugfs_create_file(#name, 0400, dir, sdata, &name##_ops);
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	MESHSTATS_ADD(fwded_mcast);
725*4882a593Smuzhiyun 	MESHSTATS_ADD(fwded_unicast);
726*4882a593Smuzhiyun 	MESHSTATS_ADD(fwded_frames);
727*4882a593Smuzhiyun 	MESHSTATS_ADD(dropped_frames_ttl);
728*4882a593Smuzhiyun 	MESHSTATS_ADD(dropped_frames_no_route);
729*4882a593Smuzhiyun 	MESHSTATS_ADD(dropped_frames_congestion);
730*4882a593Smuzhiyun #undef MESHSTATS_ADD
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun 
add_mesh_config(struct ieee80211_sub_if_data * sdata)733*4882a593Smuzhiyun static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun 	struct dentry *dir = debugfs_create_dir("mesh_config",
736*4882a593Smuzhiyun 						sdata->vif.debugfs_dir);
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun #define MESHPARAMS_ADD(name) \
739*4882a593Smuzhiyun 	debugfs_create_file(#name, 0600, dir, sdata, &name##_ops);
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshMaxRetries);
742*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshRetryTimeout);
743*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshConfirmTimeout);
744*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshHoldingTimeout);
745*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshTTL);
746*4882a593Smuzhiyun 	MESHPARAMS_ADD(element_ttl);
747*4882a593Smuzhiyun 	MESHPARAMS_ADD(auto_open_plinks);
748*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
749*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
750*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval);
751*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshHWMPperrMinInterval);
752*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime);
753*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
754*4882a593Smuzhiyun 	MESHPARAMS_ADD(path_refresh_time);
755*4882a593Smuzhiyun 	MESHPARAMS_ADD(min_discovery_timeout);
756*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshHWMPRootMode);
757*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
758*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshForwarding);
759*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
760*4882a593Smuzhiyun 	MESHPARAMS_ADD(rssi_threshold);
761*4882a593Smuzhiyun 	MESHPARAMS_ADD(ht_opmode);
762*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshHWMPactivePathToRootTimeout);
763*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshHWMProotInterval);
764*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshHWMPconfirmationInterval);
765*4882a593Smuzhiyun 	MESHPARAMS_ADD(power_mode);
766*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshAwakeWindowDuration);
767*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshConnectedToMeshGate);
768*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshNolearn);
769*4882a593Smuzhiyun 	MESHPARAMS_ADD(dot11MeshConnectedToAuthServer);
770*4882a593Smuzhiyun #undef MESHPARAMS_ADD
771*4882a593Smuzhiyun }
772*4882a593Smuzhiyun #endif
773*4882a593Smuzhiyun 
add_files(struct ieee80211_sub_if_data * sdata)774*4882a593Smuzhiyun static void add_files(struct ieee80211_sub_if_data *sdata)
775*4882a593Smuzhiyun {
776*4882a593Smuzhiyun 	if (!sdata->vif.debugfs_dir)
777*4882a593Smuzhiyun 		return;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	DEBUGFS_ADD(flags);
780*4882a593Smuzhiyun 	DEBUGFS_ADD(state);
781*4882a593Smuzhiyun 	DEBUGFS_ADD(txpower);
782*4882a593Smuzhiyun 	DEBUGFS_ADD(user_power_level);
783*4882a593Smuzhiyun 	DEBUGFS_ADD(ap_power_level);
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
786*4882a593Smuzhiyun 		add_common_files(sdata);
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 	switch (sdata->vif.type) {
789*4882a593Smuzhiyun 	case NL80211_IFTYPE_MESH_POINT:
790*4882a593Smuzhiyun #ifdef CONFIG_MAC80211_MESH
791*4882a593Smuzhiyun 		add_mesh_files(sdata);
792*4882a593Smuzhiyun 		add_mesh_stats(sdata);
793*4882a593Smuzhiyun 		add_mesh_config(sdata);
794*4882a593Smuzhiyun #endif
795*4882a593Smuzhiyun 		break;
796*4882a593Smuzhiyun 	case NL80211_IFTYPE_STATION:
797*4882a593Smuzhiyun 		add_sta_files(sdata);
798*4882a593Smuzhiyun 		break;
799*4882a593Smuzhiyun 	case NL80211_IFTYPE_ADHOC:
800*4882a593Smuzhiyun 		add_ibss_files(sdata);
801*4882a593Smuzhiyun 		break;
802*4882a593Smuzhiyun 	case NL80211_IFTYPE_AP:
803*4882a593Smuzhiyun 		add_ap_files(sdata);
804*4882a593Smuzhiyun 		break;
805*4882a593Smuzhiyun 	case NL80211_IFTYPE_AP_VLAN:
806*4882a593Smuzhiyun 		add_vlan_files(sdata);
807*4882a593Smuzhiyun 		break;
808*4882a593Smuzhiyun 	case NL80211_IFTYPE_WDS:
809*4882a593Smuzhiyun 		add_wds_files(sdata);
810*4882a593Smuzhiyun 		break;
811*4882a593Smuzhiyun 	default:
812*4882a593Smuzhiyun 		break;
813*4882a593Smuzhiyun 	}
814*4882a593Smuzhiyun }
815*4882a593Smuzhiyun 
ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data * sdata)816*4882a593Smuzhiyun void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
817*4882a593Smuzhiyun {
818*4882a593Smuzhiyun 	char buf[10+IFNAMSIZ];
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 	sprintf(buf, "netdev:%s", sdata->name);
821*4882a593Smuzhiyun 	sdata->vif.debugfs_dir = debugfs_create_dir(buf,
822*4882a593Smuzhiyun 		sdata->local->hw.wiphy->debugfsdir);
823*4882a593Smuzhiyun 	sdata->debugfs.subdir_stations = debugfs_create_dir("stations",
824*4882a593Smuzhiyun 							sdata->vif.debugfs_dir);
825*4882a593Smuzhiyun 	add_files(sdata);
826*4882a593Smuzhiyun }
827*4882a593Smuzhiyun 
ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data * sdata)828*4882a593Smuzhiyun void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
829*4882a593Smuzhiyun {
830*4882a593Smuzhiyun 	if (!sdata->vif.debugfs_dir)
831*4882a593Smuzhiyun 		return;
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	debugfs_remove_recursive(sdata->vif.debugfs_dir);
834*4882a593Smuzhiyun 	sdata->vif.debugfs_dir = NULL;
835*4882a593Smuzhiyun 	sdata->debugfs.subdir_stations = NULL;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun 
ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data * sdata)838*4882a593Smuzhiyun void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
839*4882a593Smuzhiyun {
840*4882a593Smuzhiyun 	struct dentry *dir;
841*4882a593Smuzhiyun 	char buf[10 + IFNAMSIZ];
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	dir = sdata->vif.debugfs_dir;
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	if (IS_ERR_OR_NULL(dir))
846*4882a593Smuzhiyun 		return;
847*4882a593Smuzhiyun 
848*4882a593Smuzhiyun 	sprintf(buf, "netdev:%s", sdata->name);
849*4882a593Smuzhiyun 	debugfs_rename(dir->d_parent, dir, dir->d_parent, buf);
850*4882a593Smuzhiyun }
851