Index: head/sbin/ifconfig/ifieee80211.c =================================================================== --- head/sbin/ifconfig/ifieee80211.c +++ head/sbin/ifconfig/ifieee80211.c @@ -2405,7 +2405,31 @@ &dc->dc_chaninfo); } - /* XXX TODO: VHT80P80, VHT160 */ + /* VHT160 */ + if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160MHZ( + dc->dc_vhtcaps)) { + regdomain_addchans(ci, &rd->bands_11ac, reg, + IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U | + IEEE80211_CHAN_VHT160, + &dc->dc_chaninfo); + regdomain_addchans(ci, &rd->bands_11ac, reg, + IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D | + IEEE80211_CHAN_VHT160, + &dc->dc_chaninfo); + } + + /* VHT80P80 */ + if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160_80P80MHZ( + dc->dc_vhtcaps)) { + regdomain_addchans(ci, &rd->bands_11ac, reg, + IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U | + IEEE80211_CHAN_VHT80P80, + &dc->dc_chaninfo); + regdomain_addchans(ci, &rd->bands_11ac, reg, + IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D | + IEEE80211_CHAN_VHT80P80, + &dc->dc_chaninfo); + } } if (!LIST_EMPTY(&rd->bands_11ng) && dc->dc_htcaps != 0) { Index: head/sys/net80211/ieee80211.h =================================================================== --- head/sys/net80211/ieee80211.h +++ head/sys/net80211/ieee80211.h @@ -815,6 +815,13 @@ #define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160_80P80MHZ 2 #define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_RESERVED 3 +#define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160MHZ(_vhtcaps) \ + (_IEEE80211_MASKSHIFT(_vhtcaps, IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK) >= \ + IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160MHZ) +#define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160_80P80MHZ(_vhtcaps) \ + (_IEEE80211_MASKSHIFT(_vhtcaps, IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK) == \ + IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160_80P80MHZ) + #define IEEE80211_VHTCAP_RXLDPC 0x00000010 #define IEEE80211_VHTCAP_RXLDPC_S 4 Index: head/sys/net80211/ieee80211.c =================================================================== --- head/sys/net80211/ieee80211.c +++ head/sys/net80211/ieee80211.c @@ -1163,6 +1163,12 @@ { 0, 0 } }; +struct vht_chan_range vht160_chan_ranges[] = { + { 5170, 5330 }, + { 5490, 5650 }, + { 0, 0 } +}; + static int set_vht_extchan(struct ieee80211_channel *c) { @@ -1177,8 +1183,24 @@ } if (IEEE80211_IS_CHAN_VHT160(c)) { - printf("%s: TODO VHT160 channel (ieee=%d, flags=0x%08x)\n", - __func__, c->ic_ieee, c->ic_flags); + for (i = 0; vht160_chan_ranges[i].freq_start != 0; i++) { + if (c->ic_freq >= vht160_chan_ranges[i].freq_start && + c->ic_freq < vht160_chan_ranges[i].freq_end) { + int midpoint; + + midpoint = vht160_chan_ranges[i].freq_start + 80; + c->ic_vht_ch_freq1 = + ieee80211_mhz2ieee(midpoint, c->ic_flags); + c->ic_vht_ch_freq2 = 0; +#if 0 + printf("%s: %d, freq=%d, midpoint=%d, freq1=%d, freq2=%d\n", + __func__, c->ic_ieee, c->ic_freq, midpoint, + c->ic_vht_ch_freq1, c->ic_vht_ch_freq2); +#endif + return (1); + } + } + return (0); } if (IEEE80211_IS_CHAN_VHT80(c)) { @@ -1225,11 +1247,24 @@ /* * Return whether the current channel could possibly be a part of - * a VHT80 channel. + * a VHT80/VHT160 channel. * * This doesn't check that the whole range is in the allowed list * according to regulatory. */ +static bool +is_vht160_valid_freq(uint16_t freq) +{ + int i; + + for (i = 0; vht160_chan_ranges[i].freq_start != 0; i++) { + if (freq >= vht160_chan_ranges[i].freq_start && + freq < vht160_chan_ranges[i].freq_end) + return (true); + } + return (false); +} + static int is_vht80_valid_freq(uint16_t freq) { @@ -1410,18 +1445,17 @@ * Add one 20 MHz channel into specified channel list. * You MUST NOT mix bands when calling this. It will not add 5ghz * channels if you have any B/G/N band bit set. - * This also does not support 40/80/160/80+80. + * The _cbw() variant does also support HT40/VHT80/160/80+80. */ -/* XXX VHT */ int -ieee80211_add_channel(struct ieee80211_channel chans[], int maxchans, +ieee80211_add_channel_cbw(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 chan_flags, const uint8_t bands[], int cbw_flags) { uint32_t flags[IEEE80211_MODE_MAX]; int i, error; - getflags(bands, flags, 0); + getflags(bands, flags, cbw_flags); KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__)); error = addchan(chans, maxchans, nchans, ieee, freq, maxregpower, @@ -1434,6 +1468,16 @@ return (error); } +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[]) +{ + + return (ieee80211_add_channel_cbw(chans, maxchans, nchans, ieee, freq, + maxregpower, chan_flags, bands, 0)); +} + static struct ieee80211_channel * findchannel(struct ieee80211_channel chans[], int nchans, uint16_t freq, uint32_t flags) @@ -1573,7 +1617,11 @@ is_vht = !! (flags[j] & IEEE80211_CHAN_VHT); /* XXX TODO FIXME VHT80P80. */ - /* XXX TODO FIXME VHT160. */ + + /* Test for VHT160 analogue to the VHT80 below. */ + if (is_vht && flags[j] & IEEE80211_CHAN_VHT160) + if (! is_vht160_valid_freq(freq)) + continue; /* * Test for VHT80. Index: head/sys/net80211/ieee80211_regdomain.c =================================================================== --- head/sys/net80211/ieee80211_regdomain.c +++ head/sys/net80211/ieee80211_regdomain.c @@ -151,11 +151,10 @@ if (isset(bands, IEEE80211_MODE_VHT_5GHZ)) { cbw_flags |= NET80211_CBW_FLAG_HT40; /* Make sure this is set; or assert? */ cbw_flags |= NET80211_CBW_FLAG_VHT80; - if (_IEEE80211_MASKSHIFT(ic->ic_vhtcaps, - IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK) >= 1) + if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160MHZ(ic->ic_vhtcaps)) cbw_flags |= NET80211_CBW_FLAG_VHT160; - if (_IEEE80211_MASKSHIFT(ic->ic_vhtcaps, - IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK) == 2) + if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160_80P80MHZ( + ic->ic_vhtcaps)) cbw_flags |= NET80211_CBW_FLAG_VHT80P80; ieee80211_add_channel_list_5ghz(chans, IEEE80211_CHAN_MAX, nchans, def_chan_5ghz_band1, nitems(def_chan_5ghz_band1), Index: head/sys/net80211/ieee80211_var.h =================================================================== --- head/sys/net80211/ieee80211_var.h +++ head/sys/net80211/ieee80211_var.h @@ -772,6 +772,8 @@ int ieee80211_chan2ieee(struct ieee80211com *, const struct ieee80211_channel *); u_int ieee80211_ieee2mhz(u_int, u_int); +int ieee80211_add_channel_cbw(struct ieee80211_channel[], int, int *, + uint8_t, uint16_t, int8_t, uint32_t, const uint8_t[], 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 *, Index: head/sys/net80211/ieee80211_vht.c =================================================================== --- head/sys/net80211/ieee80211_vht.c +++ head/sys/net80211/ieee80211_vht.c @@ -153,13 +153,10 @@ IEEE80211_FVHT_VHT | IEEE80211_FVHT_USEVHT40 | IEEE80211_FVHT_USEVHT80; -#if 0 - /* XXX TODO: enable VHT80+80, VHT160 capabilities */ - if (XXX TODO FIXME) + if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160MHZ(vap->iv_vhtcaps)) vap->iv_flags_vht |= IEEE80211_FVHT_USEVHT160; - if (XXX TODO FIXME) + if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160_80P80MHZ(vap->iv_vhtcaps)) vap->iv_flags_vht |= IEEE80211_FVHT_USEVHT80P80; -#endif memcpy(&vap->iv_vht_mcsinfo, &ic->ic_vht_mcsinfo, sizeof(struct ieee80211_vht_mcs_info)); @@ -202,15 +199,11 @@ return; /* Channel width */ - ic_printf(ic, "[VHT] Channel Widths: 20MHz, 40MHz, 80MHz"); - if (_IEEE80211_MASKSHIFT(ic->ic_vhtcaps, - IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK) >= 1) - printf(" 160MHz"); - if (_IEEE80211_MASKSHIFT(ic->ic_vhtcaps, - IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK) == 2) - printf(" 80+80MHz"); - printf("\n"); - + ic_printf(ic, "[VHT] Channel Widths: 20MHz, 40MHz, 80MHz%s%s\n", + (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160MHZ(ic->ic_vhtcaps)) ? + ", 160MHz" : "", + (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160_80P80MHZ(ic->ic_vhtcaps)) ? + ", 80+80MHz" : ""); /* Features */ ic_printf(ic, "[VHT] Features: %b\n", ic->ic_vhtcaps, IEEE80211_VHTCAP_BITS);