summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2009-06-02 00:33:28 +0000
committersam <sam@FreeBSD.org>2009-06-02 00:33:28 +0000
commit35d42ca22fe811992438e1615568d4e7635edba0 (patch)
treeccf8dc084c04cab525bd2e37c6e5fc02f735b98b
parent97e535876ee2651cea94436136470eb9445e3f95 (diff)
downloadFreeBSD-src-35d42ca22fe811992438e1615568d4e7635edba0.zip
FreeBSD-src-35d42ca22fe811992438e1615568d4e7635edba0.tar.gz
Fix monitor mode vaps to work as intended:
o track # bpf taps on monitor mode vaps instead of # monitor mode vaps o spam monitor mode taps on tx/rx o fix ieee80211_radiotap_rx_all to dispatch frames only if the vap is up o while here print radiotap (and superg) state in show com
-rw-r--r--sys/net80211/ieee80211.c4
-rw-r--r--sys/net80211/ieee80211_ddb.c5
-rw-r--r--sys/net80211/ieee80211_freebsd.c9
-rw-r--r--sys/net80211/ieee80211_hostap.c6
-rw-r--r--sys/net80211/ieee80211_input.c8
-rw-r--r--sys/net80211/ieee80211_radiotap.c75
-rw-r--r--sys/net80211/ieee80211_var.h5
7 files changed, 89 insertions, 23 deletions
diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c
index 22c690c..c2f0015 100644
--- a/sys/net80211/ieee80211.c
+++ b/sys/net80211/ieee80211.c
@@ -513,8 +513,6 @@ ieee80211_vap_attach(struct ieee80211vap *vap,
IEEE80211_LOCK(ic);
TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next);
- if (vap->iv_opmode == IEEE80211_M_MONITOR)
- ic->ic_monvaps++;
ieee80211_syncflag_locked(ic, IEEE80211_F_WME);
#ifdef IEEE80211_SUPPORT_SUPERG
ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP);
@@ -575,8 +573,6 @@ ieee80211_vap_detach(struct ieee80211vap *vap)
IEEE80211_LOCK(ic);
KASSERT(vap->iv_state == IEEE80211_S_INIT , ("vap still running"));
TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next);
- if (vap->iv_opmode == IEEE80211_M_MONITOR)
- ic->ic_monvaps--;
ieee80211_syncflag_locked(ic, IEEE80211_F_WME);
#ifdef IEEE80211_SUPPORT_SUPERG
ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP);
diff --git a/sys/net80211/ieee80211_ddb.c b/sys/net80211/ieee80211_ddb.c
index 8545140..2b66d6b 100644
--- a/sys/net80211/ieee80211_ddb.c
+++ b/sys/net80211/ieee80211_ddb.c
@@ -584,6 +584,11 @@ _db_show_com(const struct ieee80211com *ic, int showvaps, int showsta, int showp
db_printf(" lastnonht %d", ic->ic_lastnonht);
db_printf("\n");
+ db_printf("\tsuperg %p\n", ic->ic_superg);
+
+ db_printf("\tmontaps %d th %p txchan %p rh %p rxchan %p\n",
+ ic->ic_montaps, ic->ic_th, ic->ic_txchan, ic->ic_rh, ic->ic_rxchan);
+
if (showprocs) {
DB_PRINTSYM("\t", "ic_vap_create", ic->ic_vap_create);
DB_PRINTSYM("\t", "ic_vap_delete", ic->ic_vap_delete);
diff --git a/sys/net80211/ieee80211_freebsd.c b/sys/net80211/ieee80211_freebsd.c
index 0dfa4a9..481ef881 100644
--- a/sys/net80211/ieee80211_freebsd.c
+++ b/sys/net80211/ieee80211_freebsd.c
@@ -706,11 +706,16 @@ bpf_track(void *arg, struct ifnet *ifp, int dlt, int attach)
* vap. This flag is used by drivers to prepare radiotap
* state only when needed.
*/
- if (attach)
+ if (attach) {
ieee80211_syncflag_ext(vap, IEEE80211_FEXT_BPF);
+ if (vap->iv_opmode == IEEE80211_M_MONITOR)
+ atomic_add_int(&vap->iv_ic->ic_montaps, 1);
/* NB: if_softc is NULL on vap detach */
- else if (vap != NULL && !bpf_peers_present(vap->iv_rawbpf))
+ } else if (vap != NULL && !bpf_peers_present(vap->iv_rawbpf)) {
ieee80211_syncflag_ext(vap, -IEEE80211_FEXT_BPF);
+ if (vap->iv_opmode == IEEE80211_M_MONITOR)
+ atomic_subtract_int(&vap->iv_ic->ic_montaps, 1);
+ }
}
}
diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c
index ee83eace..eec52f9 100644
--- a/sys/net80211/ieee80211_hostap.c
+++ b/sys/net80211/ieee80211_hostap.c
@@ -302,6 +302,9 @@ hostap_deliver_data(struct ieee80211vap *vap,
struct ether_header *eh = mtod(m, struct ether_header *);
struct ifnet *ifp = vap->iv_ifp;
+ /* clear driver/net80211 flags before passing up */
+ m->m_flags &= ~(M_80211_RX | M_MCAST | M_BCAST);
+
KASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP,
("gack, opmode %d", vap->iv_opmode));
/*
@@ -316,9 +319,6 @@ hostap_deliver_data(struct ieee80211vap *vap,
} else
IEEE80211_NODE_STAT(ni, rx_ucast);
- /* clear driver/net80211 flags before passing up */
- m->m_flags &= ~M_80211_RX;
-
/* perform as a bridge within the AP */
if ((vap->iv_flags & IEEE80211_F_NOBRIDGE) == 0) {
struct mbuf *mcopy = NULL;
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index 3cd9d8a..53c2285 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -60,6 +60,8 @@ ieee80211_input_all(struct ieee80211com *ic, struct mbuf *m, int rssi, int nf)
struct ieee80211vap *vap;
int type = -1;
+ m->m_flags |= M_BCAST; /* NB: mark for bpf tap'ing */
+
/* XXX locking */
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
struct ieee80211_node *ni;
@@ -199,6 +201,9 @@ ieee80211_deliver_data(struct ieee80211vap *vap,
struct ether_header *eh = mtod(m, struct ether_header *);
struct ifnet *ifp = vap->iv_ifp;
+ /* clear driver/net80211 flags before passing up */
+ m->m_flags &= ~(M_80211_RX | M_MCAST | M_BCAST);
+
/* NB: see hostap_deliver_data, this path doesn't handle hostap */
KASSERT(vap->iv_opmode != IEEE80211_M_HOSTAP, ("gack, hostap"));
/*
@@ -214,9 +219,6 @@ ieee80211_deliver_data(struct ieee80211vap *vap,
IEEE80211_NODE_STAT(ni, rx_ucast);
m->m_pkthdr.rcvif = ifp;
- /* clear driver/net80211 flags before passing up */
- m->m_flags &= ~M_80211_RX;
-
if (ni->ni_vlan != 0) {
/* attach vlan tag */
m->m_pkthdr.ether_vtag = ni->ni_vlan;
diff --git a/sys/net80211/ieee80211_radiotap.c b/sys/net80211/ieee80211_radiotap.c
index 9c8dc4d..b39a071 100644
--- a/sys/net80211/ieee80211_radiotap.c
+++ b/sys/net80211/ieee80211_radiotap.c
@@ -168,6 +168,7 @@ ieee80211_radiotap_chan_change(struct ieee80211com *ic)
}
}
+#if 0
static void
dispatch_radiotap(struct ieee80211vap *vap0, struct mbuf *m,
struct ieee80211_radiotap_header *rh)
@@ -175,17 +176,46 @@ dispatch_radiotap(struct ieee80211vap *vap0, struct mbuf *m,
struct ieee80211com *ic = vap0->iv_ic;
int len = le16toh(rh->it_len);
- if (ieee80211_radiotap_active_vap(vap0))
+ if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF)
bpf_mtap2(vap0->iv_rawbpf, rh, len, m);
- if (ic->ic_monvaps) {
+ /*
+ * Spam monitor mode vaps with unicast frames. Multicast
+ * frames are handled by passing through ieee80211_input_all
+ * which distributes copies to the monitor mode vaps to be
+ * processed above.
+ */
+ if (ic->ic_montaps != 0 && (m->m_flags & M_BCAST) == 0) {
struct ieee80211vap *vap;
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
- if (vap->iv_opmode == IEEE80211_M_MONITOR &&
- vap != vap0 && ieee80211_radiotap_active_vap(vap))
+ if (vap != vap0 &&
+ vap->iv_opmode == IEEE80211_M_MONITOR &&
+ (vap->iv_flags_ext & IEEE80211_FEXT_BPF) &&
+ vap->iv_state != IEEE80211_S_INIT)
bpf_mtap2(vap->iv_rawbpf, rh, len, m);
}
}
}
+#endif
+
+/*
+ * Distribute radiotap data (+packet) to all monitor mode
+ * vaps with an active tap other than vap0.
+ */
+static void
+spam_vaps(struct ieee80211vap *vap0, struct mbuf *m,
+ struct ieee80211_radiotap_header *rh, int len)
+{
+ struct ieee80211com *ic = vap0->iv_ic;
+ struct ieee80211vap *vap;
+
+ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+ if (vap != vap0 &&
+ vap->iv_opmode == IEEE80211_M_MONITOR &&
+ (vap->iv_flags_ext & IEEE80211_FEXT_BPF) &&
+ vap->iv_state != IEEE80211_S_INIT)
+ bpf_mtap2(vap->iv_rawbpf, rh, len, m);
+ }
+}
/*
* Dispatch radiotap data for transmitted packet.
@@ -193,8 +223,20 @@ dispatch_radiotap(struct ieee80211vap *vap0, struct mbuf *m,
void
ieee80211_radiotap_tx(struct ieee80211vap *vap0, struct mbuf *m)
{
- KASSERT(vap0->iv_ic->ic_th != NULL, ("no tx radiotap header"));
- dispatch_radiotap(vap0, m, vap0->iv_ic->ic_th);
+ struct ieee80211com *ic = vap0->iv_ic;
+ struct ieee80211_radiotap_header *th = ic->ic_th;
+ int len;
+
+ KASSERT(th != NULL, ("no tx radiotap header"));
+ len = le16toh(th->it_len);
+
+ if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF)
+ bpf_mtap2(vap0->iv_rawbpf, th, len, m);
+ /*
+ * Spam monitor mode vaps.
+ */
+ if (ic->ic_montaps != 0)
+ spam_vaps(vap0, m, th, len);
}
/*
@@ -203,8 +245,22 @@ ieee80211_radiotap_tx(struct ieee80211vap *vap0, struct mbuf *m)
void
ieee80211_radiotap_rx(struct ieee80211vap *vap0, struct mbuf *m)
{
- KASSERT(vap0->iv_ic->ic_rh != NULL, ("no rx radiotap header"));
- dispatch_radiotap(vap0, m, vap0->iv_ic->ic_rh);
+ struct ieee80211com *ic = vap0->iv_ic;
+ struct ieee80211_radiotap_header *rh = ic->ic_rh;
+ int len;
+
+ KASSERT(rh != NULL, ("no rx radiotap header"));
+ len = le16toh(rh->it_len);
+
+ if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF)
+ bpf_mtap2(vap0->iv_rawbpf, rh, len, m);
+ /*
+ * Spam monitor mode vaps with unicast frames. Multicast
+ * frames are handled by passing through ieee80211_input_all
+ * which distributes copies to the monitor mode vaps.
+ */
+ if (ic->ic_montaps != 0 && (m->m_flags & M_BCAST) == 0)
+ spam_vaps(vap0, m, rh, len);
}
/*
@@ -221,7 +277,8 @@ ieee80211_radiotap_rx_all(struct ieee80211com *ic, struct mbuf *m)
/* XXX locking? */
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
- if (ieee80211_radiotap_active_vap(vap))
+ if (ieee80211_radiotap_active_vap(vap) &&
+ vap->iv_state != IEEE80211_S_INIT)
bpf_mtap2(vap->iv_rawbpf, rh, len, m);
}
}
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index 31037fe..3e999c8 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -215,7 +215,7 @@ struct ieee80211com {
void *ic_txchan; /* channel state in ic_th */
struct ieee80211_radiotap_header *ic_rh;/* rx radiotap headers */
void *ic_rxchan; /* channel state in ic_rh */
- int ic_monvaps; /* # monitor mode vaps */
+ int ic_montaps; /* active monitor mode taps */
/* virtual ap create/delete */
struct ieee80211vap* (*ic_vap_create)(struct ieee80211com *,
@@ -669,7 +669,8 @@ ieee80211_radiotap_active(const struct ieee80211com *ic)
static __inline int
ieee80211_radiotap_active_vap(const struct ieee80211vap *vap)
{
- return (vap->iv_flags_ext & IEEE80211_FEXT_BPF) != 0;
+ return (vap->iv_flags_ext & IEEE80211_FEXT_BPF) ||
+ vap->iv_ic->ic_montaps != 0;
}
/*
OpenPOWER on IntegriCloud