diff options
Diffstat (limited to 'sys/net80211')
-rw-r--r-- | sys/net80211/_ieee80211.h | 5 | ||||
-rw-r--r-- | sys/net80211/ieee80211.c | 88 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.c | 21 |
3 files changed, 65 insertions, 49 deletions
diff --git a/sys/net80211/_ieee80211.h b/sys/net80211/_ieee80211.h index 4eb522c..4f3fe29 100644 --- a/sys/net80211/_ieee80211.h +++ b/sys/net80211/_ieee80211.h @@ -123,6 +123,7 @@ struct ieee80211_channel { #define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ #define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ #define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ +#define IEEE80211_CHAN_GSM 0x1000 /* 900 MHz spectrum channel */ #define IEEE80211_CHAN_HALF 0x4000 /* Half rate channel */ #define IEEE80211_CHAN_QUARTER 0x8000 /* Quarter rate channel */ @@ -181,6 +182,10 @@ struct ieee80211_channel { (((_c)->ic_flags & IEEE80211_CHAN_HALF) != 0) #define IEEE80211_IS_CHAN_QUARTER(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_QUARTER) != 0) +#define IEEE80211_IS_CHAN_FULL(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_QUARTER | IEEE80211_CHAN_HALF)) == 0) +#define IEEE80211_IS_CHAN_GSM(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_GSM) != 0) /* ni_chan encoding for FH phy */ #define IEEE80211_FH_CHANMOD 80 diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c index 2fd2fa4..803c530 100644 --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -267,6 +267,7 @@ ieee80211_ifdetach(struct ieee80211com *ic) ieee80211_remove_vap(ic); ieee80211_sysctl_detach(ic); + /* NB: must be called before ieee80211_node_detach */ ieee80211_proto_detach(ic); ieee80211_crypto_detach(ic); ieee80211_node_detach(ic); @@ -278,12 +279,34 @@ ieee80211_ifdetach(struct ieee80211com *ic) ether_ifdetach(ifp); } +static __inline int +mapgsm(u_int freq, u_int flags) +{ + freq *= 10; + if (flags & IEEE80211_CHAN_QUARTER) + freq += 5; + else if (flags & IEEE80211_CHAN_HALF) + freq += 10; + else + freq += 20; + /* NB: there is no 907/20 wide but leave room */ + return (freq - 906*10) / 5; +} + +static __inline int +mappsb(u_int freq, u_int flags) +{ + return 37 + ((freq * 10) + ((freq % 5) == 2 ? 5 : 0) - 49400) / 5; +} + /* * Convert MHz frequency to IEEE channel number. */ int ieee80211_mhz2ieee(u_int freq, u_int flags) { + if (flags & IEEE80211_CHAN_GSM) + return mapgsm(freq, flags); if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ if (freq == 2484) return 14; @@ -294,20 +317,21 @@ ieee80211_mhz2ieee(u_int freq, u_int flags) } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */ if (freq <= 5000) { if (flags &(IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)) - return 37 + ((freq * 10) + - ((freq % 5) == 2 ? 5 : 0) - 49400) / 5; + return mappsb(freq, flags); return (freq - 4000) / 5; } else return (freq - 5000) / 5; } else { /* either, guess */ if (freq == 2484) return 14; - if (freq < 2484) + if (freq < 2484) { + if (907 <= freq && freq <= 922) + return mapgsm(freq, flags); return ((int) freq - 2407) / 5; + } if (freq < 5000) { if (flags &(IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)) - return 37 + ((freq * 10) + - ((freq % 5) == 2 ? 5 : 0) - 49400) / 5; + return mappsb(freq, flags); else if (freq > 4900) return (freq - 4000) / 5; else @@ -343,6 +367,8 @@ ieee80211_chan2ieee(struct ieee80211com *ic, const struct ieee80211_channel *c) u_int ieee80211_ieee2mhz(u_int chan, u_int flags) { + if (flags & IEEE80211_CHAN_GSM) + return 907 + 5 * (chan / 10); if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ if (chan == 14) return 2484; @@ -357,13 +383,13 @@ ieee80211_ieee2mhz(u_int chan, u_int flags) } return 5000 + (chan*5); } else { /* either, guess */ + /* XXX can't distinguish PSB+GSM channels */ if (chan == 14) return 2484; if (chan < 14) /* 0-13 */ return 2407 + chan*5; if (chan < 27) /* 15-26 */ return 2512 + ((chan-15)*20); - /* XXX can't distinguish PSB channels */ return 5000 + (chan*5); } } @@ -494,12 +520,10 @@ ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel * { enum ieee80211_phymode mode = ieee80211_chan2mode(ic, c); - if (mode == IEEE80211_MODE_11A) { - if (IEEE80211_IS_CHAN_HALF(c)) - return &ieee80211_rateset_half; - if (IEEE80211_IS_CHAN_QUARTER(c)) - return &ieee80211_rateset_quarter; - } + if (IEEE80211_IS_CHAN_HALF(c)) + return &ieee80211_rateset_half; + if (IEEE80211_IS_CHAN_QUARTER(c)) + return &ieee80211_rateset_quarter; return &ic->ic_sup_rates[mode]; } @@ -766,7 +790,7 @@ ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr) /* * A fixed rate is set, report that. */ - rs = &ic->ic_sup_rates[ic->ic_curmode]; + rs = ieee80211_get_suprates(ic, ic->ic_curchan); imr->ifm_active |= ieee80211_rate2media(ic, rs->rs_rates[ic->ic_fixed_rate], ic->ic_curmode); } else if (ic->ic_opmode == IEEE80211_M_STA) { @@ -923,19 +947,18 @@ ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode) * available channel from the active list. This is likely * not the right one. */ - if (ic->ic_ibss_chan == NULL || - isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { + if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_curchan))) { + ic->ic_curchan = NULL; for (i = 0; i <= IEEE80211_CHAN_MAX; i++) if (isset(ic->ic_chan_active, i)) { - ic->ic_ibss_chan = &ic->ic_channels[i]; + ic->ic_curchan = &ic->ic_channels[i]; break; } - KASSERT(ic->ic_ibss_chan != NULL && - isset(ic->ic_chan_active, - ieee80211_chan2ieee(ic, ic->ic_ibss_chan)), - ("Bad IBSS channel %u", - ieee80211_chan2ieee(ic, ic->ic_ibss_chan))); + KASSERT(ic->ic_curchan != NULL, ("no current channel")); } + if (ic->ic_ibss_chan == NULL || + isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) + ic->ic_ibss_chan = ic->ic_curchan; /* * If the desired channel is set but no longer valid then reset it. */ @@ -944,28 +967,21 @@ ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode) ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* - * Do mode-specific rate setup. + * Adjust basic rates in 11b/11g supported rate set. + * Note that if operating on a hal/quarter rate channel + * this is a noop as those rates sets are different + * and used instead. */ - if (mode == IEEE80211_MODE_11G) { - /* - * Use a mixed 11b/11g rate set. - */ - ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], - IEEE80211_MODE_11G); - } else if (mode == IEEE80211_MODE_11B) { - /* - * Force pure 11b rate set. - */ - ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], - IEEE80211_MODE_11B); - } + if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11B) + ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], mode); + /* * Setup an initial rate set according to the * current/default channel selected above. This * will be changed when scanning but must exist * now so driver have a consistent state of ic_ibss_chan. */ - if (ic->ic_bss) /* NB: can be called before lateattach */ + if (ic->ic_bss != NULL) /* NB: can be called before lateattach */ ic->ic_bss->ni_rates = ic->ic_sup_rates[mode]; ic->ic_curmode = mode; diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index 9c34c29..2be1003 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -453,17 +453,10 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan) /* * Do mode-specific rate setup. */ - if (ic->ic_curmode == IEEE80211_MODE_11G) { - /* - * Use a mixed 11b/11g rate set. - */ - ieee80211_set11gbasicrates(&ni->ni_rates, IEEE80211_MODE_11G); - } else if (ic->ic_curmode == IEEE80211_MODE_11B) { - /* - * Force pure 11b rate set. - */ - ieee80211_set11gbasicrates(&ni->ni_rates, IEEE80211_MODE_11B); - } + if (IEEE80211_IS_CHAN_FULL(chan) && + (ic->ic_curmode == IEEE80211_MODE_11G || + ic->ic_curmode == IEEE80211_MODE_11B)) + ieee80211_set11gbasicrates(&ni->ni_rates, ic->ic_curmode); (void) ieee80211_sta_join(ic, ieee80211_ref_node(ni)); } @@ -2097,7 +2090,8 @@ ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int resp IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap); ic->ic_sta_assoc++; newassoc = 1; - if (ic->ic_curmode == IEEE80211_MODE_11G) + if (ic->ic_curmode == IEEE80211_MODE_11G && + IEEE80211_IS_CHAN_FULL(ni->ni_chan)) ieee80211_node_join_11g(ic, ni); } else newassoc = 0; @@ -2222,7 +2216,8 @@ ieee80211_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) ni->ni_associd = 0; ic->ic_sta_assoc--; - if (ic->ic_curmode == IEEE80211_MODE_11G) + if (ic->ic_curmode == IEEE80211_MODE_11G && + IEEE80211_IS_CHAN_FULL(ni->ni_chan)) ieee80211_node_leave_11g(ic, ni); /* * Cleanup station state. In particular clear various |