Discussion:
Make iwn(4) pass control frames in monitor mode
Stefan Sperling
2016-02-03 16:03:46 UTC
Permalink
This allows tcpdump to see all control frames with iwn(4).

Index: if_iwn.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v
retrieving revision 1.158
diff -u -p -r1.158 if_iwn.c
--- if_iwn.c 25 Jan 2016 11:27:11 -0000 1.158
+++ if_iwn.c 3 Feb 2016 16:01:58 -0000
@@ -2007,8 +2007,11 @@ iwn_rx_done(struct iwn_softc *sc, struct
ifp->if_ierrors++;
return;
}
- /* Discard frames that are too short. */
- if (len < sizeof (*wh)) {
+ /*
+ * Discard frames that are too short, unless in monitor mode where we
+ * receive control frames which are shorter than regular data frames.
+ */
+ if (len < sizeof (*wh) && ic->ic_opmode != IEEE80211_M_MONITOR) {
DPRINTF(("frame too short: %d\n", len));
ic->ic_stats.is_rx_tooshort++;
ifp->if_ierrors++;
Mark Kettenis
2016-02-03 16:25:55 UTC
Permalink
Date: Wed, 3 Feb 2016 17:03:46 +0100
This allows tcpdump to see all control frames with iwn(4).
Hmm, the code below that does look inside the frame. How do we
guarantee it isn't looking at garbage or reading beyond the end of the
buffer?
Index: if_iwn.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v
retrieving revision 1.158
diff -u -p -r1.158 if_iwn.c
--- if_iwn.c 25 Jan 2016 11:27:11 -0000 1.158
+++ if_iwn.c 3 Feb 2016 16:01:58 -0000
@@ -2007,8 +2007,11 @@ iwn_rx_done(struct iwn_softc *sc, struct
ifp->if_ierrors++;
return;
}
- /* Discard frames that are too short. */
- if (len < sizeof (*wh)) {
+ /*
+ * Discard frames that are too short, unless in monitor mode where we
+ * receive control frames which are shorter than regular data frames.
+ */
+ if (len < sizeof (*wh) && ic->ic_opmode != IEEE80211_M_MONITOR) {
DPRINTF(("frame too short: %d\n", len));
ic->ic_stats.is_rx_tooshort++;
ifp->if_ierrors++;
Stefan Sperling
2016-02-03 17:47:31 UTC
Permalink
Post by Mark Kettenis
Date: Wed, 3 Feb 2016 17:03:46 +0100
This allows tcpdump to see all control frames with iwn(4).
Hmm, the code below that does look inside the frame. How do we
guarantee it isn't looking at garbage or reading beyond the end of the
buffer?
Eeek, quite right. How about this?

Index: if_iwn.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v
retrieving revision 1.158
diff -u -p -r1.158 if_iwn.c
--- if_iwn.c 25 Jan 2016 11:27:11 -0000 1.158
+++ if_iwn.c 3 Feb 2016 17:44:43 -0000
@@ -2008,7 +2008,15 @@ iwn_rx_done(struct iwn_softc *sc, struct
return;
}
/* Discard frames that are too short. */
- if (len < sizeof (*wh)) {
+ if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+ /* Allow control frames in monitor mode. */
+ if (len < sizeof (struct ieee80211_frame_cts)) {
+ DPRINTF(("frame too short: %d\n", len));
+ ic->ic_stats.is_rx_tooshort++;
+ ifp->if_ierrors++;
+ return;
+ }
+ } else if (len < sizeof (*wh)) {
DPRINTF(("frame too short: %d\n", len));
ic->ic_stats.is_rx_tooshort++;
ifp->if_ierrors++;
@@ -2058,12 +2066,24 @@ iwn_rx_done(struct iwn_softc *sc, struct
m->m_data = head;
m->m_pkthdr.len = m->m_len = len;

- /* Grab a reference to the source node. */
+ /*
+ * Grab a reference to the source node. Note that control frames are
+ * shorter than struct ieee80211_frame but ieee80211_find_rxnode()
+ * is being careful about control frames.
+ */
wh = mtod(m, struct ieee80211_frame *);
+ if (len < sizeof (*wh) &&
+ (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
+ ic->ic_stats.is_rx_tooshort++;
+ ifp->if_ierrors++;
+ m_freem(m);
+ return;
+ }
ni = ieee80211_find_rxnode(ic, wh);

rxi.rxi_flags = 0;
- if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
+ if (((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL)
+ && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
(ni->ni_flags & IEEE80211_NODE_RXPROT) &&
ni->ni_pairwise_key.k_cipher == IEEE80211_CIPHER_CCMP) {

Loading...