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