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 <[EMAIL PROTECTED]> --- 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 [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html