Index: sys/net80211/ieee80211.c =================================================================== --- sys/net80211/ieee80211.c (revision 311042) +++ sys/net80211/ieee80211.c (working copy) @@ -54,6 +54,7 @@ #include #endif #include +#include #include @@ -90,6 +91,7 @@ static void ieee80211_syncflag_locked(struct ieee80211com *ic, int flag); static void ieee80211_syncflag_ht_locked(struct ieee80211com *ic, int flag); static void ieee80211_syncflag_ext_locked(struct ieee80211com *ic, int flag); +static void ieee80211_syncflag_vht_locked(struct ieee80211com *ic, int flag); static int ieee80211_media_setup(struct ieee80211com *ic, struct ifmedia *media, int caps, int addsta, ifm_change_cb_t media_change, ifm_stat_cb_t media_stat); @@ -147,10 +149,13 @@ */ if (c->ic_ieee == 0) c->ic_ieee = ieee80211_mhz2ieee(c->ic_freq,c->ic_flags); + + /* XXX VHT */ if (IEEE80211_IS_CHAN_HT40(c) && c->ic_extieee == 0) c->ic_extieee = ieee80211_mhz2ieee(c->ic_freq + (IEEE80211_IS_CHAN_HT40U(c) ? 20 : -20), c->ic_flags); + /* default max tx power to max regulatory */ if (c->ic_maxpower == 0) c->ic_maxpower = 2*c->ic_maxregpower; @@ -180,6 +185,10 @@ setbit(ic->ic_modecaps, IEEE80211_MODE_11NA); if (IEEE80211_IS_CHAN_HTG(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11NG); + if (IEEE80211_IS_CHAN_VHTA(c)) + setbit(ic->ic_modecaps, IEEE80211_MODE_VHT_5GHZ); + if (IEEE80211_IS_CHAN_VHTG(c)) + setbit(ic->ic_modecaps, IEEE80211_MODE_VHT_2GHZ); } /* initialize candidate channels to all available */ memcpy(ic->ic_chan_active, ic->ic_chan_avail, @@ -207,6 +216,8 @@ DEFAULTRATES(IEEE80211_MODE_QUARTER, ieee80211_rateset_quarter); DEFAULTRATES(IEEE80211_MODE_11NA, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_11NG, ieee80211_rateset_11g); + DEFAULTRATES(IEEE80211_MODE_VHT_5GHZ, ieee80211_rateset_11a); + DEFAULTRATES(IEEE80211_MODE_VHT_2GHZ, ieee80211_rateset_11g); /* * Setup required information to fill the mcsset field, if driver did @@ -334,6 +345,7 @@ ieee80211_superg_attach(ic); #endif ieee80211_ht_attach(ic); + ieee80211_vht_attach(ic); ieee80211_scan_attach(ic); ieee80211_regdomain_attach(ic); ieee80211_dfs_attach(ic); @@ -377,6 +389,7 @@ #ifdef IEEE80211_SUPPORT_SUPERG ieee80211_superg_detach(ic); #endif + ieee80211_vht_detach(ic); ieee80211_ht_detach(ic); /* NB: must be called before ieee80211_node_detach */ ieee80211_proto_detach(ic); @@ -506,8 +519,15 @@ vap->iv_flags_ext = ic->ic_flags_ext; vap->iv_flags_ven = ic->ic_flags_ven; vap->iv_caps = ic->ic_caps &~ IEEE80211_C_OPMODE; + + /* 11n capabilities - XXX methodize */ vap->iv_htcaps = ic->ic_htcaps; vap->iv_htextcaps = ic->ic_htextcaps; + + /* 11ac capabilities - XXX methodize */ + vap->iv_vhtcaps = ic->ic_vhtcaps; + vap->iv_vhtextcaps = ic->ic_vhtextcaps; + vap->iv_opmode = opmode; vap->iv_caps |= ieee80211_opcap[opmode]; IEEE80211_ADDR_COPY(vap->iv_myaddr, ic->ic_macaddr); @@ -592,6 +612,7 @@ ieee80211_superg_vattach(vap); #endif ieee80211_ht_vattach(vap); + ieee80211_vht_vattach(vap); ieee80211_scan_vattach(vap); ieee80211_regdomain_vattach(vap); ieee80211_radiotap_vattach(vap); @@ -652,6 +673,7 @@ ieee80211_syncflag_locked(ic, IEEE80211_F_BURST); ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT); ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40); + ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_VHT); IEEE80211_UNLOCK(ic); return 1; @@ -699,6 +721,7 @@ ieee80211_syncflag_locked(ic, IEEE80211_F_BURST); ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT); ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40); + ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_VHT); /* NB: this handles the bpfdetach done below */ ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_BPF); if (vap->iv_ifflags & IFF_PROMISC) @@ -715,6 +738,7 @@ #ifdef IEEE80211_SUPPORT_SUPERG ieee80211_superg_vdetach(vap); #endif + ieee80211_vht_vdetach(vap); ieee80211_ht_vdetach(vap); /* NB: must be before ieee80211_node_vdetach */ ieee80211_proto_vdetach(vap); @@ -853,6 +877,46 @@ } /* + * Synchronize flags_vht bit state in the com structure + * according to the state of all vap's. This is used, + * for example, to handle state changes via ioctls. + */ +static void +ieee80211_syncflag_vht_locked(struct ieee80211com *ic, int flag) +{ + struct ieee80211vap *vap; + int bit; + + IEEE80211_LOCK_ASSERT(ic); + + bit = 0; + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if (vap->iv_flags_vht & flag) { + bit = 1; + break; + } + if (bit) + ic->ic_flags_vht |= flag; + else + ic->ic_flags_vht &= ~flag; +} + +void +ieee80211_syncflag_vht(struct ieee80211vap *vap, int flag) +{ + struct ieee80211com *ic = vap->iv_ic; + + IEEE80211_LOCK(ic); + if (flag < 0) { + flag = -flag; + vap->iv_flags_vht &= ~flag; + } else + vap->iv_flags_vht |= flag; + ieee80211_syncflag_vht_locked(ic, flag); + IEEE80211_UNLOCK(ic); +} + +/* * Synchronize flags_ext bit state in the com structure * according to the state of all vap's. This is used, * for example, to handle state changes via ioctls. @@ -1003,6 +1067,9 @@ } } +/* + * XXX VHT + */ static __inline void set_extchan(struct ieee80211_channel *c) { @@ -1019,6 +1086,9 @@ c->ic_extieee = 0; } +/* + * XXX VHT + */ static int addchan(struct ieee80211_channel chans[], int maxchans, int *nchans, uint8_t ieee, uint16_t freq, int8_t maxregpower, uint32_t flags) @@ -1034,6 +1104,7 @@ c->ic_maxregpower = maxregpower; c->ic_maxpower = 2 * maxregpower; c->ic_flags = flags; + /* XXX VHT */ set_extchan(c); return (0); @@ -1058,6 +1129,9 @@ return (0); } +/* + * XXX VHT-2GHz + */ static void getflags_2ghz(const uint8_t bands[], uint32_t flags[], int ht40) { @@ -1077,8 +1151,11 @@ flags[nmodes] = 0; } +/* + * XXX VHT-5GHz + */ static void -getflags_5ghz(const uint8_t bands[], uint32_t flags[], int ht40) +getflags_5ghz(const uint8_t bands[], uint32_t flags[], int ht40, int vht80) { int nmodes; @@ -1091,22 +1168,52 @@ flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U; flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D; } + + /* + * VHT builds on top of HT. I should look at unifying it a bit. + */ + if (isset(bands, IEEE80211_MODE_VHT_5GHZ)) { + flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT20 | + IEEE80211_CHAN_VHT20; + if (ht40) { + /* + * XXX TODO: maybe just have a CHAN_VHT flag, and + * infer VHT40 == VHT + HT40? + */ + flags[nmodes++] = IEEE80211_CHAN_A | + IEEE80211_CHAN_HT40U | IEEE80211_CHAN_VHT40U; + flags[nmodes++] = IEEE80211_CHAN_A | + IEEE80211_CHAN_HT40D | IEEE80211_CHAN_VHT40D; + } + if (vht80) { + flags[nmodes++] = IEEE80211_CHAN_A | + IEEE80211_CHAN_HT40U | IEEE80211_CHAN_VHT40U | + IEEE80211_CHAN_VHT80; + flags[nmodes++] = IEEE80211_CHAN_A | + IEEE80211_CHAN_HT40D | IEEE80211_CHAN_VHT40D | + IEEE80211_CHAN_VHT80; + } + } + /* XXX VHT80+80 */ + /* XXX VHT160 */ flags[nmodes] = 0; } static void -getflags(const uint8_t bands[], uint32_t flags[], int ht40) +getflags(const uint8_t bands[], uint32_t flags[], int ht40, int vht80) { flags[0] = 0; if (isset(bands, IEEE80211_MODE_11A) || - isset(bands, IEEE80211_MODE_11NA)) { + isset(bands, IEEE80211_MODE_11NA) || + isset(bands, IEEE80211_MODE_VHT_5GHZ)) { if (isset(bands, IEEE80211_MODE_11B) || isset(bands, IEEE80211_MODE_11G) || - isset(bands, IEEE80211_MODE_11NG)) + isset(bands, IEEE80211_MODE_11NG) || + isset(bands, IEEE80211_MODE_VHT_2GHZ)) return; - getflags_5ghz(bands, flags, ht40); + getflags_5ghz(bands, flags, ht40, vht80); } else getflags_2ghz(bands, flags, ht40); } @@ -1122,7 +1229,7 @@ uint32_t flags[IEEE80211_MODE_MAX]; int i, error; - getflags(bands, flags, 0); + getflags(bands, flags, 0, 0); KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__)); error = addchan(chans, maxchans, nchans, ieee, freq, maxregpower, @@ -1156,6 +1263,7 @@ /* * Add 40 MHz channel pair into specified channel list. */ +/* XXX VHT */ int ieee80211_add_channel_ht40(struct ieee80211_channel chans[], int maxchans, int *nchans, uint8_t ieee, int8_t maxregpower, uint32_t flags) @@ -1252,6 +1360,7 @@ for (i = 0; i < nieee; i++) { freq = ieee80211_ieee2mhz(ieee[i], flags[0]); for (j = 0; flags[j] != 0; j++) { + /* XXX VHT? */ if (flags[j] & IEEE80211_CHAN_HT40D) if (i == 0 || ieee[i] < ieee[0] + 4 || freq - 20 != @@ -1286,6 +1395,7 @@ { uint32_t flags[IEEE80211_MODE_MAX]; + /* XXX no VHT80 for now */ getflags_2ghz(bands, flags, ht40); KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__)); @@ -1299,7 +1409,8 @@ { uint32_t flags[IEEE80211_MODE_MAX]; - getflags_5ghz(bands, flags, ht40); + /* XXX no VHT80 for now */ + getflags_5ghz(bands, flags, ht40, 0); KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__)); return (add_chanlist(chans, maxchans, nchans, ieee, nieee, flags)); @@ -1438,6 +1549,8 @@ [IEEE80211_MODE_QUARTER] = IFM_IEEE80211_11A, /* XXX */ [IEEE80211_MODE_11NA] = IFM_IEEE80211_11NA, [IEEE80211_MODE_11NG] = IFM_IEEE80211_11NG, + [IEEE80211_MODE_VHT_2GHZ] = IFM_IEEE80211_VHT2G, + [IEEE80211_MODE_VHT_5GHZ] = IFM_IEEE80211_VHT5G, }; u_int mopt; @@ -1550,6 +1663,19 @@ if (rate > maxrate) maxrate = rate; } + + /* + * Add VHT media. + */ + for (; mode <= IEEE80211_MODE_VHT_5GHZ; mode++) { + if (isclr(ic->ic_modecaps, mode)) + continue; + addmedia(media, caps, addsta, mode, IFM_AUTO); + addmedia(media, caps, addsta, mode, IFM_IEEE80211_VHT); + + /* XXX TODO: VHT maxrate */ + } + return maxrate; } @@ -1585,6 +1711,7 @@ printf("\n"); } ieee80211_ht_announce(ic); + ieee80211_vht_announce(ic); } void Index: sys/net80211/ieee80211.h =================================================================== --- sys/net80211/ieee80211.h (revision 311042) +++ sys/net80211/ieee80211.h (working copy) @@ -839,6 +839,11 @@ #define IEEE80211_VHTCAP_RX_ANTENNA_PATTERN 0x10000000 #define IEEE80211_VHTCAP_TX_ANTENNA_PATTERN 0x20000000 +#define IEEE80211_VHTCAP_BITS \ + "\20\1MPDU7991\2MPDU11454\3CHAN160\4CHAN8080\5RXLDPC\6SHORTGI80" \ + "\7SHORTGI160\10RXSTBC1\11RXSTBC2\12RXSTBC3\13RXSTBC4\14BFERCAP" \ + "\15BFEECAP\27VHT" + /* * VHT Transmit Power Envelope element - 802.11ac-2013 8.4.2.164 * Index: sys/net80211/ieee80211_ht.c =================================================================== --- sys/net80211/ieee80211_ht.c (revision 311042) +++ sys/net80211/ieee80211_ht.c (working copy) @@ -1497,6 +1497,10 @@ * channel only; the caller is responsible for insuring any * required channel change is done (e.g. in sta mode when * parsing the contents of a beacon frame). + * + * XXX TODO VHT: In 11ac mode, what should be done here? + * We don't want to fall back to HT only channels when + * operating in VHT mode. */ static int htinfo_update_chw(struct ieee80211_node *ni, int htflags) @@ -1506,6 +1510,12 @@ int chanflags; int ret = 0; + if (ni->ni_chan->ic_flags & IEEE80211_CHAN_VHT) { + printf("%s: TODO: handle VHT with chanwidth change!\n", + __func__); + return (0); + } + chanflags = (ni->ni_chan->ic_flags &~ IEEE80211_CHAN_HT) | htflags; if (chanflags != ni->ni_chan->ic_flags) { /* XXX not right for ht40- */ @@ -2229,6 +2239,10 @@ dialogtoken = (tokens+1) % 63; /* XXX */ tid = tap->txa_tid; + + /* + * XXX TODO: This is racy with any other parallel TX going on. :( + */ tap->txa_start = ni->ni_txseqs[tid]; args[0] = dialogtoken; Index: sys/net80211/ieee80211_input.c =================================================================== --- sys/net80211/ieee80211_input.c (revision 311042) +++ sys/net80211/ieee80211_input.c (working copy) @@ -629,6 +629,12 @@ } } break; + case IEEE80211_ELEMID_VHT_CAP: + scan->vhtcap = frm; + break; + case IEEE80211_ELEMID_VHT_OPMODE: + scan->vhtopmode = frm; + break; default: IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID, wh, "unhandled", @@ -718,6 +724,19 @@ sizeof(struct ieee80211_ie_htinfo)-2, scan->htinfo = NULL); } + + /* Process VHT IEs */ + if (scan->vhtcap != NULL) { + IEEE80211_VERIFY_LENGTH(scan->vhtcap[1], + sizeof(struct ieee80211_ie_vhtcap) - 2, + scan->vhtcap = NULL); + } + if (scan->vhtopmode != NULL) { + IEEE80211_VERIFY_LENGTH(scan->vhtopmode[1], + sizeof(struct ieee80211_ie_vht_operation) - 2, + scan->vhtopmode = NULL); + } + return scan->status; } @@ -838,6 +857,9 @@ } break; #endif + case IEEE80211_ACTION_CAT_VHT: + printf("%s: TODO: VHT handling!\n", __func__); + break; } return 0; } Index: sys/net80211/ieee80211_ioctl.c =================================================================== --- sys/net80211/ieee80211_ioctl.c (revision 311042) +++ sys/net80211/ieee80211_ioctl.c (working copy) @@ -1135,6 +1135,15 @@ if (vap->iv_flags_ht & IEEE80211_FHT_STBC_RX) ireq->i_val |= 2; break; + + /* VHT */ + case IEEE80211_IOC_VHTCONF: + if (vap->iv_flags_vht & IEEE80211_FVHT_VHT) { + ireq->i_val = 1; + } else + ireq->i_val = 0; + break; + default: error = ieee80211_ioctl_getdefault(vap, ireq); break; @@ -1869,6 +1878,7 @@ /* NB: handled specially below */ [IEEE80211_MODE_11NA] = IEEE80211_CHAN_A, [IEEE80211_MODE_11NG] = IEEE80211_CHAN_G, + [IEEE80211_MODE_VHT_5GHZ] = IEEE80211_CHAN_A, }; u_int modeflags; int i; @@ -1893,11 +1903,27 @@ !find11gchannel(ic, i, c->ic_freq)) return c; } else { - /* must check HT specially */ + /* must check VHT specifically */ + if ((mode == IEEE80211_MODE_VHT_5GHZ || + mode == IEEE80211_MODE_VHT_2GHZ) && + !IEEE80211_IS_CHAN_VHT(c)) + continue; + + /* + * Must check HT specially - only match on HT, + * not HT+VHT channels + */ if ((mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG) && !IEEE80211_IS_CHAN_HT(c)) continue; + + if ((mode == IEEE80211_MODE_11NA || + mode == IEEE80211_MODE_11NG) && + IEEE80211_IS_CHAN_VHT(c)) + continue; + + /* Check that the modeflags above match */ if ((c->ic_flags & modeflags) == modeflags) return c; } @@ -2031,6 +2057,8 @@ * 11a channel returned, * if 11ng is requested, find the ht version of any * 11g channel returned, + * TODO: if 11ac is requested, find the 11ac version + * of any 11a/11na channel returned, * otherwise we should be ok with what we've got. */ switch (vap->iv_des_mode) { @@ -2067,6 +2095,15 @@ c = c2; } break; + /* XXX TODO: VHT_2GHZ */ + case IEEE80211_MODE_VHT_5GHZ: + if (IEEE80211_IS_CHAN_A(c)) { + c2 = findchannel(ic, ireq->i_val, + IEEE80211_MODE_VHT_5GHZ); + if (c2 != NULL) + c = c2; + } + break; default: /* NB: no static turboG */ break; } @@ -3321,6 +3358,16 @@ if (isvapht(vap)) error = ERESTART; break; + + /* VHT */ + case IEEE80211_IOC_VHTCONF: + if (ireq->i_val & 1) + ieee80211_syncflag_vht(vap, IEEE80211_FVHT_VHT); + else + ieee80211_syncflag_vht(vap, -IEEE80211_FVHT_VHT); + error = ENETRESET; + break; + default: error = ieee80211_ioctl_setdefault(vap, ireq); break; Index: sys/net80211/ieee80211_ioctl.h =================================================================== --- sys/net80211/ieee80211_ioctl.h (revision 311042) +++ sys/net80211/ieee80211_ioctl.h (working copy) @@ -556,6 +556,7 @@ uint32_t dc_drivercaps; /* general driver caps */ uint32_t dc_cryptocaps; /* hardware crypto support */ uint32_t dc_htcaps; /* HT/802.11n support */ + uint32_t dc_vhtcaps; /* VHT/802.11ac capabilities */ struct ieee80211req_chaninfo dc_chaninfo; }; #define IEEE80211_DEVCAPS_SIZE(_nchan) \ @@ -704,6 +705,9 @@ #define IEEE80211_IOC_STBC 113 /* STBC Tx/RX (on, off) */ #define IEEE80211_IOC_LDPC 114 /* LDPC Tx/RX (on, off) */ +/* VHT */ +#define IEEE80211_IOC_VHTCONF 130 /* VHT config (off, on (TBD: widths) */ + #define IEEE80211_IOC_MESH_ID 170 /* mesh identifier */ #define IEEE80211_IOC_MESH_AP 171 /* accepting peerings */ #define IEEE80211_IOC_MESH_FWRD 172 /* forward frames */ Index: sys/net80211/ieee80211_node.c =================================================================== --- sys/net80211/ieee80211_node.c (revision 311042) +++ sys/net80211/ieee80211_node.c (working copy) @@ -53,6 +53,7 @@ #include #include #include +#include #include @@ -412,9 +413,13 @@ /* XXX TODO: other bits and pieces - eg fast-frames? */ /* If we're an 11n channel then initialise the 11n bits */ - if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { + if (IEEE80211_IS_CHAN_VHT(ni->ni_chan)) { /* XXX what else? */ ieee80211_ht_node_init(ni); + ieee80211_vht_node_init(ni); + } else if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { + /* XXX what else? */ + ieee80211_ht_node_init(ni); } (void) ieee80211_sta_join1(ieee80211_ref_node(ni)); @@ -717,6 +722,7 @@ { struct ieee80211_channel *c; + /* XXX VHT? */ c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan, gethtadjustflags(ic)); if (c != ic->ic_curchan) { ic->ic_curchan = c; @@ -743,6 +749,7 @@ * set of running vap's. This assumes we are called * after ni_chan is setup for each vap. */ + /* XXX VHT? */ /* NB: this assumes IEEE80211_FHT_USEHT40 > IEEE80211_FHT_HT */ if (flags > ieee80211_htchanflags(c)) c = ieee80211_ht_adjust_channel(ic, c, flags); @@ -896,9 +903,13 @@ if (ni->ni_ies.tdma_ie != NULL) ieee80211_parse_tdma(ni, ni->ni_ies.tdma_ie); #endif + if (ni->ni_ies.vhtcap_ie != NULL) + ieee80211_parse_vhtcap(ni, ni->ni_ies.vhtcap_ie); + if (ni->ni_ies.vhtopmode_ie != NULL) + ieee80211_parse_vhtopmode(ni, ni->ni_ies.vhtopmode_ie); - /* XXX parse VHT IEs */ /* XXX parse BSSLOAD IE */ + /* XXX parse TXPWRENV IE */ /* XXX parse APCHANREP IE */ } @@ -930,6 +941,22 @@ IEEE80211_F_JOIN | IEEE80211_F_DOBRS); ieee80211_setup_basic_htrates(ni, ni->ni_ies.htinfo_ie); } + + /* + * Setup VHT state for this node if it's available. + * Same as the above. + */ + if (ni->ni_ies.vhtopmode_ie != NULL && + ni->ni_ies.vhtcap_ie != NULL && + vap->iv_flags_vht & IEEE80211_FVHT_VHT) { + ieee80211_vht_node_init(ni); + ieee80211_vht_updateparams(ni, + ni->ni_ies.vhtcap_ie, + ni->ni_ies.vhtopmode_ie); + ieee80211_setup_vht_rates(ni, ni->ni_ies.vhtcap_ie, + ni->ni_ies.vhtopmode_ie); + } + /* XXX else check for ath FF? */ /* XXX QoS? Difficult given that WME config is specific to a master */ @@ -1102,8 +1129,10 @@ "power save mode off, %u sta's in ps mode", vap->iv_ps_sta); } /* - * Cleanup any HT-related state. + * Cleanup any VHT and HT-related state. */ + if (ni->ni_flags & IEEE80211_NODE_VHT) + ieee80211_vht_node_cleanup(ni); if (ni->ni_flags & IEEE80211_NODE_HT) ieee80211_ht_node_cleanup(ni); #ifdef IEEE80211_SUPPORT_SUPERG @@ -1423,6 +1452,7 @@ if (vap->iv_flags & IEEE80211_F_FF) ni->ni_flags |= IEEE80211_NODE_FF; #endif + /* XXX VHT */ if ((ic->ic_htcaps & IEEE80211_HTC_HT) && (vap->iv_flags_ht & IEEE80211_FHT_HT)) { /* @@ -1431,6 +1461,9 @@ * ni_chan will be adjusted to an HT channel. */ ieee80211_ht_wds_init(ni); + if (vap->iv_flags_vht & IEEE80211_FVHT_VHT) { + printf("%s: TODO: vht_wds_init\n", __func__); + } } else { struct ieee80211_channel *c = ni->ni_chan; /* @@ -1638,7 +1671,7 @@ const struct ieee80211_frame *wh, const struct ieee80211_scanparams *sp) { - int do_ht_setup = 0; + int do_ht_setup = 0, do_vht_setup = 0; ni->ni_esslen = sp->ssid[1]; memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); @@ -1675,6 +1708,13 @@ (ni->ni_vap->iv_flags_ht & IEEE80211_FHT_HT)) { do_ht_setup = 1; } + + if ((ni->ni_ies.vhtcap_ie != NULL) && + (ni->ni_ies.vhtopmode_ie != NULL) && + (ni->ni_vap->iv_flags_vht & IEEE80211_FVHT_VHT)) { + do_vht_setup = 1; + } + } /* NB: must be after ni_chan is setup */ @@ -1697,6 +1737,17 @@ IEEE80211_F_JOIN | IEEE80211_F_DOBRS); ieee80211_setup_basic_htrates(ni, ni->ni_ies.htinfo_ie); + + if (do_vht_setup) { + ieee80211_vht_node_init(ni); + ieee80211_vht_updateparams(ni, + ni->ni_ies.vhtcap_ie, + ni->ni_ies.vhtopmode_ie); + ieee80211_setup_vht_rates(ni, + ni->ni_ies.vhtcap_ie, + ni->ni_ies.vhtopmode_ie); + } + ieee80211_node_setuptxparms(ni); ieee80211_ratectl_node_init(ni); @@ -2365,6 +2416,7 @@ IEEE80211_LOCK(ic); ieee80211_erp_timeout(ic); ieee80211_ht_timeout(ic); + ieee80211_vht_timeout(ic); IEEE80211_UNLOCK(ic); } callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz, @@ -2594,6 +2646,8 @@ if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan)) ieee80211_ht_node_join(ni); + if (IEEE80211_IS_CHAN_VHT(ic->ic_bsschan)) + ieee80211_vht_node_join(ni); if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) && IEEE80211_IS_CHAN_FULL(ic->ic_bsschan)) ieee80211_node_join_11g(ni); @@ -2774,6 +2828,8 @@ vap->iv_sta_assoc--; ic->ic_sta_assoc--; + if (IEEE80211_IS_CHAN_VHT(ic->ic_bsschan)) + ieee80211_vht_node_leave(ni); if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan)) ieee80211_ht_node_leave(ni); if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan) && Index: sys/net80211/ieee80211_node.h =================================================================== --- sys/net80211/ieee80211_node.h (revision 311042) +++ sys/net80211/ieee80211_node.h (working copy) @@ -142,6 +142,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 */ uint16_t ni_associd; /* association ID */ uint16_t ni_vlan; /* vlan tag */ uint16_t ni_txpower; /* current transmit power */ Index: sys/net80211/ieee80211_output.c =================================================================== --- sys/net80211/ieee80211_output.c (revision 311042) +++ sys/net80211/ieee80211_output.c (working copy) @@ -764,6 +764,16 @@ } *(uint16_t *)&wh->i_dur[0] = 0; + /* + * XXX TODO: this is what the TX lock is for. + * Here we're incrementing sequence numbers, and they + * need to be in lock-step with what the driver is doing + * both in TX ordering and crypto encap (IV increment.) + * + * If the driver does seqno itself, then we can skip + * assigning sequence numbers here, and we can avoid + * requiring the TX lock. + */ tap = &ni->ni_tx_ampdu[tid]; if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) m->m_flags |= M_AMPDU_MPDU; @@ -1542,6 +1552,11 @@ if (is_amsdu) qos[0] |= IEEE80211_QOS_AMSDU; + /* + * XXX TODO TX lock is needed for atomic updates of sequence + * numbers. If the driver does it, then don't do it here; + * and we don't need the TX lock held. + */ if ((m->m_flags & M_AMPDU_MPDU) == 0) { /* * NB: don't assign a sequence # to potential @@ -1561,6 +1576,11 @@ M_SEQNO_SET(m, seqno); } } else { + /* + * XXX TODO TX lock is needed for atomic updates of sequence + * numbers. If the driver does it, then don't do it here; + * and we don't need the TX lock held. + */ seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; *(uint16_t *)wh->i_seq = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); @@ -2065,6 +2085,7 @@ * Send a probe request frame with the specified ssid * and any optional information element data. */ +/* XXX VHT? */ int ieee80211_send_probereq(struct ieee80211_node *ni, const uint8_t sa[IEEE80211_ADDR_LEN], @@ -2357,6 +2378,7 @@ case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: + /* XXX VHT? */ /* * asreq frame format * [2] capability information @@ -2483,6 +2505,7 @@ case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: + /* XXX VHT? */ /* * asresp frame format * [2] capability information @@ -2600,6 +2623,7 @@ * Space is left to prepend and 802.11 header at the * front but it's left to the caller to fill in. */ +/* XXX VHT? */ struct mbuf * ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy) { @@ -2934,6 +2958,7 @@ } } +/* XXX VHT? */ static void ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm, struct ieee80211_node *ni) @@ -3097,6 +3122,7 @@ /* * Allocate a beacon frame and fillin the appropriate bits. */ +/* XXX VHT? */ struct mbuf * ieee80211_beacon_alloc(struct ieee80211_node *ni) { @@ -3138,6 +3164,7 @@ * NB: we allocate the max space required for the TIM bitmap. * XXX how big is this? */ + /* XXX VHT? */ pktlen = 8 /* time stamp */ + sizeof(uint16_t) /* beacon interval */ + sizeof(uint16_t) /* capabilities */ @@ -3242,6 +3269,15 @@ } wh = mtod(m, struct ieee80211_frame *); + + /* + * XXX TODO Strictly speaking this should be incremented with the TX + * lock held so as to serialise access to the non-qos TID sequence + * number space. + * + * If the driver identifies it does its own TX seqno management then + * we can skip this (and still not do the TX seqno.) + */ seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; *(uint16_t *)&wh->i_seq[0] = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); @@ -3347,7 +3383,12 @@ timoff = 0; timlen = 1; } + + /* + * TODO: validate this! + */ if (timlen != bo->bo_tim_len) { + /* XXX VHT? */ /* copy up/down trailer */ int adjust = tie->tim_bitmap+timlen - bo->bo_tim_trailer; @@ -3407,6 +3448,7 @@ * drop the count. The actual change happens above * when the vap's count reaches the target count. */ + /* XXX VHT */ if (vap->iv_csa_count == 0) { memmove(&csa[1], csa, bo->bo_csa_trailer_len); bo->bo_erp += sizeof(*csa); Index: sys/net80211/ieee80211_proto.h =================================================================== --- sys/net80211/ieee80211_proto.h (revision 311042) +++ sys/net80211/ieee80211_proto.h (working copy) @@ -77,6 +77,7 @@ void ieee80211_allmulti(struct ieee80211vap *, bool); void ieee80211_syncflag(struct ieee80211vap *, int flag); void ieee80211_syncflag_ht(struct ieee80211vap *, int flag); +void ieee80211_syncflag_vht(struct ieee80211vap *, int flag); void ieee80211_syncflag_ext(struct ieee80211vap *, int flag); #define ieee80211_input(ni, m, rssi, nf) \ @@ -361,7 +362,8 @@ uint8_t *bo_csa; /* start of CSA element */ uint8_t *bo_quiet; /* start of Quiet element */ uint8_t *bo_meshconf; /* start of MESHCONF element */ - uint8_t *bo_spare[3]; + uint8_t *bo_vhtinfo; /* start of VHT info element (XXX VHTCAP?) */ + uint8_t *bo_spare[2]; }; struct mbuf *ieee80211_beacon_alloc(struct ieee80211_node *); Index: sys/net80211/ieee80211_scan.h =================================================================== --- sys/net80211/ieee80211_scan.h (revision 311042) +++ sys/net80211/ieee80211_scan.h (working copy) @@ -250,7 +250,9 @@ uint8_t *quiet; uint8_t *meshid; uint8_t *meshconf; - uint8_t *spare[3]; + uint8_t *vhtcap; + uint8_t *vhtopmode; + uint8_t *spare[1]; }; /* Index: sys/net80211/ieee80211_scan_sta.c =================================================================== --- sys/net80211/ieee80211_scan_sta.c (revision 311042) +++ sys/net80211/ieee80211_scan_sta.c (working copy) @@ -325,6 +325,18 @@ } } else ise->se_chan = curchan; + + /* VHT demotion */ + if (IEEE80211_IS_CHAN_VHT(ise->se_chan) && sp->vhtcap == NULL) { + /* Demote legacy networks to a non-VHT channel. */ + c = ieee80211_find_channel(ic, ise->se_chan->ic_freq, + ise->se_chan->ic_flags & ~IEEE80211_CHAN_VHT); + KASSERT(c != NULL, + ("no non-VHT channel %u", ise->se_chan->ic_ieee)); + ise->se_chan = c; + } + + /* HT demotion */ if (IEEE80211_IS_CHAN_HT(ise->se_chan) && sp->htcap == NULL) { /* Demote legacy networks to a non-HT channel. */ c = ieee80211_find_channel(ic, ise->se_chan->ic_freq, @@ -333,6 +345,7 @@ ("no legacy channel %u", ise->se_chan->ic_ieee)); ise->se_chan = c; } + ise->se_fhdwell = sp->fhdwell; ise->se_fhindex = sp->fhindex; ise->se_erp = sp->erp; @@ -531,10 +544,11 @@ /* * Ignore dynamic turbo channels; we scan them * in normal mode (i.e. not boosted). Likewise - * for HT channels, they get scanned using + * for HT/VHT channels, they get scanned using * legacy rates. */ - if (IEEE80211_IS_CHAN_DTURBO(c) || IEEE80211_IS_CHAN_HT(c)) + if (IEEE80211_IS_CHAN_DTURBO(c) || IEEE80211_IS_CHAN_HT(c) || + IEEE80211_IS_CHAN_VHT(c)) continue; /* @@ -819,6 +833,9 @@ * that we assume compatibility/usability has already been checked * so we don't need to (e.g. validate whether privacy is supported). * Used to select the best scan candidate for association in a BSS. + * + * TODO: should we take 11n, 11ac into account when selecting the + * best? Right now it just compares frequency band and RSSI. */ static int sta_compare(const struct sta_entry *a, const struct sta_entry *b) @@ -1624,6 +1641,7 @@ * "correct" rate control capabilities being * negotiated. */ + /* XXX VHT */ chan = ieee80211_ht_adjust_channel(ic, chan, vap->iv_flags_ht); ieee80211_create_ibss(vap, chan); @@ -1655,6 +1673,7 @@ * IBSS node; we can then advertise HT IEs and speak HT * to any subsequent nodes that support it. */ + /* XXX VHT */ chan = ieee80211_ht_adjust_channel(ic, chan, vap->iv_flags_ht); if (!ieee80211_sta_join(vap, chan, &selbs->base)) @@ -1808,6 +1827,7 @@ ss->ss_flags &= ~IEEE80211_SCAN_NOPICK; return 1; } + /* XXX VHT */ ieee80211_create_ibss(vap, ieee80211_ht_adjust_channel(ic, bestchan, vap->iv_flags_ht)); return 1; @@ -1881,6 +1901,7 @@ IEEE80211_IS_CHAN_RADAR(vap->iv_des_chan)) { struct ieee80211com *ic = vap->iv_ic; + /* XXX VHT */ chan = adhoc_pick_channel(ss, 0); if (chan != NULL) chan = ieee80211_ht_adjust_channel(ic, Index: sys/net80211/ieee80211_sta.c =================================================================== --- sys/net80211/ieee80211_sta.c (revision 311042) +++ sys/net80211/ieee80211_sta.c (working copy) @@ -64,6 +64,7 @@ #endif #include #include +#include #define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2) @@ -1330,6 +1331,7 @@ struct ieee80211_frame *wh; uint8_t *frm, *efrm; uint8_t *rates, *xrates, *wme, *htcap, *htinfo; + uint8_t *vhtcap, *vhtopmode; uint8_t rate; int ht_state_change = 0; @@ -1434,6 +1436,14 @@ scan.htcap, scan.htinfo)) ht_state_change = 1; } + if (scan.vhtcap != NULL && scan.vhtopmode != NULL && + (vap->iv_flags_vht & IEEE80211_FVHT_VHT)) { + /* XXX state changes? */ + if (ieee80211_vht_updateparams(ni, + scan.vhtcap, scan.vhtopmode)) + ht_state_change = 1; + } + if (scan.quiet) ic->ic_set_quiet(ni, scan.quiet); @@ -1660,6 +1670,7 @@ frm += 2; rates = xrates = wme = htcap = htinfo = NULL; + vhtcap = vhtopmode = NULL; while (efrm - frm > 1) { IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return); switch (*frm) { @@ -1693,6 +1704,12 @@ } /* XXX Atheros OUI support */ break; + case IEEE80211_ELEMID_VHT_CAP: + vhtcap = frm; + break; + case IEEE80211_ELEMID_VHT_OPMODE: + vhtopmode = frm; + break; } frm += frm[1] + 2; } @@ -1740,6 +1757,14 @@ ieee80211_setup_htrates(ni, htcap, IEEE80211_F_JOIN | IEEE80211_F_DOBRS); ieee80211_setup_basic_htrates(ni, htinfo); + + if ((vhtcap != NULL) && (vhtopmode != NULL) & + (vap->iv_flags_vht & IEEE80211_FVHT_VHT)) { + ieee80211_vht_node_init(ni); + ieee80211_vht_updateparams(ni, vhtcap, vhtopmode); + ieee80211_setup_vht_rates(ni, vhtcap, vhtopmode); + } + ieee80211_node_setuptxparms(ni); ieee80211_ratectl_node_init(ni); } Index: sys/net80211/ieee80211_var.h =================================================================== --- sys/net80211/ieee80211_var.h (revision 311042) +++ sys/net80211/ieee80211_var.h (working copy) @@ -232,8 +232,9 @@ /* VHT information */ uint32_t ic_vhtcaps; /* VHT capabilities */ uint32_t ic_vhtextcaps; /* VHT extended capabilities (TODO) */ - struct ieee80211_vht_mcs_info iv_vht_mcsinfo; /* Support TX/RX VHT MCS */ - uint32_t ic_vht_spare[4]; + struct ieee80211_vht_mcs_info ic_vht_mcsinfo; /* Support TX/RX VHT MCS */ + uint32_t ic_flags_vht; /* VHT state flags */ + uint32_t ic_vht_spare[3]; /* optional state for Atheros SuperG protocol extensions */ struct ieee80211_superg *ic_superg; @@ -651,6 +652,10 @@ #define IEEE80211_FVEN_BITS "\20" +#define IEEE80211_FVHT_VHT 0x000000001 /* CONF: VHT supported */ +#define IEEE80211_VFHT_BITS \ + "\20\1VHT" + int ic_printf(struct ieee80211com *, const char *, ...) __printflike(2, 3); void ieee80211_ifattach(struct ieee80211com *); void ieee80211_ifdetach(struct ieee80211com *); Index: sys/net80211/ieee80211_vht.c =================================================================== --- sys/net80211/ieee80211_vht.c (nonexistent) +++ sys/net80211/ieee80211_vht.c (working copy) @@ -0,0 +1,165 @@ +/*- + * Copyright (c) 2016 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#ifdef __FreeBSD__ +__FBSDID("$FreeBSD$"); +#endif + +/* + * IEEE 802.11ac-2013 protocol support. + */ + +#include "opt_inet.h" +#include "opt_wlan.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* define here, used throughout file */ +#define MS(_v, _f) (((_v) & _f) >> _f##_S) +#define SM(_v, _f) (((_v) << _f##_S) & _f) + +static void +ieee80211_vht_init(void) +{ +} + +SYSINIT(wlan_vht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_vht_init, NULL); + +void +ieee80211_vht_attach(struct ieee80211com *ic) +{ +} + +void +ieee80211_vht_detach(struct ieee80211com *ic) +{ +} + +void +ieee80211_vht_vattach(struct ieee80211vap *vap) +{ +} + +void +ieee80211_vht_vdetach(struct ieee80211vap *vap) +{ +} + +#if 0 +static void +vht_announce(struct ieee80211com *ic, enum ieee80211_phymode mode) +{ +} +#endif + +void +ieee80211_vht_announce(struct ieee80211com *ic) +{ +} + +void +ieee80211_vht_node_init(struct ieee80211_node *ni) +{ +} + +void +ieee80211_vht_node_cleanup(struct ieee80211_node *ni) +{ +} + +/* + * Parse an 802.11ac VHT operation IE. + */ +void +ieee80211_parse_vhtopmode(struct ieee80211_node *ni, const uint8_t *ie) +{ + + printf("%s: called\n", __func__); +} + +/* + * Parse an 802.11ac VHT capability IE. + */ +void +ieee80211_parse_vhtcap(struct ieee80211_node *ni, const uint8_t *ie) +{ + + printf("%s: called\n", __func__); +} + +int +ieee80211_vht_updateparams(struct ieee80211_node *ni, + const uint8_t *vhtcap_ie, + const uint8_t *vhtop_ie) +{ + + printf("%s: called\n", __func__); + return (0); +} + +void +ieee80211_setup_vht_rates(struct ieee80211_node *ni, + const uint8_t *vhtcap_ie, + const uint8_t *vhtop_ie) +{ + + printf("%s: called\n", __func__); +} + +void +ieee80211_vht_timeout(struct ieee80211com *ic) +{ +} + +void +ieee80211_vht_node_join(struct ieee80211_node *ni) +{ + + printf("%s: called\n", __func__); +} + +void +ieee80211_vht_node_leave(struct ieee80211_node *ni) +{ + + printf("%s: called\n", __func__); +} Property changes on: sys/net80211/ieee80211_vht.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: sys/net80211/ieee80211_vht.h =================================================================== --- sys/net80211/ieee80211_vht.h (nonexistent) +++ sys/net80211/ieee80211_vht.h (working copy) @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2016 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ +#ifndef _NET80211_IEEE80211_VHT_H_ +#define _NET80211_IEEE80211_VHT_H_ + +void ieee80211_vht_attach(struct ieee80211com *); +void ieee80211_vht_detach(struct ieee80211com *); +void ieee80211_vht_vattach(struct ieee80211vap *); +void ieee80211_vht_vdetach(struct ieee80211vap *); + +void ieee80211_vht_announce(struct ieee80211com *); + +void ieee80211_vht_node_init(struct ieee80211_node *); +void ieee80211_vht_node_cleanup(struct ieee80211_node *); + +void ieee80211_parse_vhtopmode(struct ieee80211_node *, const uint8_t *); +void ieee80211_parse_vhtcap(struct ieee80211_node *, const uint8_t *); + +int ieee80211_vht_updateparams(struct ieee80211_node *, + const uint8_t *, const uint8_t *); +void ieee80211_setup_vht_rates(struct ieee80211_node *, + const uint8_t *, const uint8_t *); + +void ieee80211_vht_timeout(struct ieee80211com *ic); + +void ieee80211_vht_node_join(struct ieee80211_node *ni); +void ieee80211_vht_node_leave(struct ieee80211_node *ni); + +#endif /* _NET80211_IEEE80211_VHT_H_ */ Property changes on: sys/net80211/ieee80211_vht.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: etc/regdomain.xml =================================================================== --- etc/regdomain.xml (revision 311042) +++ etc/regdomain.xml (working copy) @@ -111,6 +111,17 @@ IEEE80211_CHAN_HT40 + + + + + 17 + IEEE80211_CHAN_HT20 + IEEE80211_CHAN_VHT20 + + @@ -1735,6 +1746,21 @@ 20 20 IEEE80211_CHAN_A + + 5180 5240 + 20 20 + IEEE80211_CHAN_A + + + 5180 5240 + 40 20 + IEEE80211_CHAN_A + + + 5180 5240 + 80 20 + IEEE80211_CHAN_A + 5180 5240 40 20 Index: sbin/ifconfig/ifieee80211.c =================================================================== --- sbin/ifconfig/ifieee80211.c (revision 311042) +++ sbin/ifconfig/ifieee80211.c (working copy) @@ -143,7 +143,9 @@ [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 +185,20 @@ 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 +216,7 @@ err(1, "unable to get channel information"); ifmr = ifmedia_getstate(s); gethtconf(s); + getvhtconf(s); } static struct regdata * @@ -502,6 +519,7 @@ printf("drivercaps: 0x%x\n", dc->dc_drivercaps); printf("cryptocaps: 0x%x\n", dc->dc_cryptocaps); printf("htcaps : 0x%x\n", dc->dc_htcaps); + /* XXX vhtcaps */ memcpy(chaninfo, &dc->dc_chaninfo, IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo)); print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, 1/*verbose*/); @@ -1863,6 +1881,13 @@ set80211(s, IEEE80211_IOC_RIFS, d, 0, NULL); } +static void +set80211vhtconf(const char *val, int d, int s, const struct afswtch *rafp) +{ + set80211(s, IEEE80211_IOC_VHTCONF, d, 0, NULL); + vhtconf = d; +} + static DECL_CMD_FUNC(set80211tdmaslot, val, d) { @@ -3807,6 +3832,11 @@ 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 +4877,18 @@ } } + if (IEEE80211_IS_CHAN_VHT(c) || verbose) { + getvhtconf(s); + switch (htconf & 0x7) { + case 0: + LINE_CHECK("-vht"); + break; + case 1: + LINE_CHECK("vht"); + break; + } + } + if (get80211val(s, IEEE80211_IOC_WME, &wme) != -1) { if (wme) LINE_CHECK("wme"); @@ -5426,6 +5468,8 @@ DEF_CMD("-ht40", 0, set80211htconf), DEF_CMD("ht", 3, set80211htconf), /* NB: 20+40 */ DEF_CMD("-ht", 0, set80211htconf), + DEF_CMD("vht", 3, set80211vhtconf), /* NB: all */ + DEF_CMD("-vht", 0, set80211vhtconf), DEF_CMD("rifs", 1, set80211rifs), DEF_CMD("-rifs", 0, set80211rifs), DEF_CMD("smps", IEEE80211_HTCAP_SMPS_ENA, set80211smps),