diff options
author | sam <sam@FreeBSD.org> | 2006-12-27 18:46:18 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2006-12-27 18:46:18 +0000 |
commit | 4442f89b49a898383c874def50a11aab97b03845 (patch) | |
tree | 8bd925a7f6c33cd28325df02b1a6153b8b091d2d | |
parent | 03269f3b4c923667476d52b5c6c3711ae678d017 (diff) | |
download | FreeBSD-src-4442f89b49a898383c874def50a11aab97b03845.zip FreeBSD-src-4442f89b49a898383c874def50a11aab97b03845.tar.gz |
First cut at half/quarter-rate 11a channel support (e.g. for use
in the Public Safety Band):
o add channel flags to identify half/quarter-rate operation
o add rate sets (need to check spec on 4Mb/s in 1/4 rate)
o add if_media definitions for new rates
o split net80211 channel setup out into ieee80211_chan_init
o fixup ieee80211_mhz2ieee and ieee80211_ieee2mhz to understand half/quarter
rate channels: note we temporarily use a nonstandard/hack numbering that
avoids overlap with 2.4G channels because we don't (yet) have enough
state to identify and/or map overlapping channel sets
o fixup ieee80211_ifmedia_init so it can be called post attach and will
recalculate the channel list and associated state; this enables changing
channel-related state like the regulatory domain after attach (will be
needed for 802.11d support too)
o add ieee80211_get_suprates to return a reference to the supported rate
set for a given channel
o add 3, 4.5, and 27 MB/s tx rates to rate <-> media conversion routines
o const-poison channel arg to ieee80211_chan2mode
-rw-r--r-- | sys/net/if_media.h | 9 | ||||
-rw-r--r-- | sys/net80211/_ieee80211.h | 6 | ||||
-rw-r--r-- | sys/net80211/ieee80211.c | 145 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.c | 5 | ||||
-rw-r--r-- | sys/net80211/ieee80211_output.c | 8 | ||||
-rw-r--r-- | sys/net80211/ieee80211_proto.c | 5 | ||||
-rw-r--r-- | sys/net80211/ieee80211_var.h | 4 |
7 files changed, 130 insertions, 52 deletions
diff --git a/sys/net/if_media.h b/sys/net/if_media.h index 81a82ca..48897e2 100644 --- a/sys/net/if_media.h +++ b/sys/net/if_media.h @@ -198,6 +198,9 @@ uint64_t ifmedia_baudrate(int); #define IFM_IEEE80211_OFDM72 18 /* OFDM 72Mbps */ #define IFM_IEEE80211_DS354k 19 /* Direct Sequence 354Kbps */ #define IFM_IEEE80211_DS512k 20 /* Direct Sequence 512Kbps */ +#define IFM_IEEE80211_OFDM3 21 /* OFDM 3Mbps */ +#define IFM_IEEE80211_OFDM4 22 /* OFDM 4.5Mbps */ +#define IFM_IEEE80211_OFDM27 23 /* OFDM 27Mbps */ #define IFM_IEEE80211_ADHOC 0x00000100 /* Operate in Adhoc mode */ #define IFM_IEEE80211_HOSTAP 0x00000200 /* Operate in Host AP mode */ @@ -437,6 +440,9 @@ struct ifmedia_description { { IFM_IEEE80211_OFDM72, "OFDM/72Mbps" }, \ { IFM_IEEE80211_DS354k, "DS/354Kbps" }, \ { IFM_IEEE80211_DS512k, "DS/512Kbps" }, \ + { IFM_IEEE80211_OFDM3, "OFDM/3Mbps" }, \ + { IFM_IEEE80211_OFDM4, "OFDM/4.5Mbps" }, \ + { IFM_IEEE80211_OFDM27, "OFDM/27Mbps" }, \ { 0, NULL }, \ } @@ -472,6 +478,9 @@ struct ifmedia_description { { IFM_IEEE80211_DS354k, "DirectSequence/354Kbps" }, \ { IFM_IEEE80211_DS512k, "DS512K" }, \ { IFM_IEEE80211_DS512k, "DirectSequence/512Kbps" }, \ + { IFM_IEEE80211_OFDM3, "OFDM3" }, \ + { IFM_IEEE80211_OFDM4, "OFDM4.5" }, \ + { IFM_IEEE80211_OFDM27, "OFDM27" }, \ { 0, NULL }, \ } diff --git a/sys/net80211/_ieee80211.h b/sys/net80211/_ieee80211.h index 0872c5d..4eb522c 100644 --- a/sys/net80211/_ieee80211.h +++ b/sys/net80211/_ieee80211.h @@ -123,6 +123,8 @@ 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_HALF 0x4000 /* Half rate channel */ +#define IEEE80211_CHAN_QUARTER 0x8000 /* Quarter rate channel */ /* * Useful combinations of channel characteristics. @@ -175,6 +177,10 @@ struct ieee80211_channel { (((_c)->ic_flags & IEEE80211_CHAN_CCK) != 0) #define IEEE80211_IS_CHAN_GFSK(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_GFSK) != 0) +#define IEEE80211_IS_CHAN_HALF(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HALF) != 0) +#define IEEE80211_IS_CHAN_QUARTER(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_QUARTER) != 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 65e71e6..f832b21 100644 --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -67,6 +67,10 @@ const char *ieee80211_phymode_name[] = { #define B(r) ((r) | IEEE80211_RATE_BASIC) static const struct ieee80211_rateset ieee80211_rateset_11a = { 8, { B(12), 18, B(24), 36, B(48), 72, 96, 108 } }; +static const struct ieee80211_rateset ieee80211_rateset_half = + { 8, { B(6), 9, B(12), 18, B(24), 36, 48, 54 } }; +static const struct ieee80211_rateset ieee80211_rateset_quarter = + { 8, { B(3), 4, B(6), 9, B(12), 18, 24, 27 } }; static const struct ieee80211_rateset ieee80211_rateset_11b = { 4, { B(2), B(4), B(11), B(22) } }; /* NB: OFDM rates are handled specially based on mode */ @@ -131,30 +135,25 @@ ieee80211_default_reset(struct ifnet *ifp) return ENETRESET; } -void -ieee80211_ifattach(struct ieee80211com *ic) +/* + * Fill in 802.11 available channel set, mark + * all available channels as active, and pick + * a default channel if not already specified. + */ +static void +ieee80211_chan_init(struct ieee80211com *ic) { #define RATESDEFINED(m) \ ((ic->ic_modecaps & (1<<m)) && ic->ic_sup_rates[m].rs_nrates != 0) +#define DEFAULTRATES(m, def) do { \ + if (!RATESDEFINED(m)) ic->ic_sup_rates[m] = def; \ +} while (0) struct ifnet *ifp = ic->ic_ifp; struct ieee80211_channel *c; int i; - ether_ifattach(ifp, ic->ic_myaddr); - ifp->if_output = ieee80211_output; - - bpfattach2(ifp, DLT_IEEE802_11, - sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf); - - ieee80211_crypto_attach(ic); - - /* - * Fill in 802.11 available channel set, mark - * all available channels as active, and pick - * a default channel if not already specified. - */ memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); - ic->ic_modecaps |= 1<<IEEE80211_MODE_AUTO; + ic->ic_modecaps = 1<<IEEE80211_MODE_AUTO; for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { c = &ic->ic_channels[i]; if (c->ic_flags) { @@ -190,22 +189,42 @@ ieee80211_ifattach(struct ieee80211com *ic) } } } - /* validate ic->ic_curmode */ - if ((ic->ic_modecaps & (1<<ic->ic_curmode)) == 0) - ic->ic_curmode = IEEE80211_MODE_AUTO; - ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ /* fillin well-known rate sets if driver has not specified */ - if (!RATESDEFINED(IEEE80211_MODE_11B)) - ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_rateset_11b; - if (!RATESDEFINED(IEEE80211_MODE_11G)) - ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_rateset_11g; - if (!RATESDEFINED(IEEE80211_MODE_11A)) - ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_rateset_11a; - if (!RATESDEFINED(IEEE80211_MODE_TURBO_A)) - ic->ic_sup_rates[IEEE80211_MODE_TURBO_A] = ieee80211_rateset_11a; - if (!RATESDEFINED(IEEE80211_MODE_TURBO_G)) - ic->ic_sup_rates[IEEE80211_MODE_TURBO_G] = ieee80211_rateset_11g; + DEFAULTRATES(IEEE80211_MODE_11B, ieee80211_rateset_11b); + DEFAULTRATES(IEEE80211_MODE_11G, ieee80211_rateset_11g); + DEFAULTRATES(IEEE80211_MODE_11A, ieee80211_rateset_11a); + DEFAULTRATES(IEEE80211_MODE_TURBO_A, ieee80211_rateset_11a); + DEFAULTRATES(IEEE80211_MODE_TURBO_G, ieee80211_rateset_11g); + + /* + * Set auto mode to reset active channel state and any desired channel. + */ + (void) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); +#undef DEFAULTRATES +#undef RATESDEFINED +} + +void +ieee80211_ifattach(struct ieee80211com *ic) +{ + struct ifnet *ifp = ic->ic_ifp; + + ether_ifattach(ifp, ic->ic_myaddr); + ifp->if_output = ieee80211_output; + + bpfattach2(ifp, DLT_IEEE802_11, + sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf); + + ieee80211_crypto_attach(ic); + + ic->ic_des_chan = IEEE80211_CHAN_ANYC; + /* + * Fill in 802.11 available channel set, mark all + * available channels as active, and pick a default + * channel if not already specified. + */ + ieee80211_chan_init(ic); #if 0 /* * Enable WME by default if we're capable. @@ -215,7 +234,6 @@ ieee80211_ifattach(struct ieee80211com *ic) #endif if (ic->ic_caps & IEEE80211_C_BURST) ic->ic_flags |= IEEE80211_F_BURST; - (void) ieee80211_setmode(ic, ic->ic_curmode); ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; ic->ic_bmissthreshold = IEEE80211_HWBMISS_DEFAULT; @@ -241,7 +259,6 @@ ieee80211_ifattach(struct ieee80211com *ic) KASSERT(ifp->if_spare2 == NULL, ("oops, hosed")); ifp->if_spare2 = ic; /* XXX temp backpointer */ -#undef RATESDEFINED } void @@ -277,9 +294,12 @@ ieee80211_mhz2ieee(u_int freq, u_int flags) else return 15 + ((freq - 2512) / 20); } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */ - if (freq <= 5000) + if (freq <= 5000) { + if (flags &(IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)) + return 37 + ((freq * 10) + + ((freq % 5) == 2 ? 5 : 0) - 49400) / 5; return (freq - 4000) / 5; - else + } else return (freq - 5000) / 5; } else { /* either, guess */ if (freq == 2484) @@ -287,7 +307,10 @@ ieee80211_mhz2ieee(u_int freq, u_int flags) if (freq < 2484) return ((int) freq - 2407) / 5; if (freq < 5000) { - if (freq > 4900) + if (flags &(IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)) + return 37 + ((freq * 10) + + ((freq % 5) == 2 ? 5 : 0) - 49400) / 5; + else if (freq > 4900) return (freq - 4000) / 5; else return 15 + ((freq - 2512) / 20); @@ -330,6 +353,10 @@ ieee80211_ieee2mhz(u_int chan, u_int flags) else return 2512 + ((chan-15)*20); } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */ + if (flags & (IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)) { + chan -= 37; + return 4940 + chan*5 + (chan % 5 ? 2 : 0); + } return 5000 + (chan*5); } else { /* either, guess */ if (chan == 14) @@ -338,6 +365,7 @@ ieee80211_ieee2mhz(u_int chan, u_int flags) return 2407 + chan*5; if (chan < 27) /* 15-26 */ return 2512 + ((chan-15)*20); + /* XXX can't distinguish PSB channels */ return 5000 + (chan*5); } } @@ -360,11 +388,22 @@ ieee80211_media_init(struct ieee80211com *ic, struct ieee80211_rateset *rs; struct ieee80211_rateset allrates; - /* - * Do late attach work that must wait for any subclass - * (i.e. driver) work such as overriding methods. - */ - ieee80211_node_lateattach(ic); + /* NB: this works because the structure is initialized to zero */ + if (LIST_EMPTY(&ic->ic_media.ifm_list)) { + /* + * Do late attach work that must wait for any subclass + * (i.e. driver) work such as overriding methods. + */ + ieee80211_node_lateattach(ic); + } else { + /* + * We are re-initializing the channel list; clear + * the existing media state as the media routines + * don't suppress duplicates. + */ + ifmedia_removeall(&ic->ic_media); + ieee80211_chan_init(ic); + } /* * Fill in media characteristics. @@ -452,6 +491,20 @@ ieee80211_media_init(struct ieee80211com *ic, #undef ADD } +const struct ieee80211_rateset * +ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *c) +{ + 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; + } + return &ic->ic_sup_rates[mode]; +} + void ieee80211_announce(struct ieee80211com *ic) { @@ -697,7 +750,7 @@ void ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr) { struct ieee80211com *ic; - struct ieee80211_rateset *rs; + const struct ieee80211_rateset *rs; ic = ieee80211_find_instance(ifp); if (!ic) { @@ -932,7 +985,7 @@ ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode) * In those cases we defer to the current operating mode when set. */ enum ieee80211_phymode -ieee80211_chan2mode(struct ieee80211com *ic, struct ieee80211_channel *chan) +ieee80211_chan2mode(struct ieee80211com *ic, const struct ieee80211_channel *chan) { if (IEEE80211_IS_CHAN_T(chan)) { return IEEE80211_MODE_TURBO_A; @@ -993,6 +1046,9 @@ ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode m { 72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 }, { 96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 }, { 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 }, + { 6 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM3 }, + { 9 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM4 }, + { 54 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM27 }, /* NB: OFDM72 doesn't realy exist so we don't handle it */ }; u_int mask, i; @@ -1053,6 +1109,11 @@ ieee80211_media2rate(int mword) 96, /* IFM_IEEE80211_OFDM48 */ 108, /* IFM_IEEE80211_OFDM54 */ 144, /* IFM_IEEE80211_OFDM72 */ + 0, /* IFM_IEEE80211_DS354k */ + 0, /* IFM_IEEE80211_DS512k */ + 6, /* IFM_IEEE80211_OFDM3 */ + 9, /* IFM_IEEE80211_OFDM4 */ + 54, /* IFM_IEEE80211_OFDM27 */ }; return IFM_SUBTYPE(mword) < N(ieeerates) ? ieeerates[IFM_SUBTYPE(mword)] : 0; diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index d9c88c9..700d4b0 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -230,7 +230,7 @@ ieee80211_set_chan(struct ieee80211com *ic, if (chan == IEEE80211_CHAN_ANYC) /* XXX while scanning */ chan = ic->ic_curchan; ni->ni_chan = chan; - ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)]; + ni->ni_rates = *ieee80211_get_suprates(ic, chan); } /* @@ -344,8 +344,7 @@ ieee80211_next_scan(struct ieee80211com *ic) * XXX drivers should do this as needed, * XXX for now maintain compatibility */ - ic->ic_bss->ni_rates = - ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)]; + ic->ic_bss->ni_rates = *ieee80211_get_suprates(ic, chan); ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); return 1; } diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index 76101be..e58bbb6 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -1110,8 +1110,8 @@ ieee80211_send_probereq(struct ieee80211_node *ni, const void *optie, size_t optielen) { struct ieee80211com *ic = ni->ni_ic; - enum ieee80211_phymode mode; struct ieee80211_frame *wh; + const struct ieee80211_rateset *rs; struct mbuf *m; u_int8_t *frm; @@ -1147,9 +1147,9 @@ ieee80211_send_probereq(struct ieee80211_node *ni, } frm = ieee80211_add_ssid(frm, ssid, ssidlen); - mode = ieee80211_chan2mode(ic, ic->ic_curchan); - frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); - frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); + rs = ieee80211_get_suprates(ic, ic->ic_curchan); + frm = ieee80211_add_rates(frm, rs); + frm = ieee80211_add_xrates(frm, rs); if (optie != NULL) { memcpy(frm, optie, optielen); diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c index e7441ef..e11fb70 100644 --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -329,7 +329,8 @@ ieee80211_fix_rate(struct ieee80211_node *ni, int flags) struct ieee80211com *ic = ni->ni_ic; int i, j, ignore, error; int okrate, badrate, fixedrate; - struct ieee80211_rateset *srs, *nrs; + const struct ieee80211_rateset *srs; + struct ieee80211_rateset *nrs; u_int8_t r; /* @@ -341,7 +342,7 @@ ieee80211_fix_rate(struct ieee80211_node *ni, int flags) flags &= ~IEEE80211_F_DOFRATE; error = 0; okrate = badrate = fixedrate = 0; - srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; + srs = ieee80211_get_suprates(ic, ni->ni_chan); nrs = &ni->ni_rates; for (i = 0; i < nrs->rs_nrates; ) { ignore = 0; diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index 00e38d4..5dbc3de 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -285,6 +285,8 @@ struct ieee80211com { void ieee80211_ifattach(struct ieee80211com *); void ieee80211_ifdetach(struct ieee80211com *); +const struct ieee80211_rateset *ieee80211_get_suprates(struct ieee80211com *, + const struct ieee80211_channel *); void ieee80211_announce(struct ieee80211com *); void ieee80211_media_init(struct ieee80211com *, ifm_change_cb_t, ifm_stat_cb_t); @@ -303,7 +305,7 @@ int ieee80211_chan2ieee(struct ieee80211com *, struct ieee80211_channel *); u_int ieee80211_ieee2mhz(u_int, u_int); int ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode); enum ieee80211_phymode ieee80211_chan2mode(struct ieee80211com *, - struct ieee80211_channel *); + const struct ieee80211_channel *); /* * Key update synchronization methods. XXX should not be visible. |