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