summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/net80211/ieee80211_scan_sta.c89
1 files changed, 72 insertions, 17 deletions
diff --git a/sys/net80211/ieee80211_scan_sta.c b/sys/net80211/ieee80211_scan_sta.c
index debbdfb..e3a4bda 100644
--- a/sys/net80211/ieee80211_scan_sta.c
+++ b/sys/net80211/ieee80211_scan_sta.c
@@ -73,8 +73,7 @@ struct sta_entry {
uint8_t se_seen; /* seen during current scan */
uint8_t se_notseen; /* not seen in previous scans */
uint8_t se_flags;
-#define STA_SSID_MATCH 0x01
-#define STA_BSSID_MATCH 0x02
+#define STA_DEMOTE11B 0x01 /* match w/ demoted 11b chan */
uint32_t se_avgrssi; /* LPF rssi state */
unsigned long se_lastupdate; /* time of last update */
unsigned long se_lastfail; /* time of last failure */
@@ -107,16 +106,16 @@ static void sta_flush_table(struct sta_table *);
* contents explains why. The following flags are or'd to to this
* mask and can be used to figure out why the entry was rejected.
*/
-#define MATCH_CHANNEL 0x001 /* channel mismatch */
-#define MATCH_CAPINFO 0x002 /* capabilities mismatch, e.g. no ess */
-#define MATCH_PRIVACY 0x004 /* privacy mismatch */
-#define MATCH_RATE 0x008 /* rate set mismatch */
-#define MATCH_SSID 0x010 /* ssid mismatch */
-#define MATCH_BSSID 0x020 /* bssid mismatch */
-#define MATCH_FAILS 0x040 /* too many failed auth attempts */
-#define MATCH_NOTSEEN 0x080 /* not seen in recent scans */
-#define MATCH_RSSI 0x100 /* rssi deemed too low to use */
-#define MATCH_CC 0x200 /* country code mismatch */
+#define MATCH_CHANNEL 0x0001 /* channel mismatch */
+#define MATCH_CAPINFO 0x0002 /* capabilities mismatch, e.g. no ess */
+#define MATCH_PRIVACY 0x0004 /* privacy mismatch */
+#define MATCH_RATE 0x0008 /* rate set mismatch */
+#define MATCH_SSID 0x0010 /* ssid mismatch */
+#define MATCH_BSSID 0x0020 /* bssid mismatch */
+#define MATCH_FAILS 0x0040 /* too many failed auth attempts */
+#define MATCH_NOTSEEN 0x0080 /* not seen in recent scans */
+#define MATCH_RSSI 0x0100 /* rssi deemed too low to use */
+#define MATCH_CC 0x0200 /* country code mismatch */
static int match_bss(struct ieee80211vap *,
const struct ieee80211_scan_state *, struct sta_entry *, int);
static void adhoc_age(struct ieee80211_scan_state *);
@@ -675,6 +674,26 @@ sta_cancel(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
((uint16_t) \
((((const uint8_t *)(p))[0] ) | \
(((const uint8_t *)(p))[1] << 8)))
+
+/*
+ * Demote any supplied 11g channel to 11b. There should
+ * always be an 11b channel but we check anyway...
+ */
+static struct ieee80211_channel *
+demote11b(struct ieee80211vap *vap, struct ieee80211_channel *chan)
+{
+ struct ieee80211_channel *c;
+
+ if (IEEE80211_IS_CHAN_ANYG(chan) &&
+ vap->iv_des_mode == IEEE80211_MODE_AUTO) {
+ c = ieee80211_find_channel(vap->iv_ic, chan->ic_freq,
+ (chan->ic_flags &~ (IEEE80211_CHAN_PUREG | IEEE80211_CHAN_G)) |
+ IEEE80211_CHAN_B);
+ if (c != NULL)
+ chan = c;
+ }
+ return chan;
+}
static int
maxrate(const struct ieee80211_scan_entry *se)
@@ -774,7 +793,8 @@ sta_compare(const struct sta_entry *a, const struct sta_entry *b)
* XXX inspect MCS for HT
*/
static int
-check_rate(struct ieee80211vap *vap, const struct ieee80211_scan_entry *se)
+check_rate(struct ieee80211vap *vap, const struct ieee80211_channel *chan,
+ const struct ieee80211_scan_entry *se)
{
#define RV(v) ((v) & IEEE80211_RATE_VAL)
const struct ieee80211_rateset *srs;
@@ -783,11 +803,11 @@ check_rate(struct ieee80211vap *vap, const struct ieee80211_scan_entry *se)
okrate = badrate = 0;
- srs = ieee80211_get_suprates(vap->iv_ic, se->se_chan);
+ srs = ieee80211_get_suprates(vap->iv_ic, chan);
nrs = se->se_rates[1];
rs = se->se_rates+2;
/* XXX MCS */
- ucastrate = vap->iv_txparms[ieee80211_chan2mode(se->se_chan)].ucastrate;
+ ucastrate = vap->iv_txparms[ieee80211_chan2mode(chan)].ucastrate;
fixedrate = IEEE80211_FIXED_RATE_NONE;
again:
for (i = 0; i < nrs; i++) {
@@ -903,9 +923,38 @@ match_bss(struct ieee80211vap *vap,
if (se->se_capinfo & IEEE80211_CAPINFO_PRIVACY)
fail |= MATCH_PRIVACY;
}
- rate = check_rate(vap, se);
- if (rate & IEEE80211_RATE_BASIC)
+ se0->se_flags &= ~STA_DEMOTE11B;
+ rate = check_rate(vap, se->se_chan, se);
+ if (rate & IEEE80211_RATE_BASIC) {
fail |= MATCH_RATE;
+ /*
+ * An 11b-only ap will give a rate mismatch if there is an
+ * OFDM fixed tx rate for 11g. Try downgrading the channel
+ * in the scan list to 11b and retry the rate check.
+ */
+ if (IEEE80211_IS_CHAN_ANYG(se->se_chan)) {
+ rate = check_rate(vap, demote11b(vap, se->se_chan), se);
+ if ((rate & IEEE80211_RATE_BASIC) == 0) {
+ fail &= ~MATCH_RATE;
+ se0->se_flags |= STA_DEMOTE11B;
+ }
+ }
+ } else if (rate < 2*24) {
+ /*
+ * This is an 11b-only ap. Check the desired mode in
+ * case that needs to be honored (mode 11g filters out
+ * 11b-only ap's). Otherwise force any 11g channel used
+ * in scanning to be demoted.
+ *
+ * NB: we cheat a bit here by looking at the max rate;
+ * we could/should check the rates.
+ */
+ if (!(vap->iv_des_mode == IEEE80211_MODE_AUTO ||
+ vap->iv_des_mode == IEEE80211_MODE_11B))
+ fail |= MATCH_RATE;
+ else
+ se0->se_flags |= STA_DEMOTE11B;
+ }
if (ss->ss_nssid != 0 &&
!match_ssid(se->se_ssid, ss->ss_nssid, ss->ss_ssid))
fail |= MATCH_SSID;
@@ -1060,6 +1109,8 @@ notfound:
if (selbs == NULL)
goto notfound;
chan = selbs->base.se_chan;
+ if (selbs->se_flags & STA_DEMOTE11B)
+ chan = demote11b(vap, chan);
if (!ieee80211_sta_join(vap, chan, &selbs->base))
goto notfound;
return 1; /* terminate scan */
@@ -1151,6 +1202,8 @@ sta_roam_check(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
curRate, roamRate, curRssi, roamRssi);
chan = selbs->base.se_chan;
+ if (selbs->se_flags & STA_DEMOTE11B)
+ chan = demote11b(vap, chan);
(void) ieee80211_sta_join(vap, chan, &selbs->base);
}
}
@@ -1430,6 +1483,8 @@ notfound:
if (selbs == NULL)
goto notfound;
chan = selbs->base.se_chan;
+ if (selbs->se_flags & STA_DEMOTE11B)
+ chan = demote11b(vap, chan);
if (!ieee80211_sta_join(vap, chan, &selbs->base))
goto notfound;
return 1; /* terminate scan */
OpenPOWER on IntegriCloud