1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e9f207f0SJiri Benc /*
3e9f207f0SJiri Benc * Copyright (c) 2006 Jiri Benc <[email protected]>
4e9f207f0SJiri Benc * Copyright 2007 Johannes Berg <[email protected]>
5bc1be54dSMiri Korenblit * Copyright (C) 2020-2023 Intel Corporation
6e9f207f0SJiri Benc */
7e9f207f0SJiri Benc
8e9f207f0SJiri Benc #include <linux/kernel.h>
9e9f207f0SJiri Benc #include <linux/device.h>
10e9f207f0SJiri Benc #include <linux/if.h>
1128656a11SJohannes Berg #include <linux/if_ether.h>
12e9f207f0SJiri Benc #include <linux/interrupt.h>
13e9f207f0SJiri Benc #include <linux/netdevice.h>
14e9f207f0SJiri Benc #include <linux/rtnetlink.h>
155a0e3ad6STejun Heo #include <linux/slab.h>
16e9f207f0SJiri Benc #include <linux/notifier.h>
17e9f207f0SJiri Benc #include <net/mac80211.h>
18e9f207f0SJiri Benc #include <net/cfg80211.h>
19e9f207f0SJiri Benc #include "ieee80211_i.h"
202c8dccc7SJohannes Berg #include "rate.h"
21e9f207f0SJiri Benc #include "debugfs.h"
22e9f207f0SJiri Benc #include "debugfs_netdev.h"
2337a41b4aSEliad Peller #include "driver-ops.h"
24e9f207f0SJiri Benc
254ded3bfeSJohannes Berg struct ieee80211_if_read_sdata_data {
264ded3bfeSJohannes Berg ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int);
274ded3bfeSJohannes Berg struct ieee80211_sub_if_data *sdata;
284ded3bfeSJohannes Berg };
294ded3bfeSJohannes Berg
ieee80211_if_read_sdata_handler(struct wiphy * wiphy,struct file * file,char * buf,size_t bufsize,void * data)304ded3bfeSJohannes Berg static ssize_t ieee80211_if_read_sdata_handler(struct wiphy *wiphy,
314ded3bfeSJohannes Berg struct file *file,
324ded3bfeSJohannes Berg char *buf,
334ded3bfeSJohannes Berg size_t bufsize,
344ded3bfeSJohannes Berg void *data)
354ded3bfeSJohannes Berg {
364ded3bfeSJohannes Berg struct ieee80211_if_read_sdata_data *d = data;
374ded3bfeSJohannes Berg
384ded3bfeSJohannes Berg return d->format(d->sdata, buf, bufsize);
394ded3bfeSJohannes Berg }
404ded3bfeSJohannes Berg
ieee80211_if_read_sdata(struct file * file,char __user * userbuf,size_t count,loff_t * ppos,ssize_t (* format)(const struct ieee80211_sub_if_data * sdata,char *,int))410ab6cba0SJohannes Berg static ssize_t ieee80211_if_read_sdata(
424ded3bfeSJohannes Berg struct file *file,
43e9f207f0SJiri Benc char __user *userbuf,
44e9f207f0SJiri Benc size_t count, loff_t *ppos,
450ab6cba0SJohannes Berg ssize_t (*format)(const struct ieee80211_sub_if_data *sdata, char *, int))
46e9f207f0SJiri Benc {
474ded3bfeSJohannes Berg struct ieee80211_sub_if_data *sdata = file->private_data;
484ded3bfeSJohannes Berg struct ieee80211_if_read_sdata_data data = {
494ded3bfeSJohannes Berg .format = format,
504ded3bfeSJohannes Berg .sdata = sdata,
514ded3bfeSJohannes Berg };
528d51dbb8SToke Høiland-Jørgensen char buf[200];
53e9f207f0SJiri Benc
544ded3bfeSJohannes Berg return wiphy_locked_debugfs_read(sdata->local->hw.wiphy,
554ded3bfeSJohannes Berg file, buf, sizeof(buf),
564ded3bfeSJohannes Berg userbuf, count, ppos,
574ded3bfeSJohannes Berg ieee80211_if_read_sdata_handler,
584ded3bfeSJohannes Berg &data);
594ded3bfeSJohannes Berg }
6073bb3e4aSLuis Carlos Cobo
614ded3bfeSJohannes Berg struct ieee80211_if_write_sdata_data {
624ded3bfeSJohannes Berg ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int);
634ded3bfeSJohannes Berg struct ieee80211_sub_if_data *sdata;
644ded3bfeSJohannes Berg };
6573bb3e4aSLuis Carlos Cobo
ieee80211_if_write_sdata_handler(struct wiphy * wiphy,struct file * file,char * buf,size_t count,void * data)664ded3bfeSJohannes Berg static ssize_t ieee80211_if_write_sdata_handler(struct wiphy *wiphy,
674ded3bfeSJohannes Berg struct file *file,
684ded3bfeSJohannes Berg char *buf,
694ded3bfeSJohannes Berg size_t count,
704ded3bfeSJohannes Berg void *data)
714ded3bfeSJohannes Berg {
724ded3bfeSJohannes Berg struct ieee80211_if_write_sdata_data *d = data;
734ded3bfeSJohannes Berg
744ded3bfeSJohannes Berg return d->write(d->sdata, buf, count);
75e9f207f0SJiri Benc }
76e9f207f0SJiri Benc
ieee80211_if_write_sdata(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos,ssize_t (* write)(struct ieee80211_sub_if_data * sdata,const char *,int))770ab6cba0SJohannes Berg static ssize_t ieee80211_if_write_sdata(
784ded3bfeSJohannes Berg struct file *file,
790f78231bSJohannes Berg const char __user *userbuf,
800f78231bSJohannes Berg size_t count, loff_t *ppos,
810ab6cba0SJohannes Berg ssize_t (*write)(struct ieee80211_sub_if_data *sdata, const char *, int))
820f78231bSJohannes Berg {
834ded3bfeSJohannes Berg struct ieee80211_sub_if_data *sdata = file->private_data;
844ded3bfeSJohannes Berg struct ieee80211_if_write_sdata_data data = {
854ded3bfeSJohannes Berg .write = write,
864ded3bfeSJohannes Berg .sdata = sdata,
874ded3bfeSJohannes Berg };
88ada577c1SEliad Peller char buf[64];
890f78231bSJohannes Berg
904ded3bfeSJohannes Berg return wiphy_locked_debugfs_write(sdata->local->hw.wiphy,
914ded3bfeSJohannes Berg file, buf, sizeof(buf),
924ded3bfeSJohannes Berg userbuf, count,
934ded3bfeSJohannes Berg ieee80211_if_write_sdata_handler,
944ded3bfeSJohannes Berg &data);
954ded3bfeSJohannes Berg }
960f78231bSJohannes Berg
974ded3bfeSJohannes Berg struct ieee80211_if_read_link_data {
984ded3bfeSJohannes Berg ssize_t (*format)(const struct ieee80211_link_data *, char *, int);
994ded3bfeSJohannes Berg struct ieee80211_link_data *link;
1004ded3bfeSJohannes Berg };
1010f78231bSJohannes Berg
ieee80211_if_read_link_handler(struct wiphy * wiphy,struct file * file,char * buf,size_t bufsize,void * data)1024ded3bfeSJohannes Berg static ssize_t ieee80211_if_read_link_handler(struct wiphy *wiphy,
1034ded3bfeSJohannes Berg struct file *file,
1044ded3bfeSJohannes Berg char *buf,
1054ded3bfeSJohannes Berg size_t bufsize,
1064ded3bfeSJohannes Berg void *data)
1074ded3bfeSJohannes Berg {
1084ded3bfeSJohannes Berg struct ieee80211_if_read_link_data *d = data;
1090ab6cba0SJohannes Berg
1104ded3bfeSJohannes Berg return d->format(d->link, buf, bufsize);
1110ab6cba0SJohannes Berg }
1120ab6cba0SJohannes Berg
ieee80211_if_read_link(struct file * file,char __user * userbuf,size_t count,loff_t * ppos,ssize_t (* format)(const struct ieee80211_link_data * link,char *,int))1130ab6cba0SJohannes Berg static ssize_t ieee80211_if_read_link(
1144ded3bfeSJohannes Berg struct file *file,
1150ab6cba0SJohannes Berg char __user *userbuf,
1160ab6cba0SJohannes Berg size_t count, loff_t *ppos,
1170ab6cba0SJohannes Berg ssize_t (*format)(const struct ieee80211_link_data *link, char *, int))
1180ab6cba0SJohannes Berg {
1194ded3bfeSJohannes Berg struct ieee80211_link_data *link = file->private_data;
1204ded3bfeSJohannes Berg struct ieee80211_if_read_link_data data = {
1214ded3bfeSJohannes Berg .format = format,
1224ded3bfeSJohannes Berg .link = link,
1234ded3bfeSJohannes Berg };
1240ab6cba0SJohannes Berg char buf[200];
1250ab6cba0SJohannes Berg
1264ded3bfeSJohannes Berg return wiphy_locked_debugfs_read(link->sdata->local->hw.wiphy,
1274ded3bfeSJohannes Berg file, buf, sizeof(buf),
1284ded3bfeSJohannes Berg userbuf, count, ppos,
1294ded3bfeSJohannes Berg ieee80211_if_read_link_handler,
1304ded3bfeSJohannes Berg &data);
1314ded3bfeSJohannes Berg }
1320ab6cba0SJohannes Berg
1334ded3bfeSJohannes Berg struct ieee80211_if_write_link_data {
1344ded3bfeSJohannes Berg ssize_t (*write)(struct ieee80211_link_data *, const char *, int);
1354ded3bfeSJohannes Berg struct ieee80211_link_data *link;
1364ded3bfeSJohannes Berg };
1370ab6cba0SJohannes Berg
ieee80211_if_write_link_handler(struct wiphy * wiphy,struct file * file,char * buf,size_t count,void * data)1384ded3bfeSJohannes Berg static ssize_t ieee80211_if_write_link_handler(struct wiphy *wiphy,
1394ded3bfeSJohannes Berg struct file *file,
1404ded3bfeSJohannes Berg char *buf,
1414ded3bfeSJohannes Berg size_t count,
1424ded3bfeSJohannes Berg void *data)
1434ded3bfeSJohannes Berg {
1444ded3bfeSJohannes Berg struct ieee80211_if_write_sdata_data *d = data;
1454ded3bfeSJohannes Berg
1464ded3bfeSJohannes Berg return d->write(d->sdata, buf, count);
1470ab6cba0SJohannes Berg }
1480ab6cba0SJohannes Berg
ieee80211_if_write_link(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos,ssize_t (* write)(struct ieee80211_link_data * link,const char *,int))1490ab6cba0SJohannes Berg static ssize_t ieee80211_if_write_link(
1504ded3bfeSJohannes Berg struct file *file,
1510ab6cba0SJohannes Berg const char __user *userbuf,
1520ab6cba0SJohannes Berg size_t count, loff_t *ppos,
1530ab6cba0SJohannes Berg ssize_t (*write)(struct ieee80211_link_data *link, const char *, int))
1540ab6cba0SJohannes Berg {
1554ded3bfeSJohannes Berg struct ieee80211_link_data *link = file->private_data;
1564ded3bfeSJohannes Berg struct ieee80211_if_write_link_data data = {
1574ded3bfeSJohannes Berg .write = write,
1584ded3bfeSJohannes Berg .link = link,
1594ded3bfeSJohannes Berg };
1600ab6cba0SJohannes Berg char buf[64];
1610ab6cba0SJohannes Berg
1624ded3bfeSJohannes Berg return wiphy_locked_debugfs_write(link->sdata->local->hw.wiphy,
1634ded3bfeSJohannes Berg file, buf, sizeof(buf),
1644ded3bfeSJohannes Berg userbuf, count,
1654ded3bfeSJohannes Berg ieee80211_if_write_link_handler,
1664ded3bfeSJohannes Berg &data);
1670f78231bSJohannes Berg }
1680f78231bSJohannes Berg
169170cd6a6SBenjamin Berg #define IEEE80211_IF_FMT(name, type, field, format_string) \
170e9f207f0SJiri Benc static ssize_t ieee80211_if_fmt_##name( \
171170cd6a6SBenjamin Berg const type *data, char *buf, \
172e9f207f0SJiri Benc int buflen) \
173e9f207f0SJiri Benc { \
174170cd6a6SBenjamin Berg return scnprintf(buf, buflen, format_string, data->field); \
175e9f207f0SJiri Benc }
176170cd6a6SBenjamin Berg #define IEEE80211_IF_FMT_DEC(name, type, field) \
177170cd6a6SBenjamin Berg IEEE80211_IF_FMT(name, type, field, "%d\n")
178170cd6a6SBenjamin Berg #define IEEE80211_IF_FMT_HEX(name, type, field) \
179170cd6a6SBenjamin Berg IEEE80211_IF_FMT(name, type, field, "%#x\n")
180170cd6a6SBenjamin Berg #define IEEE80211_IF_FMT_LHEX(name, type, field) \
181170cd6a6SBenjamin Berg IEEE80211_IF_FMT(name, type, field, "%#lx\n")
182e9f207f0SJiri Benc
183170cd6a6SBenjamin Berg #define IEEE80211_IF_FMT_HEXARRAY(name, type, field) \
18419468413SSimon Wunderlich static ssize_t ieee80211_if_fmt_##name( \
185170cd6a6SBenjamin Berg const type *data, \
18619468413SSimon Wunderlich char *buf, int buflen) \
18719468413SSimon Wunderlich { \
18819468413SSimon Wunderlich char *p = buf; \
18919468413SSimon Wunderlich int i; \
190170cd6a6SBenjamin Berg for (i = 0; i < sizeof(data->field); i++) { \
19119468413SSimon Wunderlich p += scnprintf(p, buflen + buf - p, "%.2x ", \
192170cd6a6SBenjamin Berg data->field[i]); \
19319468413SSimon Wunderlich } \
19419468413SSimon Wunderlich p += scnprintf(p, buflen + buf - p, "\n"); \
19519468413SSimon Wunderlich return p - buf; \
19619468413SSimon Wunderlich }
19719468413SSimon Wunderlich
198170cd6a6SBenjamin Berg #define IEEE80211_IF_FMT_ATOMIC(name, type, field) \
199e9f207f0SJiri Benc static ssize_t ieee80211_if_fmt_##name( \
200170cd6a6SBenjamin Berg const type *data, \
201e9f207f0SJiri Benc char *buf, int buflen) \
202e9f207f0SJiri Benc { \
203170cd6a6SBenjamin Berg return scnprintf(buf, buflen, "%d\n", atomic_read(&data->field));\
204e9f207f0SJiri Benc }
205e9f207f0SJiri Benc
206170cd6a6SBenjamin Berg #define IEEE80211_IF_FMT_MAC(name, type, field) \
207e9f207f0SJiri Benc static ssize_t ieee80211_if_fmt_##name( \
208170cd6a6SBenjamin Berg const type *data, char *buf, \
209e9f207f0SJiri Benc int buflen) \
210e9f207f0SJiri Benc { \
211170cd6a6SBenjamin Berg return scnprintf(buf, buflen, "%pM\n", data->field); \
212e9f207f0SJiri Benc }
213e9f207f0SJiri Benc
214170cd6a6SBenjamin Berg #define IEEE80211_IF_FMT_JIFFIES_TO_MS(name, type, field) \
21578e443e4SBen Greear static ssize_t ieee80211_if_fmt_##name( \
216170cd6a6SBenjamin Berg const type *data, \
21778e443e4SBen Greear char *buf, int buflen) \
21878e443e4SBen Greear { \
21978e443e4SBen Greear return scnprintf(buf, buflen, "%d\n", \
220170cd6a6SBenjamin Berg jiffies_to_msecs(data->field)); \
22178e443e4SBen Greear }
22278e443e4SBen Greear
2234cd3c4ecSJohannes Berg #define _IEEE80211_IF_FILE_OPS(name, _read, _write) \
22431cb94f7SJohannes Berg static const struct debugfs_short_fops name##_ops = { \
2254cd3c4ecSJohannes Berg .read = (_read), \
2264cd3c4ecSJohannes Berg .write = (_write), \
2274cd3c4ecSJohannes Berg .llseek = generic_file_llseek, \
2284cd3c4ecSJohannes Berg }
2294cd3c4ecSJohannes Berg
2300ab6cba0SJohannes Berg #define _IEEE80211_IF_FILE_R_FN(name) \
231e9f207f0SJiri Benc static ssize_t ieee80211_if_read_##name(struct file *file, \
232e9f207f0SJiri Benc char __user *userbuf, \
233e9f207f0SJiri Benc size_t count, loff_t *ppos) \
234e9f207f0SJiri Benc { \
2354ded3bfeSJohannes Berg return ieee80211_if_read_sdata(file, \
2360ab6cba0SJohannes Berg userbuf, count, ppos, \
237e9f207f0SJiri Benc ieee80211_if_fmt_##name); \
238e9f207f0SJiri Benc }
239e9f207f0SJiri Benc
2400ab6cba0SJohannes Berg #define _IEEE80211_IF_FILE_W_FN(name) \
2410f78231bSJohannes Berg static ssize_t ieee80211_if_write_##name(struct file *file, \
2420f78231bSJohannes Berg const char __user *userbuf, \
2430f78231bSJohannes Berg size_t count, loff_t *ppos) \
2440f78231bSJohannes Berg { \
2454ded3bfeSJohannes Berg return ieee80211_if_write_sdata(file, userbuf, \
2460ab6cba0SJohannes Berg count, ppos, \
247170cd6a6SBenjamin Berg ieee80211_if_parse_##name); \
2484cd3c4ecSJohannes Berg }
2490f78231bSJohannes Berg
2504cd3c4ecSJohannes Berg #define IEEE80211_IF_FILE_R(name) \
2510ab6cba0SJohannes Berg _IEEE80211_IF_FILE_R_FN(name) \
2524cd3c4ecSJohannes Berg _IEEE80211_IF_FILE_OPS(name, ieee80211_if_read_##name, NULL)
2534cd3c4ecSJohannes Berg
2544cd3c4ecSJohannes Berg #define IEEE80211_IF_FILE_W(name) \
2550ab6cba0SJohannes Berg _IEEE80211_IF_FILE_W_FN(name) \
2564cd3c4ecSJohannes Berg _IEEE80211_IF_FILE_OPS(name, NULL, ieee80211_if_write_##name)
2574cd3c4ecSJohannes Berg
2584cd3c4ecSJohannes Berg #define IEEE80211_IF_FILE_RW(name) \
2590ab6cba0SJohannes Berg _IEEE80211_IF_FILE_R_FN(name) \
2600ab6cba0SJohannes Berg _IEEE80211_IF_FILE_W_FN(name) \
2614cd3c4ecSJohannes Berg _IEEE80211_IF_FILE_OPS(name, ieee80211_if_read_##name, \
2624cd3c4ecSJohannes Berg ieee80211_if_write_##name)
2630f78231bSJohannes Berg
264e9f207f0SJiri Benc #define IEEE80211_IF_FILE(name, field, format) \
265170cd6a6SBenjamin Berg IEEE80211_IF_FMT_##format(name, struct ieee80211_sub_if_data, field) \
2664cd3c4ecSJohannes Berg IEEE80211_IF_FILE_R(name)
267e9f207f0SJiri Benc
2680ab6cba0SJohannes Berg #define _IEEE80211_IF_LINK_R_FN(name) \
2690ab6cba0SJohannes Berg static ssize_t ieee80211_if_read_##name(struct file *file, \
2700ab6cba0SJohannes Berg char __user *userbuf, \
2710ab6cba0SJohannes Berg size_t count, loff_t *ppos) \
2720ab6cba0SJohannes Berg { \
2734ded3bfeSJohannes Berg return ieee80211_if_read_link(file, \
2740ab6cba0SJohannes Berg userbuf, count, ppos, \
2750ab6cba0SJohannes Berg ieee80211_if_fmt_##name); \
2760ab6cba0SJohannes Berg }
2770ab6cba0SJohannes Berg
2780ab6cba0SJohannes Berg #define _IEEE80211_IF_LINK_W_FN(name) \
2790ab6cba0SJohannes Berg static ssize_t ieee80211_if_write_##name(struct file *file, \
2800ab6cba0SJohannes Berg const char __user *userbuf, \
2810ab6cba0SJohannes Berg size_t count, loff_t *ppos) \
2820ab6cba0SJohannes Berg { \
2834ded3bfeSJohannes Berg return ieee80211_if_write_link(file, userbuf, \
2840ab6cba0SJohannes Berg count, ppos, \
2850ab6cba0SJohannes Berg ieee80211_if_parse_##name); \
2860ab6cba0SJohannes Berg }
2870ab6cba0SJohannes Berg
288170cd6a6SBenjamin Berg #define IEEE80211_IF_LINK_FILE_R(name) \
2890ab6cba0SJohannes Berg _IEEE80211_IF_LINK_R_FN(name) \
290170cd6a6SBenjamin Berg _IEEE80211_IF_FILE_OPS(link_##name, ieee80211_if_read_##name, NULL)
291170cd6a6SBenjamin Berg
292170cd6a6SBenjamin Berg #define IEEE80211_IF_LINK_FILE_W(name) \
2930ab6cba0SJohannes Berg _IEEE80211_IF_LINK_W_FN(name) \
294170cd6a6SBenjamin Berg _IEEE80211_IF_FILE_OPS(link_##name, NULL, ieee80211_if_write_##name)
295170cd6a6SBenjamin Berg
296170cd6a6SBenjamin Berg #define IEEE80211_IF_LINK_FILE_RW(name) \
2970ab6cba0SJohannes Berg _IEEE80211_IF_LINK_R_FN(name) \
2980ab6cba0SJohannes Berg _IEEE80211_IF_LINK_W_FN(name) \
299170cd6a6SBenjamin Berg _IEEE80211_IF_FILE_OPS(link_##name, ieee80211_if_read_##name, \
300170cd6a6SBenjamin Berg ieee80211_if_write_##name)
301170cd6a6SBenjamin Berg
302170cd6a6SBenjamin Berg #define IEEE80211_IF_LINK_FILE(name, field, format) \
303170cd6a6SBenjamin Berg IEEE80211_IF_FMT_##format(name, struct ieee80211_link_data, field) \
304170cd6a6SBenjamin Berg IEEE80211_IF_LINK_FILE_R(name)
305170cd6a6SBenjamin Berg
306e9f207f0SJiri Benc /* common attributes */
30757fbcce3SJohannes Berg IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[NL80211_BAND_2GHZ],
30837eb0b16SJouni Malinen HEX);
30957fbcce3SJohannes Berg IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[NL80211_BAND_5GHZ],
31037eb0b16SJouni Malinen HEX);
31119468413SSimon Wunderlich IEEE80211_IF_FILE(rc_rateidx_mcs_mask_2ghz,
31257fbcce3SJohannes Berg rc_rateidx_mcs_mask[NL80211_BAND_2GHZ], HEXARRAY);
31319468413SSimon Wunderlich IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz,
31457fbcce3SJohannes Berg rc_rateidx_mcs_mask[NL80211_BAND_5GHZ], HEXARRAY);
31519468413SSimon Wunderlich
ieee80211_if_fmt_rc_rateidx_vht_mcs_mask_2ghz(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)316b119ad6eSLorenzo Bianconi static ssize_t ieee80211_if_fmt_rc_rateidx_vht_mcs_mask_2ghz(
317b119ad6eSLorenzo Bianconi const struct ieee80211_sub_if_data *sdata,
318b119ad6eSLorenzo Bianconi char *buf, int buflen)
319b119ad6eSLorenzo Bianconi {
320b119ad6eSLorenzo Bianconi int i, len = 0;
32157fbcce3SJohannes Berg const u16 *mask = sdata->rc_rateidx_vht_mcs_mask[NL80211_BAND_2GHZ];
322b119ad6eSLorenzo Bianconi
323b119ad6eSLorenzo Bianconi for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
324b119ad6eSLorenzo Bianconi len += scnprintf(buf + len, buflen - len, "%04x ", mask[i]);
325b119ad6eSLorenzo Bianconi len += scnprintf(buf + len, buflen - len, "\n");
326b119ad6eSLorenzo Bianconi
327b119ad6eSLorenzo Bianconi return len;
328b119ad6eSLorenzo Bianconi }
329b119ad6eSLorenzo Bianconi
330b119ad6eSLorenzo Bianconi IEEE80211_IF_FILE_R(rc_rateidx_vht_mcs_mask_2ghz);
331b119ad6eSLorenzo Bianconi
ieee80211_if_fmt_rc_rateidx_vht_mcs_mask_5ghz(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)332b119ad6eSLorenzo Bianconi static ssize_t ieee80211_if_fmt_rc_rateidx_vht_mcs_mask_5ghz(
333b119ad6eSLorenzo Bianconi const struct ieee80211_sub_if_data *sdata,
334b119ad6eSLorenzo Bianconi char *buf, int buflen)
335b119ad6eSLorenzo Bianconi {
336b119ad6eSLorenzo Bianconi int i, len = 0;
33757fbcce3SJohannes Berg const u16 *mask = sdata->rc_rateidx_vht_mcs_mask[NL80211_BAND_5GHZ];
338b119ad6eSLorenzo Bianconi
339b119ad6eSLorenzo Bianconi for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
340b119ad6eSLorenzo Bianconi len += scnprintf(buf + len, buflen - len, "%04x ", mask[i]);
341b119ad6eSLorenzo Bianconi len += scnprintf(buf + len, buflen - len, "\n");
342b119ad6eSLorenzo Bianconi
343b119ad6eSLorenzo Bianconi return len;
344b119ad6eSLorenzo Bianconi }
345b119ad6eSLorenzo Bianconi
346b119ad6eSLorenzo Bianconi IEEE80211_IF_FILE_R(rc_rateidx_vht_mcs_mask_5ghz);
347b119ad6eSLorenzo Bianconi
3484914b3bbSBen Greear IEEE80211_IF_FILE(flags, flags, HEX);
3494914b3bbSBen Greear IEEE80211_IF_FILE(state, state, LHEX);
350170cd6a6SBenjamin Berg IEEE80211_IF_LINK_FILE(txpower, conf->txpower, DEC);
351170cd6a6SBenjamin Berg IEEE80211_IF_LINK_FILE(ap_power_level, ap_power_level, DEC);
352170cd6a6SBenjamin Berg IEEE80211_IF_LINK_FILE(user_power_level, user_power_level, DEC);
353e9f207f0SJiri Benc
35408643315SJohannes Berg static ssize_t
ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)35508643315SJohannes Berg ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata,
35608643315SJohannes Berg char *buf, int buflen)
35708643315SJohannes Berg {
35808643315SJohannes Berg int len;
35908643315SJohannes Berg
36008643315SJohannes Berg len = scnprintf(buf, buflen, "AC queues: VO:%d VI:%d BE:%d BK:%d\n",
36108643315SJohannes Berg sdata->vif.hw_queue[IEEE80211_AC_VO],
36208643315SJohannes Berg sdata->vif.hw_queue[IEEE80211_AC_VI],
36308643315SJohannes Berg sdata->vif.hw_queue[IEEE80211_AC_BE],
36408643315SJohannes Berg sdata->vif.hw_queue[IEEE80211_AC_BK]);
36508643315SJohannes Berg
36608643315SJohannes Berg if (sdata->vif.type == NL80211_IFTYPE_AP)
36708643315SJohannes Berg len += scnprintf(buf + len, buflen - len, "cab queue: %d\n",
36808643315SJohannes Berg sdata->vif.cab_queue);
36908643315SJohannes Berg
37008643315SJohannes Berg return len;
37108643315SJohannes Berg }
3724cd3c4ecSJohannes Berg IEEE80211_IF_FILE_R(hw_queues);
37308643315SJohannes Berg
37446900298SJohannes Berg /* STA attributes */
375bfd8403aSJohannes Berg IEEE80211_IF_FILE(bssid, deflink.u.mgd.bssid, MAC);
376f276e20bSJohannes Berg IEEE80211_IF_FILE(aid, vif.cfg.aid, DEC);
37778e443e4SBen Greear IEEE80211_IF_FILE(beacon_timeout, u.mgd.beacon_timeout, JIFFIES_TO_MS);
378e9f207f0SJiri Benc
ieee80211_set_smps(struct ieee80211_link_data * link,enum ieee80211_smps_mode smps_mode)379170cd6a6SBenjamin Berg static int ieee80211_set_smps(struct ieee80211_link_data *link,
3800f78231bSJohannes Berg enum ieee80211_smps_mode smps_mode)
3810f78231bSJohannes Berg {
382170cd6a6SBenjamin Berg struct ieee80211_sub_if_data *sdata = link->sdata;
3830f78231bSJohannes Berg struct ieee80211_local *local = sdata->local;
3840f78231bSJohannes Berg
38500f823b6SIlan Peer /* The driver indicated that EML is enabled for the interface, thus do
38600f823b6SIlan Peer * not allow to override the SMPS state.
38700f823b6SIlan Peer */
38800f823b6SIlan Peer if (sdata->vif.driver_flags & IEEE80211_VIF_EML_ACTIVE)
389bc1be54dSMiri Korenblit return -EOPNOTSUPP;
390bc1be54dSMiri Korenblit
3910d8614b4SEliad Peller if (!(local->hw.wiphy->features & NL80211_FEATURE_STATIC_SMPS) &&
3920f78231bSJohannes Berg smps_mode == IEEE80211_SMPS_STATIC)
3930f78231bSJohannes Berg return -EINVAL;
3940f78231bSJohannes Berg
3950f78231bSJohannes Berg /* auto should be dynamic if in PS mode */
3960d8614b4SEliad Peller if (!(local->hw.wiphy->features & NL80211_FEATURE_DYNAMIC_SMPS) &&
3970f78231bSJohannes Berg (smps_mode == IEEE80211_SMPS_DYNAMIC ||
3980f78231bSJohannes Berg smps_mode == IEEE80211_SMPS_AUTOMATIC))
3990f78231bSJohannes Berg return -EINVAL;
4000f78231bSJohannes Berg
40152b4810bSIlan Peer if (sdata->vif.type != NL80211_IFTYPE_STATION)
4020f78231bSJohannes Berg return -EOPNOTSUPP;
4030f78231bSJohannes Berg
404076fc877SJohannes Berg return __ieee80211_request_smps_mgd(link->sdata, link, smps_mode);
4050f78231bSJohannes Berg }
4060f78231bSJohannes Berg
4070f78231bSJohannes Berg static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
4080f78231bSJohannes Berg [IEEE80211_SMPS_AUTOMATIC] = "auto",
4090f78231bSJohannes Berg [IEEE80211_SMPS_OFF] = "off",
4100f78231bSJohannes Berg [IEEE80211_SMPS_STATIC] = "static",
4110f78231bSJohannes Berg [IEEE80211_SMPS_DYNAMIC] = "dynamic",
4120f78231bSJohannes Berg };
4130f78231bSJohannes Berg
ieee80211_if_fmt_smps(const struct ieee80211_link_data * link,char * buf,int buflen)414170cd6a6SBenjamin Berg static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_link_data *link,
4150f78231bSJohannes Berg char *buf, int buflen)
4160f78231bSJohannes Berg {
417170cd6a6SBenjamin Berg if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
4180f78231bSJohannes Berg return snprintf(buf, buflen, "request: %s\nused: %s\n",
419170cd6a6SBenjamin Berg smps_modes[link->u.mgd.req_smps],
420170cd6a6SBenjamin Berg smps_modes[link->smps_mode]);
421687da132SEmmanuel Grumbach return -EINVAL;
4220f78231bSJohannes Berg }
4230f78231bSJohannes Berg
ieee80211_if_parse_smps(struct ieee80211_link_data * link,const char * buf,int buflen)424170cd6a6SBenjamin Berg static ssize_t ieee80211_if_parse_smps(struct ieee80211_link_data *link,
4250f78231bSJohannes Berg const char *buf, int buflen)
4260f78231bSJohannes Berg {
4270f78231bSJohannes Berg enum ieee80211_smps_mode mode;
4280f78231bSJohannes Berg
4290f78231bSJohannes Berg for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) {
4300f78231bSJohannes Berg if (strncmp(buf, smps_modes[mode], buflen) == 0) {
431170cd6a6SBenjamin Berg int err = ieee80211_set_smps(link, mode);
4320f78231bSJohannes Berg if (!err)
4330f78231bSJohannes Berg return buflen;
4340f78231bSJohannes Berg return err;
4350f78231bSJohannes Berg }
4360f78231bSJohannes Berg }
4370f78231bSJohannes Berg
4380f78231bSJohannes Berg return -EINVAL;
4390f78231bSJohannes Berg }
440170cd6a6SBenjamin Berg IEEE80211_IF_LINK_FILE_RW(smps);
441681d1190SJouni Malinen
ieee80211_if_parse_tkip_mic_test(struct ieee80211_sub_if_data * sdata,const char * buf,int buflen)442681d1190SJouni Malinen static ssize_t ieee80211_if_parse_tkip_mic_test(
443681d1190SJouni Malinen struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
444681d1190SJouni Malinen {
445681d1190SJouni Malinen struct ieee80211_local *local = sdata->local;
446681d1190SJouni Malinen u8 addr[ETH_ALEN];
447681d1190SJouni Malinen struct sk_buff *skb;
448681d1190SJouni Malinen struct ieee80211_hdr *hdr;
449681d1190SJouni Malinen __le16 fc;
450681d1190SJouni Malinen
45128656a11SJohannes Berg if (!mac_pton(buf, addr))
452681d1190SJouni Malinen return -EINVAL;
453681d1190SJouni Malinen
454681d1190SJouni Malinen if (!ieee80211_sdata_running(sdata))
455681d1190SJouni Malinen return -ENOTCONN;
456681d1190SJouni Malinen
457681d1190SJouni Malinen skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24 + 100);
458681d1190SJouni Malinen if (!skb)
459681d1190SJouni Malinen return -ENOMEM;
460681d1190SJouni Malinen skb_reserve(skb, local->hw.extra_tx_headroom);
461681d1190SJouni Malinen
462b080db58SJohannes Berg hdr = skb_put_zero(skb, 24);
463681d1190SJouni Malinen fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
464681d1190SJouni Malinen
465681d1190SJouni Malinen switch (sdata->vif.type) {
466681d1190SJouni Malinen case NL80211_IFTYPE_AP:
467681d1190SJouni Malinen fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
468681d1190SJouni Malinen /* DA BSSID SA */
469681d1190SJouni Malinen memcpy(hdr->addr1, addr, ETH_ALEN);
470681d1190SJouni Malinen memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
471681d1190SJouni Malinen memcpy(hdr->addr3, sdata->vif.addr, ETH_ALEN);
472681d1190SJouni Malinen break;
473681d1190SJouni Malinen case NL80211_IFTYPE_STATION:
474681d1190SJouni Malinen fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
475681d1190SJouni Malinen /* BSSID SA DA */
47641c97a20SJohannes Berg if (!sdata->u.mgd.associated) {
477681d1190SJouni Malinen dev_kfree_skb(skb);
478681d1190SJouni Malinen return -ENOTCONN;
479681d1190SJouni Malinen }
480bfd8403aSJohannes Berg memcpy(hdr->addr1, sdata->deflink.u.mgd.bssid, ETH_ALEN);
481681d1190SJouni Malinen memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
482681d1190SJouni Malinen memcpy(hdr->addr3, addr, ETH_ALEN);
483681d1190SJouni Malinen break;
484681d1190SJouni Malinen default:
485681d1190SJouni Malinen dev_kfree_skb(skb);
486681d1190SJouni Malinen return -EOPNOTSUPP;
487681d1190SJouni Malinen }
488681d1190SJouni Malinen hdr->frame_control = fc;
489681d1190SJouni Malinen
490681d1190SJouni Malinen /*
491681d1190SJouni Malinen * Add some length to the test frame to make it look bit more valid.
492681d1190SJouni Malinen * The exact contents does not matter since the recipient is required
493681d1190SJouni Malinen * to drop this because of the Michael MIC failure.
494681d1190SJouni Malinen */
495b080db58SJohannes Berg skb_put_zero(skb, 50);
496681d1190SJouni Malinen
497681d1190SJouni Malinen IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_TKIP_MIC_FAILURE;
498681d1190SJouni Malinen
499681d1190SJouni Malinen ieee80211_tx_skb(sdata, skb);
500681d1190SJouni Malinen
501681d1190SJouni Malinen return buflen;
502681d1190SJouni Malinen }
5034cd3c4ecSJohannes Berg IEEE80211_IF_FILE_W(tkip_mic_test);
504681d1190SJouni Malinen
ieee80211_if_parse_beacon_loss(struct ieee80211_sub_if_data * sdata,const char * buf,int buflen)505802ee9ecSEliad Peller static ssize_t ieee80211_if_parse_beacon_loss(
506802ee9ecSEliad Peller struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
507802ee9ecSEliad Peller {
508f276e20bSJohannes Berg if (!ieee80211_sdata_running(sdata) || !sdata->vif.cfg.assoc)
509802ee9ecSEliad Peller return -ENOTCONN;
510802ee9ecSEliad Peller
511802ee9ecSEliad Peller ieee80211_beacon_loss(&sdata->vif);
512802ee9ecSEliad Peller
513802ee9ecSEliad Peller return buflen;
514802ee9ecSEliad Peller }
515802ee9ecSEliad Peller IEEE80211_IF_FILE_W(beacon_loss);
516802ee9ecSEliad Peller
ieee80211_if_fmt_uapsd_queues(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)517dc41e4d4SEliad Peller static ssize_t ieee80211_if_fmt_uapsd_queues(
518dc41e4d4SEliad Peller const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
519dc41e4d4SEliad Peller {
520dc41e4d4SEliad Peller const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
521dc41e4d4SEliad Peller
522dc41e4d4SEliad Peller return snprintf(buf, buflen, "0x%x\n", ifmgd->uapsd_queues);
523dc41e4d4SEliad Peller }
524dc41e4d4SEliad Peller
ieee80211_if_parse_uapsd_queues(struct ieee80211_sub_if_data * sdata,const char * buf,int buflen)525dc41e4d4SEliad Peller static ssize_t ieee80211_if_parse_uapsd_queues(
526dc41e4d4SEliad Peller struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
527dc41e4d4SEliad Peller {
528dc41e4d4SEliad Peller struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
529dc41e4d4SEliad Peller u8 val;
530dc41e4d4SEliad Peller int ret;
531dc41e4d4SEliad Peller
532dc41e4d4SEliad Peller ret = kstrtou8(buf, 0, &val);
533dc41e4d4SEliad Peller if (ret)
534dc41e4d4SEliad Peller return ret;
535dc41e4d4SEliad Peller
536dc41e4d4SEliad Peller if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
537dc41e4d4SEliad Peller return -ERANGE;
538dc41e4d4SEliad Peller
539dc41e4d4SEliad Peller ifmgd->uapsd_queues = val;
540dc41e4d4SEliad Peller
541dc41e4d4SEliad Peller return buflen;
542dc41e4d4SEliad Peller }
5434cd3c4ecSJohannes Berg IEEE80211_IF_FILE_RW(uapsd_queues);
544dc41e4d4SEliad Peller
ieee80211_if_fmt_uapsd_max_sp_len(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)545dc41e4d4SEliad Peller static ssize_t ieee80211_if_fmt_uapsd_max_sp_len(
546dc41e4d4SEliad Peller const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
547dc41e4d4SEliad Peller {
548dc41e4d4SEliad Peller const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
549dc41e4d4SEliad Peller
550dc41e4d4SEliad Peller return snprintf(buf, buflen, "0x%x\n", ifmgd->uapsd_max_sp_len);
551dc41e4d4SEliad Peller }
552dc41e4d4SEliad Peller
ieee80211_if_parse_uapsd_max_sp_len(struct ieee80211_sub_if_data * sdata,const char * buf,int buflen)553dc41e4d4SEliad Peller static ssize_t ieee80211_if_parse_uapsd_max_sp_len(
554dc41e4d4SEliad Peller struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
555dc41e4d4SEliad Peller {
556dc41e4d4SEliad Peller struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
557dc41e4d4SEliad Peller unsigned long val;
558dc41e4d4SEliad Peller int ret;
559dc41e4d4SEliad Peller
560dc41e4d4SEliad Peller ret = kstrtoul(buf, 0, &val);
561dc41e4d4SEliad Peller if (ret)
562dc41e4d4SEliad Peller return -EINVAL;
563dc41e4d4SEliad Peller
564dc41e4d4SEliad Peller if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
565dc41e4d4SEliad Peller return -ERANGE;
566dc41e4d4SEliad Peller
567dc41e4d4SEliad Peller ifmgd->uapsd_max_sp_len = val;
568dc41e4d4SEliad Peller
569dc41e4d4SEliad Peller return buflen;
570dc41e4d4SEliad Peller }
5714cd3c4ecSJohannes Berg IEEE80211_IF_FILE_RW(uapsd_max_sp_len);
572dc41e4d4SEliad Peller
ieee80211_if_fmt_tdls_wider_bw(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)57382c0cc90SArik Nemtsov static ssize_t ieee80211_if_fmt_tdls_wider_bw(
57482c0cc90SArik Nemtsov const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
57582c0cc90SArik Nemtsov {
57682c0cc90SArik Nemtsov const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
57782c0cc90SArik Nemtsov bool tdls_wider_bw;
57882c0cc90SArik Nemtsov
57982c0cc90SArik Nemtsov tdls_wider_bw = ieee80211_hw_check(&sdata->local->hw, TDLS_WIDER_BW) &&
58082c0cc90SArik Nemtsov !ifmgd->tdls_wider_bw_prohibited;
58182c0cc90SArik Nemtsov
58282c0cc90SArik Nemtsov return snprintf(buf, buflen, "%d\n", tdls_wider_bw);
58382c0cc90SArik Nemtsov }
58482c0cc90SArik Nemtsov
ieee80211_if_parse_tdls_wider_bw(struct ieee80211_sub_if_data * sdata,const char * buf,int buflen)58582c0cc90SArik Nemtsov static ssize_t ieee80211_if_parse_tdls_wider_bw(
58682c0cc90SArik Nemtsov struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
58782c0cc90SArik Nemtsov {
58882c0cc90SArik Nemtsov struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
58982c0cc90SArik Nemtsov u8 val;
59082c0cc90SArik Nemtsov int ret;
59182c0cc90SArik Nemtsov
59282c0cc90SArik Nemtsov ret = kstrtou8(buf, 0, &val);
59382c0cc90SArik Nemtsov if (ret)
59482c0cc90SArik Nemtsov return ret;
59582c0cc90SArik Nemtsov
59682c0cc90SArik Nemtsov ifmgd->tdls_wider_bw_prohibited = !val;
59782c0cc90SArik Nemtsov return buflen;
59882c0cc90SArik Nemtsov }
59982c0cc90SArik Nemtsov IEEE80211_IF_FILE_RW(tdls_wider_bw);
60082c0cc90SArik Nemtsov
601e9f207f0SJiri Benc /* AP attributes */
602030ef8f8SFelix Fietkau IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
603d012a605SMarco Porsch IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC);
604d012a605SMarco Porsch IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC);
60572f15d53SMichael Braun IEEE80211_IF_FILE(num_mcast_sta_vlan, u.vlan.num_mcast_sta, ATOMIC);
606e9f207f0SJiri Benc
ieee80211_if_fmt_num_buffered_multicast(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)607e9f207f0SJiri Benc static ssize_t ieee80211_if_fmt_num_buffered_multicast(
608e9f207f0SJiri Benc const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
609e9f207f0SJiri Benc {
610e9f207f0SJiri Benc return scnprintf(buf, buflen, "%u\n",
611d012a605SMarco Porsch skb_queue_len(&sdata->u.ap.ps.bc_buf));
612e9f207f0SJiri Benc }
6134cd3c4ecSJohannes Berg IEEE80211_IF_FILE_R(num_buffered_multicast);
614e9f207f0SJiri Benc
ieee80211_if_fmt_aqm(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)6158d51dbb8SToke Høiland-Jørgensen static ssize_t ieee80211_if_fmt_aqm(
6168d51dbb8SToke Høiland-Jørgensen const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
6178d51dbb8SToke Høiland-Jørgensen {
6188d51dbb8SToke Høiland-Jørgensen struct ieee80211_local *local = sdata->local;
6198ed31a26SMiaoqing Pan struct txq_info *txqi;
6208d51dbb8SToke Høiland-Jørgensen int len;
6218d51dbb8SToke Høiland-Jørgensen
6228ed31a26SMiaoqing Pan if (!sdata->vif.txq)
6238ed31a26SMiaoqing Pan return 0;
6248ed31a26SMiaoqing Pan
6258ed31a26SMiaoqing Pan txqi = to_txq_info(sdata->vif.txq);
6268ed31a26SMiaoqing Pan
6278d51dbb8SToke Høiland-Jørgensen spin_lock_bh(&local->fq.lock);
6288d51dbb8SToke Høiland-Jørgensen rcu_read_lock();
6298d51dbb8SToke Høiland-Jørgensen
6308d51dbb8SToke Høiland-Jørgensen len = scnprintf(buf,
6318d51dbb8SToke Høiland-Jørgensen buflen,
6328d51dbb8SToke Høiland-Jørgensen "ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n"
6338d51dbb8SToke Høiland-Jørgensen "%u %u %u %u %u %u %u %u %u %u\n",
6348d51dbb8SToke Høiland-Jørgensen txqi->txq.ac,
6358d51dbb8SToke Høiland-Jørgensen txqi->tin.backlog_bytes,
6368d51dbb8SToke Høiland-Jørgensen txqi->tin.backlog_packets,
6378d51dbb8SToke Høiland-Jørgensen txqi->tin.flows,
6388d51dbb8SToke Høiland-Jørgensen txqi->cstats.drop_count,
6398d51dbb8SToke Høiland-Jørgensen txqi->cstats.ecn_mark,
6408d51dbb8SToke Høiland-Jørgensen txqi->tin.overlimit,
6418d51dbb8SToke Høiland-Jørgensen txqi->tin.collisions,
6428d51dbb8SToke Høiland-Jørgensen txqi->tin.tx_bytes,
6438d51dbb8SToke Høiland-Jørgensen txqi->tin.tx_packets);
6448d51dbb8SToke Høiland-Jørgensen
6458d51dbb8SToke Høiland-Jørgensen rcu_read_unlock();
6468d51dbb8SToke Høiland-Jørgensen spin_unlock_bh(&local->fq.lock);
6478d51dbb8SToke Høiland-Jørgensen
6488d51dbb8SToke Høiland-Jørgensen return len;
6498d51dbb8SToke Høiland-Jørgensen }
6508d51dbb8SToke Høiland-Jørgensen IEEE80211_IF_FILE_R(aqm);
6518d51dbb8SToke Høiland-Jørgensen
652ebceec86SMichael Braun IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX);
653ebceec86SMichael Braun
65437a41b4aSEliad Peller /* IBSS attributes */
ieee80211_if_fmt_tsf(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)65537a41b4aSEliad Peller static ssize_t ieee80211_if_fmt_tsf(
65637a41b4aSEliad Peller const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
65737a41b4aSEliad Peller {
65837a41b4aSEliad Peller struct ieee80211_local *local = sdata->local;
65937a41b4aSEliad Peller u64 tsf;
66037a41b4aSEliad Peller
66137a41b4aSEliad Peller tsf = drv_get_tsf(local, (struct ieee80211_sub_if_data *)sdata);
66237a41b4aSEliad Peller
66337a41b4aSEliad Peller return scnprintf(buf, buflen, "0x%016llx\n", (unsigned long long) tsf);
66437a41b4aSEliad Peller }
66537a41b4aSEliad Peller
ieee80211_if_parse_tsf(struct ieee80211_sub_if_data * sdata,const char * buf,int buflen)66637a41b4aSEliad Peller static ssize_t ieee80211_if_parse_tsf(
66737a41b4aSEliad Peller struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
66837a41b4aSEliad Peller {
66937a41b4aSEliad Peller struct ieee80211_local *local = sdata->local;
67037a41b4aSEliad Peller unsigned long long tsf;
67137a41b4aSEliad Peller int ret;
6729bdd3a6bSJavier Cardona int tsf_is_delta = 0;
67337a41b4aSEliad Peller
67437a41b4aSEliad Peller if (strncmp(buf, "reset", 5) == 0) {
67537a41b4aSEliad Peller if (local->ops->reset_tsf) {
67637a41b4aSEliad Peller drv_reset_tsf(local, sdata);
67737a41b4aSEliad Peller wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
67837a41b4aSEliad Peller }
67937a41b4aSEliad Peller } else {
6809bdd3a6bSJavier Cardona if (buflen > 10 && buf[1] == '=') {
6819bdd3a6bSJavier Cardona if (buf[0] == '+')
6829bdd3a6bSJavier Cardona tsf_is_delta = 1;
6839bdd3a6bSJavier Cardona else if (buf[0] == '-')
6849bdd3a6bSJavier Cardona tsf_is_delta = -1;
6859bdd3a6bSJavier Cardona else
6869bdd3a6bSJavier Cardona return -EINVAL;
6879bdd3a6bSJavier Cardona buf += 2;
6889bdd3a6bSJavier Cardona }
68937a41b4aSEliad Peller ret = kstrtoull(buf, 10, &tsf);
69037a41b4aSEliad Peller if (ret < 0)
6916fc1da9bSJohannes Berg return ret;
692354d381bSPedersen, Thomas if (tsf_is_delta && local->ops->offset_tsf) {
693354d381bSPedersen, Thomas drv_offset_tsf(local, sdata, tsf_is_delta * tsf);
694354d381bSPedersen, Thomas wiphy_info(local->hw.wiphy,
695354d381bSPedersen, Thomas "debugfs offset TSF by %018lld\n",
696354d381bSPedersen, Thomas tsf_is_delta * tsf);
697354d381bSPedersen, Thomas } else if (local->ops->set_tsf) {
6989bdd3a6bSJavier Cardona if (tsf_is_delta)
699354d381bSPedersen, Thomas tsf = drv_get_tsf(local, sdata) +
700354d381bSPedersen, Thomas tsf_is_delta * tsf;
70137a41b4aSEliad Peller drv_set_tsf(local, sdata, tsf);
70237a41b4aSEliad Peller wiphy_info(local->hw.wiphy,
70337a41b4aSEliad Peller "debugfs set TSF to %#018llx\n", tsf);
70437a41b4aSEliad Peller }
70537a41b4aSEliad Peller }
70637a41b4aSEliad Peller
707057d5f4bSThomas Pedersen ieee80211_recalc_dtim(local, sdata);
70837a41b4aSEliad Peller return buflen;
70937a41b4aSEliad Peller }
7104cd3c4ecSJohannes Berg IEEE80211_IF_FILE_RW(tsf);
71137a41b4aSEliad Peller
ieee80211_if_fmt_valid_links(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)7123d901102SJohannes Berg static ssize_t ieee80211_if_fmt_valid_links(const struct ieee80211_sub_if_data *sdata,
7133d901102SJohannes Berg char *buf, int buflen)
7143d901102SJohannes Berg {
7153d901102SJohannes Berg return snprintf(buf, buflen, "0x%x\n", sdata->vif.valid_links);
7163d901102SJohannes Berg }
7173d901102SJohannes Berg IEEE80211_IF_FILE_R(valid_links);
7183d901102SJohannes Berg
ieee80211_if_fmt_active_links(const struct ieee80211_sub_if_data * sdata,char * buf,int buflen)7193d901102SJohannes Berg static ssize_t ieee80211_if_fmt_active_links(const struct ieee80211_sub_if_data *sdata,
7203d901102SJohannes Berg char *buf, int buflen)
7213d901102SJohannes Berg {
7223d901102SJohannes Berg return snprintf(buf, buflen, "0x%x\n", sdata->vif.active_links);
7233d901102SJohannes Berg }
7243d901102SJohannes Berg
ieee80211_if_parse_active_links(struct ieee80211_sub_if_data * sdata,const char * buf,int buflen)7253d901102SJohannes Berg static ssize_t ieee80211_if_parse_active_links(struct ieee80211_sub_if_data *sdata,
7263d901102SJohannes Berg const char *buf, int buflen)
7273d901102SJohannes Berg {
7283d901102SJohannes Berg u16 active_links;
7293d901102SJohannes Berg
7303d901102SJohannes Berg if (kstrtou16(buf, 0, &active_links) || !active_links)
7313d901102SJohannes Berg return -EINVAL;
7323d901102SJohannes Berg
7333d901102SJohannes Berg return ieee80211_set_active_links(&sdata->vif, active_links) ?: buflen;
7343d901102SJohannes Berg }
7353d901102SJohannes Berg IEEE80211_IF_FILE_RW(active_links);
73637a41b4aSEliad Peller
737170cd6a6SBenjamin Berg IEEE80211_IF_LINK_FILE(addr, conf->addr, MAC);
738170cd6a6SBenjamin Berg
7399f42f607SLuis Carlos Cobo #ifdef CONFIG_MAC80211_MESH
740d4a5a489SAshok Nagarajan IEEE80211_IF_FILE(estab_plinks, u.mesh.estab_plinks, ATOMIC);
741d4a5a489SAshok Nagarajan
7429f42f607SLuis Carlos Cobo /* Mesh stats attributes */
743c8a61a7dSDaniel Walker IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC);
744c8a61a7dSDaniel Walker IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
745472dbc45SJohannes Berg IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
746472dbc45SJohannes Berg IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
7479f42f607SLuis Carlos Cobo IEEE80211_IF_FILE(dropped_frames_no_route,
748472dbc45SJohannes Berg u.mesh.mshstats.dropped_frames_no_route, DEC);
7499f42f607SLuis Carlos Cobo
7509f42f607SLuis Carlos Cobo /* Mesh parameters */
75136ff382dSJohannes Berg IEEE80211_IF_FILE(dot11MeshMaxRetries,
75236ff382dSJohannes Berg u.mesh.mshcfg.dot11MeshMaxRetries, DEC);
75336ff382dSJohannes Berg IEEE80211_IF_FILE(dot11MeshRetryTimeout,
75436ff382dSJohannes Berg u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);
75536ff382dSJohannes Berg IEEE80211_IF_FILE(dot11MeshConfirmTimeout,
75636ff382dSJohannes Berg u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);
75736ff382dSJohannes Berg IEEE80211_IF_FILE(dot11MeshHoldingTimeout,
75836ff382dSJohannes Berg u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
75936ff382dSJohannes Berg IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC);
76045904f21SJavier Cardona IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC);
76136ff382dSJohannes Berg IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC);
76236ff382dSJohannes Berg IEEE80211_IF_FILE(dot11MeshMaxPeerLinks,
76336ff382dSJohannes Berg u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
76436ff382dSJohannes Berg IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout,
76536ff382dSJohannes Berg u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
76636ff382dSJohannes Berg IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval,
76736ff382dSJohannes Berg u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
768dca7e943SThomas Pedersen IEEE80211_IF_FILE(dot11MeshHWMPperrMinInterval,
769dca7e943SThomas Pedersen u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC);
77036ff382dSJohannes Berg IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime,
77136ff382dSJohannes Berg u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
77236ff382dSJohannes Berg IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries,
77336ff382dSJohannes Berg u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);
77436ff382dSJohannes Berg IEEE80211_IF_FILE(path_refresh_time,
77536ff382dSJohannes Berg u.mesh.mshcfg.path_refresh_time, DEC);
77636ff382dSJohannes Berg IEEE80211_IF_FILE(min_discovery_timeout,
77736ff382dSJohannes Berg u.mesh.mshcfg.min_discovery_timeout, DEC);
77863c5723bSRui Paulo IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
77963c5723bSRui Paulo u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
78016dd7267SJavier Cardona IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol,
78116dd7267SJavier Cardona u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC);
7820507e159SJavier Cardona IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
7830507e159SJavier Cardona u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
78494f90656SChun-Yeow Yeoh IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC);
78555335137SAshok Nagarajan IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC);
7864416f5d2SAshok Nagarajan IEEE80211_IF_FILE(ht_opmode, u.mesh.mshcfg.ht_opmode, DEC);
787ac1073a6SChun-Yeow Yeoh IEEE80211_IF_FILE(dot11MeshHWMPactivePathToRootTimeout,
788ac1073a6SChun-Yeow Yeoh u.mesh.mshcfg.dot11MeshHWMPactivePathToRootTimeout, DEC);
789ac1073a6SChun-Yeow Yeoh IEEE80211_IF_FILE(dot11MeshHWMProotInterval,
790ac1073a6SChun-Yeow Yeoh u.mesh.mshcfg.dot11MeshHWMProotInterval, DEC);
791728b19e5SChun-Yeow Yeoh IEEE80211_IF_FILE(dot11MeshHWMPconfirmationInterval,
792728b19e5SChun-Yeow Yeoh u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval, DEC);
7933f52b7e3SMarco Porsch IEEE80211_IF_FILE(power_mode, u.mesh.mshcfg.power_mode, DEC);
7943f52b7e3SMarco Porsch IEEE80211_IF_FILE(dot11MeshAwakeWindowDuration,
7953f52b7e3SMarco Porsch u.mesh.mshcfg.dot11MeshAwakeWindowDuration, DEC);
79601d66fbdSBob Copeland IEEE80211_IF_FILE(dot11MeshConnectedToMeshGate,
79701d66fbdSBob Copeland u.mesh.mshcfg.dot11MeshConnectedToMeshGate, DEC);
798e3718a61SLinus Lüssing IEEE80211_IF_FILE(dot11MeshNolearn, u.mesh.mshcfg.dot11MeshNolearn, DEC);
799184eebe6SMarkus Theil IEEE80211_IF_FILE(dot11MeshConnectedToAuthServer,
800184eebe6SMarkus Theil u.mesh.mshcfg.dot11MeshConnectedToAuthServer, DEC);
8019f42f607SLuis Carlos Cobo #endif
8029f42f607SLuis Carlos Cobo
8030f78231bSJohannes Berg #define DEBUGFS_ADD_MODE(name, mode) \
804ddbfe860SStanislaw Gruszka debugfs_create_file(#name, mode, sdata->vif.debugfs_dir, \
80584674ef4STom Rix sdata, &name##_ops)
8060f78231bSJohannes Berg
807a8df1f58SIlan Peer #define DEBUGFS_ADD_X(_bits, _name, _mode) \
808a8df1f58SIlan Peer debugfs_create_x##_bits(#_name, _mode, sdata->vif.debugfs_dir, \
809a8df1f58SIlan Peer &sdata->vif._name)
810a8df1f58SIlan Peer
811a8df1f58SIlan Peer #define DEBUGFS_ADD_X8(_name, _mode) \
812a8df1f58SIlan Peer DEBUGFS_ADD_X(8, _name, _mode)
813a8df1f58SIlan Peer
814a8df1f58SIlan Peer #define DEBUGFS_ADD_X16(_name, _mode) \
815a8df1f58SIlan Peer DEBUGFS_ADD_X(16, _name, _mode)
816a8df1f58SIlan Peer
817a8df1f58SIlan Peer #define DEBUGFS_ADD_X32(_name, _mode) \
818a8df1f58SIlan Peer DEBUGFS_ADD_X(32, _name, _mode)
819a8df1f58SIlan Peer
820fcb2c9e1SFelix Fietkau #define DEBUGFS_ADD(name) DEBUGFS_ADD_MODE(name, 0400)
821fcb2c9e1SFelix Fietkau
add_common_files(struct ieee80211_sub_if_data * sdata)822fcb2c9e1SFelix Fietkau static void add_common_files(struct ieee80211_sub_if_data *sdata)
823e9f207f0SJiri Benc {
8242d46d7c1SJohannes Berg DEBUGFS_ADD(rc_rateidx_mask_2ghz);
8252d46d7c1SJohannes Berg DEBUGFS_ADD(rc_rateidx_mask_5ghz);
82619468413SSimon Wunderlich DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
82719468413SSimon Wunderlich DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
828b119ad6eSLorenzo Bianconi DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_2ghz);
829b119ad6eSLorenzo Bianconi DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz);
83008643315SJohannes Berg DEBUGFS_ADD(hw_queues);
8318d51dbb8SToke Høiland-Jørgensen
832107395f9SAlexander Wetzel if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
833942741daSFelix Fietkau sdata->vif.type != NL80211_IFTYPE_NAN)
8348d51dbb8SToke Høiland-Jørgensen DEBUGFS_ADD(aqm);
835fcb2c9e1SFelix Fietkau }
8363e122be0SJohannes Berg
add_sta_files(struct ieee80211_sub_if_data * sdata)837fcb2c9e1SFelix Fietkau static void add_sta_files(struct ieee80211_sub_if_data *sdata)
838fcb2c9e1SFelix Fietkau {
8392d46d7c1SJohannes Berg DEBUGFS_ADD(bssid);
8402d46d7c1SJohannes Berg DEBUGFS_ADD(aid);
84178e443e4SBen Greear DEBUGFS_ADD(beacon_timeout);
842681d1190SJouni Malinen DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
843802ee9ecSEliad Peller DEBUGFS_ADD_MODE(beacon_loss, 0200);
844dc41e4d4SEliad Peller DEBUGFS_ADD_MODE(uapsd_queues, 0600);
845dc41e4d4SEliad Peller DEBUGFS_ADD_MODE(uapsd_max_sp_len, 0600);
84682c0cc90SArik Nemtsov DEBUGFS_ADD_MODE(tdls_wider_bw, 0600);
8474cacadc0SIlan Peer DEBUGFS_ADD_MODE(valid_links, 0400);
8483d901102SJohannes Berg DEBUGFS_ADD_MODE(active_links, 0600);
849a8df1f58SIlan Peer DEBUGFS_ADD_X16(dormant_links, 0400);
850e9f207f0SJiri Benc }
851e9f207f0SJiri Benc
add_ap_files(struct ieee80211_sub_if_data * sdata)852e9f207f0SJiri Benc static void add_ap_files(struct ieee80211_sub_if_data *sdata)
853e9f207f0SJiri Benc {
854030ef8f8SFelix Fietkau DEBUGFS_ADD(num_mcast_sta);
8552d46d7c1SJohannes Berg DEBUGFS_ADD(num_sta_ps);
8562d46d7c1SJohannes Berg DEBUGFS_ADD(dtim_count);
8572d46d7c1SJohannes Berg DEBUGFS_ADD(num_buffered_multicast);
858681d1190SJouni Malinen DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
859ebceec86SMichael Braun DEBUGFS_ADD_MODE(multicast_to_unicast, 0600);
860e9f207f0SJiri Benc }
861e9f207f0SJiri Benc
add_vlan_files(struct ieee80211_sub_if_data * sdata)86272f15d53SMichael Braun static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
86372f15d53SMichael Braun {
86472f15d53SMichael Braun /* add num_mcast_sta_vlan using name num_mcast_sta */
86572f15d53SMichael Braun debugfs_create_file("num_mcast_sta", 0400, sdata->vif.debugfs_dir,
86672f15d53SMichael Braun sdata, &num_mcast_sta_vlan_ops);
86772f15d53SMichael Braun }
86872f15d53SMichael Braun
add_ibss_files(struct ieee80211_sub_if_data * sdata)86937a41b4aSEliad Peller static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
87037a41b4aSEliad Peller {
87137a41b4aSEliad Peller DEBUGFS_ADD_MODE(tsf, 0600);
87237a41b4aSEliad Peller }
87337a41b4aSEliad Peller
8749f42f607SLuis Carlos Cobo #ifdef CONFIG_MAC80211_MESH
8759f42f607SLuis Carlos Cobo
add_mesh_files(struct ieee80211_sub_if_data * sdata)87612ce8ba3SJavier Cardona static void add_mesh_files(struct ieee80211_sub_if_data *sdata)
87712ce8ba3SJavier Cardona {
87812ce8ba3SJavier Cardona DEBUGFS_ADD_MODE(tsf, 0600);
879d4a5a489SAshok Nagarajan DEBUGFS_ADD_MODE(estab_plinks, 0400);
88012ce8ba3SJavier Cardona }
88112ce8ba3SJavier Cardona
add_mesh_stats(struct ieee80211_sub_if_data * sdata)8829f42f607SLuis Carlos Cobo static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
8839f42f607SLuis Carlos Cobo {
8847bcfaf2fSJohannes Berg struct dentry *dir = debugfs_create_dir("mesh_stats",
885ddbfe860SStanislaw Gruszka sdata->vif.debugfs_dir);
8867bcfaf2fSJohannes Berg #define MESHSTATS_ADD(name)\
88784674ef4STom Rix debugfs_create_file(#name, 0400, dir, sdata, &name##_ops)
8887bcfaf2fSJohannes Berg
889c8a61a7dSDaniel Walker MESHSTATS_ADD(fwded_mcast);
890c8a61a7dSDaniel Walker MESHSTATS_ADD(fwded_unicast);
8919f42f607SLuis Carlos Cobo MESHSTATS_ADD(fwded_frames);
8929f42f607SLuis Carlos Cobo MESHSTATS_ADD(dropped_frames_ttl);
8939f42f607SLuis Carlos Cobo MESHSTATS_ADD(dropped_frames_no_route);
8947bcfaf2fSJohannes Berg #undef MESHSTATS_ADD
8959f42f607SLuis Carlos Cobo }
8969f42f607SLuis Carlos Cobo
add_mesh_config(struct ieee80211_sub_if_data * sdata)8979f42f607SLuis Carlos Cobo static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
8989f42f607SLuis Carlos Cobo {
8997bcfaf2fSJohannes Berg struct dentry *dir = debugfs_create_dir("mesh_config",
900ddbfe860SStanislaw Gruszka sdata->vif.debugfs_dir);
9017bcfaf2fSJohannes Berg
9027bcfaf2fSJohannes Berg #define MESHPARAMS_ADD(name) \
90384674ef4STom Rix debugfs_create_file(#name, 0600, dir, sdata, &name##_ops)
9047bcfaf2fSJohannes Berg
9059f42f607SLuis Carlos Cobo MESHPARAMS_ADD(dot11MeshMaxRetries);
9069f42f607SLuis Carlos Cobo MESHPARAMS_ADD(dot11MeshRetryTimeout);
9079f42f607SLuis Carlos Cobo MESHPARAMS_ADD(dot11MeshConfirmTimeout);
9089f42f607SLuis Carlos Cobo MESHPARAMS_ADD(dot11MeshHoldingTimeout);
9099f42f607SLuis Carlos Cobo MESHPARAMS_ADD(dot11MeshTTL);
91045904f21SJavier Cardona MESHPARAMS_ADD(element_ttl);
9119f42f607SLuis Carlos Cobo MESHPARAMS_ADD(auto_open_plinks);
9129f42f607SLuis Carlos Cobo MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
9139f42f607SLuis Carlos Cobo MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
9149f42f607SLuis Carlos Cobo MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval);
915dca7e943SThomas Pedersen MESHPARAMS_ADD(dot11MeshHWMPperrMinInterval);
9169f42f607SLuis Carlos Cobo MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime);
9179f42f607SLuis Carlos Cobo MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
9189f42f607SLuis Carlos Cobo MESHPARAMS_ADD(path_refresh_time);
9199f42f607SLuis Carlos Cobo MESHPARAMS_ADD(min_discovery_timeout);
920699403dbSJavier Cardona MESHPARAMS_ADD(dot11MeshHWMPRootMode);
9210507e159SJavier Cardona MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
9228c06e8c0SChun-Yeow Yeoh MESHPARAMS_ADD(dot11MeshForwarding);
92316dd7267SJavier Cardona MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
92455335137SAshok Nagarajan MESHPARAMS_ADD(rssi_threshold);
9254416f5d2SAshok Nagarajan MESHPARAMS_ADD(ht_opmode);
926ac1073a6SChun-Yeow Yeoh MESHPARAMS_ADD(dot11MeshHWMPactivePathToRootTimeout);
927ac1073a6SChun-Yeow Yeoh MESHPARAMS_ADD(dot11MeshHWMProotInterval);
928728b19e5SChun-Yeow Yeoh MESHPARAMS_ADD(dot11MeshHWMPconfirmationInterval);
9293f52b7e3SMarco Porsch MESHPARAMS_ADD(power_mode);
9303f52b7e3SMarco Porsch MESHPARAMS_ADD(dot11MeshAwakeWindowDuration);
93101d66fbdSBob Copeland MESHPARAMS_ADD(dot11MeshConnectedToMeshGate);
932e3718a61SLinus Lüssing MESHPARAMS_ADD(dot11MeshNolearn);
933184eebe6SMarkus Theil MESHPARAMS_ADD(dot11MeshConnectedToAuthServer);
9347bcfaf2fSJohannes Berg #undef MESHPARAMS_ADD
9359f42f607SLuis Carlos Cobo }
9369f42f607SLuis Carlos Cobo #endif
9379f42f607SLuis Carlos Cobo
add_files(struct ieee80211_sub_if_data * sdata)938e9f207f0SJiri Benc static void add_files(struct ieee80211_sub_if_data *sdata)
939e9f207f0SJiri Benc {
940ddbfe860SStanislaw Gruszka if (!sdata->vif.debugfs_dir)
941e9f207f0SJiri Benc return;
942e9f207f0SJiri Benc
943fcb2c9e1SFelix Fietkau DEBUGFS_ADD(flags);
944fcb2c9e1SFelix Fietkau DEBUGFS_ADD(state);
945fcb2c9e1SFelix Fietkau
946fcb2c9e1SFelix Fietkau if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
947fcb2c9e1SFelix Fietkau add_common_files(sdata);
948fcb2c9e1SFelix Fietkau
94951fb61e7SJohannes Berg switch (sdata->vif.type) {
95005c914feSJohannes Berg case NL80211_IFTYPE_MESH_POINT:
9519f42f607SLuis Carlos Cobo #ifdef CONFIG_MAC80211_MESH
95212ce8ba3SJavier Cardona add_mesh_files(sdata);
9539f42f607SLuis Carlos Cobo add_mesh_stats(sdata);
9549f42f607SLuis Carlos Cobo add_mesh_config(sdata);
9559f42f607SLuis Carlos Cobo #endif
956472dbc45SJohannes Berg break;
95705c914feSJohannes Berg case NL80211_IFTYPE_STATION:
958e9f207f0SJiri Benc add_sta_files(sdata);
959e9f207f0SJiri Benc break;
96046900298SJohannes Berg case NL80211_IFTYPE_ADHOC:
96137a41b4aSEliad Peller add_ibss_files(sdata);
96246900298SJohannes Berg break;
96305c914feSJohannes Berg case NL80211_IFTYPE_AP:
964e9f207f0SJiri Benc add_ap_files(sdata);
965e9f207f0SJiri Benc break;
96672f15d53SMichael Braun case NL80211_IFTYPE_AP_VLAN:
96772f15d53SMichael Braun add_vlan_files(sdata);
96872f15d53SMichael Braun break;
969e9f207f0SJiri Benc default:
970e9f207f0SJiri Benc break;
971e9f207f0SJiri Benc }
972e9f207f0SJiri Benc }
973e9f207f0SJiri Benc
974170cd6a6SBenjamin Berg #undef DEBUGFS_ADD_MODE
975170cd6a6SBenjamin Berg #undef DEBUGFS_ADD
976170cd6a6SBenjamin Berg
977170cd6a6SBenjamin Berg #define DEBUGFS_ADD_MODE(dentry, name, mode) \
978170cd6a6SBenjamin Berg debugfs_create_file(#name, mode, dentry, \
979170cd6a6SBenjamin Berg link, &link_##name##_ops)
980170cd6a6SBenjamin Berg
981170cd6a6SBenjamin Berg #define DEBUGFS_ADD(dentry, name) DEBUGFS_ADD_MODE(dentry, name, 0400)
982170cd6a6SBenjamin Berg
add_link_files(struct ieee80211_link_data * link,struct dentry * dentry)983170cd6a6SBenjamin Berg static void add_link_files(struct ieee80211_link_data *link,
984170cd6a6SBenjamin Berg struct dentry *dentry)
985170cd6a6SBenjamin Berg {
986170cd6a6SBenjamin Berg DEBUGFS_ADD(dentry, txpower);
987170cd6a6SBenjamin Berg DEBUGFS_ADD(dentry, user_power_level);
988170cd6a6SBenjamin Berg DEBUGFS_ADD(dentry, ap_power_level);
989170cd6a6SBenjamin Berg
990170cd6a6SBenjamin Berg switch (link->sdata->vif.type) {
991170cd6a6SBenjamin Berg case NL80211_IFTYPE_STATION:
992170cd6a6SBenjamin Berg DEBUGFS_ADD_MODE(dentry, smps, 0600);
993170cd6a6SBenjamin Berg break;
994170cd6a6SBenjamin Berg default:
995170cd6a6SBenjamin Berg break;
996170cd6a6SBenjamin Berg }
997170cd6a6SBenjamin Berg }
998170cd6a6SBenjamin Berg
ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data * sdata,bool mld_vif)999733c498aSJohannes Berg static void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata,
1000c942398fSMiri Korenblit bool mld_vif)
1001e9f207f0SJiri Benc {
1002e9f207f0SJiri Benc char buf[10+IFNAMSIZ];
1003e9f207f0SJiri Benc
100447846c9bSJohannes Berg sprintf(buf, "netdev:%s", sdata->name);
1005ddbfe860SStanislaw Gruszka sdata->vif.debugfs_dir = debugfs_create_dir(buf,
1006e9f207f0SJiri Benc sdata->local->hw.wiphy->debugfsdir);
1007c942398fSMiri Korenblit /* deflink also has this */
1008c942398fSMiri Korenblit sdata->deflink.debugfs_dir = sdata->vif.debugfs_dir;
1009295bafb4SBen Greear sdata->debugfs.subdir_stations = debugfs_create_dir("stations",
1010ddbfe860SStanislaw Gruszka sdata->vif.debugfs_dir);
101175636525SJohannes Berg add_files(sdata);
1012c942398fSMiri Korenblit if (!mld_vif)
1013170cd6a6SBenjamin Berg add_link_files(&sdata->deflink, sdata->vif.debugfs_dir);
1014e9f207f0SJiri Benc }
1015e9f207f0SJiri Benc
ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data * sdata)1016e9f207f0SJiri Benc void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
1017e9f207f0SJiri Benc {
1018ddbfe860SStanislaw Gruszka if (!sdata->vif.debugfs_dir)
10197bcfaf2fSJohannes Berg return;
10207bcfaf2fSJohannes Berg
1021ddbfe860SStanislaw Gruszka debugfs_remove_recursive(sdata->vif.debugfs_dir);
1022ddbfe860SStanislaw Gruszka sdata->vif.debugfs_dir = NULL;
10234479004eSTom Hughes sdata->debugfs.subdir_stations = NULL;
1024e9f207f0SJiri Benc }
1025e9f207f0SJiri Benc
ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data * sdata)102647846c9bSJohannes Berg void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
1027e9f207f0SJiri Benc {
1028*f7862dfeSAl Viro debugfs_change_name(sdata->vif.debugfs_dir, "netdev:%s", sdata->name);
1029e9f207f0SJiri Benc }
1030170cd6a6SBenjamin Berg
ieee80211_debugfs_recreate_netdev(struct ieee80211_sub_if_data * sdata,bool mld_vif)1031c942398fSMiri Korenblit void ieee80211_debugfs_recreate_netdev(struct ieee80211_sub_if_data *sdata,
1032c942398fSMiri Korenblit bool mld_vif)
1033c942398fSMiri Korenblit {
1034c942398fSMiri Korenblit ieee80211_debugfs_remove_netdev(sdata);
1035c942398fSMiri Korenblit ieee80211_debugfs_add_netdev(sdata, mld_vif);
10360a3d898eSBenjamin Berg
10370a3d898eSBenjamin Berg if (sdata->flags & IEEE80211_SDATA_IN_DRIVER) {
1038c942398fSMiri Korenblit drv_vif_add_debugfs(sdata->local, sdata);
1039c942398fSMiri Korenblit if (!mld_vif)
1040c942398fSMiri Korenblit ieee80211_link_debugfs_drv_add(&sdata->deflink);
1041c942398fSMiri Korenblit }
10420a3d898eSBenjamin Berg }
1043c942398fSMiri Korenblit
ieee80211_link_debugfs_add(struct ieee80211_link_data * link)1044170cd6a6SBenjamin Berg void ieee80211_link_debugfs_add(struct ieee80211_link_data *link)
1045170cd6a6SBenjamin Berg {
1046170cd6a6SBenjamin Berg char link_dir_name[10];
1047170cd6a6SBenjamin Berg
1048c942398fSMiri Korenblit if (WARN_ON(!link->sdata->vif.debugfs_dir || link->debugfs_dir))
1049170cd6a6SBenjamin Berg return;
1050170cd6a6SBenjamin Berg
1051170cd6a6SBenjamin Berg /* For now, this should not be called for non-MLO capable drivers */
1052170cd6a6SBenjamin Berg if (WARN_ON(!(link->sdata->local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)))
1053170cd6a6SBenjamin Berg return;
1054170cd6a6SBenjamin Berg
1055170cd6a6SBenjamin Berg snprintf(link_dir_name, sizeof(link_dir_name),
1056170cd6a6SBenjamin Berg "link-%d", link->link_id);
1057170cd6a6SBenjamin Berg
1058170cd6a6SBenjamin Berg link->debugfs_dir =
1059170cd6a6SBenjamin Berg debugfs_create_dir(link_dir_name,
1060170cd6a6SBenjamin Berg link->sdata->vif.debugfs_dir);
1061170cd6a6SBenjamin Berg
1062170cd6a6SBenjamin Berg DEBUGFS_ADD(link->debugfs_dir, addr);
1063170cd6a6SBenjamin Berg add_link_files(link, link->debugfs_dir);
1064170cd6a6SBenjamin Berg }
1065170cd6a6SBenjamin Berg
ieee80211_link_debugfs_remove(struct ieee80211_link_data * link)1066170cd6a6SBenjamin Berg void ieee80211_link_debugfs_remove(struct ieee80211_link_data *link)
1067170cd6a6SBenjamin Berg {
1068170cd6a6SBenjamin Berg if (!link->sdata->vif.debugfs_dir || !link->debugfs_dir) {
1069170cd6a6SBenjamin Berg link->debugfs_dir = NULL;
1070170cd6a6SBenjamin Berg return;
1071170cd6a6SBenjamin Berg }
1072170cd6a6SBenjamin Berg
1073170cd6a6SBenjamin Berg if (link->debugfs_dir == link->sdata->vif.debugfs_dir) {
1074170cd6a6SBenjamin Berg WARN_ON(link != &link->sdata->deflink);
1075170cd6a6SBenjamin Berg link->debugfs_dir = NULL;
1076170cd6a6SBenjamin Berg return;
1077170cd6a6SBenjamin Berg }
1078170cd6a6SBenjamin Berg
1079170cd6a6SBenjamin Berg debugfs_remove_recursive(link->debugfs_dir);
1080170cd6a6SBenjamin Berg link->debugfs_dir = NULL;
1081170cd6a6SBenjamin Berg }
1082170cd6a6SBenjamin Berg
ieee80211_link_debugfs_drv_add(struct ieee80211_link_data * link)1083170cd6a6SBenjamin Berg void ieee80211_link_debugfs_drv_add(struct ieee80211_link_data *link)
1084170cd6a6SBenjamin Berg {
1085c942398fSMiri Korenblit if (link->sdata->vif.type == NL80211_IFTYPE_MONITOR ||
1086c942398fSMiri Korenblit WARN_ON(!link->debugfs_dir))
1087170cd6a6SBenjamin Berg return;
1088170cd6a6SBenjamin Berg
1089170cd6a6SBenjamin Berg drv_link_add_debugfs(link->sdata->local, link->sdata,
1090170cd6a6SBenjamin Berg link->conf, link->debugfs_dir);
1091170cd6a6SBenjamin Berg }
1092170cd6a6SBenjamin Berg
ieee80211_link_debugfs_drv_remove(struct ieee80211_link_data * link)1093170cd6a6SBenjamin Berg void ieee80211_link_debugfs_drv_remove(struct ieee80211_link_data *link)
1094170cd6a6SBenjamin Berg {
1095170cd6a6SBenjamin Berg if (!link || !link->debugfs_dir)
1096170cd6a6SBenjamin Berg return;
1097170cd6a6SBenjamin Berg
1098170cd6a6SBenjamin Berg if (WARN_ON(link->debugfs_dir == link->sdata->vif.debugfs_dir))
1099170cd6a6SBenjamin Berg return;
1100170cd6a6SBenjamin Berg
1101170cd6a6SBenjamin Berg /* Recreate the directory excluding the driver data */
1102170cd6a6SBenjamin Berg debugfs_remove_recursive(link->debugfs_dir);
1103170cd6a6SBenjamin Berg link->debugfs_dir = NULL;
1104170cd6a6SBenjamin Berg
1105170cd6a6SBenjamin Berg ieee80211_link_debugfs_add(link);
1106170cd6a6SBenjamin Berg }
1107