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

Reply via email to