2 * Copyright (c) 2009 Sam Leffler, Errno Consulting
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
30 * IEEE 802.11 radiotap support.
34 #include <sys/param.h>
35 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/endian.h>
39 #include <sys/kernel.h>
41 #include <sys/socket.h>
45 #include <net/if_var.h>
46 #include <net/if_llc.h>
47 #include <net/if_media.h>
48 #include <net/ethernet.h>
50 #include <net80211/ieee80211_var.h>
52 static int radiotap_offset(struct ieee80211_radiotap_header *, int, int);
55 ieee80211_radiotap_attach(struct ieee80211com *ic,
56 struct ieee80211_radiotap_header *th, int tlen, uint32_t tx_radiotap,
57 struct ieee80211_radiotap_header *rh, int rlen, uint32_t rx_radiotap)
59 ieee80211_radiotap_attachv(ic, th, tlen, 0, tx_radiotap,
60 rh, rlen, 0, rx_radiotap);
64 ieee80211_radiotap_attachv(struct ieee80211com *ic,
65 struct ieee80211_radiotap_header *th,
66 int tlen, int n_tx_v, uint32_t tx_radiotap,
67 struct ieee80211_radiotap_header *rh,
68 int rlen, int n_rx_v, uint32_t rx_radiotap)
70 #define B(_v) (1<<(_v))
73 th->it_len = htole16(roundup2(tlen, sizeof(uint32_t)));
74 th->it_present = htole32(tx_radiotap);
76 /* calculate offset to channel data */
78 if (tx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
79 off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_CHANNEL);
80 else if (tx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
81 off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_XCHANNEL);
83 if_printf(ic->ic_ifp, "%s: no tx channel, radiotap 0x%x\n",
84 __func__, tx_radiotap);
85 /* NB: we handle this case but data will have no chan spec */
87 ic->ic_txchan = ((uint8_t *) th) + off;
89 rh->it_len = htole16(roundup2(rlen, sizeof(uint32_t)));
90 rh->it_present = htole32(rx_radiotap);
92 /* calculate offset to channel data */
94 if (rx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
95 off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_CHANNEL);
96 else if (rx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
97 off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_XCHANNEL);
99 if_printf(ic->ic_ifp, "%s: no rx channel, radiotap 0x%x\n",
100 __func__, rx_radiotap);
101 /* NB: we handle this case but data will have no chan spec */
103 ic->ic_rxchan = ((uint8_t *) rh) + off;
108 ieee80211_radiotap_detach(struct ieee80211com *ic)
113 ieee80211_radiotap_vattach(struct ieee80211vap *vap)
115 struct ieee80211com *ic = vap->iv_ic;
116 struct ieee80211_radiotap_header *th = ic->ic_th;
118 if (th != NULL && ic->ic_rh != NULL) {
119 /* radiotap DLT for raw 802.11 frames */
120 bpfattach2(vap->iv_ifp, DLT_IEEE802_11_RADIO,
121 sizeof(struct ieee80211_frame) + le16toh(th->it_len),
127 ieee80211_radiotap_vdetach(struct ieee80211vap *vap)
129 /* NB: bpfattach is called by ether_ifdetach and claims all taps */
133 set_channel(void *p, const struct ieee80211_channel *c)
140 rc->freq = htole16(c->ic_freq);
141 rc->flags = htole16(c->ic_flags);
145 set_xchannel(void *p, const struct ieee80211_channel *c)
154 rc->flags = htole32(c->ic_flags);
155 rc->freq = htole16(c->ic_freq);
156 rc->ieee = c->ic_ieee;
157 rc->maxpow = c->ic_maxregpower;
161 * Update radiotap state on channel change.
164 ieee80211_radiotap_chan_change(struct ieee80211com *ic)
166 if (ic->ic_rxchan != NULL) {
167 struct ieee80211_radiotap_header *rh = ic->ic_rh;
169 if (rh->it_present & htole32(1<<IEEE80211_RADIOTAP_XCHANNEL))
170 set_xchannel(ic->ic_rxchan, ic->ic_curchan);
171 else if (rh->it_present & htole32(1<<IEEE80211_RADIOTAP_CHANNEL))
172 set_channel(ic->ic_rxchan, ic->ic_curchan);
174 if (ic->ic_txchan != NULL) {
175 struct ieee80211_radiotap_header *th = ic->ic_th;
177 if (th->it_present & htole32(1<<IEEE80211_RADIOTAP_XCHANNEL))
178 set_xchannel(ic->ic_txchan, ic->ic_curchan);
179 else if (th->it_present & htole32(1<<IEEE80211_RADIOTAP_CHANNEL))
180 set_channel(ic->ic_txchan, ic->ic_curchan);
185 * Distribute radiotap data (+packet) to all monitor mode
186 * vaps with an active tap other than vap0.
189 spam_vaps(struct ieee80211vap *vap0, struct mbuf *m,
190 struct ieee80211_radiotap_header *rh, int len)
192 struct ieee80211com *ic = vap0->iv_ic;
193 struct ieee80211vap *vap;
195 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
197 vap->iv_opmode == IEEE80211_M_MONITOR &&
198 (vap->iv_flags_ext & IEEE80211_FEXT_BPF) &&
199 vap->iv_state != IEEE80211_S_INIT)
200 bpf_mtap2(vap->iv_rawbpf, rh, len, m);
205 * Dispatch radiotap data for transmitted packet.
208 ieee80211_radiotap_tx(struct ieee80211vap *vap0, struct mbuf *m)
210 struct ieee80211com *ic = vap0->iv_ic;
211 struct ieee80211_radiotap_header *th = ic->ic_th;
214 KASSERT(th != NULL, ("no tx radiotap header"));
215 len = le16toh(th->it_len);
217 if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF)
218 bpf_mtap2(vap0->iv_rawbpf, th, len, m);
220 * Spam monitor mode vaps.
222 if (ic->ic_montaps != 0)
223 spam_vaps(vap0, m, th, len);
227 * Dispatch radiotap data for received packet.
230 ieee80211_radiotap_rx(struct ieee80211vap *vap0, struct mbuf *m)
232 struct ieee80211com *ic = vap0->iv_ic;
233 struct ieee80211_radiotap_header *rh = ic->ic_rh;
236 KASSERT(rh != NULL, ("no rx radiotap header"));
237 len = le16toh(rh->it_len);
239 if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF)
240 bpf_mtap2(vap0->iv_rawbpf, rh, len, m);
242 * Spam monitor mode vaps with unicast frames. Multicast
243 * frames are handled by passing through ieee80211_input_all
244 * which distributes copies to the monitor mode vaps.
246 if (ic->ic_montaps != 0 && (m->m_flags & M_BCAST) == 0)
247 spam_vaps(vap0, m, rh, len);
251 * Dispatch radiotap data for a packet received outside the normal
252 * rx processing path; this is used, for example, to handle frames
253 * received with errors that would otherwise be dropped.
256 ieee80211_radiotap_rx_all(struct ieee80211com *ic, struct mbuf *m)
258 struct ieee80211_radiotap_header *rh = ic->ic_rh;
259 int len = le16toh(rh->it_len);
260 struct ieee80211vap *vap;
263 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
264 if (ieee80211_radiotap_active_vap(vap) &&
265 vap->iv_state != IEEE80211_S_INIT)
266 bpf_mtap2(vap->iv_rawbpf, rh, len, m);
271 * Return the offset of the specified item in the radiotap
272 * header description. If the item is not present or is not
273 * known -1 is returned.
276 radiotap_offset(struct ieee80211_radiotap_header *rh,
277 int n_vendor_attributes, int item)
279 static const struct {
282 [IEEE80211_RADIOTAP_TSFT] = {
283 .align = sizeof(uint64_t),
284 .width = sizeof(uint64_t),
286 [IEEE80211_RADIOTAP_FLAGS] = {
287 .align = sizeof(uint8_t),
288 .width = sizeof(uint8_t),
290 [IEEE80211_RADIOTAP_RATE] = {
291 .align = sizeof(uint8_t),
292 .width = sizeof(uint8_t),
294 [IEEE80211_RADIOTAP_CHANNEL] = {
295 .align = sizeof(uint16_t),
296 .width = 2*sizeof(uint16_t),
298 [IEEE80211_RADIOTAP_FHSS] = {
299 .align = sizeof(uint16_t),
300 .width = sizeof(uint16_t),
302 [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = {
303 .align = sizeof(uint8_t),
304 .width = sizeof(uint8_t),
306 [IEEE80211_RADIOTAP_DBM_ANTNOISE] = {
307 .align = sizeof(uint8_t),
308 .width = sizeof(uint8_t),
310 [IEEE80211_RADIOTAP_LOCK_QUALITY] = {
311 .align = sizeof(uint16_t),
312 .width = sizeof(uint16_t),
314 [IEEE80211_RADIOTAP_TX_ATTENUATION] = {
315 .align = sizeof(uint16_t),
316 .width = sizeof(uint16_t),
318 [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = {
319 .align = sizeof(uint16_t),
320 .width = sizeof(uint16_t),
322 [IEEE80211_RADIOTAP_DBM_TX_POWER] = {
323 .align = sizeof(uint8_t),
324 .width = sizeof(uint8_t),
326 [IEEE80211_RADIOTAP_ANTENNA] = {
327 .align = sizeof(uint8_t),
328 .width = sizeof(uint8_t),
330 [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = {
331 .align = sizeof(uint8_t),
332 .width = sizeof(uint8_t),
334 [IEEE80211_RADIOTAP_DB_ANTNOISE] = {
335 .align = sizeof(uint8_t),
336 .width = sizeof(uint8_t),
338 [IEEE80211_RADIOTAP_XCHANNEL] = {
339 .align = sizeof(uint32_t),
340 .width = 2*sizeof(uint32_t),
342 [IEEE80211_RADIOTAP_MCS] = {
343 .align = sizeof(uint8_t),
344 .width = 3*sizeof(uint8_t),
347 uint32_t present = le32toh(rh->it_present);
350 off = sizeof(struct ieee80211_radiotap_header);
351 off += n_vendor_attributes * (sizeof(uint32_t));
353 for (i = 0; i < IEEE80211_RADIOTAP_EXT; i++) {
354 if ((present & (1<<i)) == 0)
356 if (items[i].align == 0) {
357 /* NB: unidentified element, don't guess */
358 printf("%s: unknown item %d\n", __func__, i);
361 off = roundup2(off, items[i].align);
363 if (off + items[i].width > le16toh(rh->it_len)) {
364 /* NB: item does not fit in header data */
365 printf("%s: item %d not in header data, "
366 "off %d width %zu len %d\n", __func__, i,
367 off, items[i].width, le16toh(rh->it_len));
372 off += items[i].width;