mac80211: debugfs support for TSM and DLS
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.
--- net/mac80211/debugfs_netdev.c | 346 ++++++++++++++++++++++++++++++++++++++++- net/mac80211/ieee80211_i.h | 33 ++++ 2 files changed, 376 insertions(+), 3 deletions(-)
net/mac80211/debugfs_netdev.c +343 -3
@@ -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 ]; + +#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) \ + do { \ + debugfs_remove(sdata->debugfs.sta.qos.name); \ + sdata->debugfs.sta.qos.name = NULL; \ + } while (0) + +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) \ + do { \ + debugfs_remove(sdata->debugfs.sta.tsinfo.name); \ + sdata->debugfs.sta.tsinfo.name = NULL; \ + } while (0) + +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) \ + do { \ + debugfs_remove(sdata->debugfs.sta.tspec.name); \ + sdata->debugfs.sta.tspec.name = NULL; \ + } while (0) + +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 +448,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 +470,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)
@@ -271,9 +575,11 @@ static void add_files(struct ieee80211_sub_if_data *sdata) } } -#define DEBUGFS_DEL (name, type)\ - debugfs_remove(sdata->debugfs.type.name);\ - sdata->debugfs.type.name = NULL; +#define DEBUGFS_DEL (name, type) \ + do { \ + debugfs_remove(sdata->debugfs.type.name); \ + sdata->debugfs.type.name = NULL; \ + } while (0)static void del_sta_files (struct ieee80211_sub_if_data *sdata) {
@@ -295,6 +601,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)
net/mac80211/ieee80211_i.h +33 -0
@@ -355,6 +355,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;
Signature · 1 line
1.5.0.rc2.g73a2
Quoted 5 lines · Zhu Yi
net/mac80211/debugfs_netdev.c +0
-0@@ -87,6 +87,270 @@ static const struct file_operations name##_ops = { \ IEEE80211_IF_FMT_##format(name, field) \ __IEEE80211_IF_FILE(name)
net/mac80211/debugfs_netdev.c static const struct file_operations name##_ops = { \ · line 98
Quoted 10 lines
net/mac80211/debugfs_netdev.c +9
-0+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.
net/mac80211/debugfs_netdev.c static const struct file_operations name##_ops = { \ · line 110
Quoted 12 lines
net/mac80211/debugfs_netdev.c +12
-0+ +#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
Signature · 2 lines
Jiri Benc SUSE Labs
Quoted 2 lines · Jiri Benc
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.
Quoted 16 lines
net/mac80211/debugfs_netdev.c static const struct file_operations name##_ops = { \ · line 110
Quoted 12 lines
net/mac80211/debugfs_netdev.c +12
-0+ +#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.
Quoted 3 lines
Also, are you aware this is just a _debug_ stuff? Given the fact that you're calling (for example)
ieee80211_send_addtsfrom 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
Quoted 6 lines · Zhu Yi
Quoted 2 lines · Jiri Benc
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.
Quoted 2 lines
Quoted 2 lines
Triggering an event just by writing anything to the debugfs file doesn't seem like a clean and intelligible way to configure things.
(*)
Quoted 6 lines
Quoted 3 lines
Also, are you aware this is just a _debug_ stuff? Given the fact that you're calling (for example)
ieee80211_send_addtsfrom 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
Signature · 2 lines
Jiri Benc SUSE Labs