On Fri, Oct 07, 2016 at 03:28:19PM +0200, Stefan Sperling wrote:
> Currently tcpdump shows "0 Mbit/s" for any frame sent with 11n HT MCS.
> To make progress easier, I'd like to see which MCS are used on the air,
> by any device.
>
> The change below matches what FreeBSD did to pass an MCS index via radiotap.
> This simply writes the MCS index into a previously unused range of rate
> values.
> This format is already recognized by third party tools such as wireshark
> so let's just do it the same way.
>
> The diff below updates the radiotap docs, makes iwn pass the MCS index,
> shows it in tcpdump. I can now see MCS with iwn in monitor mode.
>
> ok?
Same diff, plus iwn now captures MIMO frames in monitor mode.
Index: sys/net80211/ieee80211_radiotap.h
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_radiotap.h,v
retrieving revision 1.13
diff -u -p -r1.13 ieee80211_radiotap.h
--- sys/net80211/ieee80211_radiotap.h 12 Jan 2016 09:28:09 -0000 1.13
+++ sys/net80211/ieee80211_radiotap.h 7 Oct 2016 13:15:59 -0000
@@ -90,9 +90,10 @@ struct ieee80211_radiotap_header {
* For frequency-hopping radios, the hop set (first byte)
* and pattern (second byte).
*
- * IEEE80211_RADIOTAP_RATE u_int8_t 500kb/s
+ * IEEE80211_RADIOTAP_RATE u_int8_t 500kb/s or MCS index
*
- * Tx/Rx data rate
+ * Tx/Rx data rate in units of 500kb/s. If the high bit (0x80) is set
+ * the remaining bits contain an MCS index instead of a date rate.
*
* IEEE80211_RADIOTAP_DBM_ANTSIGNAL int8_t decibels from
* one milliwatt (dBm)
Index: sys/dev/pci/if_iwn.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v
retrieving revision 1.172
diff -u -p -r1.172 if_iwn.c
--- sys/dev/pci/if_iwn.c 5 Sep 2016 08:18:18 -0000 1.172
+++ sys/dev/pci/if_iwn.c 7 Oct 2016 16:33:39 -0000
@@ -2131,23 +2131,27 @@ iwn_rx_done(struct iwn_softc *sc, struct
tap->wr_dbm_antsignal = (int8_t)rssi;
tap->wr_dbm_antnoise = (int8_t)sc->noise;
tap->wr_tsft = stat->tstamp;
- switch (stat->rate) {
- /* CCK rates. */
- case 10: tap->wr_rate = 2; break;
- case 20: tap->wr_rate = 4; break;
- case 55: tap->wr_rate = 11; break;
- case 110: tap->wr_rate = 22; break;
- /* OFDM rates. */
- case 0xd: tap->wr_rate = 12; break;
- case 0xf: tap->wr_rate = 18; break;
- case 0x5: tap->wr_rate = 24; break;
- case 0x7: tap->wr_rate = 36; break;
- case 0x9: tap->wr_rate = 48; break;
- case 0xb: tap->wr_rate = 72; break;
- case 0x1: tap->wr_rate = 96; break;
- case 0x3: tap->wr_rate = 108; break;
- /* Unknown rate: should not happen. */
- default: tap->wr_rate = 0;
+ if (stat->rflags & IWN_RFLAG_MCS) {
+ tap->wr_rate = (0x80 | stat->rate); /* HT MCS index */
+ } else {
+ switch (stat->rate) {
+ /* CCK rates. */
+ case 10: tap->wr_rate = 2; break;
+ case 20: tap->wr_rate = 4; break;
+ case 55: tap->wr_rate = 11; break;
+ case 110: tap->wr_rate = 22; break;
+ /* OFDM rates. */
+ case 0xd: tap->wr_rate = 12; break;
+ case 0xf: tap->wr_rate = 18; break;
+ case 0x5: tap->wr_rate = 24; break;
+ case 0x7: tap->wr_rate = 36; break;
+ case 0x9: tap->wr_rate = 48; break;
+ case 0xb: tap->wr_rate = 72; break;
+ case 0x1: tap->wr_rate = 96; break;
+ case 0x3: tap->wr_rate = 108; break;
+ /* Unknown rate: should not happen. */
+ default: tap->wr_rate = 0;
+ }
}
mb.m_data = (caddr_t)tap;
@@ -2876,8 +2880,7 @@ iwn_tx(struct iwn_softc *sc, struct mbuf
if ((ni->ni_flags & IEEE80211_NODE_HT) &&
!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
type == IEEE80211_FC0_TYPE_DATA) {
- /* XXX need a way to pass current MCS in 11n mode */
- tap->wt_rate = 0;
+ tap->wt_rate = (0x80 | ni->ni_txmcs);
} else
tap->wt_rate = rinfo->rate;
tap->wt_hwqueue = ac;
@@ -4498,13 +4501,18 @@ iwn_config(struct iwn_softc *sc)
sc->rxon.ht_triple_mask = 0xff;
rxchain =
IWN_RXCHAIN_VALID(sc->rxchainmask) |
- IWN_RXCHAIN_MIMO_COUNT(2) |
- IWN_RXCHAIN_IDLE_COUNT(2);
+ IWN_RXCHAIN_MIMO_COUNT(sc->nrxchains) |
+ IWN_RXCHAIN_IDLE_COUNT(sc->nrxchains);
+ if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+ rxchain |= IWN_RXCHAIN_FORCE_SEL(sc->rxchainmask);
+ rxchain |= IWN_RXCHAIN_FORCE_MIMO_SEL(sc->rxchainmask);
+ rxchain |= (IWN_RXCHAIN_DRIVER_FORCE | IWN_RXCHAIN_MIMO_FORCE);
+ }
sc->rxon.rxchain = htole16(rxchain);
DPRINTF(("setting configuration\n"));
- DPRINTF(("%s: rxon chan %d flags %x cck %x ofdm %x\n", __func__,
- sc->rxon.chan, le32toh(sc->rxon.flags), sc->rxon.cck_mask,
- sc->rxon.ofdm_mask));
+ DPRINTF(("%s: rxon chan %d flags %x cck %x ofdm %x rxchain %x\n",
+ __func__, sc->rxon.chan, le32toh(sc->rxon.flags), sc->rxon.cck_mask,
+ sc->rxon.ofdm_mask, sc->rxon.rxchain));
error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 0);
if (error != 0) {
printf("%s: RXON command failed\n", sc->sc_dev.dv_xname);
Index: usr.sbin/tcpdump/print-802_11.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/print-802_11.c,v
retrieving revision 1.33
diff -u -p -r1.33 print-802_11.c
--- usr.sbin/tcpdump/print-802_11.c 2 Sep 2016 17:11:46 -0000 1.33
+++ usr.sbin/tcpdump/print-802_11.c 7 Oct 2016 12:44:25 -0000
@@ -1075,8 +1075,13 @@ ieee802_11_radio_if_print(u_char *user,
if (RADIOTAP(RATE)) {
TCHECK2(*t, 1);
- if (vflag)
- printf(", %uMbit/s", (*(u_int8_t*)t) / 2);
+ if (vflag) {
+ uint8_t rate = *(u_int8_t*)t;
+ if (rate & 0x80)
+ printf(", MCS %u", rate & 0x7f);
+ else
+ printf(", %uMbit/s", rate / 2);
+ }
t += 1;
}