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 &&

Reply via email to