diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c index 22c690cd4a3c..c2f0015f9890 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 85451409a8be..2b66d6bc8dbb 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 0dfa4a966c87..481ef8818b70 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 ee83eacef112..eec52f93cc42 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 3cd9d8ad10ac..53c2285592bb 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 9c8dc4dcdd0b..b39a0713aad3 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 31037fed31ba..3e999c8da881 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; } /*