|
|
|
@ -23,16 +23,16 @@
|
|
|
|
|
#include "driver-ops.h"
|
|
|
|
|
|
|
|
|
|
static ssize_t ieee80211_if_read(
|
|
|
|
|
struct ieee80211_sub_if_data *sdata,
|
|
|
|
|
void *data,
|
|
|
|
|
char __user *userbuf,
|
|
|
|
|
size_t count, loff_t *ppos,
|
|
|
|
|
ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int))
|
|
|
|
|
ssize_t (*format)(const void *, char *, int))
|
|
|
|
|
{
|
|
|
|
|
char buf[200];
|
|
|
|
|
ssize_t ret = -EINVAL;
|
|
|
|
|
|
|
|
|
|
read_lock(&dev_base_lock);
|
|
|
|
|
ret = (*format)(sdata, buf, sizeof(buf));
|
|
|
|
|
ret = (*format)(data, buf, sizeof(buf));
|
|
|
|
|
read_unlock(&dev_base_lock);
|
|
|
|
|
|
|
|
|
|
if (ret >= 0)
|
|
|
|
@ -42,10 +42,10 @@ static ssize_t ieee80211_if_read(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ssize_t ieee80211_if_write(
|
|
|
|
|
struct ieee80211_sub_if_data *sdata,
|
|
|
|
|
void *data,
|
|
|
|
|
const char __user *userbuf,
|
|
|
|
|
size_t count, loff_t *ppos,
|
|
|
|
|
ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int))
|
|
|
|
|
ssize_t (*write)(void *, const char *, int))
|
|
|
|
|
{
|
|
|
|
|
char buf[64];
|
|
|
|
|
ssize_t ret;
|
|
|
|
@ -58,64 +58,64 @@ static ssize_t ieee80211_if_write(
|
|
|
|
|
buf[count] = '\0';
|
|
|
|
|
|
|
|
|
|
rtnl_lock();
|
|
|
|
|
ret = (*write)(sdata, buf, count);
|
|
|
|
|
ret = (*write)(data, buf, count);
|
|
|
|
|
rtnl_unlock();
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define IEEE80211_IF_FMT(name, field, format_string) \
|
|
|
|
|
#define IEEE80211_IF_FMT(name, type, field, format_string) \
|
|
|
|
|
static ssize_t ieee80211_if_fmt_##name( \
|
|
|
|
|
const struct ieee80211_sub_if_data *sdata, char *buf, \
|
|
|
|
|
const type *data, char *buf, \
|
|
|
|
|
int buflen) \
|
|
|
|
|
{ \
|
|
|
|
|
return scnprintf(buf, buflen, format_string, sdata->field); \
|
|
|
|
|
return scnprintf(buf, buflen, format_string, data->field); \
|
|
|
|
|
}
|
|
|
|
|
#define IEEE80211_IF_FMT_DEC(name, field) \
|
|
|
|
|
IEEE80211_IF_FMT(name, field, "%d\n")
|
|
|
|
|
#define IEEE80211_IF_FMT_HEX(name, field) \
|
|
|
|
|
IEEE80211_IF_FMT(name, field, "%#x\n")
|
|
|
|
|
#define IEEE80211_IF_FMT_LHEX(name, field) \
|
|
|
|
|
IEEE80211_IF_FMT(name, field, "%#lx\n")
|
|
|
|
|
#define IEEE80211_IF_FMT_DEC(name, type, field) \
|
|
|
|
|
IEEE80211_IF_FMT(name, type, field, "%d\n")
|
|
|
|
|
#define IEEE80211_IF_FMT_HEX(name, type, field) \
|
|
|
|
|
IEEE80211_IF_FMT(name, type, field, "%#x\n")
|
|
|
|
|
#define IEEE80211_IF_FMT_LHEX(name, type, field) \
|
|
|
|
|
IEEE80211_IF_FMT(name, type, field, "%#lx\n")
|
|
|
|
|
|
|
|
|
|
#define IEEE80211_IF_FMT_HEXARRAY(name, field) \
|
|
|
|
|
#define IEEE80211_IF_FMT_HEXARRAY(name, type, field) \
|
|
|
|
|
static ssize_t ieee80211_if_fmt_##name( \
|
|
|
|
|
const struct ieee80211_sub_if_data *sdata, \
|
|
|
|
|
const type *data, \
|
|
|
|
|
char *buf, int buflen) \
|
|
|
|
|
{ \
|
|
|
|
|
char *p = buf; \
|
|
|
|
|
int i; \
|
|
|
|
|
for (i = 0; i < sizeof(sdata->field); i++) { \
|
|
|
|
|
for (i = 0; i < sizeof(data->field); i++) { \
|
|
|
|
|
p += scnprintf(p, buflen + buf - p, "%.2x ", \
|
|
|
|
|
sdata->field[i]); \
|
|
|
|
|
data->field[i]); \
|
|
|
|
|
} \
|
|
|
|
|
p += scnprintf(p, buflen + buf - p, "\n"); \
|
|
|
|
|
return p - buf; \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define IEEE80211_IF_FMT_ATOMIC(name, field) \
|
|
|
|
|
#define IEEE80211_IF_FMT_ATOMIC(name, type, field) \
|
|
|
|
|
static ssize_t ieee80211_if_fmt_##name( \
|
|
|
|
|
const struct ieee80211_sub_if_data *sdata, \
|
|
|
|
|
const type *data, \
|
|
|
|
|
char *buf, int buflen) \
|
|
|
|
|
{ \
|
|
|
|
|
return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\
|
|
|
|
|
return scnprintf(buf, buflen, "%d\n", atomic_read(&data->field));\
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define IEEE80211_IF_FMT_MAC(name, field) \
|
|
|
|
|
#define IEEE80211_IF_FMT_MAC(name, type, field) \
|
|
|
|
|
static ssize_t ieee80211_if_fmt_##name( \
|
|
|
|
|
const struct ieee80211_sub_if_data *sdata, char *buf, \
|
|
|
|
|
const type *data, char *buf, \
|
|
|
|
|
int buflen) \
|
|
|
|
|
{ \
|
|
|
|
|
return scnprintf(buf, buflen, "%pM\n", sdata->field); \
|
|
|
|
|
return scnprintf(buf, buflen, "%pM\n", data->field); \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define IEEE80211_IF_FMT_JIFFIES_TO_MS(name, field) \
|
|
|
|
|
#define IEEE80211_IF_FMT_JIFFIES_TO_MS(name, type, field) \
|
|
|
|
|
static ssize_t ieee80211_if_fmt_##name( \
|
|
|
|
|
const struct ieee80211_sub_if_data *sdata, \
|
|
|
|
|
const type *data, \
|
|
|
|
|
char *buf, int buflen) \
|
|
|
|
|
{ \
|
|
|
|
|
return scnprintf(buf, buflen, "%d\n", \
|
|
|
|
|
jiffies_to_msecs(sdata->field)); \
|
|
|
|
|
jiffies_to_msecs(data->field)); \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define _IEEE80211_IF_FILE_OPS(name, _read, _write) \
|
|
|
|
@ -126,43 +126,67 @@ static const struct file_operations name##_ops = { \
|
|
|
|
|
.llseek = generic_file_llseek, \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define _IEEE80211_IF_FILE_R_FN(name) \
|
|
|
|
|
#define _IEEE80211_IF_FILE_R_FN(name, type) \
|
|
|
|
|
static ssize_t ieee80211_if_read_##name(struct file *file, \
|
|
|
|
|
char __user *userbuf, \
|
|
|
|
|
size_t count, loff_t *ppos) \
|
|
|
|
|
{ \
|
|
|
|
|
ssize_t (*fn)(const void *, char *, int) = (void *) \
|
|
|
|
|
((ssize_t (*)(const type, char *, int)) \
|
|
|
|
|
ieee80211_if_fmt_##name); \
|
|
|
|
|
return ieee80211_if_read(file->private_data, \
|
|
|
|
|
userbuf, count, ppos, \
|
|
|
|
|
ieee80211_if_fmt_##name); \
|
|
|
|
|
userbuf, count, ppos, fn); \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define _IEEE80211_IF_FILE_W_FN(name) \
|
|
|
|
|
#define _IEEE80211_IF_FILE_W_FN(name, type) \
|
|
|
|
|
static ssize_t ieee80211_if_write_##name(struct file *file, \
|
|
|
|
|
const char __user *userbuf, \
|
|
|
|
|
size_t count, loff_t *ppos) \
|
|
|
|
|
{ \
|
|
|
|
|
ssize_t (*fn)(void *, const char *, int) = (void *) \
|
|
|
|
|
((ssize_t (*)(type, const char *, int)) \
|
|
|
|
|
ieee80211_if_parse_##name); \
|
|
|
|
|
return ieee80211_if_write(file->private_data, userbuf, count, \
|
|
|
|
|
ppos, ieee80211_if_parse_##name); \
|
|
|
|
|
ppos, fn); \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define IEEE80211_IF_FILE_R(name) \
|
|
|
|
|
_IEEE80211_IF_FILE_R_FN(name) \
|
|
|
|
|
_IEEE80211_IF_FILE_R_FN(name, struct ieee80211_sub_if_data *) \
|
|
|
|
|
_IEEE80211_IF_FILE_OPS(name, ieee80211_if_read_##name, NULL)
|
|
|
|
|
|
|
|
|
|
#define IEEE80211_IF_FILE_W(name) \
|
|
|
|
|
_IEEE80211_IF_FILE_W_FN(name) \
|
|
|
|
|
_IEEE80211_IF_FILE_W_FN(name, struct ieee80211_sub_if_data *) \
|
|
|
|
|
_IEEE80211_IF_FILE_OPS(name, NULL, ieee80211_if_write_##name)
|
|
|
|
|
|
|
|
|
|
#define IEEE80211_IF_FILE_RW(name) \
|
|
|
|
|
_IEEE80211_IF_FILE_R_FN(name) \
|
|
|
|
|
_IEEE80211_IF_FILE_W_FN(name) \
|
|
|
|
|
_IEEE80211_IF_FILE_R_FN(name, struct ieee80211_sub_if_data *) \
|
|
|
|
|
_IEEE80211_IF_FILE_W_FN(name, struct ieee80211_sub_if_data *) \
|
|
|
|
|
_IEEE80211_IF_FILE_OPS(name, ieee80211_if_read_##name, \
|
|
|
|
|
ieee80211_if_write_##name)
|
|
|
|
|
|
|
|
|
|
#define IEEE80211_IF_FILE(name, field, format) \
|
|
|
|
|
IEEE80211_IF_FMT_##format(name, field) \
|
|
|
|
|
IEEE80211_IF_FMT_##format(name, struct ieee80211_sub_if_data, field) \
|
|
|
|
|
IEEE80211_IF_FILE_R(name)
|
|
|
|
|
|
|
|
|
|
/* Same but with a link_ prefix in the ops variable name and different type */
|
|
|
|
|
#define IEEE80211_IF_LINK_FILE_R(name) \
|
|
|
|
|
_IEEE80211_IF_FILE_R_FN(name, struct ieee80211_link_data *) \
|
|
|
|
|
_IEEE80211_IF_FILE_OPS(link_##name, ieee80211_if_read_##name, NULL)
|
|
|
|
|
|
|
|
|
|
#define IEEE80211_IF_LINK_FILE_W(name) \
|
|
|
|
|
_IEEE80211_IF_FILE_W_FN(name) \
|
|
|
|
|
_IEEE80211_IF_FILE_OPS(link_##name, NULL, ieee80211_if_write_##name)
|
|
|
|
|
|
|
|
|
|
#define IEEE80211_IF_LINK_FILE_RW(name) \
|
|
|
|
|
_IEEE80211_IF_FILE_R_FN(name, struct ieee80211_link_data *) \
|
|
|
|
|
_IEEE80211_IF_FILE_W_FN(name, struct ieee80211_link_data *) \
|
|
|
|
|
_IEEE80211_IF_FILE_OPS(link_##name, ieee80211_if_read_##name, \
|
|
|
|
|
ieee80211_if_write_##name)
|
|
|
|
|
|
|
|
|
|
#define IEEE80211_IF_LINK_FILE(name, field, format) \
|
|
|
|
|
IEEE80211_IF_FMT_##format(name, struct ieee80211_link_data, field) \
|
|
|
|
|
IEEE80211_IF_LINK_FILE_R(name)
|
|
|
|
|
|
|
|
|
|
/* common attributes */
|
|
|
|
|
IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[NL80211_BAND_2GHZ],
|
|
|
|
|
HEX);
|
|
|
|
@ -207,9 +231,9 @@ IEEE80211_IF_FILE_R(rc_rateidx_vht_mcs_mask_5ghz);
|
|
|
|
|
|
|
|
|
|
IEEE80211_IF_FILE(flags, flags, HEX);
|
|
|
|
|
IEEE80211_IF_FILE(state, state, LHEX);
|
|
|
|
|
IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC);
|
|
|
|
|
IEEE80211_IF_FILE(ap_power_level, deflink.ap_power_level, DEC);
|
|
|
|
|
IEEE80211_IF_FILE(user_power_level, deflink.user_power_level, DEC);
|
|
|
|
|
IEEE80211_IF_LINK_FILE(txpower, conf->txpower, DEC);
|
|
|
|
|
IEEE80211_IF_LINK_FILE(ap_power_level, ap_power_level, DEC);
|
|
|
|
|
IEEE80211_IF_LINK_FILE(user_power_level, user_power_level, DEC);
|
|
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
|
ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata,
|
|
|
|
@ -236,9 +260,10 @@ IEEE80211_IF_FILE(bssid, deflink.u.mgd.bssid, MAC);
|
|
|
|
|
IEEE80211_IF_FILE(aid, vif.cfg.aid, DEC);
|
|
|
|
|
IEEE80211_IF_FILE(beacon_timeout, u.mgd.beacon_timeout, JIFFIES_TO_MS);
|
|
|
|
|
|
|
|
|
|
static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
|
|
|
|
|
static int ieee80211_set_smps(struct ieee80211_link_data *link,
|
|
|
|
|
enum ieee80211_smps_mode smps_mode)
|
|
|
|
|
{
|
|
|
|
|
struct ieee80211_sub_if_data *sdata = link->sdata;
|
|
|
|
|
struct ieee80211_local *local = sdata->local;
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
@ -256,7 +281,7 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
sdata_lock(sdata);
|
|
|
|
|
err = __ieee80211_request_smps_mgd(sdata, &sdata->deflink, smps_mode);
|
|
|
|
|
err = __ieee80211_request_smps_mgd(link->sdata, link, smps_mode);
|
|
|
|
|
sdata_unlock(sdata);
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
@ -269,24 +294,24 @@ static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
|
|
|
|
|
[IEEE80211_SMPS_DYNAMIC] = "dynamic",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
|
|
|
|
|
static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_link_data *link,
|
|
|
|
|
char *buf, int buflen)
|
|
|
|
|
{
|
|
|
|
|
if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
|
|
|
|
if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
|
|
|
|
|
return snprintf(buf, buflen, "request: %s\nused: %s\n",
|
|
|
|
|
smps_modes[sdata->deflink.u.mgd.req_smps],
|
|
|
|
|
smps_modes[sdata->deflink.smps_mode]);
|
|
|
|
|
smps_modes[link->u.mgd.req_smps],
|
|
|
|
|
smps_modes[link->smps_mode]);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
|
|
|
|
|
static ssize_t ieee80211_if_parse_smps(struct ieee80211_link_data *link,
|
|
|
|
|
const char *buf, int buflen)
|
|
|
|
|
{
|
|
|
|
|
enum ieee80211_smps_mode mode;
|
|
|
|
|
|
|
|
|
|
for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) {
|
|
|
|
|
if (strncmp(buf, smps_modes[mode], buflen) == 0) {
|
|
|
|
|
int err = ieee80211_set_smps(sdata, mode);
|
|
|
|
|
int err = ieee80211_set_smps(link, mode);
|
|
|
|
|
if (!err)
|
|
|
|
|
return buflen;
|
|
|
|
|
return err;
|
|
|
|
@ -295,7 +320,7 @@ static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
|
|
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
IEEE80211_IF_FILE_RW(smps);
|
|
|
|
|
IEEE80211_IF_LINK_FILE_RW(smps);
|
|
|
|
|
|
|
|
|
|
static ssize_t ieee80211_if_parse_tkip_mic_test(
|
|
|
|
|
struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
|
|
|
|
@ -595,6 +620,8 @@ static ssize_t ieee80211_if_parse_active_links(struct ieee80211_sub_if_data *sda
|
|
|
|
|
}
|
|
|
|
|
IEEE80211_IF_FILE_RW(active_links);
|
|
|
|
|
|
|
|
|
|
IEEE80211_IF_LINK_FILE(addr, conf->addr, MAC);
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_MAC80211_MESH
|
|
|
|
|
IEEE80211_IF_FILE(estab_plinks, u.mesh.estab_plinks, ATOMIC);
|
|
|
|
|
|
|
|
|
@ -685,7 +712,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
|
|
|
|
|
DEBUGFS_ADD(bssid);
|
|
|
|
|
DEBUGFS_ADD(aid);
|
|
|
|
|
DEBUGFS_ADD(beacon_timeout);
|
|
|
|
|
DEBUGFS_ADD_MODE(smps, 0600);
|
|
|
|
|
DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
|
|
|
|
|
DEBUGFS_ADD_MODE(beacon_loss, 0200);
|
|
|
|
|
DEBUGFS_ADD_MODE(uapsd_queues, 0600);
|
|
|
|
@ -788,9 +814,6 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
|
|
|
|
|
|
|
|
|
|
DEBUGFS_ADD(flags);
|
|
|
|
|
DEBUGFS_ADD(state);
|
|
|
|
|
DEBUGFS_ADD(txpower);
|
|
|
|
|
DEBUGFS_ADD(user_power_level);
|
|
|
|
|
DEBUGFS_ADD(ap_power_level);
|
|
|
|
|
|
|
|
|
|
if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
|
|
|
|
|
add_common_files(sdata);
|
|
|
|
@ -820,6 +843,31 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef DEBUGFS_ADD_MODE
|
|
|
|
|
#undef DEBUGFS_ADD
|
|
|
|
|
|
|
|
|
|
#define DEBUGFS_ADD_MODE(dentry, name, mode) \
|
|
|
|
|
debugfs_create_file(#name, mode, dentry, \
|
|
|
|
|
link, &link_##name##_ops)
|
|
|
|
|
|
|
|
|
|
#define DEBUGFS_ADD(dentry, name) DEBUGFS_ADD_MODE(dentry, name, 0400)
|
|
|
|
|
|
|
|
|
|
static void add_link_files(struct ieee80211_link_data *link,
|
|
|
|
|
struct dentry *dentry)
|
|
|
|
|
{
|
|
|
|
|
DEBUGFS_ADD(dentry, txpower);
|
|
|
|
|
DEBUGFS_ADD(dentry, user_power_level);
|
|
|
|
|
DEBUGFS_ADD(dentry, ap_power_level);
|
|
|
|
|
|
|
|
|
|
switch (link->sdata->vif.type) {
|
|
|
|
|
case NL80211_IFTYPE_STATION:
|
|
|
|
|
DEBUGFS_ADD_MODE(dentry, smps, 0600);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
|
|
|
|
|
{
|
|
|
|
|
char buf[10+IFNAMSIZ];
|
|
|
|
@ -830,6 +878,9 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
|
|
|
|
|
sdata->debugfs.subdir_stations = debugfs_create_dir("stations",
|
|
|
|
|
sdata->vif.debugfs_dir);
|
|
|
|
|
add_files(sdata);
|
|
|
|
|
|
|
|
|
|
if (!(sdata->local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO))
|
|
|
|
|
add_link_files(&sdata->deflink, sdata->vif.debugfs_dir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
|
|
|
|
@ -855,3 +906,66 @@ void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
|
|
|
|
|
sprintf(buf, "netdev:%s", sdata->name);
|
|
|
|
|
debugfs_rename(dir->d_parent, dir, dir->d_parent, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ieee80211_link_debugfs_add(struct ieee80211_link_data *link)
|
|
|
|
|
{
|
|
|
|
|
char link_dir_name[10];
|
|
|
|
|
|
|
|
|
|
if (WARN_ON(!link->sdata->vif.debugfs_dir))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* For now, this should not be called for non-MLO capable drivers */
|
|
|
|
|
if (WARN_ON(!(link->sdata->local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
snprintf(link_dir_name, sizeof(link_dir_name),
|
|
|
|
|
"link-%d", link->link_id);
|
|
|
|
|
|
|
|
|
|
link->debugfs_dir =
|
|
|
|
|
debugfs_create_dir(link_dir_name,
|
|
|
|
|
link->sdata->vif.debugfs_dir);
|
|
|
|
|
|
|
|
|
|
DEBUGFS_ADD(link->debugfs_dir, addr);
|
|
|
|
|
add_link_files(link, link->debugfs_dir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ieee80211_link_debugfs_remove(struct ieee80211_link_data *link)
|
|
|
|
|
{
|
|
|
|
|
if (!link->sdata->vif.debugfs_dir || !link->debugfs_dir) {
|
|
|
|
|
link->debugfs_dir = NULL;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->debugfs_dir == link->sdata->vif.debugfs_dir) {
|
|
|
|
|
WARN_ON(link != &link->sdata->deflink);
|
|
|
|
|
link->debugfs_dir = NULL;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
debugfs_remove_recursive(link->debugfs_dir);
|
|
|
|
|
link->debugfs_dir = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ieee80211_link_debugfs_drv_add(struct ieee80211_link_data *link)
|
|
|
|
|
{
|
|
|
|
|
if (WARN_ON(!link->debugfs_dir))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
drv_link_add_debugfs(link->sdata->local, link->sdata,
|
|
|
|
|
link->conf, link->debugfs_dir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ieee80211_link_debugfs_drv_remove(struct ieee80211_link_data *link)
|
|
|
|
|
{
|
|
|
|
|
if (!link || !link->debugfs_dir)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (WARN_ON(link->debugfs_dir == link->sdata->vif.debugfs_dir))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Recreate the directory excluding the driver data */
|
|
|
|
|
debugfs_remove_recursive(link->debugfs_dir);
|
|
|
|
|
link->debugfs_dir = NULL;
|
|
|
|
|
|
|
|
|
|
ieee80211_link_debugfs_add(link);
|
|
|
|
|
}
|
|
|
|
|