[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20061214040302.GA10689@mail.intel.com>
Date: Thu, 14 Dec 2006 12:03:02 +0800
From: Zhu Yi <yi.zhu@...el.com>
To: netdev@...r.kernel.org
Subject: [PATCH 6/6] d80211: add sysfs interface for QoS functions
The sysfs interface here is only a proof of concept. It provides a way for
the userspace applications to use the advanced QoS features supported by
d80211 stack. The finial solution should be switched to cfg80211.
Signed-off-by: Zhu Yi <yi.zhu@...el.com>
---
net/d80211/ieee80211_i.h | 13 ++
net/d80211/ieee80211_sysfs.c | 245 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 258 insertions(+), 0 deletions(-)
83d49f70af1f38c152d8bd3abd69756ec087622e
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index d09f65e..7904033 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -20,6 +20,7 @@
#include <linux/workqueue.h>
#include <linux/types.h>
#include <linux/spinlock.h>
+#include <net/d80211_mgmt.h>
#include "ieee80211_key.h"
#include "sta_info.h"
@@ -329,6 +330,7 @@ struct ieee80211_sub_if_data {
int channel_use_raw;
struct attribute_group *sysfs_group;
+ struct attribute_group *sysfs_qos_group;
};
#define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev)
@@ -702,6 +704,17 @@ struct sta_info * ieee80211_ibss_add_sta
u8 *addr);
int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason);
int ieee80211_sta_disassociate(struct net_device *dev, u16 reason);
+void ieee80211_send_addts(struct net_device *dev,
+ struct ieee802_11_elem_tspec *tspec);
+void wmm_send_addts(struct net_device *dev,
+ struct ieee802_11_elem_tspec *tspec);
+void ieee80211_send_delts(struct net_device *dev, u8 tsid, u8 direction,
+ u32 medium_time);
+void wmm_send_delts(struct net_device *dev, u8 tsid, u8 direction,
+ u32 medium_time);
+void ieee80211_send_dls_req(struct net_device *dev, struct dls_info *dls);
+void ieee80211_send_dls_teardown(struct net_device *dev, u8 *mac, u16 reason);
+void dls_info_add(struct ieee80211_local *local, struct dls_info *dls);
void dls_info_stop(struct ieee80211_local *local);
int dls_link_status(struct ieee80211_local *local, u8 *addr);
diff --git a/net/d80211/ieee80211_sysfs.c b/net/d80211/ieee80211_sysfs.c
index 6a60077..31dc1f4 100644
--- a/net/d80211/ieee80211_sysfs.c
+++ b/net/d80211/ieee80211_sysfs.c
@@ -13,6 +13,7 @@
#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
#include <net/d80211.h>
+#include <net/d80211_mgmt.h>
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
@@ -21,6 +22,15 @@
#define to_net_dev(class) \
container_of(class, struct net_device, class_dev)
+/* For sysfs and debug only */
+static struct ieee802_11_elem_tspec _tspec;
+static u8 _dls_mac[ETH_ALEN];
+
+#define TSID _tspec.ts_info.tsid
+#define TSDIR _tspec.ts_info.direction
+#define TSUP _tspec.ts_info.up
+
+
static inline int rtnl_lock_local(struct ieee80211_local *local)
{
rtnl_lock();
@@ -657,6 +667,230 @@ static struct class ieee80211_class = {
#endif
};
+
+/* QoS sysfs entries */
+static ssize_t show_ts_info(struct class_device *dev, char *buf)
+{
+ /* TSID, Direction, UP */
+ return sprintf(buf, "%u %u %u\n", TSID, TSDIR, TSUP);
+}
+
+static ssize_t store_ts_info(struct class_device *dev, const char *buf,
+ size_t len)
+{
+ unsigned int id, index, up;
+
+ if (sscanf(buf, "%u, %u, %u", &id, &index, &up) != 3) {
+ printk(KERN_ERR "%s: sscanf error\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ if (id < 8 || id > 15) {
+ printk(KERN_ERR "invalid tsid %d\n", id);
+ return -EINVAL;
+ }
+ if ((index != 0) && (index != 1) && (index != 3)) {
+ printk(KERN_ERR "invalid direction %d\n", index);
+ return -EINVAL;
+ }
+ if (up < 0 || up > 7) {
+ printk(KERN_ERR "invalid UP %d\n", up);
+ return -EINVAL;
+ }
+ TSID = id;
+ TSDIR = index;
+ TSUP = up;
+ return len;
+}
+
+static CLASS_DEVICE_ATTR(ts_info, S_IWUSR|S_IRUGO, show_ts_info, store_ts_info);
+
+static ssize_t show_tspec(struct class_device *dev, char *buf)
+{
+ /* Nominal MSDU, Max MSDU, Min int, Max int, Inact int,
+ * susp int, start, min rate, mean rate, peak rate,
+ * max burst, delay, min phy, surp band, medium time */
+ return sprintf(buf,"%hu %hu %u %u %u %u %u %u %u %u %u %u %u %hu %hu\n",
+ _tspec.nominal_msdu_size,
+ _tspec.max_msdu_size,
+ _tspec.min_service_interval,
+ _tspec.max_service_interval,
+ _tspec.inactivity_interval,
+ _tspec.suspension_interval,
+ _tspec.service_start_time,
+ _tspec.min_data_rate,
+ _tspec.mean_data_rate,
+ _tspec.peak_data_rate,
+ _tspec.burst_size,
+ _tspec.delay_bound,
+ _tspec.min_phy_rate,
+ _tspec.surplus_band_allow,
+ _tspec.medium_time);
+}
+
+static ssize_t store_tspec(struct class_device *dev, const char *buf,
+ size_t len)
+{
+ if (sscanf(buf, "%hu %hu %u %u %u %u %u %u %u %u %u %u %u %hu %hu",
+ &_tspec.nominal_msdu_size,
+ &_tspec.max_msdu_size,
+ &_tspec.min_service_interval,
+ &_tspec.max_service_interval,
+ &_tspec.inactivity_interval,
+ &_tspec.suspension_interval,
+ &_tspec.service_start_time,
+ &_tspec.min_data_rate,
+ &_tspec.mean_data_rate,
+ &_tspec.peak_data_rate,
+ &_tspec.burst_size,
+ &_tspec.delay_bound,
+ &_tspec.min_phy_rate,
+ &_tspec.surplus_band_allow,
+ &_tspec.medium_time) != 15) {
+ printk(KERN_ERR "%s: sscanf error\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ /* Set default TSPEC Values */
+ _tspec.ts_info.access_policy = WLAN_TSINFO_EDCA;
+ _tspec.ts_info.apsd = WLAN_TSINFO_PSB_LEGACY;
+
+ return len;
+}
+
+static CLASS_DEVICE_ATTR(tspec, S_IWUSR|S_IRUGO, show_tspec, store_tspec);
+
+static ssize_t store_addts(struct class_device *dev, const char *buf,
+ size_t len)
+{
+ struct net_device *netdev;
+
+ netdev = to_net_dev(dev);
+ ieee80211_send_addts(netdev, &_tspec);
+ return len;
+}
+
+static CLASS_DEVICE_ATTR(addts, S_IWUSR, NULL, store_addts);
+
+static ssize_t store_addts_wmm(struct class_device *dev, const char *buf,
+ size_t len)
+{
+ struct net_device *netdev;
+
+ netdev = to_net_dev(dev);
+ wmm_send_addts(netdev, &_tspec);
+ return len;
+}
+
+static CLASS_DEVICE_ATTR(addts_wmm, S_IWUSR, NULL, store_addts_wmm);
+
+static ssize_t store_delts(struct class_device *dev, const char *buf,
+ size_t len)
+{
+ struct net_device *netdev;
+
+ netdev = to_net_dev(dev);
+ ieee80211_send_delts(netdev, TSID, TSDIR, _tspec.medium_time);
+ return len;
+}
+
+static CLASS_DEVICE_ATTR(delts, S_IWUSR, NULL, store_delts);
+
+static ssize_t store_delts_wmm(struct class_device *dev, const char *buf,
+ size_t len)
+{
+ struct net_device *netdev;
+
+ netdev = to_net_dev(dev);
+ wmm_send_delts(netdev, TSID, TSDIR, _tspec.medium_time);
+ return len;
+}
+
+static CLASS_DEVICE_ATTR(delts_wmm, S_IWUSR, NULL, store_delts_wmm);
+
+static ssize_t show_dls_mac(struct class_device *dev, char *buf)
+{
+ return sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X\n",
+ _dls_mac[0], _dls_mac[1], _dls_mac[2],
+ _dls_mac[3], _dls_mac[4], _dls_mac[5]);
+}
+
+static ssize_t store_dls_mac(struct class_device *dev, const char *buf,
+ size_t len)
+{
+ if (sscanf(buf, "%x:%x:%x:%x:%x:%x",
+ (int *)&_dls_mac[0], (int *)&_dls_mac[1],
+ (int *)&_dls_mac[2], (int *)&_dls_mac[3],
+ (int *)&_dls_mac[4], (int *)&_dls_mac[5]) != 6) {
+ printk(KERN_ERR "%s: sscanf error\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ return len;
+}
+
+static CLASS_DEVICE_ATTR(dls_mac, S_IWUSR|S_IRUGO, show_dls_mac, store_dls_mac);
+
+static ssize_t show_dls_op(struct class_device *dev, char *buf)
+{
+ return sprintf(buf, "DLS Operation: Setup = 1; Teardown = 2\n");
+}
+
+static ssize_t store_dls_op(struct class_device *dev, const char *buf,
+ size_t len)
+{
+ struct ieee80211_local *local;
+ struct net_device *netdev;
+ struct dls_info *dls;
+ unsigned int opt;
+
+ netdev = to_net_dev(dev);
+ local = netdev->ieee80211_ptr;
+
+ if (sscanf(buf, "%u", &opt) != 1) {
+ printk(KERN_ERR "%s: sscanf error\n", __FUNCTION__);
+ 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(local, dls);
+ ieee80211_send_dls_req(netdev, dls);
+ break;
+ case 2:
+ ieee80211_send_dls_teardown(netdev, _dls_mac,
+ WLAN_REASON_QSTA_NOT_USE);
+ break;
+ default:
+ printk(KERN_ERR "Unknown DLS Operation: %d\n", opt);
+ break;
+ }
+ return len;
+}
+
+static CLASS_DEVICE_ATTR(dls_op, S_IWUSR|S_IRUGO, show_dls_op, store_dls_op);
+
+static struct attribute *ieee80211_qos_attrs[] = {
+ &class_device_attr_ts_info.attr,
+ &class_device_attr_tspec.attr,
+ &class_device_attr_addts.attr,
+ &class_device_attr_addts_wmm.attr,
+ &class_device_attr_delts.attr,
+ &class_device_attr_delts_wmm.attr,
+ &class_device_attr_dls_mac.attr,
+ &class_device_attr_dls_op.attr,
+ NULL
+};
+
+static struct attribute_group ieee80211_qos_group = {
+ .name = "qos",
+ .attrs = ieee80211_qos_attrs,
+};
void ieee80211_dev_sysfs_init(struct ieee80211_local *local)
{
local->class_dev.class = &ieee80211_class;
@@ -696,6 +930,10 @@ void ieee80211_dev_sysfs_del(struct ieee
static void __ieee80211_remove_if_group(struct kobject *kobj,
struct ieee80211_sub_if_data *sdata)
{
+ if (sdata->sysfs_qos_group) {
+ sysfs_remove_group(kobj, sdata->sysfs_qos_group);
+ sdata->sysfs_qos_group = NULL;
+ }
if (sdata->sysfs_group) {
sysfs_remove_group(kobj, sdata->sysfs_group);
sdata->sysfs_group = NULL;
@@ -718,6 +956,7 @@ static int ieee80211_add_if_group(struct
switch (sdata->type) {
case IEEE80211_IF_TYPE_STA:
sdata->sysfs_group = &ieee80211_sta_group;
+ sdata->sysfs_qos_group = &ieee80211_qos_group;
break;
case IEEE80211_IF_TYPE_AP:
sdata->sysfs_group = &ieee80211_ap_group;
@@ -737,6 +976,12 @@ static int ieee80211_add_if_group(struct
res = sysfs_create_group(kobj, sdata->sysfs_group);
if (res)
sdata->sysfs_group = NULL;
+ if (sdata->sysfs_qos_group) {
+ res = sysfs_create_group(kobj, sdata->sysfs_qos_group);
+ if (res)
+ sdata->sysfs_qos_group = NULL;
+ }
+
out:
return res;
}
--
1.2.6
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists