diff options
author | sam <sam@FreeBSD.org> | 2009-06-02 00:33:28 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2009-06-02 00:33:28 +0000 |
commit | 35d42ca22fe811992438e1615568d4e7635edba0 (patch) | |
tree | ccf8dc084c04cab525bd2e37c6e5fc02f735b98b | |
parent | 97e535876ee2651cea94436136470eb9445e3f95 (diff) | |
download | FreeBSD-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.c | 4 | ||||
-rw-r--r-- | sys/net80211/ieee80211_ddb.c | 5 | ||||
-rw-r--r-- | sys/net80211/ieee80211_freebsd.c | 9 | ||||
-rw-r--r-- | sys/net80211/ieee80211_hostap.c | 6 | ||||
-rw-r--r-- | sys/net80211/ieee80211_input.c | 8 | ||||
-rw-r--r-- | sys/net80211/ieee80211_radiotap.c | 75 | ||||
-rw-r--r-- | sys/net80211/ieee80211_var.h | 5 |
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; } /* |