mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-07 13:14:51 +00:00
[ifconfig] add initial VHT (802.11ac) configuration and channel support to ifconfig.
This is very preliminary and mostly enough for me (with other patches) to work on VHT support. It adds: * VHT20, VHT40 and VHT80 regulatory/band awareness * VHT20, VHT40 and VHT80 channel configuration / population * Parses vht channel specifications (eg ifconfig wlan0 create wlandev athp0 wlanmode monitor channel 36:vht/80) * Configuration of VHT, VHT40, VHT80, VHT80+80, VHT160 channel width (IEEE80211_FVHT_VHT* flags in net80211) TODO: * No VHT80+80 or VHT160 channels yet - I don't yet have hardware, and I'm not yet sure how to support/populate VHT80+80 channels. * No, I won't update the manpage until this is "more done", lest someone tries using vht and gets upset with me. * No, I won't commit the regulatory database I'm testing with, so you'll just end up with no VHT channels ever populated. Which is good, as there isn't an 11ac driver in-tree yet to try it with.
This commit is contained in:
parent
35bcfd1c70
commit
e9bb7f9aa1
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=311579
@ -119,6 +119,7 @@
|
||||
#define IEEE80211_NODE_ASSOCID 0x020000 /* xmit requires associd */
|
||||
#define IEEE80211_NODE_AMSDU_RX 0x040000 /* AMSDU rx enabled */
|
||||
#define IEEE80211_NODE_AMSDU_TX 0x080000 /* AMSDU tx enabled */
|
||||
#define IEEE80211_NODE_VHT 0x100000 /* VHT enabled */
|
||||
#endif
|
||||
|
||||
#define MAXCHAN 1536 /* max 1.5K channels */
|
||||
@ -143,7 +144,9 @@ static const char *modename[IEEE80211_MODE_MAX] = {
|
||||
[IEEE80211_MODE_11NA] = "11na",
|
||||
[IEEE80211_MODE_11NG] = "11ng",
|
||||
[IEEE80211_MODE_HALF] = "half",
|
||||
[IEEE80211_MODE_QUARTER] = "quarter"
|
||||
[IEEE80211_MODE_QUARTER] = "quarter",
|
||||
[IEEE80211_MODE_VHT_2GHZ] = "11acg",
|
||||
[IEEE80211_MODE_VHT_5GHZ] = "11ac",
|
||||
};
|
||||
|
||||
static void set80211(int s, int type, int val, int len, void *data);
|
||||
@ -183,6 +186,20 @@ gethtconf(int s)
|
||||
gothtconf = 1;
|
||||
}
|
||||
|
||||
/* VHT */
|
||||
static int vhtconf = 0;
|
||||
static int gotvhtconf = 0;
|
||||
|
||||
static void
|
||||
getvhtconf(int s)
|
||||
{
|
||||
if (gotvhtconf)
|
||||
return;
|
||||
if (get80211val(s, IEEE80211_IOC_VHTCONF, &vhtconf) < 0)
|
||||
warn("unable to get VHT configuration information");
|
||||
gotvhtconf = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Collect channel info from the kernel. We use this (mostly)
|
||||
* to handle mapping between frequency and IEEE channel number.
|
||||
@ -200,6 +217,7 @@ getchaninfo(int s)
|
||||
err(1, "unable to get channel information");
|
||||
ifmr = ifmedia_getstate(s);
|
||||
gethtconf(s);
|
||||
getvhtconf(s);
|
||||
}
|
||||
|
||||
static struct regdata *
|
||||
@ -255,6 +273,9 @@ canpromote(int i, int from, int to)
|
||||
* channe list (e.g. mode 11a); we want to honor that to avoid
|
||||
* confusing behaviour.
|
||||
*/
|
||||
/*
|
||||
* XXX VHT
|
||||
*/
|
||||
static int
|
||||
promote(int i)
|
||||
{
|
||||
@ -361,6 +382,10 @@ getcurchan(int s)
|
||||
static enum ieee80211_phymode
|
||||
chan2mode(const struct ieee80211_channel *c)
|
||||
{
|
||||
if (IEEE80211_IS_CHAN_VHTA(c))
|
||||
return IEEE80211_MODE_VHT_5GHZ;
|
||||
if (IEEE80211_IS_CHAN_VHTG(c))
|
||||
return IEEE80211_MODE_VHT_2GHZ;
|
||||
if (IEEE80211_IS_CHAN_HTA(c))
|
||||
return IEEE80211_MODE_11NA;
|
||||
if (IEEE80211_IS_CHAN_HTG(c))
|
||||
@ -502,9 +527,12 @@ setregdomain_cb(int s, void *arg)
|
||||
printf("drivercaps: 0x%x\n", dc->dc_drivercaps);
|
||||
printf("cryptocaps: 0x%x\n", dc->dc_cryptocaps);
|
||||
printf("htcaps : 0x%x\n", dc->dc_htcaps);
|
||||
printf("vhtcaps : 0x%x\n", dc->dc_vhtcaps);
|
||||
#if 0
|
||||
memcpy(chaninfo, &dc->dc_chaninfo,
|
||||
IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
|
||||
print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, 1/*verbose*/);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
req = malloc(IEEE80211_REGDOMAIN_SIZE(dc->dc_chaninfo.ic_nchans));
|
||||
@ -616,6 +644,7 @@ getchannelflags(const char *val, int freq)
|
||||
#define _CHAN_HT 0x80000000
|
||||
const char *cp;
|
||||
int flags;
|
||||
int is_vht = 0;
|
||||
|
||||
flags = 0;
|
||||
|
||||
@ -636,6 +665,9 @@ getchannelflags(const char *val, int freq)
|
||||
case 'g': /* 802.11g */
|
||||
flags |= IEEE80211_CHAN_G;
|
||||
break;
|
||||
case 'v': /* vht: 802.11ac */
|
||||
is_vht = 1;
|
||||
/* Fallthrough */
|
||||
case 'h': /* ht = 802.11n */
|
||||
case 'n': /* 802.11n */
|
||||
flags |= _CHAN_HT; /* NB: private */
|
||||
@ -674,6 +706,15 @@ getchannelflags(const char *val, int freq)
|
||||
flags |= IEEE80211_CHAN_HT20;
|
||||
break;
|
||||
case 40:
|
||||
case 80:
|
||||
case 160:
|
||||
/* Handle the 80/160 VHT flag */
|
||||
if (cw == 80)
|
||||
flags |= IEEE80211_CHAN_VHT80;
|
||||
else if (cw == 160)
|
||||
flags |= IEEE80211_CHAN_VHT160;
|
||||
|
||||
/* Fallthrough */
|
||||
if (ep != NULL && *ep == '+')
|
||||
flags |= IEEE80211_CHAN_HT40U;
|
||||
else if (ep != NULL && *ep == '-')
|
||||
@ -683,6 +724,7 @@ getchannelflags(const char *val, int freq)
|
||||
errx(-1, "%s: Invalid channel width\n", val);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup specifications.
|
||||
*/
|
||||
@ -695,6 +737,7 @@ getchannelflags(const char *val, int freq)
|
||||
* are also usable for legacy operation; e.g. freq:n/40.
|
||||
*/
|
||||
flags &= ~IEEE80211_CHAN_HT;
|
||||
flags &= ~IEEE80211_CHAN_VHT;
|
||||
} else {
|
||||
/*
|
||||
* Remove private indicator that this is an HT channel
|
||||
@ -714,6 +757,25 @@ getchannelflags(const char *val, int freq)
|
||||
mapchan(&chan, freq, 0);
|
||||
flags |= (chan.ic_flags & IEEE80211_CHAN_HT);
|
||||
}
|
||||
|
||||
/*
|
||||
* If VHT is enabled, then also set the VHT flag and the
|
||||
* relevant channel up/down.
|
||||
*/
|
||||
if (is_vht && (flags & IEEE80211_CHAN_HT)) {
|
||||
/*
|
||||
* XXX yes, maybe we should just have VHT, and reuse
|
||||
* HT20/HT40U/HT40D
|
||||
*/
|
||||
if (flags & IEEE80211_CHAN_VHT80)
|
||||
;
|
||||
else if (flags & IEEE80211_CHAN_HT20)
|
||||
flags |= IEEE80211_CHAN_VHT20;
|
||||
else if (flags & IEEE80211_CHAN_HT40U)
|
||||
flags |= IEEE80211_CHAN_VHT40U;
|
||||
else if (flags & IEEE80211_CHAN_HT40D)
|
||||
flags |= IEEE80211_CHAN_VHT40D;
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
#undef _CHAN_HT
|
||||
@ -1447,6 +1509,10 @@ getmodeflags(const char *val)
|
||||
case 'q': /* 1/4-width channels */
|
||||
flags |= IEEE80211_CHAN_QUARTER;
|
||||
break;
|
||||
case 'v':
|
||||
/* XXX set HT too? */
|
||||
flags |= IEEE80211_CHAN_VHT;
|
||||
break;
|
||||
default:
|
||||
errx(-1, "%s: Invalid mode attribute %c\n",
|
||||
val, *cp);
|
||||
@ -1863,6 +1929,21 @@ set80211rifs(const char *val, int d, int s, const struct afswtch *rafp)
|
||||
set80211(s, IEEE80211_IOC_RIFS, d, 0, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
set80211vhtconf(const char *val, int d, int s, const struct afswtch *rafp)
|
||||
{
|
||||
if (get80211val(s, IEEE80211_IOC_VHTCONF, &vhtconf) < 0)
|
||||
errx(-1, "cannot set VHT setting");
|
||||
printf("%s: vhtconf=0x%08x, d=%d\n", __func__, vhtconf, d);
|
||||
if (d < 0) {
|
||||
d = -d;
|
||||
vhtconf &= ~d;
|
||||
} else
|
||||
vhtconf |= d;
|
||||
printf("%s: vhtconf is now 0x%08x\n", __func__, vhtconf);
|
||||
set80211(s, IEEE80211_IOC_VHTCONF, vhtconf, 0, NULL);
|
||||
}
|
||||
|
||||
static
|
||||
DECL_CMD_FUNC(set80211tdmaslot, val, d)
|
||||
{
|
||||
@ -2035,6 +2116,7 @@ regdomain_addchans(struct ieee80211req_chaninfo *ci,
|
||||
hi_adj = (chanFlags & IEEE80211_CHAN_HT40U) ? -20 : 0;
|
||||
lo_adj = (chanFlags & IEEE80211_CHAN_HT40D) ? 20 : 0;
|
||||
channelSep = (chanFlags & IEEE80211_CHAN_2GHZ) ? 0 : 40;
|
||||
|
||||
LIST_FOREACH(nb, bands, next) {
|
||||
b = nb->band;
|
||||
if (verbose) {
|
||||
@ -2045,6 +2127,7 @@ regdomain_addchans(struct ieee80211req_chaninfo *ci,
|
||||
putchar('\n');
|
||||
}
|
||||
prev = NULL;
|
||||
|
||||
for (freq = b->freqStart + lo_adj;
|
||||
freq <= b->freqEnd + hi_adj; freq += b->chanSep) {
|
||||
/*
|
||||
@ -2055,6 +2138,40 @@ regdomain_addchans(struct ieee80211req_chaninfo *ci,
|
||||
* then constrained according by channel separation.
|
||||
*/
|
||||
flags = nb->flags | b->flags;
|
||||
|
||||
/*
|
||||
* VHT first - HT is a subset.
|
||||
*
|
||||
* XXX TODO: VHT80p80, VHT160 is not yet done.
|
||||
*/
|
||||
if (flags & IEEE80211_CHAN_VHT) {
|
||||
if ((chanFlags & IEEE80211_CHAN_VHT20) &&
|
||||
(flags & IEEE80211_CHAN_VHT20) == 0) {
|
||||
if (verbose)
|
||||
printf("%u: skip, not a "
|
||||
"VHT20 channel\n", freq);
|
||||
continue;
|
||||
}
|
||||
if ((chanFlags & IEEE80211_CHAN_VHT40) &&
|
||||
(flags & IEEE80211_CHAN_VHT40) == 0) {
|
||||
if (verbose)
|
||||
printf("%u: skip, not a "
|
||||
"VHT40 channel\n", freq);
|
||||
continue;
|
||||
}
|
||||
if ((chanFlags & IEEE80211_CHAN_VHT80) &&
|
||||
(flags & IEEE80211_CHAN_VHT80) == 0) {
|
||||
if (verbose)
|
||||
printf("%u: skip, not a "
|
||||
"VHT80 channel\n", freq);
|
||||
continue;
|
||||
}
|
||||
|
||||
flags &= ~IEEE80211_CHAN_VHT;
|
||||
flags |= chanFlags & IEEE80211_CHAN_VHT;
|
||||
}
|
||||
|
||||
/* Now, constrain HT */
|
||||
if (flags & IEEE80211_CHAN_HT) {
|
||||
/*
|
||||
* HT channels are generated specially; we're
|
||||
@ -2127,7 +2244,7 @@ regdomain_addchans(struct ieee80211req_chaninfo *ci,
|
||||
memset(c, 0, sizeof(*c));
|
||||
c->ic_freq = freq;
|
||||
c->ic_flags = flags;
|
||||
if (c->ic_flags & IEEE80211_CHAN_DFS)
|
||||
if (c->ic_flags & IEEE80211_CHAN_DFS)
|
||||
c->ic_maxregpower = nb->maxPowerDFS;
|
||||
else
|
||||
c->ic_maxregpower = nb->maxPower;
|
||||
@ -2204,6 +2321,40 @@ regdomain_makechannels(
|
||||
&dc->dc_chaninfo);
|
||||
}
|
||||
}
|
||||
if (!LIST_EMPTY(&rd->bands_11ac) && dc->dc_vhtcaps != 0) {
|
||||
regdomain_addchans(ci, &rd->bands_11ac, reg,
|
||||
IEEE80211_CHAN_A | IEEE80211_CHAN_HT20 |
|
||||
IEEE80211_CHAN_VHT20,
|
||||
&dc->dc_chaninfo);
|
||||
|
||||
/* VHT40 is a function of HT40.. */
|
||||
if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
|
||||
regdomain_addchans(ci, &rd->bands_11ac, reg,
|
||||
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U |
|
||||
IEEE80211_CHAN_VHT40U,
|
||||
&dc->dc_chaninfo);
|
||||
regdomain_addchans(ci, &rd->bands_11ac, reg,
|
||||
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D |
|
||||
IEEE80211_CHAN_VHT40D,
|
||||
&dc->dc_chaninfo);
|
||||
}
|
||||
|
||||
/* VHT80 */
|
||||
/* XXX dc_vhtcap? */
|
||||
if (1) {
|
||||
regdomain_addchans(ci, &rd->bands_11ac, reg,
|
||||
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U |
|
||||
IEEE80211_CHAN_VHT80,
|
||||
&dc->dc_chaninfo);
|
||||
regdomain_addchans(ci, &rd->bands_11ac, reg,
|
||||
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D |
|
||||
IEEE80211_CHAN_VHT80,
|
||||
&dc->dc_chaninfo);
|
||||
}
|
||||
|
||||
/* XXX TODO: VHT80_80, VHT160 */
|
||||
}
|
||||
|
||||
if (!LIST_EMPTY(&rd->bands_11ng) && dc->dc_htcaps != 0) {
|
||||
regdomain_addchans(ci, &rd->bands_11ng, reg,
|
||||
IEEE80211_CHAN_G | IEEE80211_CHAN_HT20,
|
||||
@ -2435,6 +2586,8 @@ getflags(int flags)
|
||||
if (flags & IEEE80211_NODE_HTCOMPAT)
|
||||
*cp++ = '+';
|
||||
}
|
||||
if (flags & IEEE80211_NODE_VHT)
|
||||
*cp++ = 'V';
|
||||
if (flags & IEEE80211_NODE_WPS)
|
||||
*cp++ = 'W';
|
||||
if (flags & IEEE80211_NODE_TSN)
|
||||
@ -3574,14 +3727,31 @@ get_chaninfo(const struct ieee80211_channel *c, int precise,
|
||||
if (IEEE80211_IS_CHAN_TURBO(c))
|
||||
strlcat(buf, " Turbo", bsize);
|
||||
if (precise) {
|
||||
if (IEEE80211_IS_CHAN_HT20(c))
|
||||
/* XXX should make VHT80U, VHT80D */
|
||||
if (IEEE80211_IS_CHAN_VHT80(c) &&
|
||||
IEEE80211_IS_CHAN_HT40D(c))
|
||||
strlcat(buf, " vht/80-", bsize);
|
||||
else if (IEEE80211_IS_CHAN_VHT80(c) &&
|
||||
IEEE80211_IS_CHAN_HT40U(c))
|
||||
strlcat(buf, " vht/80+", bsize);
|
||||
else if (IEEE80211_IS_CHAN_VHT80(c))
|
||||
strlcat(buf, " vht/80", bsize);
|
||||
else if (IEEE80211_IS_CHAN_VHT40D(c))
|
||||
strlcat(buf, " vht/40-", bsize);
|
||||
else if (IEEE80211_IS_CHAN_VHT40U(c))
|
||||
strlcat(buf, " vht/40+", bsize);
|
||||
else if (IEEE80211_IS_CHAN_VHT20(c))
|
||||
strlcat(buf, " vht/20", bsize);
|
||||
else if (IEEE80211_IS_CHAN_HT20(c))
|
||||
strlcat(buf, " ht/20", bsize);
|
||||
else if (IEEE80211_IS_CHAN_HT40D(c))
|
||||
strlcat(buf, " ht/40-", bsize);
|
||||
else if (IEEE80211_IS_CHAN_HT40U(c))
|
||||
strlcat(buf, " ht/40+", bsize);
|
||||
} else {
|
||||
if (IEEE80211_IS_CHAN_HT(c))
|
||||
if (IEEE80211_IS_CHAN_VHT(c))
|
||||
strlcat(buf, " vht", bsize);
|
||||
else if (IEEE80211_IS_CHAN_HT(c))
|
||||
strlcat(buf, " ht", bsize);
|
||||
}
|
||||
return buf;
|
||||
@ -3612,6 +3782,16 @@ print_chaninfo(const struct ieee80211_channel *c, int verb)
|
||||
static int
|
||||
chanpref(const struct ieee80211_channel *c)
|
||||
{
|
||||
if (IEEE80211_IS_CHAN_VHT160(c))
|
||||
return 80;
|
||||
if (IEEE80211_IS_CHAN_VHT80_80(c))
|
||||
return 75;
|
||||
if (IEEE80211_IS_CHAN_VHT80(c))
|
||||
return 70;
|
||||
if (IEEE80211_IS_CHAN_VHT40(c))
|
||||
return 60;
|
||||
if (IEEE80211_IS_CHAN_VHT20(c))
|
||||
return 50;
|
||||
if (IEEE80211_IS_CHAN_HT40(c))
|
||||
return 40;
|
||||
if (IEEE80211_IS_CHAN_HT20(c))
|
||||
@ -3807,6 +3987,11 @@ list_capabilities(int s)
|
||||
putchar('\n');
|
||||
printb("htcaps", dc->dc_htcaps, IEEE80211_HTCAP_BITS);
|
||||
}
|
||||
if (dc->dc_vhtcaps != 0 || verbose) {
|
||||
putchar('\n');
|
||||
printb("vhtcaps", dc->dc_vhtcaps, IEEE80211_VHTCAP_BITS);
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
if (verbose) {
|
||||
chaninfo = &dc->dc_chaninfo; /* XXX */
|
||||
@ -4847,6 +5032,30 @@ ieee80211_status(int s)
|
||||
}
|
||||
}
|
||||
|
||||
if (IEEE80211_IS_CHAN_VHT(c) || verbose) {
|
||||
getvhtconf(s);
|
||||
if (vhtconf & 0x1)
|
||||
LINE_CHECK("vht");
|
||||
else
|
||||
LINE_CHECK("-vht");
|
||||
if (vhtconf & 0x2)
|
||||
LINE_CHECK("vht40");
|
||||
else
|
||||
LINE_CHECK("-vht40");
|
||||
if (vhtconf & 0x4)
|
||||
LINE_CHECK("vht80");
|
||||
else
|
||||
LINE_CHECK("-vht80");
|
||||
if (vhtconf & 0x8)
|
||||
LINE_CHECK("vht80p80");
|
||||
else
|
||||
LINE_CHECK("-vht80p80");
|
||||
if (vhtconf & 0x10)
|
||||
LINE_CHECK("vht160");
|
||||
else
|
||||
LINE_CHECK("-vht160");
|
||||
}
|
||||
|
||||
if (get80211val(s, IEEE80211_IOC_WME, &wme) != -1) {
|
||||
if (wme)
|
||||
LINE_CHECK("wme");
|
||||
@ -5426,6 +5635,16 @@ static struct cmd ieee80211_cmds[] = {
|
||||
DEF_CMD("-ht40", 0, set80211htconf),
|
||||
DEF_CMD("ht", 3, set80211htconf), /* NB: 20+40 */
|
||||
DEF_CMD("-ht", 0, set80211htconf),
|
||||
DEF_CMD("vht", 1, set80211vhtconf),
|
||||
DEF_CMD("-vht", 0, set80211vhtconf),
|
||||
DEF_CMD("vht40", 2, set80211vhtconf),
|
||||
DEF_CMD("-vht40", -2, set80211vhtconf),
|
||||
DEF_CMD("vht80", 4, set80211vhtconf),
|
||||
DEF_CMD("-vht80", -4, set80211vhtconf),
|
||||
DEF_CMD("vht80p80", 8, set80211vhtconf),
|
||||
DEF_CMD("-vht80p80", -8, set80211vhtconf),
|
||||
DEF_CMD("vht160", 16, set80211vhtconf),
|
||||
DEF_CMD("-vht160", -16, set80211vhtconf),
|
||||
DEF_CMD("rifs", 1, set80211rifs),
|
||||
DEF_CMD("-rifs", 0, set80211rifs),
|
||||
DEF_CMD("smps", IEEE80211_HTCAP_SMPS_ENA, set80211smps),
|
||||
|
Loading…
Reference in New Issue
Block a user