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
This commit is contained in:
Sam Leffler 2006-12-27 18:46:18 +00:00
parent bf42b54c6c
commit 41b3c790eb
7 changed files with 130 additions and 52 deletions

View File

@ -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 }, \
}

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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.