summaryrefslogtreecommitdiffstats
path: root/sys/net80211
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2009-05-20 20:00:40 +0000
committersam <sam@FreeBSD.org>2009-05-20 20:00:40 +0000
commit68f7a1034ab73897585652ceedd3727d57150c12 (patch)
treec9b0cc01e080db542eb19f65236177aacfa14b5d /sys/net80211
parentdf90a80062bff5ee7300c9b15aaeeaa9c1b49b5e (diff)
downloadFreeBSD-src-68f7a1034ab73897585652ceedd3727d57150c12.zip
FreeBSD-src-68f7a1034ab73897585652ceedd3727d57150c12.tar.gz
Overhaul monitor mode handling:
o replace DLT_IEEE802_11 support in net80211 with DLT_IEEE802_11_RADIO and remove explicit bpf support from wireless drivers; drivers now use ieee80211_radiotap_attach to setup shared data structures that hold the radiotap header for each packet tx/rx o remove rx timestamp from the rx path; it was used only by the tdma support for debugging and was mostly useless due to it being 32-bits and mostly unavailable o track DLT_IEEE80211_RADIO bpf attachments and maintain per-vap and per-com state when there are active taps o track the number of monitor mode vaps o use bpf tap and monitor mode vap state to decide when to collect radiotap state and dispatch frames; drivers no longer explicitly directly check bpf state or use bpf calls to tap frames o handle radiotap state updates on channel change in net80211; drivers should not do this (unless they bypass net80211 which is almost always a mistake) o update various drivers to be more consistent/correct in handling radiotap o update ral to include TSF in radiotap'd frames o add promisc mode callback to wi Reviewed by: cbzimmer, rpaulo, thompsa
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/ieee80211.c11
-rw-r--r--sys/net80211/ieee80211_adhoc.c35
-rw-r--r--sys/net80211/ieee80211_ddb.c6
-rw-r--r--sys/net80211/ieee80211_freebsd.c29
-rw-r--r--sys/net80211/ieee80211_hostap.c42
-rw-r--r--sys/net80211/ieee80211_ht.c4
-rw-r--r--sys/net80211/ieee80211_input.c5
-rw-r--r--sys/net80211/ieee80211_monitor.c8
-rw-r--r--sys/net80211/ieee80211_node.c6
-rw-r--r--sys/net80211/ieee80211_node.h1
-rw-r--r--sys/net80211/ieee80211_output.c7
-rw-r--r--sys/net80211/ieee80211_proto.c1
-rw-r--r--sys/net80211/ieee80211_proto.h7
-rw-r--r--sys/net80211/ieee80211_radiotap.c325
-rw-r--r--sys/net80211/ieee80211_scan.c6
-rw-r--r--sys/net80211/ieee80211_scan.h5
-rw-r--r--sys/net80211/ieee80211_scan_sta.c3
-rw-r--r--sys/net80211/ieee80211_sta.c39
-rw-r--r--sys/net80211/ieee80211_superg.c4
-rw-r--r--sys/net80211/ieee80211_tdma.c19
-rw-r--r--sys/net80211/ieee80211_tdma.h2
-rw-r--r--sys/net80211/ieee80211_var.h41
-rw-r--r--sys/net80211/ieee80211_wds.c39
23 files changed, 503 insertions, 142 deletions
diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c
index 2e75965..22c690c 100644
--- a/sys/net80211/ieee80211.c
+++ b/sys/net80211/ieee80211.c
@@ -465,6 +465,7 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap,
ieee80211_ht_vattach(vap);
ieee80211_scan_vattach(vap);
ieee80211_regdomain_vattach(vap);
+ ieee80211_radiotap_vattach(vap);
return 0;
}
@@ -509,10 +510,11 @@ ieee80211_vap_attach(struct ieee80211vap *vap,
vap->iv_output = ifp->if_output;
ifp->if_output = ieee80211_output;
/* NB: if_mtu set by ether_ifattach to ETHERMTU */
- bpfattach2(ifp, DLT_IEEE802_11, ifp->if_hdrlen, &vap->iv_rawbpf);
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);
@@ -573,6 +575,8 @@ 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);
@@ -581,16 +585,19 @@ ieee80211_vap_detach(struct ieee80211vap *vap)
ieee80211_syncflag_locked(ic, IEEE80211_F_BURST);
ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_HT);
ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_USEHT40);
+ /* NB: this handles the bpfdetach done below */
+ ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_BPF);
ieee80211_syncifflag_locked(ic, IFF_PROMISC);
ieee80211_syncifflag_locked(ic, IFF_ALLMULTI);
IEEE80211_UNLOCK(ic);
/* XXX can't hold com lock */
- /* NB: bpfattach is called by ether_ifdetach and claims all taps */
+ /* NB: bpfdetach is called by ether_ifdetach and claims all taps */
ether_ifdetach(ifp);
ifmedia_removeall(&vap->iv_media);
+ ieee80211_radiotap_vdetach(vap);
ieee80211_regdomain_vdetach(vap);
ieee80211_scan_vdetach(vap);
#ifdef IEEE80211_SUPPORT_SUPERG
diff --git a/sys/net80211/ieee80211_adhoc.c b/sys/net80211/ieee80211_adhoc.c
index 3b230e6..8f37808 100644
--- a/sys/net80211/ieee80211_adhoc.c
+++ b/sys/net80211/ieee80211_adhoc.c
@@ -68,12 +68,11 @@ __FBSDID("$FreeBSD$");
static void adhoc_vattach(struct ieee80211vap *);
static int adhoc_newstate(struct ieee80211vap *, enum ieee80211_state, int);
-static int adhoc_input(struct ieee80211_node *, struct mbuf *,
- int rssi, int noise, uint32_t rstamp);
+static int adhoc_input(struct ieee80211_node *, struct mbuf *, int, int);
static void adhoc_recv_mgmt(struct ieee80211_node *, struct mbuf *,
- int subtype, int rssi, int noise, uint32_t rstamp);
+ int subtype, int, int);
static void ahdemo_recv_mgmt(struct ieee80211_node *, struct mbuf *,
- int subtype, int rssi, int noise, uint32_t rstamp);
+ int subtype, int, int);
static void adhoc_recv_ctl(struct ieee80211_node *, struct mbuf *, int subtype);
void
@@ -284,8 +283,7 @@ doprint(struct ieee80211vap *vap, int subtype)
* by the 802.11 layer.
*/
static int
-adhoc_input(struct ieee80211_node *ni, struct mbuf *m,
- int rssi, int noise, uint32_t rstamp)
+adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
{
#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0)
#define HAS_SEQ(type) ((type & 0x4) == 0)
@@ -408,8 +406,7 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m,
}
}
IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
- ni->ni_noise = noise;
- ni->ni_rstamp = rstamp;
+ ni->ni_noise = nf;
if (HAS_SEQ(type)) {
uint8_t tid = ieee80211_gettid(wh);
if (IEEE80211_QOS_HAS_SEQ(wh) &&
@@ -536,8 +533,8 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m,
}
/* copy to listener after decrypt */
- if (bpf_peers_present(vap->iv_rawbpf))
- bpf_mtap(vap->iv_rawbpf, m);
+ if (ieee80211_radiotap_active_vap(vap))
+ ieee80211_radiotap_rx(vap, m);
need_tap = 0;
/*
@@ -640,7 +637,7 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m,
vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
goto out;
}
- vap->iv_recv_mgmt(ni, m, subtype, rssi, noise, rstamp);
+ vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
goto out;
case IEEE80211_FC0_TYPE_CTL:
@@ -659,8 +656,8 @@ err:
ifp->if_ierrors++;
out:
if (m != NULL) {
- if (need_tap && bpf_peers_present(vap->iv_rawbpf))
- bpf_mtap(vap->iv_rawbpf, m);
+ if (need_tap)
+ ieee80211_radiotap_rx(vap, m);
m_freem(m);
}
return type;
@@ -686,7 +683,7 @@ is11bclient(const uint8_t *rates, const uint8_t *xrates)
static void
adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
- int subtype, int rssi, int noise, uint32_t rstamp)
+ int subtype, int rssi, int nf)
{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
@@ -731,8 +728,7 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
ieee80211_probe_curchan(vap, 1);
ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
}
- ieee80211_add_scan(vap, &scan, wh,
- subtype, rssi, noise, rstamp);
+ ieee80211_add_scan(vap, &scan, wh, subtype, rssi, nf);
return;
}
if (scan.capinfo & IEEE80211_CAPINFO_IBSS) {
@@ -756,8 +752,7 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
}
if (ni != NULL) {
IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
- ni->ni_noise = noise;
- ni->ni_rstamp = rstamp;
+ ni->ni_noise = nf;
}
}
break;
@@ -912,7 +907,7 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
static void
ahdemo_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
- int subtype, int rssi, int noise, uint32_t rstamp)
+ int subtype, int rssi, int nf)
{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
@@ -922,7 +917,7 @@ ahdemo_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
* a site-survey.
*/
if (ic->ic_flags & IEEE80211_F_SCAN)
- adhoc_recv_mgmt(ni, m0, subtype, rssi, noise, rstamp);
+ adhoc_recv_mgmt(ni, m0, subtype, rssi, nf);
else
vap->iv_stats.is_rx_mgtdiscard++;
}
diff --git a/sys/net80211/ieee80211_ddb.c b/sys/net80211/ieee80211_ddb.c
index ea4e89f..8545140 100644
--- a/sys/net80211/ieee80211_ddb.c
+++ b/sys/net80211/ieee80211_ddb.c
@@ -255,9 +255,9 @@ _db_show_sta(const struct ieee80211_node *ni)
db_printf("\trxfrag[0] %p rxfrag[1] %p rxfrag[2] %p\n",
ni->ni_rxfrag[0], ni->ni_rxfrag[1], ni->ni_rxfrag[2]);
_db_show_key("\tucastkey", 0, &ni->ni_ucastkey);
- db_printf("\trstamp %u avgrssi 0x%x (rssi %d) noise %d\n",
- ni->ni_rstamp, ni->ni_avgrssi,
- IEEE80211_RSSI_GET(ni->ni_avgrssi), ni->ni_noise);
+ db_printf("\tavgrssi 0x%x (rssi %d) noise %d\n",
+ ni->ni_avgrssi, IEEE80211_RSSI_GET(ni->ni_avgrssi),
+ ni->ni_noise);
db_printf("\tintval %u capinfo %b\n",
ni->ni_intval, ni->ni_capinfo, IEEE80211_CAPINFO_BITS);
db_printf("\tbssid %s", ether_sprintf(ni->ni_bssid));
diff --git a/sys/net80211/ieee80211_freebsd.c b/sys/net80211/ieee80211_freebsd.c
index e96e71d..89292a6 100644
--- a/sys/net80211/ieee80211_freebsd.c
+++ b/sys/net80211/ieee80211_freebsd.c
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <sys/vimage.h>
+#include <net/bpf.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_clone.h>
@@ -726,6 +727,29 @@ ieee80211_load_module(const char *modname)
#endif
}
+static eventhandler_tag wlan_bpfevent;
+
+static void
+bpf_track(void *arg, struct ifnet *ifp, int attach)
+{
+ /* NB: identify vap's by if_start */
+ if (ifp->if_start == ieee80211_start) {
+ struct ieee80211vap *vap = ifp->if_softc;
+ /*
+ * Track bpf radiotap listener state. We mark the vap
+ * to indicate if any listener is present and the com
+ * to indicate if any listener exists on any associated
+ * vap. This flag is used by drivers to prepare radiotap
+ * state only when needed.
+ */
+ if (attach)
+ ieee80211_syncflag_ext(vap, IEEE80211_FEXT_BPF);
+ /* NB: if_softc is NULL on vap detach */
+ else if (vap != NULL && !bpf_peers_present(vap->iv_rawbpf))
+ ieee80211_syncflag_ext(vap, -IEEE80211_FEXT_BPF);
+ }
+}
+
/*
* Module glue.
*
@@ -738,12 +762,17 @@ wlan_modevent(module_t mod, int type, void *unused)
case MOD_LOAD:
if (bootverbose)
printf("wlan: <802.11 Link Layer>\n");
+ wlan_bpfevent = EVENTHANDLER_REGISTER(bpf_track,
+ bpf_track, 0, EVENTHANDLER_PRI_ANY);
+ if (wlan_bpfevent == NULL)
+ return ENOMEM;
if_clone_attach(&wlan_cloner);
if_register_com_alloc(IFT_IEEE80211, wlan_alloc, wlan_free);
return 0;
case MOD_UNLOAD:
if_deregister_com_alloc(IFT_IEEE80211);
if_clone_detach(&wlan_cloner);
+ EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent);
return 0;
}
return EINVAL;
diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c
index 5bf8baf..9264a71 100644
--- a/sys/net80211/ieee80211_hostap.c
+++ b/sys/net80211/ieee80211_hostap.c
@@ -67,11 +67,11 @@ __FBSDID("$FreeBSD$");
static void hostap_vattach(struct ieee80211vap *);
static int hostap_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static int hostap_input(struct ieee80211_node *ni, struct mbuf *m,
- int rssi, int noise, uint32_t rstamp);
+ int rssi, int nf);
static void hostap_deliver_data(struct ieee80211vap *,
struct ieee80211_node *, struct mbuf *);
static void hostap_recv_mgmt(struct ieee80211_node *, struct mbuf *,
- int subtype, int rssi, int noise, uint32_t rstamp);
+ int subtype, int rssi, int nf);
static void hostap_recv_ctl(struct ieee80211_node *, struct mbuf *, int);
static void hostap_recv_pspoll(struct ieee80211_node *, struct mbuf *);
@@ -418,8 +418,7 @@ doprint(struct ieee80211vap *vap, int subtype)
* by the 802.11 layer.
*/
static int
-hostap_input(struct ieee80211_node *ni, struct mbuf *m,
- int rssi, int noise, uint32_t rstamp)
+hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
{
#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0)
#define HAS_SEQ(type) ((type & 0x4) == 0)
@@ -515,8 +514,7 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m,
}
IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
- ni->ni_noise = noise;
- ni->ni_rstamp = rstamp;
+ ni->ni_noise = nf;
if (HAS_SEQ(type)) {
uint8_t tid = ieee80211_gettid(wh);
if (IEEE80211_QOS_HAS_SEQ(wh) &&
@@ -699,8 +697,8 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m,
goto out;
}
/* copy to listener after decrypt */
- if (bpf_peers_present(vap->iv_rawbpf))
- bpf_mtap(vap->iv_rawbpf, m);
+ if (ieee80211_radiotap_active_vap(vap))
+ ieee80211_radiotap_rx(vap, m);
need_tap = 0;
/*
* Finally, strip the 802.11 header.
@@ -834,7 +832,7 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m,
wh = mtod(m, struct ieee80211_frame *);
wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
}
- vap->iv_recv_mgmt(ni, m, subtype, rssi, noise, rstamp);
+ vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
goto out;
case IEEE80211_FC0_TYPE_CTL:
@@ -852,8 +850,8 @@ err:
ifp->if_ierrors++;
out:
if (m != NULL) {
- if (need_tap && bpf_peers_present(vap->iv_rawbpf))
- bpf_mtap(vap->iv_rawbpf, m);
+ if (need_tap)
+ ieee80211_radiotap_rx(vap, m);
m_freem(m);
}
return type;
@@ -862,7 +860,7 @@ out:
static void
hostap_auth_open(struct ieee80211_node *ni, struct ieee80211_frame *wh,
- int rssi, int noise, uint32_t rstamp, uint16_t seq, uint16_t status)
+ int rssi, int nf, uint16_t seq, uint16_t status)
{
struct ieee80211vap *vap = ni->ni_vap;
@@ -940,7 +938,7 @@ hostap_auth_open(struct ieee80211_node *ni, struct ieee80211_frame *wh,
static void
hostap_auth_shared(struct ieee80211_node *ni, struct ieee80211_frame *wh,
- uint8_t *frm, uint8_t *efrm, int rssi, int noise, uint32_t rstamp,
+ uint8_t *frm, uint8_t *efrm, int rssi, int nf,
uint16_t seq, uint16_t status)
{
struct ieee80211vap *vap = ni->ni_vap;
@@ -1042,8 +1040,7 @@ hostap_auth_shared(struct ieee80211_node *ni, struct ieee80211_frame *wh,
*/
ni->ni_flags |= IEEE80211_NODE_ASSOCID;
IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
- ni->ni_noise = noise;
- ni->ni_rstamp = rstamp;
+ ni->ni_noise = nf;
if (!ieee80211_alloc_challenge(ni)) {
/* NB: don't return error so they rexmit */
return;
@@ -1624,7 +1621,7 @@ is11bclient(const uint8_t *rates, const uint8_t *xrates)
static void
hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
- int subtype, int rssi, int noise, uint32_t rstamp)
+ int subtype, int rssi, int nf)
{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
@@ -1679,8 +1676,7 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
ieee80211_probe_curchan(vap, 1);
ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
}
- ieee80211_add_scan(vap, &scan, wh,
- subtype, rssi, noise, rstamp);
+ ieee80211_add_scan(vap, &scan, wh, subtype, rssi, nf);
return;
}
/*
@@ -1843,11 +1839,10 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
return;
}
if (algo == IEEE80211_AUTH_ALG_SHARED)
- hostap_auth_shared(ni, wh, frm + 6, efrm, rssi,
- noise, rstamp, seq, status);
- else if (algo == IEEE80211_AUTH_ALG_OPEN)
- hostap_auth_open(ni, wh, rssi, noise, rstamp,
+ hostap_auth_shared(ni, wh, frm + 6, efrm, rssi, nf,
seq, status);
+ else if (algo == IEEE80211_AUTH_ALG_OPEN)
+ hostap_auth_open(ni, wh, rssi, nf, seq, status);
else if (algo == IEEE80211_AUTH_ALG_LEAP) {
authalgreject(ni, wh, algo,
seq+1, IEEE80211_STATUS_ALG);
@@ -2063,8 +2058,7 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
return;
}
IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
- ni->ni_noise = noise;
- ni->ni_rstamp = rstamp;
+ ni->ni_noise = nf;
ni->ni_intval = lintval;
ni->ni_capinfo = capinfo;
ni->ni_fhdwell = vap->iv_bss->ni_fhdwell;
diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c
index 42c232d..198e95d 100644
--- a/sys/net80211/ieee80211_ht.c
+++ b/sys/net80211/ieee80211_ht.c
@@ -364,8 +364,8 @@ static __inline void
ampdu_dispatch(struct ieee80211_node *ni, struct mbuf *m)
{
m->m_flags |= M_AMPDU_MPDU; /* bypass normal processing */
- /* NB: rssi, noise, and rstamp are ignored w/ M_AMPDU_MPDU set */
- (void) ieee80211_input(ni, m, 0, 0, 0);
+ /* NB: rssi and noise are ignored w/ M_AMPDU_MPDU set */
+ (void) ieee80211_input(ni, m, 0, 0);
}
/*
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index 2134e29d..6e06918 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -55,8 +55,7 @@ __FBSDID("$FreeBSD$");
#endif
int
-ieee80211_input_all(struct ieee80211com *ic,
- struct mbuf *m, int rssi, int noise, u_int32_t rstamp)
+ieee80211_input_all(struct ieee80211com *ic, struct mbuf *m, int rssi, int nf)
{
struct ieee80211vap *vap;
int type = -1;
@@ -89,7 +88,7 @@ ieee80211_input_all(struct ieee80211com *ic,
m = NULL;
}
ni = ieee80211_ref_node(vap->iv_bss);
- type = ieee80211_input(ni, mcopy, rssi, noise, rstamp);
+ type = ieee80211_input(ni, mcopy, rssi, nf);
ieee80211_free_node(ni);
}
if (m != NULL) /* no vaps, reclaim mbuf */
diff --git a/sys/net80211/ieee80211_monitor.c b/sys/net80211/ieee80211_monitor.c
index b1e98eb..119c87d 100644
--- a/sys/net80211/ieee80211_monitor.c
+++ b/sys/net80211/ieee80211_monitor.c
@@ -60,7 +60,7 @@ __FBSDID("$FreeBSD$");
static void monitor_vattach(struct ieee80211vap *);
static int monitor_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static int monitor_input(struct ieee80211_node *ni, struct mbuf *m,
- int rssi, int noise, uint32_t rstamp);
+ int rssi, int nf);
void
ieee80211_monitor_attach(struct ieee80211com *ic)
@@ -124,13 +124,11 @@ monitor_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
* Process a received frame in monitor mode.
*/
static int
-monitor_input(struct ieee80211_node *ni, struct mbuf *m,
- int rssi, int noise, uint32_t rstamp)
+monitor_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
{
struct ieee80211vap *vap = ni->ni_vap;
- if (bpf_peers_present(vap->iv_rawbpf))
- bpf_mtap(vap->iv_rawbpf, m);
+ ieee80211_radiotap_rx(vap, m);
m_freem(m);
return -1;
}
diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c
index c23a092..eb56b8d 100644
--- a/sys/net80211/ieee80211_node.c
+++ b/sys/net80211/ieee80211_node.c
@@ -631,6 +631,7 @@ ieee80211_sync_curchan(struct ieee80211com *ic)
ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan);
IEEE80211_UNLOCK(ic);
ic->ic_set_channel(ic);
+ ieee80211_radiotap_chan_change(ic);
IEEE80211_LOCK(ic);
}
}
@@ -754,7 +755,6 @@ ieee80211_sta_join(struct ieee80211vap *vap, struct ieee80211_channel *chan,
IEEE80211_ADDR_COPY(ni->ni_bssid, se->se_bssid);
ni->ni_esslen = se->se_ssid[1];
memcpy(ni->ni_essid, se->se_ssid+2, ni->ni_esslen);
- ni->ni_rstamp = se->se_rstamp;
ni->ni_tstamp.tsf = se->se_tstamp.tsf;
ni->ni_intval = se->se_intval;
ni->ni_capinfo = se->se_capinfo;
@@ -2125,8 +2125,8 @@ ieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
ni->ni_rxseqs[IEEE80211_NONQOS_TID] >> IEEE80211_SEQ_SEQ_SHIFT,
ni->ni_rxseqs[IEEE80211_NONQOS_TID] & IEEE80211_SEQ_FRAG_MASK,
ni->ni_rxfragstamp);
- printf("\trstamp %u rssi %d noise %d intval %u capinfo 0x%x\n",
- ni->ni_rstamp, node_getrssi(ni), ni->ni_noise,
+ printf("\trssi %d noise %d intval %u capinfo 0x%x\n",
+ node_getrssi(ni), ni->ni_noise,
ni->ni_intval, ni->ni_capinfo);
printf("\tbssid %s essid \"%.*s\" channel %u:0x%x\n",
ether_sprintf(ni->ni_bssid),
diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h
index 8f19ce7..a118de5 100644
--- a/sys/net80211/ieee80211_node.h
+++ b/sys/net80211/ieee80211_node.h
@@ -145,7 +145,6 @@ struct ieee80211_node {
struct ieee80211_key ni_ucastkey; /* unicast key */
/* hardware */
- uint32_t ni_rstamp; /* recv timestamp */
uint32_t ni_avgrssi; /* recv ssi state */
int8_t ni_noise; /* noise floor */
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index 6ee8f52..a46b228 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -307,10 +307,6 @@ ieee80211_start(struct ifnet *ifp)
}
}
- /* XXX fragmented frames not handled */
- if (bpf_peers_present(vap->iv_rawbpf))
- bpf_mtap(vap->iv_rawbpf, m);
-
error = parent->if_transmit(parent, m);
if (error != 0) {
/* NB: IFQ_HANDOFF reclaims mbuf */
@@ -420,9 +416,6 @@ ieee80211_output(struct ifnet *ifp, struct mbuf *m,
if (ieee80211_classify(ni, m))
senderr(EIO); /* XXX */
- if (bpf_peers_present(vap->iv_rawbpf))
- bpf_mtap(vap->iv_rawbpf, m);
-
IEEE80211_NODE_STAT(ni, tx_data);
if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
IEEE80211_NODE_STAT(ni, tx_mcast);
diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c
index 467a362..99b995c8 100644
--- a/sys/net80211/ieee80211_proto.c
+++ b/sys/net80211/ieee80211_proto.c
@@ -1107,6 +1107,7 @@ update_channel(void *arg, int npending)
struct ieee80211com *ic = arg;
ic->ic_set_channel(ic);
+ ieee80211_radiotap_chan_change(ic);
}
/*
diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h
index 3712c1e..6a55809 100644
--- a/sys/net80211/ieee80211_proto.h
+++ b/sys/net80211/ieee80211_proto.h
@@ -60,10 +60,9 @@ void ieee80211_syncifflag_locked(struct ieee80211com *, int flag);
void ieee80211_syncflag(struct ieee80211vap *, int flag);
void ieee80211_syncflag_ext(struct ieee80211vap *, int flag);
-#define ieee80211_input(ni, m, rssi, noise, rstamp) \
- ((ni)->ni_vap->iv_input(ni, m, rssi, noise, rstamp))
-int ieee80211_input_all(struct ieee80211com *, struct mbuf *,
- int, int, uint32_t);
+#define ieee80211_input(ni, m, rssi, nf) \
+ ((ni)->ni_vap->iv_input(ni, m, rssi, nf))
+int ieee80211_input_all(struct ieee80211com *, struct mbuf *, int, int);
struct ieee80211_bpf_params;
int ieee80211_mgmt_output(struct ieee80211_node *, struct mbuf *, int,
struct ieee80211_bpf_params *);
diff --git a/sys/net80211/ieee80211_radiotap.c b/sys/net80211/ieee80211_radiotap.c
new file mode 100644
index 0000000..2c4482f
--- /dev/null
+++ b/sys/net80211/ieee80211_radiotap.c
@@ -0,0 +1,325 @@
+/*-
+ * Copyright (c) 2009 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * IEEE 802.11 radiotap support.
+ */
+#include "opt_wlan.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+
+#include <sys/socket.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_llc.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+
+static int radiotap_offset(struct ieee80211_radiotap_header *, int);
+
+void
+ieee80211_radiotap_attach(struct ieee80211com *ic,
+ struct ieee80211_radiotap_header *th, int tlen, uint32_t tx_radiotap,
+ struct ieee80211_radiotap_header *rh, int rlen, uint32_t rx_radiotap)
+{
+#define B(_v) (1<<(_v))
+ int off;
+
+ th->it_len = htole16(roundup2(tlen, sizeof(uint32_t)));
+ th->it_present = htole32(tx_radiotap);
+ ic->ic_th = th;
+ /* calculate offset to channel data */
+ off = -1;
+ if (tx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
+ off = radiotap_offset(th, IEEE80211_RADIOTAP_CHANNEL);
+ else if (tx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
+ off = radiotap_offset(th, IEEE80211_RADIOTAP_XCHANNEL);
+ if (off == -1) {
+ if_printf(ic->ic_ifp, "%s: no tx channel, radiotap 0x%x",
+ __func__, tx_radiotap);
+ /* NB: we handle this case but data will have no chan spec */
+ } else
+ ic->ic_txchan = ((uint8_t *) th) + off;
+
+ rh->it_len = htole16(roundup2(rlen, sizeof(uint32_t)));
+ rh->it_present = htole32(rx_radiotap);
+ ic->ic_rh = rh;
+ /* calculate offset to channel data */
+ off = -1;
+ if (rx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
+ off = radiotap_offset(rh, IEEE80211_RADIOTAP_CHANNEL);
+ else if (rx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
+ off = radiotap_offset(rh, IEEE80211_RADIOTAP_XCHANNEL);
+ if (off == -1) {
+ if_printf(ic->ic_ifp, "%s: no rx channel, radiotap 0x%x",
+ __func__, rx_radiotap);
+ /* NB: we handle this case but data will have no chan spec */
+ } else
+ ic->ic_rxchan = ((uint8_t *) rh) + off;
+#undef B
+}
+
+void
+ieee80211_radiotap_detach(struct ieee80211com *ic)
+{
+}
+
+void
+ieee80211_radiotap_vattach(struct ieee80211vap *vap)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ieee80211_radiotap_header *th = ic->ic_th;
+
+ KASSERT(th != NULL, ("no radiotap setup"));
+
+ /* radiotap DLT for raw 802.11 frames */
+ bpfattach2(vap->iv_ifp, DLT_IEEE802_11_RADIO,
+ sizeof(struct ieee80211_frame) + le16toh(th->it_len),
+ &vap->iv_rawbpf);
+}
+
+void
+ieee80211_radiotap_vdetach(struct ieee80211vap *vap)
+{
+ /* NB: bpfattach is called by ether_ifdetach and claims all taps */
+}
+
+static void
+set_channel(void *p, const struct ieee80211_channel *c)
+{
+ struct {
+ uint16_t freq;
+ uint16_t flags;
+ } *rc = p;
+
+ rc->freq = htole16(c->ic_freq);
+ rc->flags = htole16(c->ic_flags);
+}
+
+static void
+set_xchannel(void *p, const struct ieee80211_channel *c)
+{
+ struct {
+ uint32_t flags;
+ uint16_t freq;
+ uint8_t ieee;
+ uint8_t maxpow;
+ } *rc = p;
+
+ rc->flags = htole32(c->ic_flags);
+ rc->freq = htole16(c->ic_freq);
+ rc->ieee = c->ic_ieee;
+ rc->maxpow = c->ic_maxregpower;
+}
+
+/*
+ * Update radiotap state on channel change.
+ */
+void
+ieee80211_radiotap_chan_change(struct ieee80211com *ic)
+{
+ if (ic->ic_rxchan != NULL) {
+ struct ieee80211_radiotap_header *rh = ic->ic_rh;
+
+ if (rh->it_present & (1<<IEEE80211_RADIOTAP_XCHANNEL))
+ set_xchannel(ic->ic_rxchan, ic->ic_curchan);
+ else if (rh->it_present & (1<<IEEE80211_RADIOTAP_CHANNEL))
+ set_channel(ic->ic_rxchan, ic->ic_curchan);
+ }
+ if (ic->ic_txchan != NULL) {
+ struct ieee80211_radiotap_header *th = ic->ic_th;
+
+ if (th->it_present & (1<<IEEE80211_RADIOTAP_XCHANNEL))
+ set_xchannel(ic->ic_txchan, ic->ic_curchan);
+ else if (th->it_present & (1<<IEEE80211_RADIOTAP_CHANNEL))
+ set_channel(ic->ic_txchan, ic->ic_curchan);
+ }
+}
+
+static void
+dispatch_radiotap(struct ieee80211vap *vap0, struct mbuf *m,
+ struct ieee80211_radiotap_header *rh)
+{
+ struct ieee80211com *ic = vap0->iv_ic;
+ int len = le16toh(rh->it_len);
+
+ if (ieee80211_radiotap_active_vap(vap0))
+ bpf_mtap2(vap0->iv_rawbpf, rh, len, m);
+ if (ic->ic_monvaps) {
+ 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))
+ bpf_mtap2(vap->iv_rawbpf, rh, len, m);
+ }
+ }
+}
+
+/*
+ * Dispatch radiotap data for transmitted packet.
+ */
+void
+ieee80211_radiotap_tx(struct ieee80211vap *vap0, struct mbuf *m)
+{
+ dispatch_radiotap(vap0, m, vap0->iv_ic->ic_th);
+}
+
+/*
+ * Dispatch radiotap data for received packet.
+ */
+void
+ieee80211_radiotap_rx(struct ieee80211vap *vap0, struct mbuf *m)
+{
+ dispatch_radiotap(vap0, m, vap0->iv_ic->ic_rh);
+}
+
+/*
+ * Dispatch radiotap data for a packet received outside the normal
+ * rx processing path; this is used, for example, to handle frames
+ * received with errors that would otherwise be dropped.
+ */
+void
+ieee80211_radiotap_rx_all(struct ieee80211com *ic, struct mbuf *m)
+{
+ struct ieee80211_radiotap_header *rh = ic->ic_rh;
+ int len = le16toh(rh->it_len);
+ struct ieee80211vap *vap;
+
+ /* XXX locking? */
+ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+ if (ieee80211_radiotap_active_vap(vap))
+ bpf_mtap2(vap->iv_rawbpf, rh, len, m);
+ }
+}
+
+/*
+ * Return the offset of the specified item in the radiotap
+ * header description. If the item is not present or is not
+ * known -1 is returned.
+ */
+static int
+radiotap_offset(struct ieee80211_radiotap_header *rh, int item)
+{
+ static const struct {
+ size_t align, width;
+ } items[] = {
+ [IEEE80211_RADIOTAP_TSFT] = {
+ .align = sizeof(uint64_t),
+ .width = sizeof(uint64_t),
+ },
+ [IEEE80211_RADIOTAP_FLAGS] = {
+ .align = sizeof(uint8_t),
+ .width = sizeof(uint8_t),
+ },
+ [IEEE80211_RADIOTAP_RATE] = {
+ .align = sizeof(uint8_t),
+ .width = sizeof(uint8_t),
+ },
+ [IEEE80211_RADIOTAP_CHANNEL] = {
+ .align = sizeof(uint16_t),
+ .width = 2*sizeof(uint16_t),
+ },
+ [IEEE80211_RADIOTAP_FHSS] = {
+ .align = sizeof(uint16_t),
+ .width = sizeof(uint16_t),
+ },
+ [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = {
+ .align = sizeof(uint8_t),
+ .width = sizeof(uint8_t),
+ },
+ [IEEE80211_RADIOTAP_DBM_ANTNOISE] = {
+ .align = sizeof(uint8_t),
+ .width = sizeof(uint8_t),
+ },
+ [IEEE80211_RADIOTAP_LOCK_QUALITY] = {
+ .align = sizeof(uint16_t),
+ .width = sizeof(uint16_t),
+ },
+ [IEEE80211_RADIOTAP_TX_ATTENUATION] = {
+ .align = sizeof(uint16_t),
+ .width = sizeof(uint16_t),
+ },
+ [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = {
+ .align = sizeof(uint16_t),
+ .width = sizeof(uint16_t),
+ },
+ [IEEE80211_RADIOTAP_DBM_TX_POWER] = {
+ .align = sizeof(uint8_t),
+ .width = sizeof(uint8_t),
+ },
+ [IEEE80211_RADIOTAP_ANTENNA] = {
+ .align = sizeof(uint8_t),
+ .width = sizeof(uint8_t),
+ },
+ [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = {
+ .align = sizeof(uint8_t),
+ .width = sizeof(uint8_t),
+ },
+ [IEEE80211_RADIOTAP_DB_ANTNOISE] = {
+ .align = sizeof(uint8_t),
+ .width = sizeof(uint8_t),
+ },
+ [IEEE80211_RADIOTAP_XCHANNEL] = {
+ .align = sizeof(uint32_t),
+ .width = 2*sizeof(uint32_t),
+ },
+ };
+ uint32_t present = le32toh(rh->it_present);
+ int off, i;
+
+ off = sizeof(struct ieee80211_radiotap_header);
+ for (i = 0; i < IEEE80211_RADIOTAP_EXT; i++) {
+ if ((present & (1<<i)) == 0)
+ continue;
+ if (items[i].align == 0) {
+ /* NB: unidentified element, don't guess */
+ printf("%s: unknown item %d\n", __func__, i);
+ return -1;
+ }
+ off = roundup2(off, items[i].align);
+ if (i == item) {
+ if (off + items[i].width > le16toh(rh->it_len)) {
+ /* NB: item does not fit in header data */
+ printf("%s: item %d not in header data, "
+ "off %d width %zu len %d\n", __func__, i,
+ off, items[i].width, le16toh(rh->it_len));
+ return -1;
+ }
+ return off;
+ }
+ off += items[i].width;
+ }
+ return -1;
+}
diff --git a/sys/net80211/ieee80211_scan.c b/sys/net80211/ieee80211_scan.c
index c1f4a13..b41ed59 100644
--- a/sys/net80211/ieee80211_scan.c
+++ b/sys/net80211/ieee80211_scan.c
@@ -920,6 +920,7 @@ scan_task(void *arg, int pending)
* completed the channel change.
*/
ic->ic_set_channel(ic);
+ ieee80211_radiotap_chan_change(ic);
/*
* Scan curchan. Drivers for "intelligent hardware"
@@ -966,6 +967,7 @@ scan_task(void *arg, int pending)
ieee80211_setupcurchan(ic, ic->ic_bsschan);
IEEE80211_UNLOCK(ic);
ic->ic_set_channel(ic);
+ ieee80211_radiotap_chan_change(ic);
IEEE80211_LOCK(ic);
}
/* clear internal flags and any indication of a pick */
@@ -1095,7 +1097,7 @@ void
ieee80211_add_scan(struct ieee80211vap *vap,
const struct ieee80211_scanparams *sp,
const struct ieee80211_frame *wh,
- int subtype, int rssi, int noise, int rstamp)
+ int subtype, int rssi, int noise)
{
struct ieee80211com *ic = vap->iv_ic;
struct ieee80211_scan_state *ss = ic->ic_scan;
@@ -1115,7 +1117,7 @@ ieee80211_add_scan(struct ieee80211vap *vap,
dump_probe_beacon(subtype, 1, wh->i_addr2, sp, rssi);
#endif
if (ss->ss_ops != NULL &&
- ss->ss_ops->scan_add(ss, sp, wh, subtype, rssi, noise, rstamp)) {
+ ss->ss_ops->scan_add(ss, sp, wh, subtype, rssi, noise)) {
/*
* If we've reached the min dwell time terminate
* the timer so we'll switch to the next channel.
diff --git a/sys/net80211/ieee80211_scan.h b/sys/net80211/ieee80211_scan.h
index edba660..84a57ff 100644
--- a/sys/net80211/ieee80211_scan.h
+++ b/sys/net80211/ieee80211_scan.h
@@ -150,7 +150,7 @@ struct ieee80211_scanparams;
void ieee80211_add_scan(struct ieee80211vap *,
const struct ieee80211_scanparams *,
const struct ieee80211_frame *,
- int subtype, int rssi, int noise, int rstamp);
+ int subtype, int rssi, int noise);
void ieee80211_scan_timeout(struct ieee80211com *);
void ieee80211_scan_assoc_success(struct ieee80211vap *,
@@ -224,7 +224,6 @@ struct ieee80211_scan_entry {
uint8_t se_ssid[2+IEEE80211_NWID_LEN];
uint8_t se_rates[2+IEEE80211_RATE_MAXSIZE];
uint8_t se_xrates[2+IEEE80211_RATE_MAXSIZE];
- uint32_t se_rstamp; /* recv timestamp */
union {
uint8_t data[8];
u_int64_t tsf;
@@ -269,7 +268,7 @@ struct ieee80211_scanner {
int (*scan_add)(struct ieee80211_scan_state *,
const struct ieee80211_scanparams *,
const struct ieee80211_frame *,
- int subtype, int rssi, int noise, int rstamp);
+ int subtype, int rssi, int noise);
/* age and/or purge entries in the cache */
void (*scan_age)(struct ieee80211_scan_state *);
/* note that association failed for an entry */
diff --git a/sys/net80211/ieee80211_scan_sta.c b/sys/net80211/ieee80211_scan_sta.c
index cef3db4..62ef39e 100644
--- a/sys/net80211/ieee80211_scan_sta.c
+++ b/sys/net80211/ieee80211_scan_sta.c
@@ -219,7 +219,7 @@ static int
sta_add(struct ieee80211_scan_state *ss,
const struct ieee80211_scanparams *sp,
const struct ieee80211_frame *wh,
- int subtype, int rssi, int noise, int rstamp)
+ int subtype, int rssi, int noise)
{
#define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
#define PICK1ST(_ss) \
@@ -278,7 +278,6 @@ found:
ise->se_rssi = IEEE80211_RSSI_GET(se->se_avgrssi);
ise->se_noise = noise;
}
- ise->se_rstamp = rstamp;
memcpy(ise->se_tstamp.data, sp->tstamp, sizeof(ise->se_tstamp));
ise->se_intval = sp->bintval;
ise->se_capinfo = sp->capinfo;
diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c
index 33f6c27..9a52917 100644
--- a/sys/net80211/ieee80211_sta.c
+++ b/sys/net80211/ieee80211_sta.c
@@ -66,10 +66,9 @@ __FBSDID("$FreeBSD$");
static void sta_vattach(struct ieee80211vap *);
static void sta_beacon_miss(struct ieee80211vap *);
static int sta_newstate(struct ieee80211vap *, enum ieee80211_state, int);
-static int sta_input(struct ieee80211_node *, struct mbuf *,
- int rssi, int noise, uint32_t rstamp);
+static int sta_input(struct ieee80211_node *, struct mbuf *, int, int);
static void sta_recv_mgmt(struct ieee80211_node *, struct mbuf *,
- int subtype, int rssi, int noise, uint32_t rstamp);
+ int subtype, int rssi, int nf);
static void sta_recv_ctl(struct ieee80211_node *, struct mbuf *, int subtype);
void
@@ -490,8 +489,7 @@ doprint(struct ieee80211vap *vap, int subtype)
* by the 802.11 layer.
*/
static int
-sta_input(struct ieee80211_node *ni, struct mbuf *m,
- int rssi, int noise, uint32_t rstamp)
+sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
{
#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0)
#define HAS_SEQ(type) ((type & 0x4) == 0)
@@ -566,8 +564,7 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m,
goto out;
}
IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
- ni->ni_noise = noise;
- ni->ni_rstamp = rstamp;
+ ni->ni_noise = nf;
if (HAS_SEQ(type)) {
uint8_t tid = ieee80211_gettid(wh);
if (IEEE80211_QOS_HAS_SEQ(wh) &&
@@ -743,8 +740,8 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m,
}
/* copy to listener after decrypt */
- if (bpf_peers_present(vap->iv_rawbpf))
- bpf_mtap(vap->iv_rawbpf, m);
+ if (ieee80211_radiotap_active_vap(vap))
+ ieee80211_radiotap_tx(vap, m);
need_tap = 0;
/*
@@ -869,7 +866,7 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m,
wh = mtod(m, struct ieee80211_frame *);
wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
}
- vap->iv_recv_mgmt(ni, m, subtype, rssi, noise, rstamp);
+ vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
goto out;
case IEEE80211_FC0_TYPE_CTL:
@@ -888,8 +885,8 @@ err:
ifp->if_ierrors++;
out:
if (m != NULL) {
- if (need_tap && bpf_peers_present(vap->iv_rawbpf))
- bpf_mtap(vap->iv_rawbpf, m);
+ if (need_tap)
+ ieee80211_radiotap_rx(vap, m);
m_freem(m);
}
return type;
@@ -898,7 +895,7 @@ out:
static void
sta_auth_open(struct ieee80211_node *ni, struct ieee80211_frame *wh,
- int rssi, int noise, uint32_t rstamp, uint16_t seq, uint16_t status)
+ int rssi, int nf, uint16_t seq, uint16_t status)
{
struct ieee80211vap *vap = ni->ni_vap;
@@ -927,7 +924,7 @@ sta_auth_open(struct ieee80211_node *ni, struct ieee80211_frame *wh,
static void
sta_auth_shared(struct ieee80211_node *ni, struct ieee80211_frame *wh,
- uint8_t *frm, uint8_t *efrm, int rssi, int noise, uint32_t rstamp,
+ uint8_t *frm, uint8_t *efrm, int rssi, int nf,
uint16_t seq, uint16_t status)
{
struct ieee80211vap *vap = ni->ni_vap;
@@ -1128,7 +1125,7 @@ startbgscan(struct ieee80211vap *vap)
static void
sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
- int subtype, int rssi, int noise, uint32_t rstamp)
+ int subtype, int rssi, int nf)
{
#define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
#define ISREASSOC(_st) ((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP)
@@ -1264,7 +1261,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
*/
if (ic->ic_flags & IEEE80211_F_SCAN) {
ieee80211_add_scan(vap, &scan, wh,
- subtype, rssi, noise, rstamp);
+ subtype, rssi, nf);
} else if (contbgscan(vap)) {
ieee80211_bg_scan(vap, 0);
} else if (startbgscan(vap)) {
@@ -1293,8 +1290,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
ieee80211_probe_curchan(vap, 1);
ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
}
- ieee80211_add_scan(vap, &scan, wh,
- subtype, rssi, noise, rstamp);
+ ieee80211_add_scan(vap, &scan, wh, subtype, rssi, nf);
return;
}
break;
@@ -1329,11 +1325,10 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
return;
}
if (algo == IEEE80211_AUTH_ALG_SHARED)
- sta_auth_shared(ni, wh, frm + 6, efrm, rssi,
- noise, rstamp, seq, status);
- else if (algo == IEEE80211_AUTH_ALG_OPEN)
- sta_auth_open(ni, wh, rssi, noise, rstamp,
+ sta_auth_shared(ni, wh, frm + 6, efrm, rssi, nf,
seq, status);
+ else if (algo == IEEE80211_AUTH_ALG_OPEN)
+ sta_auth_open(ni, wh, rssi, nf, seq, status);
else {
IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
wh, "auth", "unsupported alg %d", algo);
diff --git a/sys/net80211/ieee80211_superg.c b/sys/net80211/ieee80211_superg.c
index de5df09..d75917b 100644
--- a/sys/net80211/ieee80211_superg.c
+++ b/sys/net80211/ieee80211_superg.c
@@ -503,9 +503,6 @@ ff_transmit(struct ieee80211_node *ni, struct mbuf *m)
struct ifnet *ifp = vap->iv_ifp;
struct ifnet *parent = ni->ni_ic->ic_ifp;
- if (bpf_peers_present(vap->iv_rawbpf))
- bpf_mtap(vap->iv_rawbpf, m);
-
error = parent->if_transmit(parent, m);
if (error != 0) {
/* NB: IFQ_HANDOFF reclaims mbuf */
@@ -835,6 +832,7 @@ ieee80211_dturbo_switch(struct ieee80211vap *vap, int newflags)
ic->ic_curchan = chan;
ic->ic_rt = ieee80211_get_ratetable(chan);
ic->ic_set_channel(ic);
+ ieee80211_radiotap_chan_change(ic);
/* NB: do not need to reset ERP state 'cuz we're in sta mode */
}
diff --git a/sys/net80211/ieee80211_tdma.c b/sys/net80211/ieee80211_tdma.c
index f9dd317..8747b4e 100644
--- a/sys/net80211/ieee80211_tdma.c
+++ b/sys/net80211/ieee80211_tdma.c
@@ -108,12 +108,12 @@ static void tdma_vdetach(struct ieee80211vap *vap);
static int tdma_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void tdma_beacon_miss(struct ieee80211vap *vap);
static void tdma_recv_mgmt(struct ieee80211_node *, struct mbuf *,
- int subtype, int rssi, int noise, uint32_t rstamp);
+ int subtype, int rssi, int nf);
static int tdma_update(struct ieee80211vap *vap,
const struct ieee80211_tdma_param *tdma, struct ieee80211_node *ni,
int pickslot);
static int tdma_process_params(struct ieee80211_node *ni,
- const u_int8_t *ie, u_int32_t rstamp, const struct ieee80211_frame *wh);
+ const u_int8_t *ie, int rssi, int nf, const struct ieee80211_frame *wh);
static void
settxparms(struct ieee80211vap *vap, enum ieee80211_phymode mode, int rate)
@@ -304,7 +304,7 @@ tdma_beacon_miss(struct ieee80211vap *vap)
static void
tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
- int subtype, int rssi, int noise, uint32_t rstamp)
+ int subtype, int rssi, int nf)
{
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211vap *vap = ni->ni_vap;
@@ -367,7 +367,7 @@ tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
* Process tdma ie. The contents are used to sync
* the slot timing, reconfigure the bss, etc.
*/
- (void) tdma_process_params(ni, scan.tdma, rstamp, wh);
+ (void) tdma_process_params(ni, scan.tdma, rssi, nf, wh);
return;
}
/*
@@ -375,7 +375,7 @@ tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
* 2x parsing of the frame but should happen infrequently
*/
}
- ts->tdma_recv_mgmt(ni, m0, subtype, rssi, noise, rstamp);
+ ts->tdma_recv_mgmt(ni, m0, subtype, rssi, nf);
}
/*
@@ -497,8 +497,8 @@ tdma_update(struct ieee80211vap *vap, const struct ieee80211_tdma_param *tdma,
* Process received TDMA parameters.
*/
static int
-tdma_process_params(struct ieee80211_node *ni,
- const u_int8_t *ie, u_int32_t rstamp, const struct ieee80211_frame *wh)
+tdma_process_params(struct ieee80211_node *ni, const u_int8_t *ie,
+ int rssi, int nf, const struct ieee80211_frame *wh)
{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_tdma_state *ts = vap->iv_tdma;
@@ -563,12 +563,16 @@ tdma_process_params(struct ieee80211_node *ni,
/* XXX reschedule swbmiss timer on parameter change */
} else if (tdma->tdma_slot == ts->tdma_slot+1) {
uint64_t tstamp;
+#if 0
+ uint32_t rstamp = (uint32_t) le64toh(rs->tsf);
int32_t rtt;
+#endif
/*
* Use returned timstamp to calculate the
* roundtrip time.
*/
memcpy(&tstamp, tdma->tdma_tstamp, 8);
+#if 0
/* XXX use only 15 bits of rstamp */
rtt = rstamp - (le64toh(tstamp) & 0x7fff);
if (rtt < 0)
@@ -578,6 +582,7 @@ tdma_process_params(struct ieee80211_node *ni,
"tdma rtt %5u [rstamp %5u tstamp %llu]\n",
rtt, rstamp,
(unsigned long long) le64toh(tstamp));
+#endif
} else if (tdma->tdma_slot == ts->tdma_slot &&
le64toh(ni->ni_tstamp.tsf) > vap->iv_bss->ni_tstamp.tsf) {
/*
diff --git a/sys/net80211/ieee80211_tdma.h b/sys/net80211/ieee80211_tdma.h
index 41ca09e..2fe591f 100644
--- a/sys/net80211/ieee80211_tdma.h
+++ b/sys/net80211/ieee80211_tdma.h
@@ -81,7 +81,7 @@ struct ieee80211_tdma_state {
int (*tdma_newstate)(struct ieee80211vap *, enum ieee80211_state,
int arg);
void (*tdma_recv_mgmt)(struct ieee80211_node *,
- struct mbuf *, int, int, int, uint32_t);
+ struct mbuf *, int, int, int);
void (*tdma_opdetach)(struct ieee80211vap *);
};
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index 09b63d2..27095f4 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -51,6 +51,7 @@
#include <net80211/ieee80211_power.h>
#include <net80211/ieee80211_node.h>
#include <net80211/ieee80211_proto.h>
+#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_scan.h>
#define IEEE80211_TXPOWER_MAX 100 /* .5 dbM (XXX units?) */
@@ -209,6 +210,13 @@ struct ieee80211com {
/* optional state for Atheros SuperG protocol extensions */
struct ieee80211_superg *ic_superg;
+ /* radiotap handling */
+ struct ieee80211_radiotap_header *ic_th;/* tx radiotap headers */
+ 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 */
+
/* virtual ap create/delete */
struct ieee80211vap* (*ic_vap_create)(struct ieee80211com *,
const char name[IFNAMSIZ], int unit,
@@ -421,10 +429,9 @@ struct ieee80211vap {
void (*iv_opdetach)(struct ieee80211vap *);
/* receive processing */
int (*iv_input)(struct ieee80211_node *,
- struct mbuf *, int rssi, int noise,
- uint32_t rstamp);
+ struct mbuf *, int, int);
void (*iv_recv_mgmt)(struct ieee80211_node *,
- struct mbuf *, int, int, int, uint32_t);
+ struct mbuf *, int, int, int);
void (*iv_recv_ctl)(struct ieee80211_node *,
struct mbuf *, int);
void (*iv_deliver_data)(struct ieee80211vap *,
@@ -522,6 +529,7 @@ MALLOC_DECLARE(M_80211_VAP);
#define IEEE80211_FEXT_DOTD 0x00001000 /* CONF: 11d enabled */
#define IEEE80211_FEXT_STATEWAIT 0x00002000 /* STATUS: awaiting state chg */
#define IEEE80211_FEXT_REINIT 0x00004000 /* STATUS: INIT state first */
+#define IEEE80211_FEXT_BPF 0x00008000 /* STATUS: BPF tap present */
/* NB: immutable: should be set only when creating a vap */
#define IEEE80211_FEXT_WDSLEGACY 0x00010000 /* CONF: legacy WDS operation */
#define IEEE80211_FEXT_PROBECHAN 0x00020000 /* CONF: probe passive channel*/
@@ -540,7 +548,7 @@ MALLOC_DECLARE(M_80211_VAP);
#define IEEE80211_FEXT_BITS \
"\20\1NONHT_PR\2INACT\3SCANWAIT\4BGSCAN\5WPS\6TSN\7SCANREQ\10RESUME" \
"\0114ADDR\12NONEPR_PR\13SWBMISS\14DFS\15DOTD\16STATEWAIT\17REINIT" \
- "\22WDSLEGACY\23PROBECHAN\24HT\25AMDPU_TX\26AMPDU_TX\27AMSDU_TX" \
+ "\20BPF\21WDSLEGACY\22PROBECHAN\24HT\25AMDPU_TX\26AMPDU_TX\27AMSDU_TX" \
"\30AMSDU_RX\31USEHT40\32PUREN\33SHORTGI20\34SHORTGI40\35HTCOMPAT" \
"\36RIFS"
@@ -637,6 +645,31 @@ struct ieee80211_channel *ieee80211_find_channel_byieee(struct ieee80211com *,
int ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode);
enum ieee80211_phymode ieee80211_chan2mode(const struct ieee80211_channel *);
+void ieee80211_radiotap_attach(struct ieee80211com *,
+ struct ieee80211_radiotap_header *th, int tlen,
+ uint32_t tx_radiotap,
+ struct ieee80211_radiotap_header *rh, int rlen,
+ uint32_t rx_radiotap);
+void ieee80211_radiotap_detach(struct ieee80211com *);
+void ieee80211_radiotap_vattach(struct ieee80211vap *);
+void ieee80211_radiotap_vdetach(struct ieee80211vap *);
+void ieee80211_radiotap_chan_change(struct ieee80211com *);
+void ieee80211_radiotap_tx(struct ieee80211vap *, struct mbuf *);
+void ieee80211_radiotap_rx(struct ieee80211vap *, struct mbuf *);
+void ieee80211_radiotap_rx_all(struct ieee80211com *, struct mbuf *);
+
+static __inline int
+ieee80211_radiotap_active(const struct ieee80211com *ic)
+{
+ return (ic->ic_flags_ext & IEEE80211_FEXT_BPF) != 0;
+}
+
+static __inline int
+ieee80211_radiotap_active_vap(const struct ieee80211vap *vap)
+{
+ return (vap->iv_flags_ext & IEEE80211_FEXT_BPF) != 0;
+}
+
/*
* Enqueue a task on the state thread.
*/
diff --git a/sys/net80211/ieee80211_wds.c b/sys/net80211/ieee80211_wds.c
index 6ab8f11..85ab544 100644
--- a/sys/net80211/ieee80211_wds.c
+++ b/sys/net80211/ieee80211_wds.c
@@ -63,10 +63,9 @@ __FBSDID("$FreeBSD$");
static void wds_vattach(struct ieee80211vap *);
static int wds_newstate(struct ieee80211vap *, enum ieee80211_state, int);
-static int wds_input(struct ieee80211_node *ni, struct mbuf *m,
- int rssi, int noise, uint32_t rstamp);
+static int wds_input(struct ieee80211_node *ni, struct mbuf *m, int, int);
static void wds_recv_mgmt(struct ieee80211_node *, struct mbuf *,
- int subtype, int rssi, int noise, u_int32_t rstamp);
+ int subtype, int, int);
void
ieee80211_wds_attach(struct ieee80211com *ic)
@@ -199,12 +198,12 @@ ieee80211_create_wds(struct ieee80211vap *vap, struct ieee80211_channel *chan)
* Flush pending frames now that were setup.
*/
if (ni != NULL && IEEE80211_NODE_WDSQ_QLEN(ni) != 0) {
- int8_t rssi, noise;
+ int8_t rssi, nf;
IEEE80211_NOTE(vap, IEEE80211_MSG_WDS, ni,
"flush wds queue, %u packets queued",
IEEE80211_NODE_WDSQ_QLEN(ni));
- ic->ic_node_getsignal(ni, &rssi, &noise);
+ ic->ic_node_getsignal(ni, &rssi, &nf);
for (;;) {
struct mbuf *m;
@@ -213,8 +212,7 @@ ieee80211_create_wds(struct ieee80211vap *vap, struct ieee80211_channel *chan)
IEEE80211_NODE_WDSQ_UNLOCK(ni);
if (m == NULL)
break;
- /* XXX cheat and re-use last rstamp */
- ieee80211_input(ni, m, rssi, noise, ni->ni_rstamp);
+ ieee80211_input(ni, m, rssi, nf);
}
}
return (ni == NULL ? ENOENT : 0);
@@ -292,9 +290,6 @@ ieee80211_dwds_mcast(struct ieee80211vap *vap0, struct mbuf *m)
mcopy->m_flags |= M_MCAST;
mcopy->m_pkthdr.rcvif = (void *) ni;
- if (bpf_peers_present(vap->iv_rawbpf))
- bpf_mtap(vap->iv_rawbpf, m);
-
err = parent->if_transmit(parent, mcopy);
if (err) {
/* NB: IFQ_HANDOFF reclaims mbuf */
@@ -470,8 +465,7 @@ wds_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
* by the 802.11 layer.
*/
static int
-wds_input(struct ieee80211_node *ni, struct mbuf *m,
- int rssi, int noise, uint32_t rstamp)
+wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
{
#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0)
#define HAS_SEQ(type) ((type & 0x4) == 0)
@@ -553,8 +547,7 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m,
goto out;
}
IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
- ni->ni_noise = noise;
- ni->ni_rstamp = rstamp;
+ ni->ni_noise = nf;
if (HAS_SEQ(type)) {
uint8_t tid = ieee80211_gettid(wh);
if (IEEE80211_QOS_HAS_SEQ(wh) &&
@@ -686,8 +679,8 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m,
}
/* copy to listener after decrypt */
- if (bpf_peers_present(vap->iv_rawbpf))
- bpf_mtap(vap->iv_rawbpf, m);
+ if (ieee80211_radiotap_active_vap(vap))
+ ieee80211_radiotap_rx(vap, m);
need_tap = 0;
/*
@@ -786,16 +779,14 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m,
vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
goto out;
}
- if (bpf_peers_present(vap->iv_rawbpf))
- bpf_mtap(vap->iv_rawbpf, m);
- vap->iv_recv_mgmt(ni, m, subtype, rssi, noise, rstamp);
- m_freem(m);
- return IEEE80211_FC0_TYPE_MGT;
+ vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
+ goto out;
case IEEE80211_FC0_TYPE_CTL:
vap->iv_stats.is_rx_ctl++;
IEEE80211_NODE_STAT(ni, rx_ctrl);
goto out;
+
default:
IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
wh, "bad", "frame type 0x%x", type);
@@ -806,8 +797,8 @@ err:
ifp->if_ierrors++;
out:
if (m != NULL) {
- if (bpf_peers_present(vap->iv_rawbpf) && need_tap)
- bpf_mtap(vap->iv_rawbpf, m);
+ if (need_tap)
+ ieee80211_radiotap_rx(vap, m);
m_freem(m);
}
return type;
@@ -816,7 +807,7 @@ out:
static void
wds_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
- int subtype, int rssi, int noise, u_int32_t rstamp)
+ int subtype, int rssi, int nf)
{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
OpenPOWER on IntegriCloud