2007-05-25 11:52:47

by Zhu Yi

[permalink] [raw]
Subject: [PATCH 3/3] mac80211: debugfs support for TSM and DLS

This adds the debugfs support for the TSM and DLS features. All
the stuff will be in the new directory
/sys/kernel/debug/ieee80211/phy0/netdev:wlan0/qos/ in STA mode.

Signed-off-by: Zhu Yi <[email protected]>
---
net/mac80211/debugfs_netdev.c | 332 +++++++++++++++++++++++++++++++++++++++++
net/mac80211/ieee80211_i.h | 33 ++++
2 files changed, 365 insertions(+), 0 deletions(-)

diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 9e39646..e0f77f9 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -87,6 +87,264 @@ static const struct file_operations name##_ops = { \
IEEE80211_IF_FMT_##format(name, field) \
__IEEE80211_IF_FILE(name)

+static struct ieee80211_elem_tspec _tspec = {
+ .nominal_msdu_size = 200,
+ .inactivity_interval = 40,
+ .mean_data_rate = 40000,
+ .min_phy_rate = 6000000,
+ .surplus_band_allow = 8192,
+ .medium_time = 30,
+};
+static u8 _dls_mac[ETH_ALEN];
+
+#define DEBUGFS_QOS_FILE(name, f) \
+static ssize_t qos_ ##name## _write(struct file *file, \
+ const char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ struct ieee80211_sub_if_data *sdata = file->private_data; \
+ \
+ f(sdata->dev, &sdata->u.sta, &_tspec); \
+ \
+ return count; \
+} \
+ \
+static const struct file_operations qos_ ##name## _ops = { \
+ .write = qos_ ##name## _write, \
+ .open = mac80211_open_file_generic, \
+};
+
+#define DEBUGFS_QOS_ADD(name) \
+ sdata->debugfs.sta.qos.name = debugfs_create_file(#name, 0444, qosd,\
+ sdata, &qos_ ##name## _ops);
+
+#define DEBUGFS_QOS_DEL(name) \
+ debugfs_remove(sdata->debugfs.sta.qos.name); \
+ sdata->debugfs.sta.qos.name = NULL;
+
+DEBUGFS_QOS_FILE(addts_11e, ieee80211_send_addts);
+DEBUGFS_QOS_FILE(addts_wmm, wmm_send_addts);
+DEBUGFS_QOS_FILE(delts_11e, ieee80211_send_delts);
+DEBUGFS_QOS_FILE(delts_wmm, wmm_send_delts);
+
+static ssize_t qos_if_dls_mac(const struct ieee80211_sub_if_data *sdata,
+ char *buf, int buflen)
+{
+ return scnprintf(buf, buflen, MAC_FMT "\n", MAC_ARG(_dls_mac));
+}
+
+static ssize_t qos_dls_mac_read(struct file *file,
+ char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ return ieee80211_if_read(file->private_data,
+ userbuf, count, ppos,
+ qos_if_dls_mac);
+}
+
+static ssize_t qos_dls_mac_write(struct file *file, const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_sub_if_data *sdata = file->private_data;
+ char buf[20];
+ size_t size;
+ u8 m[ETH_ALEN];
+
+ size = min(sizeof(buf) - 1, count);
+ buf[size] = '\0';
+ if (copy_from_user(buf, userbuf, size))
+ return -EFAULT;
+
+ if (sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+ &((u8*)(m))[0], &((u8*)(m))[1], &((u8*)(m))[2],
+ &((u8*)(m))[3], &((u8*)(m))[4], &((u8*)(m))[5]) != ETH_ALEN){
+ printk(KERN_ERR "%s: sscanf input error\n", sdata->dev->name);
+ return -EINVAL;
+ }
+ memcpy(_dls_mac, m, ETH_ALEN);
+ return count;
+}
+
+static const struct file_operations qos_dls_mac_ops = {
+ .read = qos_dls_mac_read,
+ .write = qos_dls_mac_write,
+ .open = mac80211_open_file_generic,
+};
+
+static ssize_t qos_if_dls_op(const struct ieee80211_sub_if_data *sdata,
+ char *buf, int buflen)
+{
+ return scnprintf(buf, buflen,
+ "DLS Operation: Setup = 1; Teardown = 2\n");
+}
+
+static ssize_t qos_dls_op_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ return ieee80211_if_read(file->private_data,
+ userbuf, count, ppos,
+ qos_if_dls_op);
+}
+
+static ssize_t qos_dls_op_write(struct file *file, const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_sub_if_data *sdata = file->private_data;
+ char buf[20];
+ size_t size;
+ unsigned int opt;
+
+ size = min(sizeof(buf) - 1, count);
+ buf[size] = '\0';
+ if (copy_from_user(buf, userbuf, size))
+ return -EFAULT;
+
+ if (sscanf(buf, "%u", &opt) != 1) {
+ printk(KERN_ERR "%s: sscanf input error\n", sdata->dev->name);
+ return -EINVAL;
+ }
+ switch (opt) {
+ case 1:
+ ieee80211_send_dls_req(sdata->dev, &sdata->u.sta, _dls_mac, 0);
+ break;
+ case 2:
+ ieee80211_send_dls_teardown(sdata->dev, &sdata->u.sta, _dls_mac,
+ WLAN_REASON_QSTA_NOT_USE);
+ break;
+ default:
+ printk(KERN_ERR "Unknown DLS Operation: %d\n", opt);
+ break;
+ }
+ return count;
+}
+
+static const struct file_operations qos_dls_op_ops = {
+ .read = qos_dls_op_read,
+ .write = qos_dls_op_write,
+ .open = mac80211_open_file_generic,
+};
+
+#define DEBUGFS_TSINFO_FILE(_name, min_val, max_val) \
+static ssize_t tsinfo_ ##_name## _read(struct file *file, \
+ char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ char buf[20]; \
+ int res = scnprintf(buf, count, "%u\n", \
+ IEEE80211_TSINFO_## _name (_tspec.ts_info)); \
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
+} \
+ \
+static ssize_t tsinfo_ ##_name## _write(struct file *file, \
+ const char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ char buf[20]; \
+ size_t size; \
+ int val; \
+ \
+ size = min(sizeof(buf) - 1, count); \
+ buf[size] = '\0'; \
+ if (copy_from_user(buf, userbuf, size)) \
+ return -EFAULT; \
+ \
+ val = simple_strtoul(buf, NULL, 0); \
+ if ((val < min_val) || (val > max_val)) { \
+ struct ieee80211_sub_if_data *sdata = file->private_data;\
+ printk(KERN_ERR "%s: set value (%u) out of range " \
+ "[%u, %u]\n",sdata->dev->name,val,min_val,max_val);\
+ return -EINVAL; \
+ } \
+ SET_TSINFO_ ##_name (_tspec.ts_info, val); \
+ return count; \
+} \
+ \
+static const struct file_operations tsinfo_ ##_name## _ops = { \
+ .read = tsinfo_ ##_name## _read, \
+ .write = tsinfo_ ##_name## _write, \
+ .open = mac80211_open_file_generic, \
+};
+
+#define DEBUGFS_TSINFO_ADD_TSID \
+ sdata->debugfs.sta.tsinfo.tsid = \
+ debugfs_create_file("tsid", 0444, tsinfod, \
+ sdata, &tsinfo_TSID_ops);
+
+#define DEBUGFS_TSINFO_ADD_DIR \
+ sdata->debugfs.sta.tsinfo.direction = \
+ debugfs_create_file("direction", 0444, tsinfod, \
+ sdata, &tsinfo_DIR_ops);
+
+#define DEBUGFS_TSINFO_ADD_UP \
+ sdata->debugfs.sta.tsinfo.up = \
+ debugfs_create_file("up", 0444, tsinfod, \
+ sdata, &tsinfo_UP_ops);
+
+#define DEBUGFS_TSINFO_DEL(name) \
+ debugfs_remove(sdata->debugfs.sta.tsinfo.name); \
+ sdata->debugfs.sta.tsinfo.name = NULL;
+
+DEBUGFS_TSINFO_FILE(TSID, 8, 15);
+DEBUGFS_TSINFO_FILE(DIR, 0, 3);
+DEBUGFS_TSINFO_FILE(UP, 0, 7);
+
+#define DEBUGFS_TSPEC_FILE(name) \
+static ssize_t tspec_ ##name## _read(struct file *file, \
+ char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ char buf[20]; \
+ int res = scnprintf(buf, count, "%u\n", _tspec.name); \
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
+} \
+ \
+static ssize_t tspec_ ##name## _write(struct file *file, \
+ const char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ char buf[20]; \
+ size_t size; \
+ \
+ size = min(sizeof(buf) - 1, count); \
+ buf[size] = '\0'; \
+ if (copy_from_user(buf, userbuf, size)) \
+ return -EFAULT; \
+ \
+ _tspec.name = simple_strtoul(buf, NULL, 0); \
+ return count; \
+} \
+ \
+static const struct file_operations tspec_ ##name## _ops = { \
+ .read = tspec_ ##name## _read, \
+ .write = tspec_ ##name## _write, \
+ .open = mac80211_open_file_generic, \
+};
+
+#define DEBUGFS_TSPEC_ADD(name) \
+ sdata->debugfs.sta.tspec.name = debugfs_create_file(#name, \
+ 0444, tspecd, sdata, &tspec_ ##name## _ops);
+
+#define DEBUGFS_TSPEC_DEL(name) \
+ debugfs_remove(sdata->debugfs.sta.tspec.name); \
+ sdata->debugfs.sta.tspec.name = NULL;
+
+DEBUGFS_TSPEC_FILE(nominal_msdu_size);
+DEBUGFS_TSPEC_FILE(max_msdu_size);
+DEBUGFS_TSPEC_FILE(min_service_interval);
+DEBUGFS_TSPEC_FILE(max_service_interval);
+DEBUGFS_TSPEC_FILE(inactivity_interval);
+DEBUGFS_TSPEC_FILE(suspension_interval);
+DEBUGFS_TSPEC_FILE(service_start_time);
+DEBUGFS_TSPEC_FILE(min_data_rate);
+DEBUGFS_TSPEC_FILE(mean_data_rate);
+DEBUGFS_TSPEC_FILE(peak_data_rate);
+DEBUGFS_TSPEC_FILE(burst_size);
+DEBUGFS_TSPEC_FILE(delay_bound);
+DEBUGFS_TSPEC_FILE(min_phy_rate);
+DEBUGFS_TSPEC_FILE(surplus_band_allow);
+DEBUGFS_TSPEC_FILE(medium_time);
+
+
/* common attributes */
IEEE80211_IF_FILE(channel_use, channel_use, DEC);
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
@@ -184,6 +442,10 @@ __IEEE80211_IF_FILE(mode);

static void add_sta_files(struct ieee80211_sub_if_data *sdata)
{
+ struct dentry *qosd;
+ struct dentry *tsinfod;
+ struct dentry *tspecd;
+
DEBUGFS_ADD(channel_use, sta);
DEBUGFS_ADD(drop_unencrypted, sta);
DEBUGFS_ADD(eapol, sta);
@@ -202,6 +464,42 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(auth_alg, sta);
DEBUGFS_ADD(auth_transaction, sta);
DEBUGFS_ADD(flags, sta);
+
+ qosd = debugfs_create_dir("qos", sdata->debugfsdir);
+ sdata->debugfs.sta.qos_dir = qosd;
+
+ DEBUGFS_QOS_ADD(addts_11e);
+ DEBUGFS_QOS_ADD(addts_wmm);
+ DEBUGFS_QOS_ADD(delts_11e);
+ DEBUGFS_QOS_ADD(delts_wmm);
+ DEBUGFS_QOS_ADD(dls_mac);
+ DEBUGFS_QOS_ADD(dls_op);
+
+ tsinfod = debugfs_create_dir("ts_info", qosd);
+ sdata->debugfs.sta.tsinfo_dir = tsinfod;
+
+ DEBUGFS_TSINFO_ADD_TSID;
+ DEBUGFS_TSINFO_ADD_DIR;
+ DEBUGFS_TSINFO_ADD_UP;
+
+ tspecd = debugfs_create_dir("tspec", qosd);
+ sdata->debugfs.sta.tspec_dir = tspecd;
+
+ DEBUGFS_TSPEC_ADD(nominal_msdu_size);
+ DEBUGFS_TSPEC_ADD(max_msdu_size);
+ DEBUGFS_TSPEC_ADD(min_service_interval);
+ DEBUGFS_TSPEC_ADD(max_service_interval);
+ DEBUGFS_TSPEC_ADD(inactivity_interval);
+ DEBUGFS_TSPEC_ADD(suspension_interval);
+ DEBUGFS_TSPEC_ADD(service_start_time);
+ DEBUGFS_TSPEC_ADD(min_data_rate);
+ DEBUGFS_TSPEC_ADD(mean_data_rate);
+ DEBUGFS_TSPEC_ADD(peak_data_rate);
+ DEBUGFS_TSPEC_ADD(burst_size);
+ DEBUGFS_TSPEC_ADD(delay_bound);
+ DEBUGFS_TSPEC_ADD(min_phy_rate);
+ DEBUGFS_TSPEC_ADD(surplus_band_allow);
+ DEBUGFS_TSPEC_ADD(medium_time);
}

static void add_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -295,6 +593,40 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_DEL(auth_alg, sta);
DEBUGFS_DEL(auth_transaction, sta);
DEBUGFS_DEL(flags, sta);
+
+ DEBUGFS_TSINFO_DEL(tsid);
+ DEBUGFS_TSINFO_DEL(direction);
+ DEBUGFS_TSINFO_DEL(up);
+
+ DEBUGFS_TSPEC_DEL(nominal_msdu_size);
+ DEBUGFS_TSPEC_DEL(max_msdu_size);
+ DEBUGFS_TSPEC_DEL(min_service_interval);
+ DEBUGFS_TSPEC_DEL(max_service_interval);
+ DEBUGFS_TSPEC_DEL(inactivity_interval);
+ DEBUGFS_TSPEC_DEL(suspension_interval);
+ DEBUGFS_TSPEC_DEL(service_start_time);
+ DEBUGFS_TSPEC_DEL(min_data_rate);
+ DEBUGFS_TSPEC_DEL(mean_data_rate);
+ DEBUGFS_TSPEC_DEL(peak_data_rate);
+ DEBUGFS_TSPEC_DEL(burst_size);
+ DEBUGFS_TSPEC_DEL(delay_bound);
+ DEBUGFS_TSPEC_DEL(min_phy_rate);
+ DEBUGFS_TSPEC_DEL(surplus_band_allow);
+ DEBUGFS_TSPEC_DEL(medium_time);
+
+ DEBUGFS_QOS_DEL(addts_11e);
+ DEBUGFS_QOS_DEL(addts_wmm);
+ DEBUGFS_QOS_DEL(delts_11e);
+ DEBUGFS_QOS_DEL(delts_wmm);
+ DEBUGFS_QOS_DEL(dls_mac);
+ DEBUGFS_QOS_DEL(dls_op);
+
+ debugfs_remove(sdata->debugfs.sta.tspec_dir);
+ sdata->debugfs.sta.tspec_dir = NULL;
+ debugfs_remove(sdata->debugfs.sta.tsinfo_dir);
+ sdata->debugfs.sta.tsinfo_dir = NULL;
+ debugfs_remove(sdata->debugfs.sta.qos_dir);
+ sdata->debugfs.sta.qos_dir = NULL;
}

static void del_ap_files(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3d40645..4968723 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -363,6 +363,39 @@ struct ieee80211_sub_if_data {
struct dentry *auth_alg;
struct dentry *auth_transaction;
struct dentry *flags;
+ struct dentry *qos_dir;
+ struct {
+ struct dentry *addts_11e;
+ struct dentry *addts_wmm;
+ struct dentry *delts_11e;
+ struct dentry *delts_wmm;
+ struct dentry *dls_mac;
+ struct dentry *dls_op;
+ } qos;
+ struct dentry *tsinfo_dir;
+ struct {
+ struct dentry *tsid;
+ struct dentry *direction;
+ struct dentry *up;
+ } tsinfo;
+ struct dentry *tspec_dir;
+ struct {
+ struct dentry *nominal_msdu_size;
+ struct dentry *max_msdu_size;
+ struct dentry *min_service_interval;
+ struct dentry *max_service_interval;
+ struct dentry *inactivity_interval;
+ struct dentry *suspension_interval;
+ struct dentry *service_start_time;
+ struct dentry *min_data_rate;
+ struct dentry *mean_data_rate;
+ struct dentry *peak_data_rate;
+ struct dentry *burst_size;
+ struct dentry *delay_bound;
+ struct dentry *min_phy_rate;
+ struct dentry *surplus_band_allow;
+ struct dentry *medium_time;
+ } tspec;
} sta;
struct {
struct dentry *channel_use;
--
1.5.0.rc2.g73a2


2007-06-07 20:39:28

by Jiri Benc

[permalink] [raw]
Subject: Re: [PATCH 3/3] mac80211: debugfs support for TSM and DLS

On Wed, 6 Jun 2007 16:22:39 +0800, Zhu Yi wrote:
> --- a/net/mac80211/debugfs_netdev.c
> +++ b/net/mac80211/debugfs_netdev.c
> @@ -87,6 +87,270 @@ static const struct file_operations name##_ops = { \
> IEEE80211_IF_FMT_##format(name, field) \
> __IEEE80211_IF_FILE(name)
>
> +static struct ieee80211_elem_tspec _tspec = {
> + .nominal_msdu_size = 200,
> + .inactivity_interval = 40,
> + .mean_data_rate = 40000,
> + .min_phy_rate = 6000000,
> + .surplus_band_allow = 8192,
> + .medium_time = 30,
> +};
> +static u8 _dls_mac[ETH_ALEN];

A global variable? Common for all devices you have in your computer?
That's broken.

> +
> +#define DEBUGFS_QOS_FILE(name, f) \
> +static ssize_t qos_ ##name## _write(struct file *file, \
> + const char __user *userbuf, \
> + size_t count, loff_t *ppos) \
> +{ \
> + struct ieee80211_sub_if_data *sdata = file->private_data; \
> + \
> + f(sdata->dev, &sdata->u.sta, &_tspec); \
> + \
> + return count; \
> +} \

Triggering an event just by writing anything to the debugfs file
doesn't seem like a clean and intelligible way to configure things.

Also, are you aware this is just a _debug_ stuff? Given the fact that
you're calling (for example) ieee80211_send_addts from debugfs handler
only, it looks like you're misusing it as an user space API.

Jiri

--
Jiri Benc
SUSE Labs

2007-06-08 09:59:19

by Jiri Benc

[permalink] [raw]
Subject: Re: [PATCH 3/3] mac80211: debugfs support for TSM and DLS

On Fri, 08 Jun 2007 09:17:55 +0800, Zhu Yi wrote:
> On Thu, 2007-06-07 at 22:39 +0200, Jiri Benc wrote:
> > A global variable? Common for all devices you have in your computer?
> > That's broken.
>
> OK, it can be fixed. But it is that broken if you treat it as a debug
> helper and don't use it on mulitple interfaces simultaneously.

It's broken even when it's just a debug code. Please fix it.

> > Triggering an event just by writing anything to the debugfs file
> > doesn't seem like a clean and intelligible way to configure things.

(*)

> > Also, are you aware this is just a _debug_ stuff? Given the fact that
> > you're calling (for example) ieee80211_send_addts from debugfs handler
> > only, it looks like you're misusing it as an user space API.
>
> If you follow the thread, I will write a user space API with cfg80211.
> This one for debugging only.

Ok, I somehow missed that. I suppose that's fine for wireless-dev then.
Except that I'm still not happy with (*). But that's probably just a
matter of taste and therefore doesn't constitute a real problem in a
debug code.

Thanks,

Jiri

--
Jiri Benc
SUSE Labs

2007-06-08 01:18:36

by Zhu Yi

[permalink] [raw]
Subject: Re: [PATCH 3/3] mac80211: debugfs support for TSM and DLS

On Thu, 2007-06-07 at 22:39 +0200, Jiri Benc wrote:
> A global variable? Common for all devices you have in your computer?
> That's broken.

OK, it can be fixed. But it is that broken if you treat it as a debug
helper and don't use it on mulitple interfaces simultaneously.

> > +
> > +#define DEBUGFS_QOS_FILE(name, f) \
> > +static ssize_t qos_ ##name## _write(struct file *file, \
> > + const char __user *userbuf, \
> > + size_t count, loff_t *ppos) \
> > +{ \
> > + struct ieee80211_sub_if_data *sdata = file->private_data; \
> > + \
> > + f(sdata->dev, &sdata->u.sta, &_tspec); \
> > + \
> > + return count; \
> > +} \
>
> Triggering an event just by writing anything to the debugfs file
> doesn't seem like a clean and intelligible way to configure things.
>
> Also, are you aware this is just a _debug_ stuff? Given the fact that
> you're calling (for example) ieee80211_send_addts from debugfs handler
> only, it looks like you're misusing it as an user space API.

If you follow the thread, I will write a user space API with cfg80211.
This one for debugging only.

-yi