* [PATCH 0/8] d80211: rate control modules locking and changing
@ 2006-10-02 18:26 Jiri Benc
2006-10-02 18:26 ` [PATCH 1/8] d80211: add missing rtnl_unlock() Jiri Benc
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Jiri Benc @ 2006-10-02 18:26 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
The following patch series fixes locking issues with rate control modules
and adds support for on-the-fly changing of the rate control algorithms.
During the work I discovered some bugs which are not exactly related to rate
controling; they are included in the series as well.
All patches are also available in the 'devel' branch of
git://git.kernel.org/pub/scm/linux/kernel/git/jbenc/dscape.git
Jiri
--
Jiri Benc
SUSE Labs
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/8] d80211: add missing rtnl_unlock()
2006-10-02 18:26 [PATCH 0/8] d80211: rate control modules locking and changing Jiri Benc
@ 2006-10-02 18:26 ` Jiri Benc
2006-10-02 18:26 ` [PATCH 2/8] d80211: del sta timer on interface close Jiri Benc
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Jiri Benc @ 2006-10-02 18:26 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
Add forgotten rtnl_unlock() in the error path of ieee80211_register_hw.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
a0ed5768c0c3b9481dda8b59f6a183e000451acf
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 3efba6a..036eca1 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -4449,8 +4449,10 @@ int ieee80211_register_hw(struct net_dev
result = sysfs_create_link(&local->class_dev.kobj,
&dev->class_dev.kobj,
"master");
- if (result < 0)
+ if (result < 0) {
+ rtnl_unlock();
goto fail_masterlink;
+ }
result = ieee80211_sysfs_add_netdevice(dev);
rtnl_unlock();
if (result < 0)
--
1.3.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/8] d80211: del sta timer on interface close
2006-10-02 18:26 [PATCH 0/8] d80211: rate control modules locking and changing Jiri Benc
2006-10-02 18:26 ` [PATCH 1/8] d80211: add missing rtnl_unlock() Jiri Benc
@ 2006-10-02 18:26 ` Jiri Benc
2006-10-02 18:26 ` [PATCH 3/8] d80211: rename rate_control.h to ieee80211_rate.h Jiri Benc
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Jiri Benc @ 2006-10-02 18:26 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
Delete sta timer when the corresponding network interface is brought down.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211.c | 24 ++++++++++++++++++++++++
net/d80211/ieee80211_i.h | 1 +
net/d80211/ieee80211_iface.c | 12 +++---------
net/d80211/ieee80211_sta.c | 3 +++
4 files changed, 31 insertions(+), 9 deletions(-)
832beeb503d7c41a6a9f3ea73cf31dee5c9f1eb9
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 036eca1..b30bd80 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -2106,6 +2106,29 @@ static struct net_device_stats *ieee8021
return &(sdata->stats);
}
+void ieee80211_if_shutdown(struct net_device *dev)
+{
+ struct ieee80211_local *local = dev->ieee80211_ptr;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ ASSERT_RTNL();
+ switch (sdata->type) {
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
+ sdata->u.sta.state = IEEE80211_DISABLED;
+ del_timer_sync(&sdata->u.sta.timer);
+ if (local->scan_work.data == sdata->dev) {
+ local->sta_scanning = 0;
+ cancel_delayed_work(&local->scan_work);
+ flush_scheduled_work();
+ /* see comment in ieee80211_unregister_hw to
+ * understand why this works */
+ local->scan_work.data = NULL;
+ }
+ break;
+ }
+}
+
static inline int identical_mac_addr_allowed(int type1, int type2)
{
return (type1 == IEEE80211_IF_TYPE_MNTR ||
@@ -2306,6 +2329,7 @@ static int ieee80211_stop(struct net_dev
conf.mac_addr = dev->dev_addr;
local->hw->remove_interface(sdata->master, &conf);
}
+ ieee80211_if_shutdown(dev);
ieee80211_start_hard_monitor(local);
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 425fc9b..6fd208e 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -583,6 +583,7 @@ void ieee80211_tx_set_iswep(struct ieee8
int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
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);
/* ieee80211_ioctl.c */
int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 0a10c86..9a187af 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -242,6 +242,9 @@ #endif
ieee80211_key_free(sdata->keys[i]);
}
+ /* Shouldn't be necessary but won't hurt */
+ ieee80211_if_shutdown(dev);
+
switch (sdata->type) {
case IEEE80211_IF_TYPE_AP: {
/* Remove all virtual interfaces that use this BSS
@@ -286,15 +289,6 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
break;
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
- del_timer_sync(&sdata->u.sta.timer);
- if (local->scan_work.data == sdata->dev) {
- local->sta_scanning = 0;
- cancel_delayed_work(&local->scan_work);
- flush_scheduled_work();
- /* see comment in ieee80211_unregister_hw to
- * understand why this works */
- local->scan_work.data = NULL;
- }
kfree(sdata->u.sta.extra_ie);
sdata->u.sta.extra_ie = NULL;
kfree(sdata->u.sta.assocreq_ies);
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index dd95ce8..159474f 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -1848,6 +1848,9 @@ void ieee80211_sta_timer(unsigned long p
struct ieee80211_if_sta *ifsta;
dev = (struct net_device *) ptr;
+ if (!netif_running(dev))
+ return;
+
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->type != IEEE80211_IF_TYPE_STA &&
sdata->type != IEEE80211_IF_TYPE_IBSS) {
--
1.3.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/8] d80211: rename rate_control.h to ieee80211_rate.h
2006-10-02 18:26 [PATCH 0/8] d80211: rate control modules locking and changing Jiri Benc
2006-10-02 18:26 ` [PATCH 1/8] d80211: add missing rtnl_unlock() Jiri Benc
2006-10-02 18:26 ` [PATCH 2/8] d80211: del sta timer on interface close Jiri Benc
@ 2006-10-02 18:26 ` Jiri Benc
2006-10-02 18:26 ` [PATCH 4/8] d80211: proper rate_control loading Jiri Benc
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Jiri Benc @ 2006-10-02 18:26 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
rate_control.h is not a header for rate_control.c as the name suggests.
Furthermore, we want to introduce ieee80211_rate.c which implements some
things defined in rate_control.h.
This patch renames rate_control.h to ieee80211_rate.h.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211.c | 2 -
net/d80211/ieee80211_ioctl.c | 2 -
net/d80211/ieee80211_rate.h | 154 ++++++++++++++++++++++++++++++++++++++++++
net/d80211/ieee80211_scan.c | 2 -
net/d80211/ieee80211_sta.c | 2 -
net/d80211/ieee80211_sysfs.c | 2 -
net/d80211/rate_control.c | 2 -
net/d80211/rate_control.h | 154 ------------------------------------------
net/d80211/sta_info.c | 2 -
9 files changed, 161 insertions(+), 161 deletions(-)
create mode 100644 net/d80211/ieee80211_rate.h
delete mode 100644 net/d80211/rate_control.h
f0ab1336dc23b25ed00a7a26ec0ba0b9a1a96cdf
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index b30bd80..b138eb0 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -25,7 +25,7 @@ #include <net/d80211.h>
#include <net/d80211_common.h>
#include <net/d80211_mgmt.h>
#include "ieee80211_i.h"
-#include "rate_control.h"
+#include "ieee80211_rate.h"
#include "wep.h"
#include "wpa.h"
#include "tkip.h"
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 445adad..36759e4 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -23,7 +23,7 @@ #include <net/d80211.h>
#include <net/d80211_mgmt.h>
#include "ieee80211_i.h"
#include "hostapd_ioctl.h"
-#include "rate_control.h"
+#include "ieee80211_rate.h"
#include "wpa.h"
#include "aes_ccm.h"
diff --git a/net/d80211/ieee80211_rate.h b/net/d80211/ieee80211_rate.h
new file mode 100644
index 0000000..e1c9e05
--- /dev/null
+++ b/net/d80211/ieee80211_rate.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef IEEE80211_RATE_H
+#define IEEE80211_RATE_H
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <net/d80211.h>
+#include "ieee80211_i.h"
+#include "sta_info.h"
+
+#define RATE_CONTROL_NUM_DOWN 20
+#define RATE_CONTROL_NUM_UP 15
+
+
+struct rate_control_extra {
+ /* values from rate_control_get_rate() to the caller: */
+ struct ieee80211_rate *probe; /* probe with this rate, or NULL for no
+ * probing */
+ int startidx, endidx, rateidx;
+ struct ieee80211_rate *nonerp;
+ int nonerp_idx;
+
+ /* parameters from the caller to rate_control_get_rate(): */
+ int mgmt_data; /* this is data frame that is used for management
+ * (e.g., IEEE 802.1X EAPOL) */
+ u16 ethertype;
+};
+
+
+struct rate_control_ops {
+ const char *name;
+ void (*tx_status)(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);
+ void (*clear)(void *priv);
+
+ void * (*alloc)(struct ieee80211_local *local);
+ void (*free)(void *priv);
+ void * (*alloc_sta)(void);
+ void (*free_sta)(void *priv);
+
+ 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 ieee80211_rate_control_register(struct rate_control_ops *ops);
+void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
+
+
+static inline void rate_control_tx_status(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);
+}
+
+
+static inline struct ieee80211_rate *
+rate_control_get_rate(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);
+}
+
+
+static inline void rate_control_rate_init(struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ local->rate_ctrl->rate_init(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 ieee80211_local *local)
+{
+ return local->rate_ctrl->alloc(local);
+}
+
+
+static inline void rate_control_free(struct ieee80211_local *local)
+{
+ if (!local->rate_ctrl || !local->rate_ctrl_priv)
+ return;
+ local->rate_ctrl->free(local->rate_ctrl_priv);
+ local->rate_ctrl_priv = NULL;
+}
+
+
+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,
+ void *priv)
+{
+ local->rate_ctrl->free_sta(priv);
+}
+
+static inline int rate_control_add_attrs(struct ieee80211_local *local,
+ void *priv, struct kobject *kobj)
+{
+ if (local->rate_ctrl->add_attrs)
+ return local->rate_ctrl->add_attrs(priv, kobj);
+ return 0;
+}
+
+static inline void rate_control_remove_attrs(struct ieee80211_local *local,
+ void *priv, struct kobject *kobj)
+{
+ if (local->rate_ctrl->remove_attrs)
+ local->rate_ctrl->remove_attrs(priv, kobj);
+}
+
+static inline int rate_control_add_sta_attrs(struct ieee80211_local *local,
+ void *priv, struct kobject *kobj)
+{
+ if (local->rate_ctrl->add_sta_attrs)
+ return local->rate_ctrl->add_sta_attrs(priv, kobj);
+ return 0;
+}
+
+static inline void rate_control_remove_sta_attrs(struct ieee80211_local *local,
+ void *priv,
+ struct kobject *kobj)
+{
+ if (local->rate_ctrl->remove_sta_attrs)
+ local->rate_ctrl->remove_sta_attrs(priv, kobj);
+}
+
+#endif /* IEEE80211_RATE_H */
diff --git a/net/d80211/ieee80211_scan.c b/net/d80211/ieee80211_scan.c
index 8ed1e39..0774e9a 100644
--- a/net/d80211/ieee80211_scan.c
+++ b/net/d80211/ieee80211_scan.c
@@ -14,7 +14,7 @@ #include <linux/skbuff.h>
#include <net/d80211.h>
#include "ieee80211_i.h"
-#include "rate_control.h"
+#include "ieee80211_rate.h"
/* Maximum number of seconds to wait for the traffic load to get below
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 159474f..3ea75ee 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -28,7 +28,7 @@ #include <asm/delay.h>
#include <net/d80211.h>
#include <net/d80211_mgmt.h>
#include "ieee80211_i.h"
-#include "rate_control.h"
+#include "ieee80211_rate.h"
#include "hostapd_ioctl.h"
#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
diff --git a/net/d80211/ieee80211_sysfs.c b/net/d80211/ieee80211_sysfs.c
index bb93723..f9d0e12 100644
--- a/net/d80211/ieee80211_sysfs.c
+++ b/net/d80211/ieee80211_sysfs.c
@@ -14,7 +14,7 @@ #include <linux/netdevice.h>
#include <linux/rtnetlink.h>
#include <net/d80211.h>
#include "ieee80211_i.h"
-#include "rate_control.h"
+#include "ieee80211_rate.h"
#define to_ieee80211_local(class) container_of(class, struct ieee80211_local, class_dev)
#define to_net_dev(class) container_of(class, struct net_device, class_dev)
diff --git a/net/d80211/rate_control.c b/net/d80211/rate_control.c
index 30c31ee..90326a8 100644
--- a/net/d80211/rate_control.c
+++ b/net/d80211/rate_control.c
@@ -17,7 +17,7 @@ #include <linux/compiler.h>
#include <net/d80211.h>
#include "ieee80211_i.h"
-#include "rate_control.h"
+#include "ieee80211_rate.h"
/* This is a minimal implementation of TX rate controlling that can be used
diff --git a/net/d80211/rate_control.h b/net/d80211/rate_control.h
deleted file mode 100644
index 08a8add..0000000
--- a/net/d80211/rate_control.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright 2002-2005, Instant802 Networks, Inc.
- * Copyright 2005, Devicescape Software, Inc.
- *
- * 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
- * published by the Free Software Foundation.
- */
-
-#ifndef RATE_CONTROL
-#define RATE_CONTROL
-
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/types.h>
-#include <net/d80211.h>
-#include "ieee80211_i.h"
-#include "sta_info.h"
-
-#define RATE_CONTROL_NUM_DOWN 20
-#define RATE_CONTROL_NUM_UP 15
-
-
-struct rate_control_extra {
- /* values from rate_control_get_rate() to the caller: */
- struct ieee80211_rate *probe; /* probe with this rate, or NULL for no
- * probing */
- int startidx, endidx, rateidx;
- struct ieee80211_rate *nonerp;
- int nonerp_idx;
-
- /* parameters from the caller to rate_control_get_rate(): */
- int mgmt_data; /* this is data frame that is used for management
- * (e.g., IEEE 802.1X EAPOL) */
- u16 ethertype;
-};
-
-
-struct rate_control_ops {
- const char *name;
- void (*tx_status)(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);
- void (*clear)(void *priv);
-
- void * (*alloc)(struct ieee80211_local *local);
- void (*free)(void *priv);
- void * (*alloc_sta)(void);
- void (*free_sta)(void *priv);
-
- 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 ieee80211_rate_control_register(struct rate_control_ops *ops);
-void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
-
-
-static inline void rate_control_tx_status(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);
-}
-
-
-static inline struct ieee80211_rate *
-rate_control_get_rate(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);
-}
-
-
-static inline void rate_control_rate_init(struct ieee80211_local *local,
- struct sta_info *sta)
-{
- local->rate_ctrl->rate_init(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 ieee80211_local *local)
-{
- return local->rate_ctrl->alloc(local);
-}
-
-
-static inline void rate_control_free(struct ieee80211_local *local)
-{
- if (!local->rate_ctrl || !local->rate_ctrl_priv)
- return;
- local->rate_ctrl->free(local->rate_ctrl_priv);
- local->rate_ctrl_priv = NULL;
-}
-
-
-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,
- void *priv)
-{
- local->rate_ctrl->free_sta(priv);
-}
-
-static inline int rate_control_add_attrs(struct ieee80211_local *local,
- void *priv, struct kobject *kobj)
-{
- if (local->rate_ctrl->add_attrs)
- return local->rate_ctrl->add_attrs(priv, kobj);
- return 0;
-}
-
-static inline void rate_control_remove_attrs(struct ieee80211_local *local,
- void *priv, struct kobject *kobj)
-{
- if (local->rate_ctrl->remove_attrs)
- local->rate_ctrl->remove_attrs(priv, kobj);
-}
-
-static inline int rate_control_add_sta_attrs(struct ieee80211_local *local,
- void *priv, struct kobject *kobj)
-{
- if (local->rate_ctrl->add_sta_attrs)
- return local->rate_ctrl->add_sta_attrs(priv, kobj);
- return 0;
-}
-
-static inline void rate_control_remove_sta_attrs(struct ieee80211_local *local,
- void *priv,
- struct kobject *kobj)
-{
- if (local->rate_ctrl->remove_sta_attrs)
- local->rate_ctrl->remove_sta_attrs(priv, kobj);
-}
-
-#endif /* RATE_CONTROL */
diff --git a/net/d80211/sta_info.c b/net/d80211/sta_info.c
index a326c4a..6a1a466 100644
--- a/net/d80211/sta_info.c
+++ b/net/d80211/sta_info.c
@@ -17,7 +17,7 @@ #include <linux/if_arp.h>
#include <net/d80211.h>
#include "ieee80211_i.h"
-#include "rate_control.h"
+#include "ieee80211_rate.h"
#include "sta_info.h"
--
1.3.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/8] d80211: proper rate_control loading
2006-10-02 18:26 [PATCH 0/8] d80211: rate control modules locking and changing Jiri Benc
` (2 preceding siblings ...)
2006-10-02 18:26 ` [PATCH 3/8] d80211: rename rate_control.h to ieee80211_rate.h Jiri Benc
@ 2006-10-02 18:26 ` Jiri Benc
2006-10-02 18:26 ` [PATCH 5/8] d80211: rename rate_control.c to rc80211_simple.c Jiri Benc
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Jiri Benc @ 2006-10-02 18:26 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
Fix locking issues with loading of rate_control modules. This still doesn't
allow changing of the modules on the fly.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/Makefile | 1
net/d80211/ieee80211.c | 108 ++++++++++++++-----------------------------
net/d80211/ieee80211_rate.c | 92 +++++++++++++++++++++++++++++++++++++
net/d80211/ieee80211_rate.h | 8 ++-
net/d80211/rate_control.c | 3 +
5 files changed, 136 insertions(+), 76 deletions(-)
create mode 100644 net/d80211/ieee80211_rate.c
57da83fffc22dc16bc244a4453a09c8a177d881e
diff --git a/net/d80211/Makefile b/net/d80211/Makefile
index 2a2a0c6..27d90e5 100644
--- a/net/d80211/Makefile
+++ b/net/d80211/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_D80211) += 80211.o rate_con
ieee80211_sta.o \
ieee80211_dev.o \
ieee80211_iface.o \
+ ieee80211_rate.o \
ieee80211_sysfs.o \
ieee80211_sysfs_sta.o \
michael.o \
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index b138eb0..8c4a6d6 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -46,16 +46,6 @@ static unsigned char eapol_header[] =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e };
-struct rate_control_algs {
- struct rate_control_algs *next;
- struct rate_control_ops *ops;
-};
-
-static struct rate_control_algs *ieee80211_rate_ctrl_algs;
-
-static int rate_control_initialize(struct ieee80211_local *local);
-
-
static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len);
static int ieee80211_mgmt_start_xmit(struct sk_buff *skb,
@@ -4312,6 +4302,39 @@ static void ieee80211_precalc_modes(stru
}
}
+static int rate_control_initialize(struct ieee80211_local *local)
+{
+ struct rate_control_ops *ops;
+
+ ops = ieee80211_rate_control_ops_get(NULL);
+ if (!ops) {
+ 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;
+
+ printk(KERN_DEBUG "%s: Selected rate control "
+ "algorithm '%s'\n", local->mdev->name,
+ local->rate_ctrl->name);
+
+ return 0;
+}
+
+static void rate_control_deinitialize(struct ieee80211_local *local)
+{
+ struct rate_control_ops *ops;
+
+ rate_control_free(local);
+ ops = local->rate_ctrl;
+ local->rate_ctrl = NULL;
+ ieee80211_rate_control_ops_put(ops);
+}
struct net_device *ieee80211_alloc_hw(size_t priv_data_len,
void (*setup)(struct net_device *))
@@ -4520,7 +4543,7 @@ int ieee80211_register_hw(struct net_dev
return 0;
fail_rate_attrs:
- rate_control_free(local);
+ rate_control_deinitialize(local);
fail_rate:
ieee80211_sysfs_remove_netdevice(dev);
fail_if_sysfs:
@@ -4639,7 +4662,7 @@ EXPORT_SYMBOL(ieee80211_free_hw);
void ieee80211_release_hw(struct ieee80211_local *local)
{
- rate_control_free(local);
+ rate_control_deinitialize(local);
kfree(local);
}
@@ -4742,67 +4765,6 @@ void * ieee80211_dev_stats(struct net_de
}
EXPORT_SYMBOL(ieee80211_dev_stats);
-int ieee80211_rate_control_register(struct rate_control_ops *ops)
-{
- struct rate_control_algs *alg;
-
- alg = kzalloc(sizeof(*alg), GFP_KERNEL);
- if (!alg)
- return -1;
-
- alg->next = ieee80211_rate_ctrl_algs;
- alg->ops = ops;
- ieee80211_rate_ctrl_algs = alg;
-
- return 0;
-}
-EXPORT_SYMBOL(ieee80211_rate_control_register);
-
-void ieee80211_rate_control_unregister(struct rate_control_ops *ops)
-{
- struct rate_control_algs *alg, *prev;
-
- prev = NULL;
- alg = ieee80211_rate_ctrl_algs;
- while (alg) {
- if (alg->ops == ops) {
- if (prev)
- prev->next = alg->next;
- else
- ieee80211_rate_ctrl_algs = alg->next;
- kfree(alg);
- break;
- }
- prev = alg;
- alg = alg->next;
- }
-}
-EXPORT_SYMBOL(ieee80211_rate_control_unregister);
-
-static int rate_control_initialize(struct ieee80211_local *local)
-{
- struct rate_control_algs *algs;
-
- if (!ieee80211_rate_ctrl_algs)
- request_module("ieee80211_rate_control");
-
- for (algs = ieee80211_rate_ctrl_algs; algs; algs = algs->next) {
- local->rate_ctrl = algs->ops;
- local->rate_ctrl_priv = rate_control_alloc(local);
- if (local->rate_ctrl_priv) {
- printk(KERN_DEBUG "%s: Selected rate control "
- "algorithm '%s'\n", local->mdev->name,
- local->rate_ctrl->name);
- return 0;
- }
- }
-
- printk(KERN_WARNING "%s: Failed to select rate control algorithm\n",
- local->mdev->name);
- return -1;
-}
-
-
static int __init ieee80211_init(void)
{
struct sk_buff *skb;
diff --git a/net/d80211/ieee80211_rate.c b/net/d80211/ieee80211_rate.c
new file mode 100644
index 0000000..3ec370f
--- /dev/null
+++ b/net/d80211/ieee80211_rate.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include "ieee80211_rate.h"
+#include "ieee80211_i.h"
+
+struct rate_control_alg {
+ struct list_head list;
+ struct rate_control_ops *ops;
+};
+
+static LIST_HEAD(rate_ctrl_algs);
+static DEFINE_MUTEX(rate_ctrl_mutex);
+
+int ieee80211_rate_control_register(struct rate_control_ops *ops)
+{
+ struct rate_control_alg *alg;
+
+ alg = kmalloc(sizeof(*alg), GFP_KERNEL);
+ if (alg == NULL) {
+ return -ENOMEM;
+ }
+ memset(alg, 0, sizeof(*alg));
+ alg->ops = ops;
+
+ mutex_lock(&rate_ctrl_mutex);
+ list_add_tail(&alg->list, &rate_ctrl_algs);
+ mutex_unlock(&rate_ctrl_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(ieee80211_rate_control_register);
+
+void ieee80211_rate_control_unregister(struct rate_control_ops *ops)
+{
+ struct rate_control_alg *alg;
+
+ mutex_lock(&rate_ctrl_mutex);
+ list_for_each_entry(alg, &rate_ctrl_algs, list) {
+ if (alg->ops == ops) {
+ list_del(&alg->list);
+ break;
+ }
+ }
+ mutex_unlock(&rate_ctrl_mutex);
+ kfree(alg);
+}
+EXPORT_SYMBOL(ieee80211_rate_control_unregister);
+
+static struct rate_control_ops *ieee80211_try_rate_control_ops_get(char *name)
+{
+ struct rate_control_alg *alg;
+ struct rate_control_ops *ops = NULL;
+
+ mutex_lock(&rate_ctrl_mutex);
+ list_for_each_entry(alg, &rate_ctrl_algs, list) {
+ if (!name || !strcmp(alg->ops->name, name))
+ if (try_module_get(alg->ops->module)) {
+ ops = alg->ops;
+ break;
+ }
+ }
+ mutex_unlock(&rate_ctrl_mutex);
+ return ops;
+}
+
+/* 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)
+{
+ struct rate_control_ops *ops;
+
+ ops = ieee80211_try_rate_control_ops_get(name);
+ if (!ops) {
+ request_module("rc80211_%s", name ? name : "default");
+ ops = ieee80211_try_rate_control_ops_get(name);
+ }
+ return ops;
+}
+
+void ieee80211_rate_control_ops_put(struct rate_control_ops *ops)
+{
+ module_put(ops->module);
+}
diff --git a/net/d80211/ieee80211_rate.h b/net/d80211/ieee80211_rate.h
index e1c9e05..2a4c662 100644
--- a/net/d80211/ieee80211_rate.h
+++ b/net/d80211/ieee80211_rate.h
@@ -37,6 +37,7 @@ 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,
struct ieee80211_tx_status *status);
@@ -61,6 +62,8 @@ struct rate_control_ops {
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);
static inline void rate_control_tx_status(struct net_device *dev,
struct sk_buff *skb,
@@ -93,9 +96,10 @@ static inline void rate_control_clear(st
}
-static inline void * rate_control_alloc(struct ieee80211_local *local)
+static inline void *rate_control_alloc(struct rate_control_ops *ops,
+ struct ieee80211_local *local)
{
- return local->rate_ctrl->alloc(local);
+ return ops->alloc(local);
}
diff --git a/net/d80211/rate_control.c b/net/d80211/rate_control.c
index 90326a8..6703931 100644
--- a/net/d80211/rate_control.c
+++ b/net/d80211/rate_control.c
@@ -28,7 +28,7 @@ #define RATE_CONTROL_EMERG_DEC 2
#define RATE_CONTROL_INTERVAL (HZ / 20)
#define RATE_CONTROL_MIN_TX 10
-MODULE_ALIAS("ieee80211_rate_control");
+MODULE_ALIAS("rc80211_default");
static void rate_control_rate_inc(struct ieee80211_local *local,
struct sta_info *sta)
@@ -361,6 +361,7 @@ static void rate_control_simple_remove_s
}
static struct rate_control_ops rate_control_simple = {
+ .module = THIS_MODULE,
.name = "simple",
.tx_status = rate_control_simple_tx_status,
.get_rate = rate_control_simple_get_rate,
--
1.3.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/8] d80211: rename rate_control.c to rc80211_simple.c
2006-10-02 18:26 [PATCH 0/8] d80211: rate control modules locking and changing Jiri Benc
` (3 preceding siblings ...)
2006-10-02 18:26 ` [PATCH 4/8] d80211: proper rate_control loading Jiri Benc
@ 2006-10-02 18:26 ` Jiri Benc
2006-10-02 18:26 ` [PATCH 6/8] d80211: proper rate control structures freeing Jiri Benc
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Jiri Benc @ 2006-10-02 18:26 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
To support changing of the rate control modules on the fly we need
well-defined names of the modules.
Let it be rc80211_*. Rename the only one rate control module
(rate_control.c) into rc80211_simple.c. The module alias for the default
module is changed to rc80211_default.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/Makefile | 2
net/d80211/rate_control.c | 395 -------------------------------------------
net/d80211/rc80211_simple.c | 395 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 396 insertions(+), 396 deletions(-)
delete mode 100644 net/d80211/rate_control.c
create mode 100644 net/d80211/rc80211_simple.c
f1d25465387bf4b09b505d90daafaff0e276060a
diff --git a/net/d80211/Makefile b/net/d80211/Makefile
index 27d90e5..d5d4d41 100644
--- a/net/d80211/Makefile
+++ b/net/d80211/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_D80211) += 80211.o rate_control.o
+obj-$(CONFIG_D80211) += 80211.o rc80211_simple.o
80211-objs-$(CONFIG_D80211_LEDS) += ieee80211_led.o
diff --git a/net/d80211/rate_control.c b/net/d80211/rate_control.c
deleted file mode 100644
index 6703931..0000000
--- a/net/d80211/rate_control.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * Copyright 2002-2005, Instant802 Networks, Inc.
- * Copyright 2005, Devicescape Software, Inc.
- *
- * 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
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/compiler.h>
-
-#include <net/d80211.h>
-#include "ieee80211_i.h"
-#include "ieee80211_rate.h"
-
-
-/* This is a minimal implementation of TX rate controlling that can be used
- * as the default when no improved mechanisms are available. */
-
-
-#define RATE_CONTROL_EMERG_DEC 2
-#define RATE_CONTROL_INTERVAL (HZ / 20)
-#define RATE_CONTROL_MIN_TX 10
-
-MODULE_ALIAS("rc80211_default");
-
-static void rate_control_rate_inc(struct ieee80211_local *local,
- struct sta_info *sta)
-{
- struct ieee80211_sub_if_data *sdata;
- int i = sta->txrate;
- int maxrate;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
- if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
- /* forced unicast rate - do not change STA rate */
- return;
- }
-
- maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1;
-
- if (i > local->num_curr_rates)
- i = local->num_curr_rates - 2;
-
- while (i + 1 < local->num_curr_rates) {
- i++;
- if (sta->supp_rates & BIT(i) &&
- local->curr_rates[i].flags & IEEE80211_RATE_SUPPORTED &&
- (maxrate < 0 || i <= maxrate)) {
- sta->txrate = i;
- break;
- }
- }
-}
-
-
-static void rate_control_rate_dec(struct ieee80211_local *local,
- struct sta_info *sta)
-{
- struct ieee80211_sub_if_data *sdata;
- int i = sta->txrate;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
- if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
- /* forced unicast rate - do not change STA rate */
- return;
- }
-
- if (i > local->num_curr_rates)
- i = local->num_curr_rates;
-
- while (i > 0) {
- i--;
- if (sta->supp_rates & BIT(i) &&
- local->curr_rates[i].flags & IEEE80211_RATE_SUPPORTED) {
- sta->txrate = i;
- break;
- }
- }
-}
-
-
-static struct ieee80211_rate *
-rate_control_lowest_rate(struct ieee80211_local *local)
-{
- int i;
-
- for (i = 0; i < local->num_curr_rates; i++) {
- struct ieee80211_rate *rate = &local->curr_rates[i];
-
- if (rate->flags & IEEE80211_RATE_SUPPORTED
- )
- return rate;
- }
-
- printk(KERN_DEBUG "rate_control_lowest_rate - no supported rates "
- "found\n");
- return &local->curr_rates[0];
-}
-
-
-struct global_rate_control {
- int dummy;
-};
-
-struct sta_rate_control {
- unsigned long last_rate_change;
- u32 tx_num_failures;
- u32 tx_num_xmit;
-
- unsigned long avg_rate_update;
- u32 tx_avg_rate_sum;
- u32 tx_avg_rate_num;
-};
-
-
-static void rate_control_simple_tx_status(struct net_device *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status)
-{
- struct ieee80211_local *local = dev->ieee80211_ptr;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- struct sta_info *sta;
- struct sta_rate_control *srctrl;
-
- sta = sta_info_get(local, hdr->addr1);
-
- if (!sta)
- return;
-
- srctrl = sta->rate_ctrl_priv;
- srctrl->tx_num_xmit++;
- if (status->excessive_retries) {
- sta->antenna_sel = sta->antenna_sel == 1 ? 2 : 1;
- if (local->sta_antenna_sel == STA_ANTENNA_SEL_SW_CTRL_DEBUG) {
- printk(KERN_DEBUG "%s: " MAC_FMT " TX antenna --> %d "
- "(@%lu)\n",
- dev->name, MAC_ARG(hdr->addr1),
- sta->antenna_sel, jiffies);
- }
- srctrl->tx_num_failures++;
- sta->tx_retry_failed++;
- sta->tx_num_consecutive_failures++;
- sta->tx_num_mpdu_fail++;
- } else {
- sta->last_ack_rssi[0] = sta->last_ack_rssi[1];
- sta->last_ack_rssi[1] = sta->last_ack_rssi[2];
- sta->last_ack_rssi[2] = status->ack_signal;
- sta->tx_num_consecutive_failures = 0;
- sta->tx_num_mpdu_ok++;
- }
- sta->tx_retry_count += status->retry_count;
- sta->tx_num_mpdu_fail += status->retry_count;
-
- if (time_after(jiffies,
- srctrl->last_rate_change + RATE_CONTROL_INTERVAL) &&
- srctrl->tx_num_xmit > RATE_CONTROL_MIN_TX) {
- u32 per_failed;
- srctrl->last_rate_change = jiffies;
-
- per_failed = (100 * sta->tx_num_mpdu_fail) /
- (sta->tx_num_mpdu_fail + sta->tx_num_mpdu_ok);
- /* TODO: calculate average per_failed to make adjusting
- * parameters easier */
-#if 0
- if (net_ratelimit()) {
- printk(KERN_DEBUG "MPDU fail=%d ok=%d per_failed=%d\n",
- sta->tx_num_mpdu_fail, sta->tx_num_mpdu_ok,
- per_failed);
- }
-#endif
-
- if (per_failed > local->rate_ctrl_num_down) {
- rate_control_rate_dec(local, sta);
- } else if (per_failed < local->rate_ctrl_num_up) {
- rate_control_rate_inc(local, sta);
- }
- srctrl->tx_avg_rate_sum += local->curr_rates[sta->txrate].rate;
- srctrl->tx_avg_rate_num++;
- srctrl->tx_num_failures = 0;
- srctrl->tx_num_xmit = 0;
- } else if (sta->tx_num_consecutive_failures >=
- RATE_CONTROL_EMERG_DEC) {
- rate_control_rate_dec(local, sta);
- }
-
- if (srctrl->avg_rate_update + 60 * HZ < jiffies) {
- srctrl->avg_rate_update = jiffies;
- if (srctrl->tx_avg_rate_num > 0) {
-#ifdef CONFIG_D80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: STA " MAC_FMT " Average rate: "
- "%d (%d/%d)\n",
- dev->name, MAC_ARG(sta->addr),
- srctrl->tx_avg_rate_sum /
- srctrl->tx_avg_rate_num,
- srctrl->tx_avg_rate_sum,
- srctrl->tx_avg_rate_num);
-#endif /* CONFIG_D80211_VERBOSE_DEBUG */
- srctrl->tx_avg_rate_sum = 0;
- srctrl->tx_avg_rate_num = 0;
- }
- }
-
- sta_info_put(sta);
-}
-
-
-static struct ieee80211_rate *
-rate_control_simple_get_rate(struct net_device *dev, struct sk_buff *skb,
- struct rate_control_extra *extra)
-{
- struct ieee80211_local *local = dev->ieee80211_ptr;
- struct ieee80211_sub_if_data *sdata;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- struct sta_info *sta;
- int rateidx, nonerp_idx;
- u16 fc;
-
- memset(extra, 0, sizeof(*extra));
-
- fc = le16_to_cpu(hdr->frame_control);
- if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
- (hdr->addr1[0] & 0x01)) {
- /* Send management frames and broadcast/multicast data using
- * lowest rate. */
- /* TODO: this could probably be improved.. */
- return rate_control_lowest_rate(local);
- }
-
- sta = sta_info_get(local, hdr->addr1);
-
- if (!sta)
- return rate_control_lowest_rate(local);
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
- sta->txrate = sdata->bss->force_unicast_rateidx;
-
- rateidx = sta->txrate;
-
- if (rateidx >= local->num_curr_rates)
- rateidx = local->num_curr_rates - 1;
-
- sta->last_txrate = rateidx;
- nonerp_idx = rateidx;
- while (nonerp_idx > 0 &&
- ((local->curr_rates[nonerp_idx].flags & IEEE80211_RATE_ERP) ||
- !(local->curr_rates[nonerp_idx].flags &
- IEEE80211_RATE_SUPPORTED) ||
- !(sta->supp_rates & BIT(nonerp_idx))))
- nonerp_idx--;
- extra->nonerp_idx = nonerp_idx;
- extra->nonerp = &local->curr_rates[extra->nonerp_idx];
-
- sta_info_put(sta);
-
- return &local->curr_rates[rateidx];
-}
-
-
-static void rate_control_simple_rate_init(struct ieee80211_local *local,
- struct sta_info *sta)
-{
- int i;
- sta->txrate = 0;
- /* TODO: what is a good starting rate for STA? About middle? Maybe not
- * the lowest or the highest rate.. Could consider using RSSI from
- * previous packets? Need to have IEEE 802.1X auth succeed immediately
- * after assoc.. */
- for (i = 0; i < local->num_curr_rates; i++) {
- if ((sta->supp_rates & BIT(i)) &&
- (local->curr_rates[i].flags & IEEE80211_RATE_SUPPORTED))
- sta->txrate = i;
- }
-}
-
-
-static void * rate_control_simple_alloc(struct ieee80211_local *local)
-{
- struct global_rate_control *rctrl;
-
- rctrl = kzalloc(sizeof(*rctrl), GFP_ATOMIC);
-
- return rctrl;
-}
-
-
-static void rate_control_simple_free(void *priv)
-{
- struct global_rate_control *rctrl = priv;
- kfree(rctrl);
-}
-
-
-static void rate_control_simple_clear(void *priv)
-{
-}
-
-
-static void * rate_control_simple_alloc_sta(void)
-{
- struct sta_rate_control *rctrl;
-
- rctrl = kzalloc(sizeof(*rctrl), GFP_ATOMIC);
-
- return rctrl;
-}
-
-
-static void rate_control_simple_free_sta(void *priv)
-{
- struct sta_rate_control *rctrl = priv;
- kfree(rctrl);
-}
-
-static ssize_t show_sta_tx_avg_rate_sum(const struct sta_info *sta, char *buf)
-{
- struct sta_rate_control *srctrl = sta->rate_ctrl_priv;
-
- return sprintf(buf, "%d\n", srctrl->tx_avg_rate_sum);
-}
-
-static ssize_t show_sta_tx_avg_rate_num(const struct sta_info *sta, char *buf)
-{
- struct sta_rate_control *srctrl = sta->rate_ctrl_priv;
-
- return sprintf(buf, "%d\n", srctrl->tx_avg_rate_num);
-}
-
-static struct sta_attribute sta_attr_tx_avg_rate_sum =
- __ATTR(tx_avg_rate_sum, S_IRUSR, show_sta_tx_avg_rate_sum, NULL);
-static struct sta_attribute sta_attr_tx_avg_rate_num =
- __ATTR(tx_avg_rate_num, S_IRUSR, show_sta_tx_avg_rate_num, NULL);
-
-static struct attribute *rate_control_simple_sta_attrs[] = {
- &sta_attr_tx_avg_rate_sum.attr,
- &sta_attr_tx_avg_rate_num.attr,
- NULL,
-};
-
-static struct attribute_group rate_control_simple_sta_group = {
- .name = "rate_control_simple",
- .attrs = rate_control_simple_sta_attrs,
-};
-
-static int rate_control_simple_add_sta_attrs(void *priv, struct kobject *kobj)
-{
- return sysfs_create_group(kobj, &rate_control_simple_sta_group);
-}
-
-static void rate_control_simple_remove_sta_attrs(void *priv,
- struct kobject *kobj)
-{
- sysfs_remove_group(kobj, &rate_control_simple_sta_group);
-}
-
-static struct rate_control_ops rate_control_simple = {
- .module = THIS_MODULE,
- .name = "simple",
- .tx_status = rate_control_simple_tx_status,
- .get_rate = rate_control_simple_get_rate,
- .rate_init = rate_control_simple_rate_init,
- .clear = rate_control_simple_clear,
- .alloc = rate_control_simple_alloc,
- .free = rate_control_simple_free,
- .alloc_sta = rate_control_simple_alloc_sta,
- .free_sta = rate_control_simple_free_sta,
- .add_sta_attrs = rate_control_simple_add_sta_attrs,
- .remove_sta_attrs = rate_control_simple_remove_sta_attrs,
-};
-
-
-static int __init rate_control_simple_init(void)
-{
- return ieee80211_rate_control_register(&rate_control_simple);
-}
-
-
-static void __exit rate_control_simple_exit(void)
-{
- ieee80211_rate_control_unregister(&rate_control_simple);
-}
-
-
-module_init(rate_control_simple_init);
-module_exit(rate_control_simple_exit);
-
-MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211");
-MODULE_LICENSE("GPL");
diff --git a/net/d80211/rc80211_simple.c b/net/d80211/rc80211_simple.c
new file mode 100644
index 0000000..6703931
--- /dev/null
+++ b/net/d80211/rc80211_simple.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/compiler.h>
+
+#include <net/d80211.h>
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+
+
+/* This is a minimal implementation of TX rate controlling that can be used
+ * as the default when no improved mechanisms are available. */
+
+
+#define RATE_CONTROL_EMERG_DEC 2
+#define RATE_CONTROL_INTERVAL (HZ / 20)
+#define RATE_CONTROL_MIN_TX 10
+
+MODULE_ALIAS("rc80211_default");
+
+static void rate_control_rate_inc(struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata;
+ int i = sta->txrate;
+ int maxrate;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
+ /* forced unicast rate - do not change STA rate */
+ return;
+ }
+
+ maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1;
+
+ if (i > local->num_curr_rates)
+ i = local->num_curr_rates - 2;
+
+ while (i + 1 < local->num_curr_rates) {
+ i++;
+ if (sta->supp_rates & BIT(i) &&
+ local->curr_rates[i].flags & IEEE80211_RATE_SUPPORTED &&
+ (maxrate < 0 || i <= maxrate)) {
+ sta->txrate = i;
+ break;
+ }
+ }
+}
+
+
+static void rate_control_rate_dec(struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata;
+ int i = sta->txrate;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
+ /* forced unicast rate - do not change STA rate */
+ return;
+ }
+
+ if (i > local->num_curr_rates)
+ i = local->num_curr_rates;
+
+ while (i > 0) {
+ i--;
+ if (sta->supp_rates & BIT(i) &&
+ local->curr_rates[i].flags & IEEE80211_RATE_SUPPORTED) {
+ sta->txrate = i;
+ break;
+ }
+ }
+}
+
+
+static struct ieee80211_rate *
+rate_control_lowest_rate(struct ieee80211_local *local)
+{
+ int i;
+
+ for (i = 0; i < local->num_curr_rates; i++) {
+ struct ieee80211_rate *rate = &local->curr_rates[i];
+
+ if (rate->flags & IEEE80211_RATE_SUPPORTED
+ )
+ return rate;
+ }
+
+ printk(KERN_DEBUG "rate_control_lowest_rate - no supported rates "
+ "found\n");
+ return &local->curr_rates[0];
+}
+
+
+struct global_rate_control {
+ int dummy;
+};
+
+struct sta_rate_control {
+ unsigned long last_rate_change;
+ u32 tx_num_failures;
+ u32 tx_num_xmit;
+
+ unsigned long avg_rate_update;
+ u32 tx_avg_rate_sum;
+ u32 tx_avg_rate_num;
+};
+
+
+static void rate_control_simple_tx_status(struct net_device *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_status *status)
+{
+ struct ieee80211_local *local = dev->ieee80211_ptr;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct sta_info *sta;
+ struct sta_rate_control *srctrl;
+
+ sta = sta_info_get(local, hdr->addr1);
+
+ if (!sta)
+ return;
+
+ srctrl = sta->rate_ctrl_priv;
+ srctrl->tx_num_xmit++;
+ if (status->excessive_retries) {
+ sta->antenna_sel = sta->antenna_sel == 1 ? 2 : 1;
+ if (local->sta_antenna_sel == STA_ANTENNA_SEL_SW_CTRL_DEBUG) {
+ printk(KERN_DEBUG "%s: " MAC_FMT " TX antenna --> %d "
+ "(@%lu)\n",
+ dev->name, MAC_ARG(hdr->addr1),
+ sta->antenna_sel, jiffies);
+ }
+ srctrl->tx_num_failures++;
+ sta->tx_retry_failed++;
+ sta->tx_num_consecutive_failures++;
+ sta->tx_num_mpdu_fail++;
+ } else {
+ sta->last_ack_rssi[0] = sta->last_ack_rssi[1];
+ sta->last_ack_rssi[1] = sta->last_ack_rssi[2];
+ sta->last_ack_rssi[2] = status->ack_signal;
+ sta->tx_num_consecutive_failures = 0;
+ sta->tx_num_mpdu_ok++;
+ }
+ sta->tx_retry_count += status->retry_count;
+ sta->tx_num_mpdu_fail += status->retry_count;
+
+ if (time_after(jiffies,
+ srctrl->last_rate_change + RATE_CONTROL_INTERVAL) &&
+ srctrl->tx_num_xmit > RATE_CONTROL_MIN_TX) {
+ u32 per_failed;
+ srctrl->last_rate_change = jiffies;
+
+ per_failed = (100 * sta->tx_num_mpdu_fail) /
+ (sta->tx_num_mpdu_fail + sta->tx_num_mpdu_ok);
+ /* TODO: calculate average per_failed to make adjusting
+ * parameters easier */
+#if 0
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "MPDU fail=%d ok=%d per_failed=%d\n",
+ sta->tx_num_mpdu_fail, sta->tx_num_mpdu_ok,
+ per_failed);
+ }
+#endif
+
+ if (per_failed > local->rate_ctrl_num_down) {
+ rate_control_rate_dec(local, sta);
+ } else if (per_failed < local->rate_ctrl_num_up) {
+ rate_control_rate_inc(local, sta);
+ }
+ srctrl->tx_avg_rate_sum += local->curr_rates[sta->txrate].rate;
+ srctrl->tx_avg_rate_num++;
+ srctrl->tx_num_failures = 0;
+ srctrl->tx_num_xmit = 0;
+ } else if (sta->tx_num_consecutive_failures >=
+ RATE_CONTROL_EMERG_DEC) {
+ rate_control_rate_dec(local, sta);
+ }
+
+ if (srctrl->avg_rate_update + 60 * HZ < jiffies) {
+ srctrl->avg_rate_update = jiffies;
+ if (srctrl->tx_avg_rate_num > 0) {
+#ifdef CONFIG_D80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: STA " MAC_FMT " Average rate: "
+ "%d (%d/%d)\n",
+ dev->name, MAC_ARG(sta->addr),
+ srctrl->tx_avg_rate_sum /
+ srctrl->tx_avg_rate_num,
+ srctrl->tx_avg_rate_sum,
+ srctrl->tx_avg_rate_num);
+#endif /* CONFIG_D80211_VERBOSE_DEBUG */
+ srctrl->tx_avg_rate_sum = 0;
+ srctrl->tx_avg_rate_num = 0;
+ }
+ }
+
+ sta_info_put(sta);
+}
+
+
+static struct ieee80211_rate *
+rate_control_simple_get_rate(struct net_device *dev, struct sk_buff *skb,
+ struct rate_control_extra *extra)
+{
+ struct ieee80211_local *local = dev->ieee80211_ptr;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct sta_info *sta;
+ int rateidx, nonerp_idx;
+ u16 fc;
+
+ memset(extra, 0, sizeof(*extra));
+
+ fc = le16_to_cpu(hdr->frame_control);
+ if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
+ (hdr->addr1[0] & 0x01)) {
+ /* Send management frames and broadcast/multicast data using
+ * lowest rate. */
+ /* TODO: this could probably be improved.. */
+ return rate_control_lowest_rate(local);
+ }
+
+ sta = sta_info_get(local, hdr->addr1);
+
+ if (!sta)
+ return rate_control_lowest_rate(local);
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
+ sta->txrate = sdata->bss->force_unicast_rateidx;
+
+ rateidx = sta->txrate;
+
+ if (rateidx >= local->num_curr_rates)
+ rateidx = local->num_curr_rates - 1;
+
+ sta->last_txrate = rateidx;
+ nonerp_idx = rateidx;
+ while (nonerp_idx > 0 &&
+ ((local->curr_rates[nonerp_idx].flags & IEEE80211_RATE_ERP) ||
+ !(local->curr_rates[nonerp_idx].flags &
+ IEEE80211_RATE_SUPPORTED) ||
+ !(sta->supp_rates & BIT(nonerp_idx))))
+ nonerp_idx--;
+ extra->nonerp_idx = nonerp_idx;
+ extra->nonerp = &local->curr_rates[extra->nonerp_idx];
+
+ sta_info_put(sta);
+
+ return &local->curr_rates[rateidx];
+}
+
+
+static void rate_control_simple_rate_init(struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ int i;
+ sta->txrate = 0;
+ /* TODO: what is a good starting rate for STA? About middle? Maybe not
+ * the lowest or the highest rate.. Could consider using RSSI from
+ * previous packets? Need to have IEEE 802.1X auth succeed immediately
+ * after assoc.. */
+ for (i = 0; i < local->num_curr_rates; i++) {
+ if ((sta->supp_rates & BIT(i)) &&
+ (local->curr_rates[i].flags & IEEE80211_RATE_SUPPORTED))
+ sta->txrate = i;
+ }
+}
+
+
+static void * rate_control_simple_alloc(struct ieee80211_local *local)
+{
+ struct global_rate_control *rctrl;
+
+ rctrl = kzalloc(sizeof(*rctrl), GFP_ATOMIC);
+
+ return rctrl;
+}
+
+
+static void rate_control_simple_free(void *priv)
+{
+ struct global_rate_control *rctrl = priv;
+ kfree(rctrl);
+}
+
+
+static void rate_control_simple_clear(void *priv)
+{
+}
+
+
+static void * rate_control_simple_alloc_sta(void)
+{
+ struct sta_rate_control *rctrl;
+
+ rctrl = kzalloc(sizeof(*rctrl), GFP_ATOMIC);
+
+ return rctrl;
+}
+
+
+static void rate_control_simple_free_sta(void *priv)
+{
+ struct sta_rate_control *rctrl = priv;
+ kfree(rctrl);
+}
+
+static ssize_t show_sta_tx_avg_rate_sum(const struct sta_info *sta, char *buf)
+{
+ struct sta_rate_control *srctrl = sta->rate_ctrl_priv;
+
+ return sprintf(buf, "%d\n", srctrl->tx_avg_rate_sum);
+}
+
+static ssize_t show_sta_tx_avg_rate_num(const struct sta_info *sta, char *buf)
+{
+ struct sta_rate_control *srctrl = sta->rate_ctrl_priv;
+
+ return sprintf(buf, "%d\n", srctrl->tx_avg_rate_num);
+}
+
+static struct sta_attribute sta_attr_tx_avg_rate_sum =
+ __ATTR(tx_avg_rate_sum, S_IRUSR, show_sta_tx_avg_rate_sum, NULL);
+static struct sta_attribute sta_attr_tx_avg_rate_num =
+ __ATTR(tx_avg_rate_num, S_IRUSR, show_sta_tx_avg_rate_num, NULL);
+
+static struct attribute *rate_control_simple_sta_attrs[] = {
+ &sta_attr_tx_avg_rate_sum.attr,
+ &sta_attr_tx_avg_rate_num.attr,
+ NULL,
+};
+
+static struct attribute_group rate_control_simple_sta_group = {
+ .name = "rate_control_simple",
+ .attrs = rate_control_simple_sta_attrs,
+};
+
+static int rate_control_simple_add_sta_attrs(void *priv, struct kobject *kobj)
+{
+ return sysfs_create_group(kobj, &rate_control_simple_sta_group);
+}
+
+static void rate_control_simple_remove_sta_attrs(void *priv,
+ struct kobject *kobj)
+{
+ sysfs_remove_group(kobj, &rate_control_simple_sta_group);
+}
+
+static struct rate_control_ops rate_control_simple = {
+ .module = THIS_MODULE,
+ .name = "simple",
+ .tx_status = rate_control_simple_tx_status,
+ .get_rate = rate_control_simple_get_rate,
+ .rate_init = rate_control_simple_rate_init,
+ .clear = rate_control_simple_clear,
+ .alloc = rate_control_simple_alloc,
+ .free = rate_control_simple_free,
+ .alloc_sta = rate_control_simple_alloc_sta,
+ .free_sta = rate_control_simple_free_sta,
+ .add_sta_attrs = rate_control_simple_add_sta_attrs,
+ .remove_sta_attrs = rate_control_simple_remove_sta_attrs,
+};
+
+
+static int __init rate_control_simple_init(void)
+{
+ return ieee80211_rate_control_register(&rate_control_simple);
+}
+
+
+static void __exit rate_control_simple_exit(void)
+{
+ ieee80211_rate_control_unregister(&rate_control_simple);
+}
+
+
+module_init(rate_control_simple_init);
+module_exit(rate_control_simple_exit);
+
+MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211");
+MODULE_LICENSE("GPL");
--
1.3.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 6/8] d80211: proper rate control structures freeing
2006-10-02 18:26 [PATCH 0/8] d80211: rate control modules locking and changing Jiri Benc
` (4 preceding siblings ...)
2006-10-02 18:26 ` [PATCH 5/8] d80211: rename rate_control.c to rc80211_simple.c Jiri Benc
@ 2006-10-02 18:26 ` Jiri Benc
2006-10-02 18:26 ` [PATCH 7/8] d80211: allow changing of the rate control algorithm Jiri Benc
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Jiri Benc @ 2006-10-02 18:26 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
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 <jbenc@suse.cz>
---
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(-)
d0b148eaaa06082e00c9e2a753cf6106d468b5b0
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 <jbenc@suse.cz>
*
* 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
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 7/8] d80211: allow changing of the rate control algorithm
2006-10-02 18:26 [PATCH 0/8] d80211: rate control modules locking and changing Jiri Benc
` (5 preceding siblings ...)
2006-10-02 18:26 ` [PATCH 6/8] d80211: proper rate control structures freeing Jiri Benc
@ 2006-10-02 18:26 ` Jiri Benc
2006-10-02 18:26 ` [PATCH 8/8] d80211: rate_control: do not use atomic allocations when not necessary Jiri Benc
2006-10-02 18:26 ` d80211: for testing only: really stupid rate control algorithm Jiri Benc
8 siblings, 0 replies; 10+ messages in thread
From: Jiri Benc @ 2006-10-02 18:26 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
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 <jbenc@suse.cz>
---
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(-)
7fc923b53c8689378512c6fe51b21e85224f860b
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
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 8/8] d80211: rate_control: do not use atomic allocations when not necessary
2006-10-02 18:26 [PATCH 0/8] d80211: rate control modules locking and changing Jiri Benc
` (6 preceding siblings ...)
2006-10-02 18:26 ` [PATCH 7/8] d80211: allow changing of the rate control algorithm Jiri Benc
@ 2006-10-02 18:26 ` Jiri Benc
2006-10-02 18:26 ` d80211: for testing only: really stupid rate control algorithm Jiri Benc
8 siblings, 0 replies; 10+ messages in thread
From: Jiri Benc @ 2006-10-02 18:26 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
Allow GFP_KERNEL to be used for allocations of sta entries triggered from
the user space.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211_ioctl.c | 2 +-
net/d80211/ieee80211_rate.h | 7 ++++---
net/d80211/ieee80211_sta.c | 4 ++--
net/d80211/rc80211_simple.c | 4 ++--
net/d80211/sta_info.c | 8 +++-----
net/d80211/sta_info.h | 2 +-
6 files changed, 13 insertions(+), 14 deletions(-)
53c1534ebad3c02a67517ed7339c76140812947e
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index ff6718b..cded685 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -277,7 +277,7 @@ static int ieee80211_ioctl_add_sta(struc
sta = sta_info_get(local, param->sta_addr);
if (!sta) {
- sta = sta_info_add(local, dev, param->sta_addr);
+ sta = sta_info_add(local, dev, param->sta_addr, GFP_KERNEL);
if (!sta)
return -ENOMEM;
}
diff --git a/net/d80211/ieee80211_rate.h b/net/d80211/ieee80211_rate.h
index 60e4879..04c7465 100644
--- a/net/d80211/ieee80211_rate.h
+++ b/net/d80211/ieee80211_rate.h
@@ -52,7 +52,7 @@ struct rate_control_ops {
void *(*alloc)(struct ieee80211_local *local);
void (*free)(void *priv);
- void *(*alloc_sta)(void *priv);
+ void *(*alloc_sta)(void *priv, gfp_t gfp);
void (*free_sta)(void *priv, void *priv_sta);
int (*add_attrs)(void *priv, struct kobject *kobj);
@@ -112,9 +112,10 @@ static inline void rate_control_clear(st
ref->ops->clear(ref->priv);
}
-static inline void *rate_control_alloc_sta(struct rate_control_ref *ref)
+static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
+ gfp_t gfp)
{
- return ref->ops->alloc_sta(ref->priv);
+ return ref->ops->alloc_sta(ref->priv, gfp);
}
static inline void rate_control_free_sta(struct rate_control_ref *ref,
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index ed6747a..480e9c9 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -1158,7 +1158,7 @@ static void ieee80211_rx_mgmt_assoc_resp
/* Add STA entry for the AP */
sta = sta_info_get(local, ifsta->bssid);
if (!sta) {
- sta = sta_info_add(local, dev, ifsta->bssid);
+ sta = sta_info_add(local, dev, ifsta->bssid, GFP_ATOMIC);
if (!sta) {
printk(KERN_DEBUG "%s: failed to add STA entry for the"
" AP\n", dev->name);
@@ -2832,7 +2832,7 @@ struct sta_info * ieee80211_ibss_add_sta
printk(KERN_DEBUG "%s: Adding new IBSS station " MAC_FMT " (dev=%s)\n",
dev->name, MAC_ARG(addr), sta_dev->name);
- sta = sta_info_add(local, dev, addr);
+ sta = sta_info_add(local, dev, addr, GFP_ATOMIC);
if (!sta)
return NULL;
diff --git a/net/d80211/rc80211_simple.c b/net/d80211/rc80211_simple.c
index 055a167..3634d00 100644
--- a/net/d80211/rc80211_simple.c
+++ b/net/d80211/rc80211_simple.c
@@ -305,11 +305,11 @@ static void rate_control_simple_clear(vo
}
-static void * rate_control_simple_alloc_sta(void *priv)
+static void * rate_control_simple_alloc_sta(void *priv, gfp_t gfp)
{
struct sta_rate_control *rctrl;
- rctrl = kzalloc(sizeof(*rctrl), GFP_ATOMIC);
+ rctrl = kzalloc(sizeof(*rctrl), gfp);
return rctrl;
}
diff --git a/net/d80211/sta_info.c b/net/d80211/sta_info.c
index a177d2f..c18365b 100644
--- a/net/d80211/sta_info.c
+++ b/net/d80211/sta_info.c
@@ -130,16 +130,14 @@ void sta_info_release(struct kobject *ko
struct sta_info * sta_info_add(struct ieee80211_local *local,
- struct net_device *dev, u8 *addr)
+ struct net_device *dev, u8 *addr, gfp_t gfp)
{
struct sta_info *sta;
- sta = kmalloc(sizeof(*sta), GFP_ATOMIC);
+ sta = kzalloc(sizeof(*sta), gfp);
if (!sta)
return NULL;
- memset(sta, 0, sizeof(*sta));
-
if (kobject_set_name(&sta->kobj, MAC_FMT, MAC_ARG(addr))) {
kfree(sta);
return NULL;
@@ -148,7 +146,7 @@ struct sta_info * sta_info_add(struct ie
kobject_init(&sta->kobj);
sta->rate_ctrl = rate_control_get(local->rate_ctrl);
- sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl);
+ sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp);
if (!sta->rate_ctrl_priv) {
rate_control_put(sta->rate_ctrl);
kobject_put(&sta->kobj);
diff --git a/net/d80211/sta_info.h b/net/d80211/sta_info.h
index 9bd7e0d..ed1a104 100644
--- a/net/d80211/sta_info.h
+++ b/net/d80211/sta_info.h
@@ -133,7 +133,7 @@ struct sta_info * sta_info_get(struct ie
int sta_info_min_txrate_get(struct ieee80211_local *local);
void sta_info_put(struct sta_info *sta);
struct sta_info * sta_info_add(struct ieee80211_local *local,
- struct net_device *dev, u8 *addr);
+ struct net_device *dev, u8 *addr, gfp_t gfp);
void sta_info_free(struct sta_info *sta, int locked);
void sta_info_release(struct kobject *kobj);
void sta_info_init(struct ieee80211_local *local);
--
1.3.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* d80211: for testing only: really stupid rate control algorithm
2006-10-02 18:26 [PATCH 0/8] d80211: rate control modules locking and changing Jiri Benc
` (7 preceding siblings ...)
2006-10-02 18:26 ` [PATCH 8/8] d80211: rate_control: do not use atomic allocations when not necessary Jiri Benc
@ 2006-10-02 18:26 ` Jiri Benc
8 siblings, 0 replies; 10+ messages in thread
From: Jiri Benc @ 2006-10-02 18:26 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
This is a rate control algorithm intended for the testing of rate modules
changing. It's name is "lowest". It uses always the lowest rate available.
Usage:
echo -n lowest > /sys/class/ieee80211/phy0/rate_ctrl_alg
---
net/d80211/Makefile | 2 -
net/d80211/rc80211_lowest.c | 106 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 107 insertions(+), 1 deletions(-)
create mode 100644 net/d80211/rc80211_lowest.c
5b994b344d168fae604c7c4270a651d562d4701d
diff --git a/net/d80211/Makefile b/net/d80211/Makefile
index d5d4d41..d02c2d6 100644
--- a/net/d80211/Makefile
+++ b/net/d80211/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_D80211) += 80211.o rc80211_simple.o
+obj-$(CONFIG_D80211) += 80211.o rc80211_simple.o rc80211_lowest.o
80211-objs-$(CONFIG_D80211_LEDS) += ieee80211_led.o
diff --git a/net/d80211/rc80211_lowest.c b/net/d80211/rc80211_lowest.c
new file mode 100644
index 0000000..e1b6ccf
--- /dev/null
+++ b/net/d80211/rc80211_lowest.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+
+#include <net/d80211.h>
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+
+static void rate_control_lowest_tx_status(void *priv, struct net_device *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_status *status)
+{
+}
+
+static struct ieee80211_rate *
+rate_control_lowest_get_rate(void *priv, struct net_device *dev,
+ struct sk_buff *skb,
+ struct rate_control_extra *extra)
+{
+ struct ieee80211_local *local = dev->ieee80211_ptr;
+ int i;
+
+ for (i = 0; i < local->num_curr_rates; i++) {
+ struct ieee80211_rate *rate = &local->curr_rates[i];
+
+ if (rate->flags & IEEE80211_RATE_SUPPORTED)
+ return rate;
+ }
+ return &local->curr_rates[0];
+}
+
+static void rate_control_lowest_rate_init(void *priv, void *priv_sta,
+ struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ sta->txrate = 0;
+}
+
+static void *rate_control_lowest_alloc(struct ieee80211_local *local)
+{
+ return kzalloc(sizeof(int), GFP_KERNEL);
+}
+
+static void rate_control_lowest_free(void *priv)
+{
+ kfree(priv);
+}
+
+static void rate_control_lowest_clear(void *priv)
+{
+}
+
+static void * rate_control_lowest_alloc_sta(void *priv, gfp_t gfp)
+{
+ return kzalloc(sizeof(int), gfp);
+}
+
+
+static void rate_control_lowest_free_sta(void *priv, void *priv_sta)
+{
+ kfree(priv_sta);
+}
+
+static struct rate_control_ops rate_control_lowest = {
+ .module = THIS_MODULE,
+ .name = "lowest",
+ .tx_status = rate_control_lowest_tx_status,
+ .get_rate = rate_control_lowest_get_rate,
+ .rate_init = rate_control_lowest_rate_init,
+ .clear = rate_control_lowest_clear,
+ .alloc = rate_control_lowest_alloc,
+ .free = rate_control_lowest_free,
+ .alloc_sta = rate_control_lowest_alloc_sta,
+ .free_sta = rate_control_lowest_free_sta,
+};
+
+static int __init rate_control_lowest_init(void)
+{
+ return ieee80211_rate_control_register(&rate_control_lowest);
+}
+
+
+static void __exit rate_control_lowest_exit(void)
+{
+ ieee80211_rate_control_unregister(&rate_control_lowest);
+}
+
+
+module_init(rate_control_lowest_init);
+module_exit(rate_control_lowest_exit);
+
+MODULE_DESCRIPTION("Testing rate control algorithm for ieee80211");
+MODULE_LICENSE("GPL");
--
1.3.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2006-10-02 18:26 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-10-02 18:26 [PATCH 0/8] d80211: rate control modules locking and changing Jiri Benc
2006-10-02 18:26 ` [PATCH 1/8] d80211: add missing rtnl_unlock() Jiri Benc
2006-10-02 18:26 ` [PATCH 2/8] d80211: del sta timer on interface close Jiri Benc
2006-10-02 18:26 ` [PATCH 3/8] d80211: rename rate_control.h to ieee80211_rate.h Jiri Benc
2006-10-02 18:26 ` [PATCH 4/8] d80211: proper rate_control loading Jiri Benc
2006-10-02 18:26 ` [PATCH 5/8] d80211: rename rate_control.c to rc80211_simple.c Jiri Benc
2006-10-02 18:26 ` [PATCH 6/8] d80211: proper rate control structures freeing Jiri Benc
2006-10-02 18:26 ` [PATCH 7/8] d80211: allow changing of the rate control algorithm Jiri Benc
2006-10-02 18:26 ` [PATCH 8/8] d80211: rate_control: do not use atomic allocations when not necessary Jiri Benc
2006-10-02 18:26 ` d80211: for testing only: really stupid rate control algorithm Jiri Benc
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).