madwifi: improve the autochannel decision making on systems with multiple cards
SVN-Revision: 14748
This commit is contained in:
parent
d8f6369756
commit
165f60bba9
1 changed files with 347 additions and 0 deletions
347
package/madwifi/patches/460-autochannel_multi.patch
Normal file
347
package/madwifi/patches/460-autochannel_multi.patch
Normal file
|
@ -0,0 +1,347 @@
|
|||
--- a/net80211/ieee80211_scan.c
|
||||
+++ b/net80211/ieee80211_scan.c
|
||||
@@ -97,6 +97,123 @@ struct scan_state {
|
||||
static void scan_restart_pwrsav(unsigned long);
|
||||
static void scan_next(unsigned long);
|
||||
|
||||
+spinlock_t channel_lock = SPIN_LOCK_UNLOCKED;
|
||||
+static LIST_HEAD(channels_inuse);
|
||||
+
|
||||
+struct channel_inuse {
|
||||
+ struct list_head list;
|
||||
+ struct ieee80211com *ic;
|
||||
+ u16 freq;
|
||||
+ u8 bw;
|
||||
+};
|
||||
+
|
||||
+static inline u32
|
||||
+get_signal(u8 bw, u8 distance)
|
||||
+{
|
||||
+ u32 v;
|
||||
+
|
||||
+ /* signal = 1 - (distance / bw)^2 [scale: 100] */
|
||||
+ v = 100 * distance / bw;
|
||||
+ v = (100 - ((v * v) / 100));
|
||||
+ return v;
|
||||
+}
|
||||
+
|
||||
+static u32
|
||||
+get_overlap(u16 f1, u16 f2, u8 b1, u8 b2)
|
||||
+{
|
||||
+ u32 v;
|
||||
+ u16 d, c;
|
||||
+
|
||||
+ /* add offsets for sidechannel interference */
|
||||
+ b1 += (b1 / 5);
|
||||
+ b2 += (b2 / 5);
|
||||
+
|
||||
+ /* use only one direction */
|
||||
+ b1 /= 2;
|
||||
+ b2 /= 2;
|
||||
+
|
||||
+ if (f1 + b1 < f2 - b2)
|
||||
+ return 0;
|
||||
+
|
||||
+ d = f2 - f1;
|
||||
+ c = d * b1 / (b1 + b2);
|
||||
+ v = get_signal(b1, c);
|
||||
+
|
||||
+ return v * v / 100;
|
||||
+}
|
||||
+
|
||||
+static u8
|
||||
+get_channel_bw(struct ieee80211_channel *c)
|
||||
+{
|
||||
+ switch(c->ic_flags & (
|
||||
+ IEEE80211_CHAN_HALF |
|
||||
+ IEEE80211_CHAN_QUARTER |
|
||||
+ IEEE80211_CHAN_TURBO |
|
||||
+ IEEE80211_CHAN_STURBO)) {
|
||||
+ case IEEE80211_CHAN_QUARTER:
|
||||
+ return 5;
|
||||
+ case IEEE80211_CHAN_HALF:
|
||||
+ return 10;
|
||||
+ case IEEE80211_CHAN_TURBO:
|
||||
+ case IEEE80211_CHAN_STURBO:
|
||||
+ return 40;
|
||||
+ default:
|
||||
+ return 20;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* must be called with channel_lock held */
|
||||
+u32
|
||||
+ieee80211_scan_get_bias(struct ieee80211_channel *c)
|
||||
+{
|
||||
+ struct channel_inuse *ch;
|
||||
+ u8 bw = get_channel_bw(c);
|
||||
+ u32 bias = 0;
|
||||
+
|
||||
+ list_for_each_entry(ch, &channels_inuse, list) {
|
||||
+ if (ch->freq == c->ic_freq) {
|
||||
+ bias += 50;
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (c->ic_freq < ch->freq)
|
||||
+ bias += get_overlap(c->ic_freq, ch->freq, bw, ch->bw);
|
||||
+ else
|
||||
+ bias += get_overlap(ch->freq, c->ic_freq, ch->bw, bw);
|
||||
+ }
|
||||
+ return min(bias, (u32) 100);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_scan_get_bias);
|
||||
+
|
||||
+/* must be called with channel_lock held */
|
||||
+void
|
||||
+ieee80211_scan_set_bss_channel(struct ieee80211com *ic, struct ieee80211_channel *c)
|
||||
+{
|
||||
+ unsigned long flags;
|
||||
+ struct channel_inuse *ch;
|
||||
+
|
||||
+ list_for_each_entry(ch, &channels_inuse, list) {
|
||||
+ if (ch->ic == ic)
|
||||
+ goto found;
|
||||
+ }
|
||||
+ ch = NULL;
|
||||
+found:
|
||||
+ if (c && (c != IEEE80211_CHAN_ANYC)) {
|
||||
+ if (!ch) {
|
||||
+ ch = kmalloc(sizeof(struct channel_inuse), GFP_ATOMIC);
|
||||
+ ch->ic = ic;
|
||||
+ INIT_LIST_HEAD(&ch->list);
|
||||
+ list_add(&ch->list, &channels_inuse);
|
||||
+ }
|
||||
+ ch->freq = c->ic_freq;
|
||||
+ ch->bw = get_channel_bw(c);
|
||||
+ } else if (ch) {
|
||||
+ list_del(&ch->list);
|
||||
+ kfree(ch);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_scan_set_bss_channel);
|
||||
+
|
||||
+
|
||||
void
|
||||
ieee80211_scan_attach(struct ieee80211com *ic)
|
||||
{
|
||||
@@ -1155,7 +1272,7 @@ ieee80211_scan_dfs_action(struct ieee802
|
||||
IEEE80211_RADAR_CHANCHANGE_TBTT_COUNT;
|
||||
ic->ic_flags |= IEEE80211_F_CHANSWITCH;
|
||||
} else {
|
||||
-
|
||||
+ unsigned long flags;
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
|
||||
"%s: directly switching to channel "
|
||||
"%3d (%4d MHz)\n", __func__,
|
||||
@@ -1166,6 +1283,9 @@ ieee80211_scan_dfs_action(struct ieee802
|
||||
* change the channel here. */
|
||||
change_channel(ic, new_channel);
|
||||
ic->ic_bsschan = new_channel;
|
||||
+ spin_lock_irqsave(&channel_lock, flags);
|
||||
+ ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
|
||||
+ spin_unlock_irqrestore(&channel_lock, flags);
|
||||
if (vap->iv_bss)
|
||||
vap->iv_bss->ni_chan = new_channel;
|
||||
}
|
||||
--- a/net80211/ieee80211_scan.h
|
||||
+++ b/net80211/ieee80211_scan.h
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
#define IEEE80211_SCAN_MAX IEEE80211_CHAN_MAX
|
||||
|
||||
+extern spinlock_t channel_lock;
|
||||
struct ieee80211_scanner;
|
||||
struct ieee80211_scan_entry;
|
||||
|
||||
@@ -116,6 +117,8 @@ void ieee80211_scan_flush(struct ieee802
|
||||
struct ieee80211_scan_entry;
|
||||
typedef int ieee80211_scan_iter_func(void *, const struct ieee80211_scan_entry *);
|
||||
int ieee80211_scan_iterate(struct ieee80211com *, ieee80211_scan_iter_func *, void *);
|
||||
+u32 ieee80211_scan_get_bias(struct ieee80211_channel *c);
|
||||
+void ieee80211_scan_set_bss_channel(struct ieee80211com *ic, struct ieee80211_channel *c);
|
||||
|
||||
/*
|
||||
* Parameters supplied when adding/updating an entry in a
|
||||
--- a/net80211/ieee80211.c
|
||||
+++ b/net80211/ieee80211.c
|
||||
@@ -373,8 +373,16 @@ void
|
||||
ieee80211_ifdetach(struct ieee80211com *ic)
|
||||
{
|
||||
struct ieee80211vap *vap;
|
||||
+ unsigned long flags;
|
||||
int count;
|
||||
|
||||
+ /* mark the channel as no longer in use */
|
||||
+ ic->ic_bsschan = IEEE80211_CHAN_ANYC;
|
||||
+ spin_lock_irqsave(&channel_lock, flags);
|
||||
+ ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
|
||||
+ spin_unlock_irqrestore(&channel_lock, flags);
|
||||
+
|
||||
+
|
||||
/* bring down all vaps */
|
||||
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
|
||||
ieee80211_stop(vap->iv_dev);
|
||||
--- a/net80211/ieee80211_input.c
|
||||
+++ b/net80211/ieee80211_input.c
|
||||
@@ -2772,6 +2772,7 @@ static void
|
||||
ieee80211_doth_switch_channel(struct ieee80211vap *vap)
|
||||
{
|
||||
struct ieee80211com *ic = vap->iv_ic;
|
||||
+ unsigned long flags;
|
||||
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
|
||||
"%s: Channel switch to %3d (%4d MHz) NOW!\n",
|
||||
@@ -2794,6 +2795,9 @@ ieee80211_doth_switch_channel(struct iee
|
||||
|
||||
ic->ic_curchan = ic->ic_bsschan = vap->iv_csa_chan;
|
||||
ic->ic_set_channel(ic);
|
||||
+ spin_lock_irqsave(&channel_lock, flags);
|
||||
+ ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
|
||||
+ spin_unlock_irqrestore(&channel_lock, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
--- a/net80211/ieee80211_node.c
|
||||
+++ b/net80211/ieee80211_node.c
|
||||
@@ -308,6 +308,7 @@ ieee80211_create_ibss(struct ieee80211va
|
||||
{
|
||||
struct ieee80211com *ic = vap->iv_ic;
|
||||
struct ieee80211_node *ni;
|
||||
+ unsigned long flags;
|
||||
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
|
||||
"%s: creating ibss on channel %u\n", __func__,
|
||||
@@ -386,6 +387,9 @@ ieee80211_create_ibss(struct ieee80211va
|
||||
ic->ic_bsschan = chan;
|
||||
ieee80211_node_set_chan(ic, ni);
|
||||
ic->ic_curmode = ieee80211_chan2mode(chan);
|
||||
+ spin_lock_irqsave(&channel_lock, flags);
|
||||
+ ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
|
||||
+ spin_unlock_irqrestore(&channel_lock, flags);
|
||||
|
||||
/* Update country ie information */
|
||||
ieee80211_build_countryie(ic);
|
||||
@@ -622,6 +626,7 @@ ieee80211_sta_join1(struct ieee80211_nod
|
||||
struct ieee80211vap *vap = selbs->ni_vap;
|
||||
struct ieee80211com *ic = selbs->ni_ic;
|
||||
struct ieee80211_node *obss;
|
||||
+ unsigned long flags;
|
||||
int canreassoc;
|
||||
|
||||
if (vap->iv_opmode == IEEE80211_M_IBSS) {
|
||||
@@ -650,6 +655,9 @@ ieee80211_sta_join1(struct ieee80211_nod
|
||||
ic->ic_curchan = ic->ic_bsschan;
|
||||
ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan);
|
||||
ic->ic_set_channel(ic);
|
||||
+ spin_lock_irqsave(&channel_lock, flags);
|
||||
+ ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
|
||||
+ spin_unlock_irqrestore(&channel_lock, flags);
|
||||
/*
|
||||
* Set the erp state (mostly the slot time) to deal with
|
||||
* the auto-select case; this should be redundant if the
|
||||
--- a/net80211/ieee80211_proto.c
|
||||
+++ b/net80211/ieee80211_proto.c
|
||||
@@ -1225,6 +1225,7 @@ ieee80211_dturbo_switch(struct ieee80211
|
||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
||||
#endif
|
||||
struct ieee80211_channel *chan;
|
||||
+ unsigned long flags;
|
||||
|
||||
chan = ieee80211_find_channel(ic, ic->ic_bsschan->ic_freq, newflags);
|
||||
if (chan == NULL) { /* XXX should not happen */
|
||||
@@ -1243,6 +1244,9 @@ ieee80211_dturbo_switch(struct ieee80211
|
||||
ic->ic_bsschan = chan;
|
||||
ic->ic_curchan = chan;
|
||||
ic->ic_set_channel(ic);
|
||||
+ spin_lock_irqsave(&channel_lock, flags);
|
||||
+ ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
|
||||
+ spin_unlock_irqrestore(&channel_lock, flags);
|
||||
/* NB: do not need to reset ERP state because in sta mode */
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_dturbo_switch);
|
||||
--- a/net80211/ieee80211_wireless.c
|
||||
+++ b/net80211/ieee80211_wireless.c
|
||||
@@ -4076,8 +4076,13 @@ ieee80211_ioctl_setchanlist(struct net_d
|
||||
if (nchan == 0) /* no valid channels, disallow */
|
||||
return -EINVAL;
|
||||
if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && /* XXX */
|
||||
- isclr(chanlist, ic->ic_bsschan->ic_ieee))
|
||||
+ isclr(chanlist, ic->ic_bsschan->ic_ieee)) {
|
||||
+ unsigned long flags;
|
||||
ic->ic_bsschan = IEEE80211_CHAN_ANYC; /* invalidate */
|
||||
+ spin_lock_irqsave(&channel_lock, flags);
|
||||
+ ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
|
||||
+ spin_unlock_irqrestore(&channel_lock, flags);
|
||||
+ }
|
||||
|
||||
memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
|
||||
/* update Supported Channels information element */
|
||||
--- a/net80211/ieee80211_scan_ap.c
|
||||
+++ b/net80211/ieee80211_scan_ap.c
|
||||
@@ -213,9 +213,15 @@ ap_start(struct ieee80211_scan_state *ss
|
||||
struct ieee80211com *ic = NULL;
|
||||
int i;
|
||||
unsigned int mode = 0;
|
||||
+ unsigned long sflags;
|
||||
|
||||
SCAN_AP_LOCK_IRQ(as);
|
||||
ic = vap->iv_ic;
|
||||
+
|
||||
+ spin_lock_irqsave(&channel_lock, sflags);
|
||||
+ ieee80211_scan_set_bss_channel(ic, NULL);
|
||||
+ spin_unlock_irqrestore(&channel_lock, sflags);
|
||||
+
|
||||
/* Determine mode flags to match, or leave zero for auto mode */
|
||||
as->as_vap_desired_mode = vap->iv_des_mode;
|
||||
as->as_required_mode = 0;
|
||||
@@ -429,8 +435,10 @@ pc_cmp_idletime(struct ieee80211_channel
|
||||
if (!a->ic_idletime || !b->ic_idletime)
|
||||
return 0;
|
||||
|
||||
- /* a is better than b (return < 0) when a has more idle time than b */
|
||||
- return b->ic_idletime - a->ic_idletime;
|
||||
+ /* a is better than b (return < 0) when a has more idle and less bias time than b */
|
||||
+ return
|
||||
+ ((100 - (u32) a->ic_idletime) + ieee80211_scan_get_bias(a)) -
|
||||
+ ((100 - (u32) b->ic_idletime) + ieee80211_scan_get_bias(b));
|
||||
}
|
||||
|
||||
|
||||
@@ -616,6 +624,7 @@ ap_end(struct ieee80211_scan_state *ss,
|
||||
struct ap_state *as = ss->ss_priv;
|
||||
struct ieee80211_channel *bestchan = NULL;
|
||||
struct ieee80211com *ic = NULL;
|
||||
+ unsigned long sflags;
|
||||
int res = 1;
|
||||
|
||||
SCAN_AP_LOCK_IRQ(as);
|
||||
@@ -624,8 +633,11 @@ ap_end(struct ieee80211_scan_state *ss,
|
||||
("wrong opmode %u", vap->iv_opmode));
|
||||
|
||||
ic = vap->iv_ic;
|
||||
+ spin_lock_irqsave(&channel_lock, sflags);
|
||||
+ ieee80211_scan_set_bss_channel(ic, NULL);
|
||||
bestchan = pick_channel(ss, vap, flags);
|
||||
if (bestchan == NULL) {
|
||||
+ spin_unlock_irqrestore(&channel_lock, sflags);
|
||||
if (ss->ss_last > 0) {
|
||||
/* no suitable channel, should not happen */
|
||||
printk(KERN_ERR "%s: %s: no suitable channel! "
|
||||
@@ -644,6 +656,7 @@ ap_end(struct ieee80211_scan_state *ss,
|
||||
bestchan->ic_freq, bestchan->ic_flags &
|
||||
~IEEE80211_CHAN_TURBO)) == NULL) {
|
||||
/* should never happen ?? */
|
||||
+ spin_unlock_irqrestore(&channel_lock, sflags);
|
||||
SCAN_AP_UNLOCK_IRQ_EARLY(as);
|
||||
return 0;
|
||||
}
|
||||
@@ -656,6 +669,9 @@ ap_end(struct ieee80211_scan_state *ss,
|
||||
as->as_action = action;
|
||||
as->as_selbss = se;
|
||||
|
||||
+ ieee80211_scan_set_bss_channel(ic, bestchan);
|
||||
+ spin_unlock_irqrestore(&channel_lock, sflags);
|
||||
+
|
||||
/* Must defer action to avoid possible recursive call through
|
||||
* 80211 state machine, which would result in recursive
|
||||
* locking. */
|
Loading…
Reference in a new issue