Search Linux Wireless

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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch 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 <yi.zhu@xxxxxxxxx>
--
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8b939d0..c273afe 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -59,6 +60,10 @@ struct ieee80211_local;
  * increased memory use (about 2 kB of RAM per entry). */
 #define IEEE80211_FRAGMENT_MAX 4
 
+/* Minimum and Maximum TSID used by EDCA. EDCA uses 0~7; HCCA uses 8~15 */
+#define EDCA_TSID_MIN 0
+#define EDCA_TSID_MAX 7
+
 struct ieee80211_fragment_entry {
 	unsigned long first_frag_time;
 	unsigned int seq;
@@ -178,6 +183,31 @@ struct ieee80211_tx_stored_packet {
 	unsigned int last_frag_rate_ctrl_probe:1;
 };
 
+struct sta_ts_data {
+	enum {
+		TS_STATUS_UNUSED	= 0,
+		TS_STATUS_ACTIVE	= 1,
+		TS_STATUS_INACTIVE	= 2,
+		TS_STATUS_THROTTLING	= 3,
+	} status;
+	u8 dialog_token;
+	u8 up;
+	u32 admitted_time_usec;
+	u32 used_time_usec;
+};
+
+#define DLS_STATUS_OK		0
+#define DLS_STATUS_NOLINK	1
+#define DLS_STATUS_SETUP	2
+struct dls_info {
+	atomic_t refcnt;
+	int status;
+	u8 addr[ETH_ALEN];
+	struct dls_info *hnext; /* next entry in hash table list */
+	u32 timeout;
+	u32 supp_rates;
+};
+
 typedef ieee80211_txrx_result (*ieee80211_tx_handler)
 (struct ieee80211_txrx_data *tx);
 
@@ -222,6 +252,7 @@ struct ieee80211_if_sta {
 	} state;
 	struct timer_list timer;
 	struct work_struct work;
+	struct timer_list admit_timer; /* Recompute EDCA admitted time */
 	u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	size_t ssid_len;
@@ -271,6 +302,16 @@ struct ieee80211_if_sta {
 	u32 supp_rates_bits;
 
 	int wmm_last_param_set;
+
+	u32 dot11EDCAAveragingPeriod;
+	u32 MPDUExchangeTime;
+#define STA_TSID_NUM   16
+#define STA_TSDIR_NUM  2
+	/* EDCA: 0~7, HCCA: 8~15 */
+	struct sta_ts_data ts_data[STA_TSID_NUM][STA_TSDIR_NUM];
+
+	struct dls_info *dls_hash[STA_HASH_SIZE];
+	spinlock_t dls_lock;
 };
 
 
@@ -338,6 +379,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;
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 9e39646..5e0101e 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -87,6 +87,275 @@ 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;
+	struct dls_info *dls;
+
+	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:
+		dls = kzalloc(sizeof(struct dls_info), GFP_KERNEL);
+	        if (!dls) {
+			printk(KERN_ERR "No memory to allocate dls_info\n");
+			return -ENOMEM;
+		}
+		atomic_set(&dls->refcnt, 1);
+		dls->status = DLS_STATUS_SETUP;
+		dls->timeout = 0;
+		memcpy(dls->addr, _dls_mac, ETH_ALEN);
+		dls_info_add(&sdata->u.sta, dls);
+		ieee80211_send_dls_req(sdata->dev, &sdata->u.sta, dls);
+		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 +453,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 +475,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 +604,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)
-
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux