aboutsummaryrefslogtreecommitdiff
path: root/sys/net80211
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2006-12-27 18:46:18 +0000
committerSam Leffler <sam@FreeBSD.org>2006-12-27 18:46:18 +0000
commit41b3c790eb3c76184859eb20f3f2eba98ec7d47c (patch)
tree8bd925a7f6c33cd28325df02b1a6153b8b091d2d /sys/net80211
parentbf42b54c6c0af191821902285ec0f6e3166b5c89 (diff)
downloadsrc-41b3c790eb3c76184859eb20f3f2eba98ec7d47c.tar.gz
src-41b3c790eb3c76184859eb20f3f2eba98ec7d47c.zip
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
Notes
Notes: svn path=/head/; revision=165569
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/_ieee80211.h6
-rw-r--r--sys/net80211/ieee80211.c145
-rw-r--r--sys/net80211/ieee80211_node.c5
-rw-r--r--sys/net80211/ieee80211_output.c8
-rw-r--r--sys/net80211/ieee80211_proto.c5
-rw-r--r--sys/net80211/ieee80211_var.h4
6 files changed, 121 insertions, 52 deletions
diff --git a/sys/net80211/_ieee80211.h b/sys/net80211/_ieee80211.h
index 0872c5d58651..4eb522c069a1 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 65e71e697c00..f832b211d2b6 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 d9c88c91d0d6..700d4b00b0d2 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 76101bead1e2..e58bbb6e549a 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 e7441efd089b..e11fb70da555 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 00e38d49689d..5dbc3de63c6c 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.