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
This commit is contained in:
sam 2009-06-02 00:33:28 +00:00
parent 97e535876e
commit 35d42ca22f
7 changed files with 89 additions and 23 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;
}
/*