From owner-svn-src-head@FreeBSD.ORG Sun Oct 26 21:56:27 2008 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6535B106566C; Sun, 26 Oct 2008 21:56:27 +0000 (UTC) (envelope-from sam@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 5315B8FC18; Sun, 26 Oct 2008 21:56:27 +0000 (UTC) (envelope-from sam@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id m9QLuRxw097075; Sun, 26 Oct 2008 21:56:27 GMT (envelope-from sam@svn.freebsd.org) Received: (from sam@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id m9QLuRZN097074; Sun, 26 Oct 2008 21:56:27 GMT (envelope-from sam@svn.freebsd.org) Message-Id: <200810262156.m9QLuRZN097074@svn.freebsd.org> From: Sam Leffler Date: Sun, 26 Oct 2008 21:56:27 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r184302 - head/sys/net80211 X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 26 Oct 2008 21:56:27 -0000 Author: sam Date: Sun Oct 26 21:56:27 2008 New Revision: 184302 URL: http://svn.freebsd.org/changeset/base/184302 Log: Fix joining an 11b BSS: scanning is normally done using 11g channels (unless explicitly locked to mode 11b) so when we join the bss the channel attached to the scan cache entry may need to be demoted. o demote to 11b if the ap is advertising 11b rates o skip the ap if it's 11b but we're locked to 11g (could consider this advisory but for now treat it as mandatory) o handle an odd edge case, if there is a fixed transmit rate for 11g then the rate check against the 11b ap will fail, try to demote to 11b and retry the rate check Reviewed by: sephe, thompsa Modified: head/sys/net80211/ieee80211_scan_sta.c Modified: head/sys/net80211/ieee80211_scan_sta.c ============================================================================== --- head/sys/net80211/ieee80211_scan_sta.c Sun Oct 26 21:56:06 2008 (r184301) +++ head/sys/net80211/ieee80211_scan_sta.c Sun Oct 26 21:56:27 2008 (r184302) @@ -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_t * 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 * ((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, c * 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, con 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_sta 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 */