Add a reference counting to the rate control algorithm structure. This
prevents unloading of the rate control module when there still exists a sta
entry which uses that module.

To achieve this some other things need to be done in this patch as well:

- The new rate_control_ref structure is introduced. It replaces the
  rate_ctrl and rate_ctrl_priv fields in the ieee80211_local.

- Parameters for most rate control callbacks are changed.

Signed-off-by: Jiri Benc <[EMAIL PROTECTED]>

---

 net/d80211/ieee80211.c       |   37 +++++--------
 net/d80211/ieee80211_i.h     |    3 -
 net/d80211/ieee80211_ioctl.c |    2 -
 net/d80211/ieee80211_rate.c  |   54 +++++++++++++++++-
 net/d80211/ieee80211_rate.h  |  124 +++++++++++++++++++++---------------------
 net/d80211/ieee80211_scan.c  |    2 -
 net/d80211/ieee80211_sta.c   |    6 +-
 net/d80211/ieee80211_sysfs.c |    5 +-
 net/d80211/rc80211_simple.c  |   19 ++++--
 net/d80211/sta_info.c        |   14 +++--
 net/d80211/sta_info.h        |    1 
 11 files changed, 158 insertions(+), 109 deletions(-)

a020fc0696485e6cf460060c7fc03c1066897ba0
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 8c4a6d6..8d8149e 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -351,7 +351,8 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
        extra.startidx  = 0;
        extra.endidx    = tx->local->num_curr_rates;
 
-       tx->u.tx.rate = rate_control_get_rate(tx->dev, tx->skb, &extra);
+       tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, tx->skb,
+                                             &extra);
        if (unlikely(extra.probe != NULL)) {
                tx->u.tx.control->rate_ctrl_probe = 1;
                tx->u.tx.probe_last_frag = 1;
@@ -1781,7 +1782,7 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
                memset(&extra, 0, sizeof(extra));
                extra.endidx = local->num_curr_rates;
 
-               rate = rate_control_get_rate(dev, skb, &extra);
+               rate = rate_control_get_rate(local, dev, skb, &extra);
                if (!rate) {
                        if (net_ratelimit()) {
                                printk(KERN_DEBUG "%s: ieee80211_beacon_get: no 
rate "
@@ -4102,7 +4103,7 @@ void ieee80211_tx_status(struct net_devi
                        return;
                }
        } else {
-               rate_control_tx_status(dev, skb, status);
+               rate_control_tx_status(local, dev, skb, status);
        }
 
        ieee80211_led_tx(local, 0);
@@ -4304,36 +4305,30 @@ static void ieee80211_precalc_modes(stru
 
 static int rate_control_initialize(struct ieee80211_local *local)
 {
-       struct rate_control_ops *ops;
+       struct rate_control_ref *ref;
 
-       ops = ieee80211_rate_control_ops_get(NULL);
-       if (!ops) {
+       ref = rate_control_alloc(NULL, local);
+       if (!ref) {
                printk(KERN_WARNING "%s: Failed to select rate control "
                       "algorithm\n", local->mdev->name);
                return -1;
        }
-       local->rate_ctrl_priv = rate_control_alloc(ops, local);
-       if (!local->rate_ctrl_priv) {
-               ieee80211_rate_control_ops_put(ops);
-               return -1;
-       }
-       local->rate_ctrl = ops;
+       local->rate_ctrl = ref;
 
        printk(KERN_DEBUG "%s: Selected rate control "
               "algorithm '%s'\n", local->mdev->name,
-              local->rate_ctrl->name);
+              ref->ops->name);
 
        return 0;
 }
 
 static void rate_control_deinitialize(struct ieee80211_local *local)
 {
-       struct rate_control_ops *ops;
+       struct rate_control_ref *ref;
 
-       rate_control_free(local);
-       ops = local->rate_ctrl;
+       ref = local->rate_ctrl;
        local->rate_ctrl = NULL;
-       ieee80211_rate_control_ops_put(ops);
+       rate_control_put(ref);
 }
 
 struct net_device *ieee80211_alloc_hw(size_t priv_data_len,
@@ -4511,8 +4506,7 @@ int ieee80211_register_hw(struct net_dev
                       "algorithm\n", dev->name);
                goto fail_rate;
        }
-       result = rate_control_add_attrs(local, local->rate_ctrl_priv,
-                                       &local->class_dev.kobj);
+       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);
@@ -4630,8 +4624,8 @@ 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, local->rate_ctrl_priv,
-                                 &local->class_dev.kobj);
+       rate_control_remove_attrs(local->ref, &local->class_dev.kobj);
+       rate_control_deinitialize(local);
        ieee80211_dev_sysfs_del(local);
 
        for (i = 0; i < NUM_IEEE80211_MODES; i++) {
@@ -4662,7 +4656,6 @@ EXPORT_SYMBOL(ieee80211_free_hw);
 
 void ieee80211_release_hw(struct ieee80211_local *local)
 {
-       rate_control_deinitialize(local);
        kfree(local);
 }
 
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 6fd208e..9c81c48 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -382,8 +382,7 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12
        struct ieee80211_rate *curr_rates;
        int num_curr_rates;
 
-       void *rate_ctrl_priv;
-       struct rate_control_ops *rate_ctrl;
+       struct rate_control_ref *rate_ctrl;
 
        int next_mode; /* MODE_IEEE80211*
                        * The mode preference for next channel change. This is
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 36759e4..30390de 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -311,7 +311,7 @@ static int ieee80211_ioctl_add_sta(struc
        }
        sta->supp_rates = rates;
 
-       rate_control_rate_init(local, sta);
+       rate_control_rate_init(sta, local);
 
        if (param->u.add_sta.wds_flags & 0x01)
                sta->flags |= WLAN_STA_WDS;
diff --git a/net/d80211/ieee80211_rate.c b/net/d80211/ieee80211_rate.c
index 3ec370f..16e8508 100644
--- a/net/d80211/ieee80211_rate.c
+++ b/net/d80211/ieee80211_rate.c
@@ -55,7 +55,8 @@ void ieee80211_rate_control_unregister(s
 }
 EXPORT_SYMBOL(ieee80211_rate_control_unregister);
 
-static struct rate_control_ops *ieee80211_try_rate_control_ops_get(char *name)
+static struct rate_control_ops *
+ieee80211_try_rate_control_ops_get(const char *name)
 {
        struct rate_control_alg *alg;
        struct rate_control_ops *ops = NULL;
@@ -74,7 +75,8 @@ static struct rate_control_ops *ieee8021
 
 /* Get the rate control algorithm. If `name' is NULL, get the first
  * available algorithm. */
-struct rate_control_ops *ieee80211_rate_control_ops_get(char *name)
+static struct rate_control_ops *
+ieee80211_rate_control_ops_get(const char *name)
 {
        struct rate_control_ops *ops;
 
@@ -86,7 +88,53 @@ struct rate_control_ops *ieee80211_rate_
        return ops;
 }
 
-void ieee80211_rate_control_ops_put(struct rate_control_ops *ops)
+static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops)
 {
        module_put(ops->module);
 }
+
+struct rate_control_ref *rate_control_alloc(const char *name,
+                                           struct ieee80211_local *local)
+{
+       struct rate_control_ref *ref;
+
+       ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
+       if (!ref)
+               goto fail_ref;
+       kref_init(&ref->kref);
+       ref->ops = ieee80211_rate_control_ops_get(name);
+       if (!ref->ops)
+               goto fail_ops;
+       ref->priv = ref->ops->alloc(local);
+       if (!ref->priv)
+               goto fail_priv;
+       return ref;
+
+fail_priv:
+       ieee80211_rate_control_ops_put(ref->ops);
+fail_ops:
+       kfree(ref);
+fail_ref:
+       return NULL;
+}
+
+static void rate_control_release(struct kref *kref)
+{
+       struct rate_control_ref *ctrl_ref;
+
+       ctrl_ref = container_of(kref, struct rate_control_ref, kref);
+       ctrl_ref->ops->free(ctrl_ref->priv);
+       ieee80211_rate_control_ops_put(ctrl_ref->ops);
+       kfree(ctrl_ref);
+}
+
+struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
+{
+       kref_get(&ref->kref);
+       return ref;
+}
+
+void rate_control_put(struct rate_control_ref *ref)
+{
+       kref_put(&ref->kref, rate_control_release);
+}
diff --git a/net/d80211/ieee80211_rate.h b/net/d80211/ieee80211_rate.h
index 2a4c662..60e4879 100644
--- a/net/d80211/ieee80211_rate.h
+++ b/net/d80211/ieee80211_rate.h
@@ -1,6 +1,7 @@
 /*
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2005, Devicescape Software, Inc.
+ * Copyright (c) 2006 Jiri Benc <[EMAIL PROTECTED]>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -39,120 +40,121 @@ struct rate_control_extra {
 struct rate_control_ops {
        struct module *module;
        const char *name;
-       void (*tx_status)(struct net_device *dev, struct sk_buff *skb,
+       void (*tx_status)(void *priv, struct net_device *dev,
+                         struct sk_buff *skb,
                          struct ieee80211_tx_status *status);
-       struct ieee80211_rate *
-       (*get_rate)(struct net_device *dev, struct sk_buff *skb,
-                   struct rate_control_extra *extra);
-       void (*rate_init)(struct ieee80211_local *local, struct sta_info *sta);
+       struct ieee80211_rate *(*get_rate)(void *priv, struct net_device *dev,
+                                          struct sk_buff *skb,
+                                          struct rate_control_extra *extra);
+       void (*rate_init)(void *priv, void *priv_sta,
+                         struct ieee80211_local *local, struct sta_info *sta);
        void (*clear)(void *priv);
 
-       void * (*alloc)(struct ieee80211_local *local);
+       void *(*alloc)(struct ieee80211_local *local);
        void (*free)(void *priv);
-       void * (*alloc_sta)(void);
-       void (*free_sta)(void *priv);
+       void *(*alloc_sta)(void *priv);
+       void (*free_sta)(void *priv, void *priv_sta);
 
        int (*add_attrs)(void *priv, struct kobject *kobj);
        void (*remove_attrs)(void *priv, struct kobject *kobj);
-       int (*add_sta_attrs)(void *priv, struct kobject *kobj);
-       void (*remove_sta_attrs)(void *priv, struct kobject *kobj);
+       int (*add_sta_attrs)(void *priv, void *priv_sta,
+                            struct kobject *kobj);
+       void (*remove_sta_attrs)(void *priv, void *priv_sta,
+                                struct kobject *kobj);
 };
 
+struct rate_control_ref {
+       struct rate_control_ops *ops;
+       void *priv;
+       struct kref kref;
+};
 
 int ieee80211_rate_control_register(struct rate_control_ops *ops);
 void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
 
-struct rate_control_ops *ieee80211_rate_control_ops_get(char *name);
-void ieee80211_rate_control_ops_put(struct rate_control_ops *ops);
+/* Get a reference to the rate control algorithm. If `name' is NULL, get the
+ * first available algorithm. */
+struct rate_control_ref *rate_control_alloc(const char *name,
+                                           struct ieee80211_local *local);
+struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
+void rate_control_put(struct rate_control_ref *ref);
 
-static inline void rate_control_tx_status(struct net_device *dev,
+static inline void rate_control_tx_status(struct ieee80211_local *local,
+                                         struct net_device *dev,
                                          struct sk_buff *skb,
                                          struct ieee80211_tx_status *status)
 {
-       struct ieee80211_local *local = dev->ieee80211_ptr;
-       local->rate_ctrl->tx_status(dev, skb, status);
+       struct rate_control_ref *ref = local->rate_ctrl;
+       ref->ops->tx_status(ref->priv, dev, skb, status);
 }
 
 
 static inline struct ieee80211_rate *
-rate_control_get_rate(struct net_device *dev, struct sk_buff *skb,
-                     struct rate_control_extra *extra)
+rate_control_get_rate(struct ieee80211_local *local, struct net_device *dev,
+                     struct sk_buff *skb, struct rate_control_extra *extra)
 {
-       struct ieee80211_local *local = dev->ieee80211_ptr;
-       return local->rate_ctrl->get_rate(dev, skb, extra);
+       struct rate_control_ref *ref = local->rate_ctrl;
+       return ref->ops->get_rate(ref->priv, dev, skb, extra);
 }
 
 
-static inline void rate_control_rate_init(struct ieee80211_local *local,
-                                         struct sta_info *sta)
+static inline void rate_control_rate_init(struct sta_info *sta,
+                                         struct ieee80211_local *local)
 {
-       local->rate_ctrl->rate_init(local, sta);
+       struct rate_control_ref *ref = sta->rate_ctrl;
+       ref->ops->rate_init(ref->priv, sta->rate_ctrl_priv, local, sta);
 }
 
 
 static inline void rate_control_clear(struct ieee80211_local *local)
 {
-       local->rate_ctrl->clear(local->rate_ctrl_priv);
-}
-
-
-static inline void *rate_control_alloc(struct rate_control_ops *ops,
-                                      struct ieee80211_local *local)
-{
-       return ops->alloc(local);
+       struct rate_control_ref *ref = local->rate_ctrl;
+       ref->ops->clear(ref->priv);
 }
 
-
-static inline void rate_control_free(struct ieee80211_local *local)
+static inline void *rate_control_alloc_sta(struct rate_control_ref *ref)
 {
-       if (!local->rate_ctrl || !local->rate_ctrl_priv)
-               return;
-       local->rate_ctrl->free(local->rate_ctrl_priv);
-       local->rate_ctrl_priv = NULL;
+       return ref->ops->alloc_sta(ref->priv);
 }
 
-
-static inline void * rate_control_alloc_sta(struct ieee80211_local *local)
-{
-       return local->rate_ctrl->alloc_sta();
-}
-
-
-static inline void rate_control_free_sta(struct ieee80211_local *local,
+static inline void rate_control_free_sta(struct rate_control_ref *ref,
                                         void *priv)
 {
-       local->rate_ctrl->free_sta(priv);
+       ref->ops->free_sta(ref->priv, priv);
 }
 
-static inline int rate_control_add_attrs(struct ieee80211_local *local,
-                                        void *priv, struct kobject *kobj)
+static inline int rate_control_add_attrs(struct rate_control_ref *ref,
+                                        struct kobject *kobj)
 {
-       if (local->rate_ctrl->add_attrs)
-               return local->rate_ctrl->add_attrs(priv, kobj);
+       if (ref->ops->add_attrs)
+               return ref->ops->add_attrs(ref->priv, kobj);
        return 0;
 }
 
-static inline void rate_control_remove_attrs(struct ieee80211_local *local,
-                                            void *priv, struct kobject *kobj)
+static inline void rate_control_remove_attrs(struct rate_control_ref *ref,
+                                            struct kobject *kobj)
 {
-       if (local->rate_ctrl->remove_attrs)
-               local->rate_ctrl->remove_attrs(priv, kobj);
+       if (ref->ops->remove_attrs)
+               ref->ops->remove_attrs(ref->priv, kobj);
 }
 
-static inline int rate_control_add_sta_attrs(struct ieee80211_local *local,
-                                            void *priv, struct kobject *kobj)
+static inline int rate_control_add_sta_attrs(struct sta_info *sta,
+                                            struct kobject *kobj)
 {
-       if (local->rate_ctrl->add_sta_attrs)
-               return local->rate_ctrl->add_sta_attrs(priv, kobj);
+       struct rate_control_ref *ref = sta->rate_ctrl;
+       if (ref->ops->add_sta_attrs)
+               return ref->ops->add_sta_attrs(ref->priv, sta->rate_ctrl_priv,
+                                              kobj);
        return 0;
 }
 
-static inline void rate_control_remove_sta_attrs(struct ieee80211_local *local,
-                                                void *priv,
+static inline void rate_control_remove_sta_attrs(struct sta_info *sta,
                                                 struct kobject *kobj)
 {
-       if (local->rate_ctrl->remove_sta_attrs)
-               local->rate_ctrl->remove_sta_attrs(priv, kobj);
+       struct rate_control_ref *ref = sta->rate_ctrl;
+       if (ref->ops->remove_sta_attrs)
+               ref->ops->remove_sta_attrs(ref->priv, sta->rate_ctrl_priv,
+                                          kobj);
 }
 
 #endif /* IEEE80211_RATE_H */
diff --git a/net/d80211/ieee80211_scan.c b/net/d80211/ieee80211_scan.c
index 0774e9a..add0bf3 100644
--- a/net/d80211/ieee80211_scan.c
+++ b/net/d80211/ieee80211_scan.c
@@ -333,7 +333,7 @@ void ieee80211_init_scan(struct net_devi
        memset(&extra, 0, sizeof(extra));
        extra.endidx = local->num_curr_rates;
        local->scan.tx_control.tx_rate =
-               rate_control_get_rate(dev, local->scan.skb, &extra)->val;
+               rate_control_get_rate(local, dev, local->scan.skb, &extra)->val;
        local->scan.tx_control.no_ack = 1;
 }
 
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 3ea75ee..ed6747a 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -1189,7 +1189,7 @@ static void ieee80211_rx_mgmt_assoc_resp
        }
        sta->supp_rates = rates;
 
-       rate_control_rate_init(local, sta);
+       rate_control_rate_init(sta, local);
 
        if (elems.wmm_param && ifsta->wmm_enabled) {
                sta->flags |= WLAN_STA_WME;
@@ -2054,7 +2054,7 @@ static int ieee80211_sta_join_ibss(struc
                control.pkt_type = PKT_PROBE_RESP;
                memset(&extra, 0, sizeof(extra));
                extra.endidx = local->num_curr_rates;
-               rate = rate_control_get_rate(dev, skb, &extra);
+               rate = rate_control_get_rate(local, dev, skb, &extra);
                if (!rate) {
                        printk(KERN_DEBUG "%s: Failed to determine TX rate "
                               "for IBSS beacon\n", dev->name);
@@ -2839,7 +2839,7 @@ struct sta_info * ieee80211_ibss_add_sta
        sta->dev = sta_dev;
        sta->supp_rates = sdata->u.sta.supp_rates_bits;
 
-       rate_control_rate_init(local, sta);
+       rate_control_rate_init(sta, local);
 
        return sta; /* caller will call sta_info_put() */
 }
diff --git a/net/d80211/ieee80211_sysfs.c b/net/d80211/ieee80211_sysfs.c
index f9d0e12..c0aab4a 100644
--- a/net/d80211/ieee80211_sysfs.c
+++ b/net/d80211/ieee80211_sysfs.c
@@ -188,8 +188,9 @@ __IEEE80211_LOCAL_SHOW(modes);
 static ssize_t ieee80211_local_fmt_rate_ctrl_alg(struct ieee80211_local *local,
                                                 char *buf)
 {
-       if (local->rate_ctrl && local->rate_ctrl_priv)
-               return sprintf(buf, "%s\n", local->rate_ctrl->name);
+       struct rate_control_ref *ref = local->rate_ctrl;
+       if (ref)
+               return sprintf(buf, "%s\n", ref->ops->name);
        return 0;
 }
 __IEEE80211_LOCAL_SHOW(rate_ctrl_alg);
diff --git a/net/d80211/rc80211_simple.c b/net/d80211/rc80211_simple.c
index 6703931..055a167 100644
--- a/net/d80211/rc80211_simple.c
+++ b/net/d80211/rc80211_simple.c
@@ -120,7 +120,7 @@ struct sta_rate_control {
 };
 
 
-static void rate_control_simple_tx_status(struct net_device *dev,
+static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
                                          struct sk_buff *skb,
                                          struct ieee80211_tx_status *status)
 {
@@ -212,7 +212,8 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
 
 
 static struct ieee80211_rate *
-rate_control_simple_get_rate(struct net_device *dev, struct sk_buff *skb,
+rate_control_simple_get_rate(void *priv, struct net_device *dev,
+                            struct sk_buff *skb,
                             struct rate_control_extra *extra)
 {
        struct ieee80211_local *local = dev->ieee80211_ptr;
@@ -264,7 +265,8 @@ rate_control_simple_get_rate(struct net_
 }
 
 
-static void rate_control_simple_rate_init(struct ieee80211_local *local,
+static void rate_control_simple_rate_init(void *priv, void *priv_sta,
+                                         struct ieee80211_local *local,
                                          struct sta_info *sta)
 {
        int i;
@@ -303,7 +305,7 @@ static void rate_control_simple_clear(vo
 }
 
 
-static void * rate_control_simple_alloc_sta(void)
+static void * rate_control_simple_alloc_sta(void *priv)
 {
        struct sta_rate_control *rctrl;
 
@@ -313,9 +315,9 @@ static void * rate_control_simple_alloc_
 }
 
 
-static void rate_control_simple_free_sta(void *priv)
+static void rate_control_simple_free_sta(void *priv, void *priv_sta)
 {
-       struct sta_rate_control *rctrl = priv;
+       struct sta_rate_control *rctrl = priv_sta;
        kfree(rctrl);
 }
 
@@ -349,12 +351,13 @@ static struct attribute_group rate_contr
        .attrs = rate_control_simple_sta_attrs,
 };
 
-static int rate_control_simple_add_sta_attrs(void *priv, struct kobject *kobj)
+static int rate_control_simple_add_sta_attrs(void *priv, void *priv_sta,
+                                            struct kobject *kobj)
 {
        return sysfs_create_group(kobj, &rate_control_simple_sta_group);
 }
 
-static void rate_control_simple_remove_sta_attrs(void *priv,
+static void rate_control_simple_remove_sta_attrs(void *priv, void *priv_sta,
                                                 struct kobject *kobj)
 {
        sysfs_remove_group(kobj, &rate_control_simple_sta_group);
diff --git a/net/d80211/sta_info.c b/net/d80211/sta_info.c
index 6a1a466..a177d2f 100644
--- a/net/d80211/sta_info.c
+++ b/net/d80211/sta_info.c
@@ -123,7 +123,8 @@ void sta_info_release(struct kobject *ko
        while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
                dev_kfree_skb_any(skb);
        }
-       rate_control_free_sta(local, sta->rate_ctrl_priv);
+       rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
+       rate_control_put(sta->rate_ctrl);
        kfree(sta);
 }
 
@@ -146,8 +147,10 @@ struct sta_info * sta_info_add(struct ie
        sta->kobj.kset = &local->sta_kset;
        kobject_init(&sta->kobj);
 
-       sta->rate_ctrl_priv = rate_control_alloc_sta(local);
+       sta->rate_ctrl = rate_control_get(local->rate_ctrl);
+       sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl);
        if (!sta->rate_ctrl_priv) {
+               rate_control_put(sta->rate_ctrl);
                kobject_put(&sta->kobj);
                kfree(sta);
                return NULL;
@@ -177,8 +180,7 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
        if (!in_interrupt()) {
                sta->sysfs_registered = 1;
                ieee80211_sta_sysfs_add(sta);
-               rate_control_add_sta_attrs(local, sta->rate_ctrl_priv,
-                                          &sta->kobj);
+               rate_control_add_sta_attrs(sta, &sta->kobj);
        } else {
                /* procfs entry adding might sleep, so schedule process context
                 * task for adding proc entry for STAs that do not yet have
@@ -203,7 +205,7 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
                sta->key = NULL;
        }
 
-       rate_control_remove_sta_attrs(local, sta->rate_ctrl_priv, &sta->kobj);
+       rate_control_remove_sta_attrs(sta, &sta->kobj);
        ieee80211_sta_sysfs_remove(sta);
 
        sta_info_put(sta);
@@ -370,7 +372,7 @@ static void sta_info_proc_add_task(void 
 
                sta->sysfs_registered = 1;
                ieee80211_sta_sysfs_add(sta);
-               rate_control_add_sta_attrs(local, sta->rate_ctrl_priv, 
&sta->kobj);
+               rate_control_add_sta_attrs(sta, &sta->kobj);
                sta_info_put(sta);
        }
 }
diff --git a/net/d80211/sta_info.h b/net/d80211/sta_info.h
index 8d23047..9bd7e0d 100644
--- a/net/d80211/sta_info.h
+++ b/net/d80211/sta_info.h
@@ -71,6 +71,7 @@ struct sta_info {
        u32 tx_num_mpdu_ok;
        u32 tx_num_mpdu_fail;
 
+       struct rate_control_ref *rate_ctrl;
        void *rate_ctrl_priv;
 
        /* last received seq/frag number from this STA (per RX queue) */
-- 
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