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
This commit is contained in:
parent
794277da54
commit
355fec4842
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=298812
@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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 *,
|
||||
|
Loading…
Reference in New Issue
Block a user