This makes bwfm(4) display whether 11ac is being used by firmware.
It extends changes made earlier to display 11n.

Even though this touches more of net80211 than bwfm, no behaviour
changes should be seen with other drivers.

diff 9c4fc15973cfe90e53accb22e71ee9895aaf2d8a /usr/src
blob - bcb6861698792b3569a50755911a5d1ca351d947
file + sbin/ifconfig/ifconfig.c
--- sbin/ifconfig/ifconfig.c
+++ sbin/ifconfig/ifconfig.c
@@ -2697,7 +2697,9 @@ ieee80211_printnode(struct ieee80211_nodereq *nr)
         * Print the fastest supported rate for APs.
         */
        if ((nr->nr_flags & (IEEE80211_NODEREQ_AP)) == 0) {
-               if (nr->nr_flags & IEEE80211_NODEREQ_HT) {
+               if (nr->nr_flags & IEEE80211_NODEREQ_VHT) {
+                       printf("VHT-MCS%d/%dSS", nr->nr_txmcs, nr->nr_vht_ss);
+               } else if (nr->nr_flags & IEEE80211_NODEREQ_HT) {
                        printf("HT-MCS%d ", nr->nr_txmcs);
                } else if (nr->nr_nrates) {
                        printf("%uM ",
blob - d63757f5fd4045c5f19b6e1ed88a1ebac59ab55b
file + sys/dev/ic/bwfm.c
--- sys/dev/ic/bwfm.c
+++ sys/dev/ic/bwfm.c
@@ -281,6 +281,7 @@ bwfm_preinit(struct bwfm_softc *sc)
                                if (nmode)
                                        ic->ic_channels[chan].ic_flags |=
                                            IEEE80211_CHAN_HT;
+                               /* VHT is 5GHz only */
                        }
                        break;
                case BWFM_BAND_5G:
@@ -298,6 +299,9 @@ bwfm_preinit(struct bwfm_softc *sc)
                                if (nmode)
                                        ic->ic_channels[chan].ic_flags |=
                                            IEEE80211_CHAN_HT;
+                               if (vhtmode)
+                                       ic->ic_channels[chan].ic_flags |=
+                                           IEEE80211_CHAN_VHT;
                        }
                        break;
                default:
@@ -556,11 +560,25 @@ bwfm_watchdog(struct ifnet *ifp)
  * But this is the best we can do given that firmware only reports kbit/s.
  */
 
-int
-bwfm_rate2vhtmcs(uint32_t txrate)
+void
+bwfm_rate2vhtmcs(int *mcs, int *ss, uint32_t txrate)
 {
-       /* TODO */
-       return -1;
+       const struct ieee80211_vht_rateset *rs;
+       int i, j;
+       
+       *mcs = -1;
+       *ss = -1;
+       /* TODO: Select specific ratesets based on BSS channel width. */
+       for (i = 0; i < IEEE80211_VHT_NUM_RATESETS; i++) {
+               rs = &ieee80211_std_ratesets_11ac[i];
+               for (j = 0; j < rs->nrates; j++) {
+                       if (rs->rates[j] == txrate / 500) {
+                               *mcs = j;
+                               *ss = rs->num_ss;
+                               return;
+                       }
+               }
+       }
 }
 
 int
@@ -569,6 +587,7 @@ bwfm_rate2htmcs(uint32_t txrate)
        const struct ieee80211_ht_rateset *rs;
        int i, j;
        
+       /* TODO: Select specific ratesets based on BSS channel width. */
        for (i = 0; i < IEEE80211_HT_NUM_RATESETS; i++) {
                rs = &ieee80211_std_ratesets_11n[i];
                for (j = 0; j < rs->nrates; j++) {
@@ -589,7 +608,7 @@ bwfm_update_node(void *arg, struct ieee80211_node *ni)
        uint32_t flags;
        int8_t rssi;
        uint32_t txrate;
-       int mcs, i;
+       int i;
 
        memset(&sta, 0, sizeof(sta));
        memcpy((uint8_t *)&sta, ni->ni_macaddr, sizeof(ni->ni_macaddr));
@@ -621,32 +640,37 @@ bwfm_update_node(void *arg, struct ieee80211_node *ni)
        if (txrate == 0xffffffff) /* Seen this happening during association. */
                return;
 
-       if ((le32toh(sta.flags) & BWFM_STA_VHT_CAP) &&
-           (mcs = bwfm_rate2vhtmcs(txrate)) >= 0) {
-               /* TODO: Can't store VHT MCS in ni yet... */
-       } else if ((le32toh(sta.flags) & BWFM_STA_N_CAP) &&
-           (mcs = bwfm_rate2htmcs(txrate)) >= 0) {
+       if ((le32toh(sta.flags) & BWFM_STA_VHT_CAP)) {
+               int mcs, ss;
+               /* Tell net80211 that firmware has negotiated 11ac. */
+               ni->ni_flags |= IEEE80211_NODE_VHT;
+               ni->ni_flags |= IEEE80211_NODE_HT; /* VHT implies HT support */
+               if (ic->ic_curmode < IEEE80211_MODE_11AC)
+                       ieee80211_setmode(ic, IEEE80211_MODE_11AC);
+               bwfm_rate2vhtmcs(&mcs, &ss, txrate);
+               if (mcs >= 0) {
+                       ni->ni_txmcs = mcs;
+                       ni->ni_vht_ss = ss;
+               } else {
+                       ni->ni_txmcs = 0;
+                       ni->ni_vht_ss = 1;
+               }
+       } else if ((le32toh(sta.flags) & BWFM_STA_N_CAP)) {
+               int mcs;
                /* Tell net80211 that firmware has negotiated 11n. */
                ni->ni_flags |= IEEE80211_NODE_HT;
                if (ic->ic_curmode < IEEE80211_MODE_11N)
                        ieee80211_setmode(ic, IEEE80211_MODE_11N);
-               ni->ni_txmcs = mcs;
+               mcs = bwfm_rate2htmcs(txrate);
+               ni->ni_txmcs = (mcs >= 0 ? mcs : 0);
        } else {
-               /*
-                * In 11n mode a fallback to legacy rates is transparent
-                * to net80211. Just pretend we were using MCS 0.
-                */
-               if (ni->ni_flags & IEEE80211_NODE_HT) {
-                       ni->ni_txmcs = 0;
-               } else {
-                       /* We're in 11a/g mode. Map to a legacy rate. */
-                       for (i = 0; i < ni->ni_rates.rs_nrates; i++) {
-                               uint8_t rate = ni->ni_rates.rs_rates[i];
-                               rate &= IEEE80211_RATE_VAL;
-                               if (rate == txrate / 500) {
-                                       ni->ni_txrate = i;
-                                       break;
-                               }
+               /* We're in 11a/g mode. Map to a legacy rate. */
+               for (i = 0; i < ni->ni_rates.rs_nrates; i++) {
+                       uint8_t rate = ni->ni_rates.rs_rates[i];
+                       rate &= IEEE80211_RATE_VAL;
+                       if (rate == txrate / 500) {
+                               ni->ni_txrate = i;
+                               break;
                        }
                }
        }
blob - 95e2e651fdfeed0561246abdf54669a9468346af
file + sys/net80211/ieee80211.c
--- sys/net80211/ieee80211.c
+++ sys/net80211/ieee80211.c
@@ -143,6 +143,8 @@ ieee80211_channel_init(struct ifnet *ifp)
                                ic->ic_modecaps |= 1<<IEEE80211_MODE_11G;
                        if (IEEE80211_IS_CHAN_N(c))
                                ic->ic_modecaps |= 1<<IEEE80211_MODE_11N;
+                       if (IEEE80211_IS_CHAN_AC(c))
+                               ic->ic_modecaps |= 1<<IEEE80211_MODE_11AC;
                }
        }
        /* validate ic->ic_curmode */
@@ -409,6 +411,41 @@ ieee80211_media_init(struct ifnet *ifp,
                ic->ic_flags |= IEEE80211_F_HTON; /* enable 11n by default */
        }
 
+       if (ic->ic_modecaps & (1 << IEEE80211_MODE_11AC)) {
+               mopt = IFM_IEEE80211_11AC;
+               ADD(ic, IFM_AUTO, mopt);
+#ifndef IEEE80211_STA_ONLY
+               if (ic->ic_caps & IEEE80211_C_IBSS)
+                       ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_IBSS);
+               if (ic->ic_caps & IEEE80211_C_HOSTAP)
+                       ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_HOSTAP);
+#endif
+               if (ic->ic_caps & IEEE80211_C_MONITOR)
+                       ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_MONITOR);
+               for (i = 0; i < IEEE80211_VHT_NUM_MCS; i++) {
+#if 0
+                       /* TODO: Obtain VHT MCS information from VHT CAP IE. */
+                       if (!vht_mcs_supported)
+                               continue;
+#endif
+                       ADD(ic, IFM_IEEE80211_VHT_MCS0 + i, mopt);
+#ifndef IEEE80211_STA_ONLY
+                       if (ic->ic_caps & IEEE80211_C_IBSS)
+                               ADD(ic, IFM_IEEE80211_VHT_MCS0 + i,
+                                    mopt | IFM_IEEE80211_IBSS);
+                       if (ic->ic_caps & IEEE80211_C_HOSTAP)
+                               ADD(ic, IFM_IEEE80211_VHT_MCS0 + i,
+                                   mopt | IFM_IEEE80211_HOSTAP);
+#endif
+                       if (ic->ic_caps & IEEE80211_C_MONITOR)
+                               ADD(ic, IFM_IEEE80211_VHT_MCS0 + i,
+                                   mopt | IFM_IEEE80211_MONITOR);
+               }
+#if 0
+               ic->ic_flags |= IEEE80211_F_VHTON; /* enable 11ac by default */
+#endif
+       }
+
        ieee80211_media_status(ifp, &imr);
        ifmedia_set(&ic->ic_media, imr.ifm_active);
 
@@ -461,6 +498,9 @@ ieee80211_media_change(struct ifnet *ifp)
        case IFM_IEEE80211_11N:
                newphymode = IEEE80211_MODE_11N;
                break;
+       case IFM_IEEE80211_11AC:
+               newphymode = IEEE80211_MODE_11AC;
+               break;
        case IFM_AUTO:
                newphymode = IEEE80211_MODE_AUTO;
                break;
@@ -478,7 +518,18 @@ ieee80211_media_change(struct ifnet *ifp)
         * Next, the fixed/variable rate.
         */
        i = -1;
-       if (IFM_SUBTYPE(ime->ifm_media) >= IFM_IEEE80211_HT_MCS0 &&
+       if (IFM_SUBTYPE(ime->ifm_media) >= IFM_IEEE80211_VHT_MCS0 &&
+           IFM_SUBTYPE(ime->ifm_media) <= IFM_IEEE80211_VHT_MCS9) {
+               if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11AC)) == 0)
+                       return EINVAL;
+               if (newphymode != IEEE80211_MODE_AUTO &&
+                   newphymode != IEEE80211_MODE_11AC)
+                       return EINVAL;
+               i = ieee80211_media2mcs(ime->ifm_media);
+               /* TODO: Obtain VHT MCS information from VHT CAP IE. */
+               if (i == -1 /* || !vht_mcs_supported */)
+                       return EINVAL;
+       } else if (IFM_SUBTYPE(ime->ifm_media) >= IFM_IEEE80211_HT_MCS0 &&
            IFM_SUBTYPE(ime->ifm_media) <= IFM_IEEE80211_HT_MCS76) {
                if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11N)) == 0)
                        return EINVAL;
@@ -547,7 +598,9 @@ ieee80211_media_change(struct ifnet *ifp)
         */
        if (newopmode == IEEE80211_M_HOSTAP &&
            newphymode == IEEE80211_MODE_AUTO) {
-               if (ic->ic_modecaps & (1 << IEEE80211_MODE_11N))
+               if (ic->ic_modecaps & (1 << IEEE80211_MODE_11AC))
+                       newphymode = IEEE80211_MODE_11AC;
+               else if (ic->ic_modecaps & (1 << IEEE80211_MODE_11N))
                        newphymode = IEEE80211_MODE_11N;
                else if (ic->ic_modecaps & (1 << IEEE80211_MODE_11A))
                        newphymode = IEEE80211_MODE_11A;
@@ -571,12 +624,16 @@ ieee80211_media_change(struct ifnet *ifp)
        /*
         * Committed to changes, install the MCS/rate setting.
         */
-       ic->ic_flags &= ~IEEE80211_F_HTON;
-       if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11N)) &&
+       ic->ic_flags &= ~(IEEE80211_F_HTON | IEEE80211_F_VHTON);
+       if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11AC)) &&
            (newphymode == IEEE80211_MODE_AUTO ||
+           newphymode == IEEE80211_MODE_11AC))
+               ic->ic_flags |= IEEE80211_F_VHTON;
+       else if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11N)) &&
+           (newphymode == IEEE80211_MODE_AUTO ||
            newphymode == IEEE80211_MODE_11N))
                ic->ic_flags |= IEEE80211_F_HTON;
-       if ((ic->ic_flags & IEEE80211_F_HTON) == 0) {
+       if ((ic->ic_flags & (IEEE80211_F_HTON | IEEE80211_F_VHTON)) == 0) {
                ic->ic_fixed_mcs = -1;
                if (ic->ic_fixed_rate != i) {
                        ic->ic_fixed_rate = i;          /* set fixed tx rate */
@@ -640,7 +697,8 @@ ieee80211_media_status(struct ifnet *ifp, struct ifmed
        switch (ic->ic_opmode) {
        case IEEE80211_M_STA:
                ni = ic->ic_bss;
-               if (ic->ic_curmode == IEEE80211_MODE_11N)
+               if (ic->ic_curmode == IEEE80211_MODE_11N ||
+                   ic->ic_curmode == IEEE80211_MODE_11AC)
                        imr->ifm_active |= ieee80211_mcs2media(ic,
                                ni->ni_txmcs, ic->ic_curmode);
                else
@@ -679,6 +737,9 @@ ieee80211_media_status(struct ifnet *ifp, struct ifmed
        case IEEE80211_MODE_11N:
                imr->ifm_active |= IFM_IEEE80211_11N;
                break;
+       case IEEE80211_MODE_11AC:
+               imr->ifm_active |= IFM_IEEE80211_11AC;
+               break;
        }
 }
 
@@ -729,6 +790,44 @@ const struct ieee80211_ht_rateset ieee80211_std_ratese
        { 8, { 58, 116, 173, 231, 347, 462, 520, 578 }, 0xff000000, 24, 31, 1 },
 };
 
+const struct ieee80211_vht_rateset ieee80211_std_ratesets_11ac[] = {
+       /* MCS 0-8 (MCS 9 N/A), 1 SS, 20MHz channel, no SGI */
+       { 9, { 13, 26, 39, 52, 78, 104, 117, 130, 156 }, 1, 0 },
+
+       /* MCS 0-8 (MCS 9 N/A), 1 SS, 20MHz channel, SGI */
+       { 9, { 14, 29, 43, 58, 87, 116, 130, 144, 174 }, 1, 1 },
+
+       /* MCS 0-8 (MCS 9 N/A), 2 SS, 20MHz channel, no SGI */
+       { 9, { 26, 52, 78, 104, 156, 208, 234, 260, 312 }, 2, 0 },
+
+       /* MCS 0-8 (MCS 9 N/A), 2 SS, 20MHz channel, SGI */
+       { 9, { 29, 58, 87, 116, 173, 231, 261, 289, 347 }, 2, 1 },
+
+       /* MCS 0-9, 1 SS, 40MHz channel, no SGI */
+       { 10, { 27, 54, 81, 108, 162, 216, 243, 270, 324, 360 }, 1, 0 },
+
+       /* MCS 0-9, 1 SS, 40MHz channel, SGI */
+       { 10, { 30, 60, 90, 120, 180, 240, 270, 300, 360, 400 }, 1, 1 },
+
+       /* MCS 0-9, 2 SS, 40MHz channel, no SGI */
+       { 10, { 54, 108, 162, 216, 324, 432, 486, 540, 648, 720 }, 2, 0 },
+
+       /* MCS 0-9, 2 SS, 40MHz channel, SGI */
+       { 10, { 60, 120, 180, 240, 360, 480, 540, 600, 720, 800 }, 2, 1 },
+
+       /* MCS 0-9, 1 SS, 80MHz channel, no SGI */
+       { 10, { 59, 117, 176, 234, 351, 468, 527, 585, 702, 780 }, 1, 0 },
+
+       /* MCS 0-9, 1 SS, 80MHz channel, SGI */
+       { 10, { 65, 130, 195, 260, 390, 520, 585, 650, 780, 867 }, 1, 1 },
+
+       /* MCS 0-9, 2 SS, 80MHz channel, no SGI */
+       { 10, { 117, 234, 351, 468, 702, 936, 1053, 1404, 1560 }, 2, 0 }, 
+
+       /* MCS 0-9, 2 SS, 80MHz channel, SGI */
+       { 10, { 130, 260, 390, 520, 780, 1040, 1170, 1300, 1560, 1734 }, 2, 1 },
+};
+
 /*
  * Mark the basic rates for the 11g rate table based on the
  * operating mode.  For real 11g we mark all the 11b rates
@@ -827,6 +926,7 @@ ieee80211_setmode(struct ieee80211com *ic, enum ieee80
                IEEE80211_CHAN_B,       /* IEEE80211_MODE_11B */
                IEEE80211_CHAN_PUREG,   /* IEEE80211_MODE_11G */
                IEEE80211_CHAN_HT,      /* IEEE80211_MODE_11N */
+               IEEE80211_CHAN_VHT,     /* IEEE80211_MODE_11AC */
        };
        const struct ieee80211_channel *c;
        u_int modeflags;
@@ -928,6 +1028,12 @@ ieee80211_next_mode(struct ifnet *ifp)
                 */
                if (ic->ic_curmode == IEEE80211_MODE_11N)
                        continue;
+               /* 
+                * Skip over 11ac mode. Its set of channels is the set
+                * of all channels supported by 11a.
+                */
+               if (ic->ic_curmode == IEEE80211_MODE_11AC)
+                       continue;
 
                /* Always scan in AUTO mode if the driver scans all bands. */
                if (ic->ic_curmode >= IEEE80211_MODE_MAX ||
@@ -963,6 +1069,7 @@ ieee80211_chan2mode(struct ieee80211com *ic,
         *     unless it was already compatible with the current mode.
         */
        if (ic->ic_curmode != IEEE80211_MODE_11N &&
+           ic->ic_curmode != IEEE80211_MODE_11AC &&
            (ic->ic_curmode != IEEE80211_MODE_AUTO ||
            chan == IEEE80211_CHAN_ANYC))
                return ic->ic_curmode;
@@ -992,12 +1099,18 @@ ieee80211_mcs2media(struct ieee80211com *ic, int mcs,
                /* these modes use rates, not MCS */
                panic("%s: unexpected mode %d", __func__, mode);
                break;
-       case IEEE80211_MODE_AUTO:
        case IEEE80211_MODE_11N:
                if (mcs >= 0 && mcs < IEEE80211_HT_NUM_MCS)
                        return (IFM_IEEE80211_11N |
                            (IFM_IEEE80211_HT_MCS0 + mcs));
                break;
+       case IEEE80211_MODE_11AC:
+               if (mcs >= 0 && mcs < IEEE80211_VHT_NUM_MCS)
+                       return (IFM_IEEE80211_11AC |
+                           (IFM_IEEE80211_VHT_MCS0 + mcs));
+               break;
+       case IEEE80211_MODE_AUTO:
+               break;
        }
 
        return IFM_AUTO;
@@ -1022,6 +1135,10 @@ ieee80211_media2mcs(uint64_t mword)
            subtype <= IFM_IEEE80211_HT_MCS76)
                return (int)(subtype - IFM_IEEE80211_HT_MCS0);
 
+       if (subtype >= IFM_IEEE80211_VHT_MCS0 &&
+           subtype <= IFM_IEEE80211_VHT_MCS9)
+               return (int)(subtype - IFM_IEEE80211_VHT_MCS0);
+
        return -1;
 }
 
@@ -1082,7 +1199,8 @@ ieee80211_rate2media(struct ieee80211com *ic, int rate
                mask |= IFM_IEEE80211_11G;
                break;
        case IEEE80211_MODE_11N:
-               /* 11n uses MCS, not rates. */
+       case IEEE80211_MODE_11AC:
+               /* 11n/11ac uses MCS, not rates. */
                panic("%s: unexpected mode %d", __func__, mode);
                break;
        }
blob - 42089548b4130a2860978a373d4c09b417a2b88e
file + sys/net80211/ieee80211.h
--- sys/net80211/ieee80211.h
+++ sys/net80211/ieee80211.h
@@ -505,6 +505,7 @@ enum {
 #define        IEEE80211_RATE_MAXSIZE                  15      /* max rates 
we'll handle */
 
 #define        IEEE80211_HT_NUM_MCS                    77
+#define        IEEE80211_VHT_NUM_MCS                   10
 
 /*
  * BlockAck/BlockAckReq Control field (see 802.11-2012 8.3.1.9 Figure 8-25).
blob - a57df7f8f6b3105019fd07bdf4f5a27b97acd2f3
file + sys/net80211/ieee80211_ioctl.c
--- sys/net80211/ieee80211_ioctl.c
+++ sys/net80211/ieee80211_ioctl.c
@@ -137,9 +137,16 @@ ieee80211_node2req(struct ieee80211com *ic, const stru
        memcpy(nr->nr_rxmcs, ni->ni_rxmcs, sizeof(nr->nr_rxmcs));
        nr->nr_max_rxrate = ni->ni_max_rxrate;
        nr->nr_tx_mcs_set = ni->ni_tx_mcs_set;
-       nr->nr_txmcs = ni->ni_txmcs;
        if (ni->ni_flags & IEEE80211_NODE_HT)
                nr->nr_flags |= IEEE80211_NODEREQ_HT;
+
+       /* HT / VHT */
+       nr->nr_txmcs = ni->ni_txmcs;
+
+       /* VHT */
+       nr->nr_vht_ss = ni->ni_vht_ss;
+       if (ni->ni_flags & IEEE80211_NODE_VHT)
+               nr->nr_flags |= IEEE80211_NODEREQ_VHT;
 }
 
 void
blob - d2ee6f5bd28a6b5e814fdccc7e80e461f8d56b77
file + sys/net80211/ieee80211_ioctl.h
--- sys/net80211/ieee80211_ioctl.h
+++ sys/net80211/ieee80211_ioctl.h
@@ -353,7 +353,12 @@ struct ieee80211_nodereq {
        uint8_t                 nr_rxmcs[howmany(80,NBBY)];
        uint16_t                nr_max_rxrate;  /* in Mb/s, 0 <= rate <= 1023 */
        uint8_t                 nr_tx_mcs_set;
+
+       /* HT / VHT */
        uint8_t                 nr_txmcs;
+
+       /* VHT */
+       uint8_t                 nr_vht_ss;
 };
 
 #define IEEE80211_NODEREQ_STATE(_s)    (1 << _s)
@@ -368,6 +373,7 @@ struct ieee80211_nodereq {
 #define IEEE80211_NODEREQ_AP_BSS       0x02    /* current bss access point */
 #define IEEE80211_NODEREQ_COPY         0x04    /* add node with flags */
 #define IEEE80211_NODEREQ_HT           0x08    /* HT negotiated */
+#define IEEE80211_NODEREQ_VHT          0x10    /* VHT negotiated */
 
 #define SIOCG80211NODE         _IOWR('i', 211, struct ieee80211_nodereq)
 #define SIOCS80211NODE          _IOW('i', 212, struct ieee80211_nodereq)
blob - ef5b276fe98788fb800b71ea3a48d0634b3a2e90
file + sys/net80211/ieee80211_node.h
--- sys/net80211/ieee80211_node.h
+++ sys/net80211/ieee80211_node.h
@@ -88,6 +88,36 @@ struct ieee80211_ht_rateset {
 
 extern const struct ieee80211_ht_rateset ieee80211_std_ratesets_11n[];
 
+/* Index into ieee80211_std_rateset_11ac[] array. */
+#define IEEE80211_VHT_RATESET_SISO             0
+#define IEEE80211_VHT_RATESET_SISO_SGI         1
+#define IEEE80211_VHT_RATESET_MIMO2            2
+#define IEEE80211_VHT_RATESET_MIMO2_SGI                3
+#define IEEE80211_VHT_RATESET_SISO_40          4
+#define IEEE80211_VHT_RATESET_SISO_40_SGI      5
+#define IEEE80211_VHT_RATESET_MIMO2_40         6
+#define IEEE80211_VHT_RATESET_MIMO2_40_SGI     7
+#define IEEE80211_VHT_RATESET_SISO_80          8
+#define IEEE80211_VHT_RATESET_SISO_80_SGI      9
+#define IEEE80211_VHT_RATESET_MIMO2_80         10
+#define IEEE80211_VHT_RATESET_MIMO2_80_SGI     11
+#define IEEE80211_VHT_NUM_RATESETS             12
+
+/* Maximum number of rates in a HT rateset. */
+#define IEEE80211_VHT_RATESET_MAX_NRATES       10
+
+struct ieee80211_vht_rateset {
+       uint32_t nrates;
+       uint32_t rates[IEEE80211_VHT_RATESET_MAX_NRATES]; /* 500 kbit/s units */
+
+       /* Number of spatial streams used by rates in this rateset. */
+       int num_ss;
+
+       int sgi;
+};
+
+extern const struct ieee80211_vht_rateset ieee80211_std_ratesets_11ac[];
+
 enum ieee80211_node_state {
        IEEE80211_STA_CACHE,    /* cached node */
        IEEE80211_STA_BSS,      /* ic->ic_bss, the network we joined */
@@ -305,6 +335,7 @@ struct ieee80211_node {
        struct ieee80211_rx_ba  ni_rx_ba[IEEE80211_NUM_TID];
 
        int                     ni_txmcs;       /* current MCS used for TX */
+       int                     ni_vht_ss;      /* VHT # spatial streams */
 
        /* others */
        u_int16_t               ni_associd;     /* assoc response */
@@ -317,7 +348,7 @@ struct ieee80211_node {
        int                     ni_txrate;      /* index to ni_rates[] */
        int                     ni_state;
 
-       u_int16_t               ni_flags;       /* special-purpose state */
+       u_int32_t               ni_flags;       /* special-purpose state */
 #define IEEE80211_NODE_ERP             0x0001
 #define IEEE80211_NODE_QOS             0x0002
 #define IEEE80211_NODE_REKEY           0x0004  /* GTK rekeying in progress */
@@ -336,6 +367,7 @@ struct ieee80211_node {
 #define IEEE80211_NODE_RSN_NEW_PTK     0x2000  /* expecting a new PTK */
 #define IEEE80211_NODE_HT_SGI20                0x4000  /* SGI on 20 MHz 
negotiated */ 
 #define IEEE80211_NODE_HT_SGI40                0x8000  /* SGI on 40 MHz 
negotiated */ 
+#define IEEE80211_NODE_VHT             0x10000 /* VHT negotiated */
 
        /* If not NULL, this function gets called when ni_refcnt hits zero. */
        void                    (*ni_unref_cb)(struct ieee80211com *,
blob - 5e0921776bf3efe77dae66895f51c2816f847de4
file + sys/net80211/ieee80211_radiotap.h
--- sys/net80211/ieee80211_radiotap.h
+++ sys/net80211/ieee80211_radiotap.h
@@ -197,6 +197,7 @@ enum ieee80211_radiotap_type {
 #define IEEE80211_CHAN_GFSK    0x0800  /* GFSK channel (FHSS PHY) */
 #define IEEE80211_CHAN_XR      0x1000  /* Extended range OFDM channel */
 #define IEEE80211_CHAN_HT      0x2000  /* 11n/HT channel */
+#define IEEE80211_CHAN_VHT     0x4000  /* 11ac/VHT channel */
 #endif /* !_KERNEL */
 
 /* For IEEE80211_RADIOTAP_FLAGS */
blob - 1ca13814b449eb98a6dbe1914b14f0ff25c11041
file + sys/net80211/ieee80211_var.h
--- sys/net80211/ieee80211_var.h
+++ sys/net80211/ieee80211_var.h
@@ -77,9 +77,10 @@ enum ieee80211_phymode {
        IEEE80211_MODE_11A      = 1,    /* 5GHz, OFDM */
        IEEE80211_MODE_11B      = 2,    /* 2GHz, CCK */
        IEEE80211_MODE_11G      = 3,    /* 2GHz, OFDM */
-       IEEE80211_MODE_11N      = 4,    /* 11n, 2GHz/5GHz */
+       IEEE80211_MODE_11N      = 4,    /* 2GHz/5GHz, OFDM/HT */
+       IEEE80211_MODE_11AC     = 5,    /* 5GHz, OFDM/VHT */
 };
-#define        IEEE80211_MODE_MAX      (IEEE80211_MODE_11N+1)
+#define        IEEE80211_MODE_MAX      (IEEE80211_MODE_11AC+1)
 
 enum ieee80211_opmode {
        IEEE80211_M_STA         = 1,    /* infrastructure station */
@@ -119,6 +120,7 @@ struct ieee80211_channel {
 #define IEEE80211_CHAN_DYN     0x0400  /* Dynamic CCK-OFDM channel */
 #define IEEE80211_CHAN_XR      0x1000  /* Extended range OFDM channel */
 #define IEEE80211_CHAN_HT      0x2000  /* 11n/HT channel */
+#define IEEE80211_CHAN_VHT     0x4000  /* 11ac/VHT channel */
 
 /*
  * Useful combinations of channel characteristics.
@@ -142,6 +144,8 @@ struct ieee80211_channel {
        (((_c)->ic_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
 #define        IEEE80211_IS_CHAN_N(_c) \
        (((_c)->ic_flags & IEEE80211_CHAN_HT) == IEEE80211_CHAN_HT)
+#define        IEEE80211_IS_CHAN_AC(_c) \
+       (((_c)->ic_flags & IEEE80211_CHAN_VHT) == IEEE80211_CHAN_VHT)
 
 #define        IEEE80211_IS_CHAN_2GHZ(_c) \
        (((_c)->ic_flags & IEEE80211_CHAN_2GHZ) != 0)
@@ -390,7 +394,8 @@ struct ieee80211_ess {
 #define        IEEE80211_F_PBAR        0x04000000      /* CONF: PBAC required 
*/
 #define        IEEE80211_F_BGSCAN      0x08000000      /* STATUS: background 
scan */
 #define IEEE80211_F_AUTO_JOIN  0x10000000      /* CONF: auto-join active */
-#define IEEE80211_F_USERMASK   0xe0000000      /* CONF: ioctl flag mask */
+#define        IEEE80211_F_VHTON       0x20000000      /* CONF: VHT enabled */
+#define IEEE80211_F_USERMASK   0xc0000000      /* CONF: ioctl flag mask */
 
 /* ic_xflags */
 #define        IEEE80211_F_TX_MGMT_ONLY 0x00000001     /* leave data frames on 
ifq */


Reply via email to