Allow changing of the rate control algorithm.
This has some limitations:
- The rate control algorithm can be set per-wiphy only.
- All of network interfaces of the wiphy have to be down to change the
algorithm.
- All sta entries are flushed when the algorithm is succesfully changed.
- The add_sta ioctl can be called only at a running interface from now.
Changing of the algorithm is possible by writing a new algorithm name into
/sys/class/ieee80211/phyX/rate_ctrl_alg. This will be most likely changed in
the future.
Signed-off-by: Jiri Benc <[EMAIL PROTECTED]>
---
net/d80211/ieee80211.c | 50 +++++++++++++++++++++++++++++-------------
net/d80211/ieee80211_i.h | 2 ++
net/d80211/ieee80211_ioctl.c | 4 +++
net/d80211/ieee80211_sysfs.c | 18 ++++++++++++++-
4 files changed, 57 insertions(+), 17 deletions(-)
61a4837fa8e08fc3200b8fa026a84b4afcb674ff
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 8d8149e..ce56fd3 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -4303,22 +4303,44 @@ static void ieee80211_precalc_modes(stru
}
}
-static int rate_control_initialize(struct ieee80211_local *local)
+int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
+ const char *name)
{
- struct rate_control_ref *ref;
+ struct rate_control_ref *ref, *old;
+ int res;
+
+ ASSERT_RTNL();
+ if (local->open_count || netif_running(local->mdev) ||
+ (local->apdev && netif_running(local->apdev)))
+ return -EBUSY;
- ref = rate_control_alloc(NULL, local);
+ ref = rate_control_alloc(name, local);
if (!ref) {
printk(KERN_WARNING "%s: Failed to select rate control "
"algorithm\n", local->mdev->name);
- return -1;
+ return -ENOENT;
+ }
+ res = rate_control_add_attrs(ref, &local->class_dev.kobj);
+ if (res < 0) {
+ printk(KERN_DEBUG "%s: Failed to register sysfs attributes "
+ "for rate control\n", local->mdev->name);
+ rate_control_put(ref);
+ return res;
}
+
+ old = local->rate_ctrl;
local->rate_ctrl = ref;
+ if (old) {
+ rate_control_remove_attrs(ref, &local->class_dev.kobj);
+ rate_control_put(old);
+ sta_info_flush(local, NULL);
+ }
printk(KERN_DEBUG "%s: Selected rate control "
"algorithm '%s'\n", local->mdev->name,
ref->ops->name);
+
return 0;
}
@@ -4328,6 +4350,7 @@ static void rate_control_deinitialize(st
ref = local->rate_ctrl;
local->rate_ctrl = NULL;
+ rate_control_remove_attrs(ref, &local->class_dev.kobj);
rate_control_put(ref);
}
@@ -4496,28 +4519,24 @@ int ieee80211_register_hw(struct net_dev
goto fail_masterlink;
}
result = ieee80211_sysfs_add_netdevice(dev);
- rtnl_unlock();
- if (result < 0)
+ if (result < 0) {
+ rtnl_unlock();
goto fail_if_sysfs;
+ }
- result = rate_control_initialize(local);
+ result = ieee80211_init_rate_ctrl_alg(local, NULL);
+ rtnl_unlock();
if (result < 0) {
printk(KERN_DEBUG "%s: Failed to initialize rate control "
"algorithm\n", dev->name);
goto fail_rate;
}
- result = rate_control_add_attrs(local->ref, &local->class_dev.kobj);
- if (result < 0) {
- printk(KERN_DEBUG "%s: Failed to register sysfs attributes "
- "for rate control\n", dev->name);
- goto fail_rate_attrs;
- }
result = ieee80211_wep_init(local);
if (result < 0) {
printk(KERN_DEBUG "%s: Failed to initialize wep\n", dev->name);
- goto fail_rate_attrs;
+ goto fail_wep;
}
/* TODO: add rtnl locking around device creation and qdisc install */
@@ -4536,7 +4555,7 @@ int ieee80211_register_hw(struct net_dev
return 0;
-fail_rate_attrs:
+fail_wep:
rate_control_deinitialize(local);
fail_rate:
ieee80211_sysfs_remove_netdevice(dev);
@@ -4624,7 +4643,6 @@ void ieee80211_unregister_hw(struct net_
ieee80211_rx_bss_list_deinit(dev);
ieee80211_clear_tx_pending(local);
sta_info_stop(local);
- rate_control_remove_attrs(local->ref, &local->class_dev.kobj);
rate_control_deinitialize(local);
ieee80211_dev_sysfs_del(local);
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 9c81c48..314235b 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -583,6 +583,8 @@ int ieee80211_if_update_wds(struct net_d
void ieee80211_if_setup(struct net_device *dev);
void ieee80211_if_mgmt_setup(struct net_device *dev);
void ieee80211_if_shutdown(struct net_device *dev);
+int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
+ const char *name);
/* ieee80211_ioctl.c */
int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 30390de..ff6718b 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -270,6 +270,10 @@ static int ieee80211_ioctl_add_sta(struc
struct ieee80211_sub_if_data *sdata;
int add_key_entry = 1;
+ /* Prevent a race with changing the rate control algorithm */
+ if (!netif_running(dev))
+ return -ENETDOWN;
+
sta = sta_info_get(local, param->sta_addr);
if (!sta) {
diff --git a/net/d80211/ieee80211_sysfs.c b/net/d80211/ieee80211_sysfs.c
index c0aab4a..2b74a7a 100644
--- a/net/d80211/ieee80211_sysfs.c
+++ b/net/d80211/ieee80211_sysfs.c
@@ -102,6 +102,22 @@ static ssize_t store_remove_iface(struct
return res < 0 ? res : len;
}
+static ssize_t store_rate_ctrl_alg(struct class_device *dev,
+ const char *buf, size_t len)
+{
+ struct ieee80211_local *local = to_ieee80211_local(dev);
+ int res;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ res = rtnl_lock_local(local);
+ if (res)
+ return res;
+ res = ieee80211_init_rate_ctrl_alg(local, buf);
+ rtnl_unlock();
+ return res < 0 ? res : len;
+}
+
static ssize_t ieee80211_local_show(struct class_device *dev, char *buf,
ssize_t (*format)(struct ieee80211_local *, char *))
{
@@ -214,7 +230,7 @@ static struct class_device_attribute iee
__ATTR(wep_iv, S_IRUGO, ieee80211_local_show_wep_iv, NULL),
__ATTR(tx_power_reduction, S_IRUGO,
ieee80211_local_show_tx_power_reduction, NULL),
__ATTR(modes, S_IRUGO, ieee80211_local_show_modes, NULL),
- __ATTR(rate_ctrl_alg, S_IRUGO, ieee80211_local_show_rate_ctrl_alg,
NULL),
+ __ATTR(rate_ctrl_alg, S_IRUGO | S_IWUGO,
ieee80211_local_show_rate_ctrl_alg, store_rate_ctrl_alg),
{}
};
--
1.3.0
-
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