summaryrefslogtreecommitdiffstats
path: root/sys/net80211
diff options
context:
space:
mode:
authoravos <avos@FreeBSD.org>2016-04-29 21:18:14 +0000
committeravos <avos@FreeBSD.org>2016-04-29 21:18:14 +0000
commitd3b6c9c90faa979f0fbec505c7207a8414476c8d (patch)
treede8937a36670edfb65a18b6b2308b0d4391f60fc /sys/net80211
parenteffae8a6ec7270e09599f54cff195ceaef0df923 (diff)
downloadFreeBSD-src-d3b6c9c90faa979f0fbec505c7207a8414476c8d.zip
FreeBSD-src-d3b6c9c90faa979f0fbec505c7207a8414476c8d.tar.gz
net80211: provide a set of ieee80211_add_channel*() functions
This change adds few methods for net80211 channel table setup: - ieee80211_add_channel() - ieee80211_add_channel_ht40() (primarily for drivers, that parse EEPROM to get channel list - they will allow to hide implementation details). - ieee80211_add_channel_list_2ghz() - ieee80211_add_channel_list_5ghz() (mostly as a replacement for ieee80211_init_channels() - they will allow to specify non-default channel list; may be used in ic_getradiocaps()). Tested with wpi(4) (add_channel) and rum(4) (add_channel_list_2ghz). Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D6124
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/ieee80211.c264
-rw-r--r--sys/net80211/ieee80211_regdomain.c112
-rw-r--r--sys/net80211/ieee80211_var.h8
3 files changed, 292 insertions, 92 deletions
diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c
index bb4b141..86f4d81 100644
--- a/sys/net80211/ieee80211.c
+++ b/sys/net80211/ieee80211.c
@@ -970,6 +970,261 @@ ieee80211_ieee2mhz(u_int chan, u_int flags)
}
}
+static __inline void
+set_extchan(struct ieee80211_channel *c)
+{
+
+ /*
+ * IEEE Std 802.11-2012, page 1738, subclause 20.3.15.4:
+ * "the secondary channel number shall be 'N + [1,-1] * 4'
+ */
+ if (c->ic_flags & IEEE80211_CHAN_HT40U)
+ c->ic_extieee = c->ic_ieee + 4;
+ else if (c->ic_flags & IEEE80211_CHAN_HT40D)
+ c->ic_extieee = c->ic_ieee - 4;
+ else
+ c->ic_extieee = 0;
+}
+
+static int
+addchan(struct ieee80211_channel chans[], int maxchans, int *nchans,
+ uint8_t ieee, uint16_t freq, int8_t maxregpower, uint32_t flags)
+{
+ struct ieee80211_channel *c;
+
+ if (*nchans >= maxchans)
+ return (ENOBUFS);
+
+ c = &chans[(*nchans)++];
+ c->ic_ieee = ieee;
+ c->ic_freq = freq != 0 ? freq : ieee80211_ieee2mhz(ieee, flags);
+ c->ic_maxregpower = maxregpower;
+ c->ic_maxpower = 2 * maxregpower;
+ c->ic_flags = flags;
+ set_extchan(c);
+
+ return (0);
+}
+
+static int
+copychan_prev(struct ieee80211_channel chans[], int maxchans, int *nchans,
+ uint32_t flags)
+{
+ struct ieee80211_channel *c;
+
+ KASSERT(*nchans > 0, ("channel list is empty\n"));
+
+ if (*nchans >= maxchans)
+ return (ENOBUFS);
+
+ c = &chans[(*nchans)++];
+ c[0] = c[-1];
+ c->ic_flags = flags;
+ set_extchan(c);
+
+ return (0);
+}
+
+static void
+getflags_2ghz(const uint8_t bands[], uint32_t flags[], int ht40)
+{
+ int nmodes;
+
+ nmodes = 0;
+ if (isset(bands, IEEE80211_MODE_11B))
+ flags[nmodes++] = IEEE80211_CHAN_B;
+ if (isset(bands, IEEE80211_MODE_11G))
+ flags[nmodes++] = IEEE80211_CHAN_G;
+ if (isset(bands, IEEE80211_MODE_11NG))
+ flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT20;
+ if (ht40) {
+ flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U;
+ flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D;
+ }
+ flags[nmodes] = 0;
+}
+
+static void
+getflags_5ghz(const uint8_t bands[], uint32_t flags[], int ht40)
+{
+ int nmodes;
+
+ nmodes = 0;
+ if (isset(bands, IEEE80211_MODE_11A))
+ flags[nmodes++] = IEEE80211_CHAN_A;
+ if (isset(bands, IEEE80211_MODE_11NA))
+ flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT20;
+ if (ht40) {
+ flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U;
+ flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D;
+ }
+ flags[nmodes] = 0;
+}
+
+static void
+getflags(const uint8_t bands[], uint32_t flags[], int ht40)
+{
+
+ flags[0] = 0;
+ if (isset(bands, IEEE80211_MODE_11A) ||
+ isset(bands, IEEE80211_MODE_11NA)) {
+ if (isset(bands, IEEE80211_MODE_11B) ||
+ isset(bands, IEEE80211_MODE_11G) ||
+ isset(bands, IEEE80211_MODE_11NG))
+ return;
+
+ getflags_5ghz(bands, flags, ht40);
+ } else
+ getflags_2ghz(bands, flags, ht40);
+}
+
+/*
+ * Add one 20 MHz channel into specified channel list.
+ */
+int
+ieee80211_add_channel(struct ieee80211_channel chans[], int maxchans,
+ int *nchans, uint8_t ieee, uint16_t freq, int8_t maxregpower,
+ uint32_t chan_flags, const uint8_t bands[])
+{
+ uint32_t flags[IEEE80211_MODE_MAX];
+ int i, error;
+
+ getflags(bands, flags, 0);
+ KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__));
+
+ error = addchan(chans, maxchans, nchans, ieee, freq, maxregpower,
+ flags[0] | chan_flags);
+ for (i = 1; flags[i] != 0 && error == 0; i++) {
+ error = copychan_prev(chans, maxchans, nchans,
+ flags[i] | chan_flags);
+ }
+
+ return (error);
+}
+
+static struct ieee80211_channel *
+findchannel(struct ieee80211_channel chans[], int nchans, uint16_t freq,
+ uint32_t flags)
+{
+ struct ieee80211_channel *c;
+ int i;
+
+ flags &= IEEE80211_CHAN_ALLTURBO;
+ /* brute force search */
+ for (i = 0; i < nchans; i++) {
+ c = &chans[i];
+ if (c->ic_freq == freq &&
+ (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
+ return c;
+ }
+ return NULL;
+}
+
+/*
+ * Add 40 MHz channel pair into specified channel list.
+ */
+int
+ieee80211_add_channel_ht40(struct ieee80211_channel chans[], int maxchans,
+ int *nchans, uint8_t ieee, int8_t maxregpower, uint32_t flags)
+{
+ struct ieee80211_channel *cent, *extc;
+ uint16_t freq;
+ int error;
+
+ freq = ieee80211_ieee2mhz(ieee, flags);
+
+ /*
+ * Each entry defines an HT40 channel pair; find the
+ * center channel, then the extension channel above.
+ */
+ flags |= IEEE80211_CHAN_HT20;
+ cent = findchannel(chans, *nchans, freq, flags);
+ if (cent == NULL)
+ return (EINVAL);
+
+ extc = findchannel(chans, *nchans, freq + 20, flags);
+ if (extc == NULL)
+ return (ENOENT);
+
+ flags &= ~IEEE80211_CHAN_HT;
+ error = addchan(chans, maxchans, nchans, cent->ic_ieee, cent->ic_freq,
+ maxregpower, flags | IEEE80211_CHAN_HT40U);
+ if (error != 0)
+ return (error);
+
+ error = addchan(chans, maxchans, nchans, extc->ic_ieee, extc->ic_freq,
+ maxregpower, flags | IEEE80211_CHAN_HT40D);
+
+ return (error);
+}
+
+/*
+ * Adds channels into specified channel list (ieee[] array must be sorted).
+ * Channels are already sorted.
+ */
+static int
+add_chanlist(struct ieee80211_channel chans[], int maxchans, int *nchans,
+ const uint8_t ieee[], int nieee, uint32_t flags[])
+{
+ uint16_t freq;
+ int i, j, error;
+
+ for (i = 0; i < nieee; i++) {
+ freq = ieee80211_ieee2mhz(ieee[i], flags[0]);
+ for (j = 0; flags[j] != 0; j++) {
+ if (flags[j] & IEEE80211_CHAN_HT40D)
+ if (i == 0 || ieee[i] < ieee[0] + 4 ||
+ freq - 20 !=
+ ieee80211_ieee2mhz(ieee[i] - 4, flags[j]))
+ continue;
+ if (flags[j] & IEEE80211_CHAN_HT40U)
+ if (i == nieee - 1 ||
+ ieee[i] + 4 > ieee[nieee - 1] ||
+ freq + 20 !=
+ ieee80211_ieee2mhz(ieee[i] + 4, flags[j]))
+ continue;
+
+ if (j == 0) {
+ error = addchan(chans, maxchans, nchans,
+ ieee[i], freq, 0, flags[j]);
+ } else {
+ error = copychan_prev(chans, maxchans, nchans,
+ flags[j]);
+ }
+ if (error != 0)
+ return (error);
+ }
+ }
+
+ return (error);
+}
+
+int
+ieee80211_add_channel_list_2ghz(struct ieee80211_channel chans[], int maxchans,
+ int *nchans, const uint8_t ieee[], int nieee, const uint8_t bands[],
+ int ht40)
+{
+ uint32_t flags[IEEE80211_MODE_MAX];
+
+ getflags_2ghz(bands, flags, ht40);
+ KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__));
+
+ return (add_chanlist(chans, maxchans, nchans, ieee, nieee, flags));
+}
+
+int
+ieee80211_add_channel_list_5ghz(struct ieee80211_channel chans[], int maxchans,
+ int *nchans, const uint8_t ieee[], int nieee, const uint8_t bands[],
+ int ht40)
+{
+ uint32_t flags[IEEE80211_MODE_MAX];
+
+ getflags_5ghz(bands, flags, ht40);
+ KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__));
+
+ return (add_chanlist(chans, maxchans, nchans, ieee, nieee, flags));
+}
+
/*
* Locate a channel given a frequency+flags. We cache
* the previous lookup to optimize switching between two
@@ -979,7 +1234,6 @@ struct ieee80211_channel *
ieee80211_find_channel(struct ieee80211com *ic, int freq, int flags)
{
struct ieee80211_channel *c;
- int i;
flags &= IEEE80211_CHAN_ALLTURBO;
c = ic->ic_prevchan;
@@ -987,13 +1241,7 @@ ieee80211_find_channel(struct ieee80211com *ic, int freq, int flags)
(c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
return c;
/* brute force search */
- for (i = 0; i < ic->ic_nchans; i++) {
- c = &ic->ic_channels[i];
- if (c->ic_freq == freq &&
- (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
- return c;
- }
- return NULL;
+ return (findchannel(ic->ic_channels, ic->ic_nchans, freq, flags));
}
/*
diff --git a/sys/net80211/ieee80211_regdomain.c b/sys/net80211/ieee80211_regdomain.c
index efbe1a8..4db08fd 100644
--- a/sys/net80211/ieee80211_regdomain.c
+++ b/sys/net80211/ieee80211_regdomain.c
@@ -98,22 +98,14 @@ ieee80211_regdomain_vdetach(struct ieee80211vap *vap)
{
}
-static void
-addchan(struct ieee80211com *ic, int ieee, int flags)
-{
- struct ieee80211_channel *c;
-
- c = &ic->ic_channels[ic->ic_nchans++];
- c->ic_freq = ieee80211_ieee2mhz(ieee, flags);
- c->ic_ieee = ieee;
- c->ic_flags = flags;
- if (flags & IEEE80211_CHAN_HT40U)
- c->ic_extieee = ieee + 4;
- else if (flags & IEEE80211_CHAN_HT40D)
- c->ic_extieee = ieee - 4;
- else
- c->ic_extieee = 0;
-}
+static const uint8_t def_chan_2ghz[] =
+ { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
+static const uint8_t def_chan_5ghz_band1[] =
+ { 36, 40, 44, 48, 52, 56, 60, 64 };
+static const uint8_t def_chan_5ghz_band2[] =
+ { 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 };
+static const uint8_t def_chan_5ghz_band3[] =
+ { 149, 153, 157, 161 };
/*
* Setup the channel list for the specified regulatory domain,
@@ -125,82 +117,34 @@ int
ieee80211_init_channels(struct ieee80211com *ic,
const struct ieee80211_regdomain *rd, const uint8_t bands[])
{
- int i;
+ struct ieee80211_channel *chans = ic->ic_channels;
+ int *nchans = &ic->ic_nchans;
+ int ht40;
/* XXX just do something for now */
- ic->ic_nchans = 0;
+ ht40 = !!(ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40);
+ *nchans = 0;
if (isset(bands, IEEE80211_MODE_11B) ||
isset(bands, IEEE80211_MODE_11G) ||
isset(bands, IEEE80211_MODE_11NG)) {
- int maxchan = 11;
- if (rd != NULL && rd->ecm)
- maxchan = 14;
- for (i = 1; i <= maxchan; i++) {
- if (isset(bands, IEEE80211_MODE_11B))
- addchan(ic, i, IEEE80211_CHAN_B);
- if (isset(bands, IEEE80211_MODE_11G))
- addchan(ic, i, IEEE80211_CHAN_G);
- if (isset(bands, IEEE80211_MODE_11NG)) {
- addchan(ic, i,
- IEEE80211_CHAN_G | IEEE80211_CHAN_HT20);
- }
- if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) == 0)
- continue;
- if (i <= 7) {
- addchan(ic, i,
- IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U);
- addchan(ic, i + 4,
- IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D);
- }
- }
+ int nchan = nitems(def_chan_2ghz);
+ if (!(rd != NULL && rd->ecm))
+ nchan -= 3;
+
+ ieee80211_add_channel_list_2ghz(chans, IEEE80211_CHAN_MAX,
+ nchans, def_chan_2ghz, nchan, bands, ht40);
}
if (isset(bands, IEEE80211_MODE_11A) ||
isset(bands, IEEE80211_MODE_11NA)) {
- for (i = 36; i <= 64; i += 4) {
- addchan(ic, i, IEEE80211_CHAN_A);
- if (isset(bands, IEEE80211_MODE_11NA)) {
- addchan(ic, i,
- IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
- }
- if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) == 0)
- continue;
- if ((i % 8) == 4) {
- addchan(ic, i,
- IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
- addchan(ic, i + 4,
- IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
- }
- }
- for (i = 100; i <= 140; i += 4) {
- addchan(ic, i, IEEE80211_CHAN_A);
- if (isset(bands, IEEE80211_MODE_11NA)) {
- addchan(ic, i,
- IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
- }
- if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) == 0)
- continue;
- if ((i % 8) == 4 && i != 140) {
- addchan(ic, i,
- IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
- addchan(ic, i + 4,
- IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
- }
- }
- for (i = 149; i <= 161; i += 4) {
- addchan(ic, i, IEEE80211_CHAN_A);
- if (isset(bands, IEEE80211_MODE_11NA)) {
- addchan(ic, i,
- IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
- }
- if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) == 0)
- continue;
- if ((i % 8) == 5) {
- addchan(ic, i,
- IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
- addchan(ic, i + 4,
- IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
- }
- }
+ ieee80211_add_channel_list_5ghz(chans, IEEE80211_CHAN_MAX,
+ nchans, def_chan_5ghz_band1, nitems(def_chan_5ghz_band1),
+ bands, ht40);
+ ieee80211_add_channel_list_5ghz(chans, IEEE80211_CHAN_MAX,
+ nchans, def_chan_5ghz_band2, nitems(def_chan_5ghz_band2),
+ bands, ht40);
+ ieee80211_add_channel_list_5ghz(chans, IEEE80211_CHAN_MAX,
+ nchans, def_chan_5ghz_band3, nitems(def_chan_5ghz_band3),
+ bands, ht40);
}
if (rd != NULL)
ic->ic_regdomain = *rd;
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index fbaa782..8c0f6fb 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -723,6 +723,14 @@ int ieee80211_mhz2ieee(u_int, u_int);
int ieee80211_chan2ieee(struct ieee80211com *,
const struct ieee80211_channel *);
u_int ieee80211_ieee2mhz(u_int, u_int);
+int ieee80211_add_channel(struct ieee80211_channel[], int, int *,
+ uint8_t, uint16_t, int8_t, uint32_t, const uint8_t[]);
+int ieee80211_add_channel_ht40(struct ieee80211_channel[], int, int *,
+ uint8_t, int8_t, uint32_t);
+int ieee80211_add_channel_list_2ghz(struct ieee80211_channel[], int, int *,
+ const uint8_t[], int, const uint8_t[], int);
+int ieee80211_add_channel_list_5ghz(struct ieee80211_channel[], int, int *,
+ const uint8_t[], int, const uint8_t[], int);
struct ieee80211_channel *ieee80211_find_channel(struct ieee80211com *,
int freq, int flags);
struct ieee80211_channel *ieee80211_find_channel_byieee(struct ieee80211com *,
OpenPOWER on IntegriCloud