bwfm(4): show 11ac

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

bwfm(4): show 11ac

Stefan Sperling-5
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 */