This diff makes 'tcpdump -i iwn0 -y IEEE802_11_RADIO' show the correct mode for a channel in 11n mode. Before: <radiotap v0, chan 36, 11a, sig -46dBm, noise -91dBm> After: <radiotap v0, chan 36, 11n, sig -46dBm, noise -91dBm>
Unfortunately this requires a kernel tweak because the kernel must be more careful about the channel flags it passes to userland. Channels exist in the 11b/g (2GHz) and 11a (5GHz) ranges. So net80211 has a "mode" concept, where a given mode is available if supported channels exist in a particular range. And there is the default "auto" mode which picks one of the other available modes. (This may not be the best design but it is how it was designed historically. Changing this is not in my radar.) The HT-channel flag is set to indicate whether a channel may be used in 11n mode. In practice this is just the superset of all channels supported by the device. When 11n support was introduced it was easier to fold the new 11n mode into the existing code with a flag like this, and avoid letting 11n mode be a special case which works against this design. And this HT-channel flag is set regardless of whether we're currently in 11n mode because we need this flag to enter 11n mode from another mode. A mode which has no channels available to it is not available. So the kernel needs this flag to be set on all channels at all times if the driver supports 11n. Now, we copy this flag out to userspace even in non-11n modes. If the kernel instead omits the HT-channel flag from the userspace copy if the current mode is not 11n, then tcpdump can inspect this flag to detect whether the channel is in fact an "11n" channel and print the mode correctly. In the end, this is just a cosmetic fix. If this is too much code churn and quirks for too little gain, I am happy to drop this diff. Index: sys/dev/pci/if_iwm.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v retrieving revision 1.154 diff -u -p -r1.154 if_iwm.c --- sys/dev/pci/if_iwm.c 10 Dec 2016 19:03:53 -0000 1.154 +++ sys/dev/pci/if_iwm.c 11 Dec 2016 14:54:58 -0000 @@ -3339,14 +3339,17 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, str if (sc->sc_drvbpf != NULL) { struct mbuf mb; struct iwm_rx_radiotap_header *tap = &sc->sc_rxtap; + uint16_t chan_flags; tap->wr_flags = 0; if (phy_info->phy_flags & htole16(IWM_PHY_INFO_FLAG_SHPREAMBLE)) tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; tap->wr_chan_freq = htole16(ic->ic_channels[phy_info->channel].ic_freq); - tap->wr_chan_flags = - htole16(ic->ic_channels[phy_info->channel].ic_flags); + chan_flags = ic->ic_channels[phy_info->channel].ic_flags; + if (ic->ic_curmode != IEEE80211_MODE_11N) + chan_flags &= ~IEEE80211_CHAN_HT; + tap->wr_chan_flags = htole16(chan_flags); tap->wr_dbm_antsignal = (int8_t)rssi; tap->wr_dbm_antnoise = (int8_t)sc->sc_noise; tap->wr_tsft = phy_info->system_timestamp; @@ -3991,10 +3994,14 @@ iwm_tx(struct iwm_softc *sc, struct mbuf if (sc->sc_drvbpf != NULL) { struct mbuf mb; struct iwm_tx_radiotap_header *tap = &sc->sc_txtap; + uint16_t chan_flags; tap->wt_flags = 0; tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq); - tap->wt_chan_flags = htole16(ni->ni_chan->ic_flags); + chan_flags = ni->ni_chan->ic_flags; + if (ic->ic_curmode != IEEE80211_MODE_11N) + chan_flags &= ~IEEE80211_CHAN_HT; + tap->wt_chan_flags = htole16(chan_flags); if ((ni->ni_flags & IEEE80211_NODE_HT) && !IEEE80211_IS_MULTICAST(wh->i_addr1) && type == IEEE80211_FC0_TYPE_DATA && Index: sys/dev/pci/if_iwn.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v retrieving revision 1.178 diff -u -p -r1.178 if_iwn.c --- sys/dev/pci/if_iwn.c 10 Dec 2016 13:22:07 -0000 1.178 +++ sys/dev/pci/if_iwn.c 11 Dec 2016 14:54:25 -0000 @@ -2130,14 +2130,17 @@ iwn_rx_done(struct iwn_softc *sc, struct if (sc->sc_drvbpf != NULL) { struct mbuf mb; struct iwn_rx_radiotap_header *tap = &sc->sc_rxtap; + uint16_t chan_flags; tap->wr_flags = 0; if (stat->flags & htole16(IWN_STAT_FLAG_SHPREAMBLE)) tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; tap->wr_chan_freq = htole16(ic->ic_channels[stat->chan].ic_freq); - tap->wr_chan_flags = - htole16(ic->ic_channels[stat->chan].ic_flags); + chan_flags = ic->ic_channels[stat->chan].ic_flags; + if (ic->ic_curmode != IEEE80211_MODE_11N) + chan_flags &= ~IEEE80211_CHAN_HT; + tap->wr_chan_flags = htole16(chan_flags); tap->wr_dbm_antsignal = (int8_t)rssi; tap->wr_dbm_antnoise = (int8_t)sc->noise; tap->wr_tsft = stat->tstamp; @@ -2908,10 +2911,14 @@ iwn_tx(struct iwn_softc *sc, struct mbuf if (sc->sc_drvbpf != NULL) { struct mbuf mb; struct iwn_tx_radiotap_header *tap = &sc->sc_txtap; + uint16_t chan_flags; tap->wt_flags = 0; tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq); - tap->wt_chan_flags = htole16(ni->ni_chan->ic_flags); + chan_flags = ni->ni_chan->ic_flags; + if (ic->ic_curmode != IEEE80211_MODE_11N) + chan_flags &= ~IEEE80211_CHAN_HT; + tap->wt_chan_flags = htole16(chan_flags); if ((ni->ni_flags & IEEE80211_NODE_HT) && !IEEE80211_IS_MULTICAST(wh->i_addr1) && type == IEEE80211_FC0_TYPE_DATA) { Index: sys/net80211/ieee80211_ioctl.c =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_ioctl.c,v retrieving revision 1.44 diff -u -p -r1.44 ieee80211_ioctl.c --- sys/net80211/ieee80211_ioctl.c 15 Sep 2016 03:32:48 -0000 1.44 +++ sys/net80211/ieee80211_ioctl.c 11 Dec 2016 14:56:03 -0000 @@ -71,6 +71,8 @@ ieee80211_node2req(struct ieee80211com * /* Channel and rates */ nr->nr_channel = ieee80211_chan2ieee(ic, ni->ni_chan); nr->nr_chan_flags = ni->ni_chan->ic_flags; + if (ic->ic_curmode != IEEE80211_MODE_11N) + nr->nr_chan_flags &= ~IEEE80211_CHAN_HT; nr->nr_nrates = ni->ni_rates.rs_nrates; bcopy(ni->ni_rates.rs_rates, nr->nr_rates, IEEE80211_RATE_MAXSIZE); Index: usr.sbin/tcpdump/print-802_11.c =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/print-802_11.c,v retrieving revision 1.35 diff -u -p -r1.35 print-802_11.c --- usr.sbin/tcpdump/print-802_11.c 19 Nov 2016 19:35:46 -0000 1.35 +++ usr.sbin/tcpdump/print-802_11.c 11 Dec 2016 14:18:05 -0000 @@ -1101,7 +1101,12 @@ ieee802_11_radio_if_print(u_char *user, printf(", chan %u", ieee80211_any2ieee(freq, flags)); - if (flags & IEEE80211_CHAN_DYN && + if (flags & IEEE80211_CHAN_HT) + printf(", 11n"); + else if (flags & IEEE80211_CHAN_DYN && + flags & IEEE80211_CHAN_2GHZ) + printf(", 11g"); + else if (flags & IEEE80211_CHAN_DYN && flags & IEEE80211_CHAN_2GHZ) printf(", 11g"); else if (flags & IEEE80211_CHAN_CCK &&