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_media.h>
47 #include <net/ethernet.h>
49 #include <net80211/ieee80211_var.h>
51 static int radiotap_offset(struct ieee80211_radiotap_header
*, int, int);
54 ieee80211_radiotap_attach(struct ieee80211com
*ic
,
55 struct ieee80211_radiotap_header
*th
, int tlen
, uint32_t tx_radiotap
,
56 struct ieee80211_radiotap_header
*rh
, int rlen
, uint32_t rx_radiotap
)
58 ieee80211_radiotap_attachv(ic
, th
, tlen
, 0, tx_radiotap
,
59 rh
, rlen
, 0, rx_radiotap
);
63 ieee80211_radiotap_attachv(struct ieee80211com
*ic
,
64 struct ieee80211_radiotap_header
*th
,
65 int tlen
, int n_tx_v
, uint32_t tx_radiotap
,
66 struct ieee80211_radiotap_header
*rh
,
67 int rlen
, int n_rx_v
, uint32_t rx_radiotap
)
69 #define B(_v) (1<<(_v))
72 th
->it_len
= htole16(roundup2(tlen
, sizeof(uint32_t)));
73 th
->it_present
= htole32(tx_radiotap
);
75 /* calculate offset to channel data */
77 if (tx_radiotap
& B(IEEE80211_RADIOTAP_CHANNEL
))
78 off
= radiotap_offset(th
, n_tx_v
, IEEE80211_RADIOTAP_CHANNEL
);
79 else if (tx_radiotap
& B(IEEE80211_RADIOTAP_XCHANNEL
))
80 off
= radiotap_offset(th
, n_tx_v
, IEEE80211_RADIOTAP_XCHANNEL
);
82 ic_printf(ic
, "%s: no tx channel, radiotap 0x%x\n", __func__
,
84 /* NB: we handle this case but data will have no chan spec */
86 ic
->ic_txchan
= ((uint8_t *) th
) + off
;
88 rh
->it_len
= htole16(roundup2(rlen
, sizeof(uint32_t)));
89 rh
->it_present
= htole32(rx_radiotap
);
91 /* calculate offset to channel data */
93 if (rx_radiotap
& B(IEEE80211_RADIOTAP_CHANNEL
))
94 off
= radiotap_offset(rh
, n_rx_v
, IEEE80211_RADIOTAP_CHANNEL
);
95 else if (rx_radiotap
& B(IEEE80211_RADIOTAP_XCHANNEL
))
96 off
= radiotap_offset(rh
, n_rx_v
, IEEE80211_RADIOTAP_XCHANNEL
);
98 ic_printf(ic
, "%s: no rx channel, radiotap 0x%x\n", __func__
,
100 /* NB: we handle this case but data will have no chan spec */
102 ic
->ic_rxchan
= ((uint8_t *) rh
) + off
;
107 ieee80211_radiotap_detach(struct ieee80211com
*ic
)
112 ieee80211_radiotap_vattach(struct ieee80211vap
*vap
)
114 struct ieee80211com
*ic
= vap
->iv_ic
;
115 struct ieee80211_radiotap_header
*th
= ic
->ic_th
;
117 if (th
!= NULL
&& ic
->ic_rh
!= NULL
) {
118 /* radiotap DLT for raw 802.11 frames */
119 bpfattach2(vap
->iv_ifp
, DLT_IEEE802_11_RADIO
,
120 sizeof(struct ieee80211_frame
) + le16toh(th
->it_len
),
126 ieee80211_radiotap_vdetach(struct ieee80211vap
*vap
)
128 /* NB: bpfattach is called by ether_ifdetach and claims all taps */
132 set_channel(void *p
, const struct ieee80211_channel
*c
)
139 rc
->freq
= htole16(c
->ic_freq
);
140 rc
->flags
= htole16(c
->ic_flags
);
144 set_xchannel(void *p
, const struct ieee80211_channel
*c
)
153 rc
->flags
= htole32(c
->ic_flags
);
154 rc
->freq
= htole16(c
->ic_freq
);
155 rc
->ieee
= c
->ic_ieee
;
156 rc
->maxpow
= c
->ic_maxregpower
;
160 * Update radiotap state on channel change.
163 ieee80211_radiotap_chan_change(struct ieee80211com
*ic
)
165 if (ic
->ic_rxchan
!= NULL
) {
166 struct ieee80211_radiotap_header
*rh
= ic
->ic_rh
;
168 if (rh
->it_present
& htole32(1<<IEEE80211_RADIOTAP_XCHANNEL
))
169 set_xchannel(ic
->ic_rxchan
, ic
->ic_curchan
);
170 else if (rh
->it_present
& htole32(1<<IEEE80211_RADIOTAP_CHANNEL
))
171 set_channel(ic
->ic_rxchan
, ic
->ic_curchan
);
173 if (ic
->ic_txchan
!= NULL
) {
174 struct ieee80211_radiotap_header
*th
= ic
->ic_th
;
176 if (th
->it_present
& htole32(1<<IEEE80211_RADIOTAP_XCHANNEL
))
177 set_xchannel(ic
->ic_txchan
, ic
->ic_curchan
);
178 else if (th
->it_present
& htole32(1<<IEEE80211_RADIOTAP_CHANNEL
))
179 set_channel(ic
->ic_txchan
, ic
->ic_curchan
);
184 * Distribute radiotap data (+packet) to all monitor mode
185 * vaps with an active tap other than vap0.
188 spam_vaps(struct ieee80211vap
*vap0
, struct mbuf
*m
,
189 struct ieee80211_radiotap_header
*rh
, int len
)
191 struct ieee80211com
*ic
= vap0
->iv_ic
;
192 struct ieee80211vap
*vap
;
194 TAILQ_FOREACH(vap
, &ic
->ic_vaps
, iv_next
) {
196 vap
->iv_opmode
== IEEE80211_M_MONITOR
&&
197 (vap
->iv_flags_ext
& IEEE80211_FEXT_BPF
) &&
198 vap
->iv_state
!= IEEE80211_S_INIT
)
199 bpf_mtap2(vap
->iv_rawbpf
, rh
, len
, m
);
204 * Dispatch radiotap data for transmitted packet.
207 ieee80211_radiotap_tx(struct ieee80211vap
*vap0
, struct mbuf
*m
)
209 struct ieee80211com
*ic
= vap0
->iv_ic
;
210 struct ieee80211_radiotap_header
*th
= ic
->ic_th
;
213 KASSERT(th
!= NULL
, ("no tx radiotap header"));
214 len
= le16toh(th
->it_len
);
216 if (vap0
->iv_flags_ext
& IEEE80211_FEXT_BPF
)
217 bpf_mtap2(vap0
->iv_rawbpf
, th
, len
, m
);
219 * Spam monitor mode vaps.
221 if (ic
->ic_montaps
!= 0)
222 spam_vaps(vap0
, m
, th
, len
);
226 * Dispatch radiotap data for received packet.
229 ieee80211_radiotap_rx(struct ieee80211vap
*vap0
, struct mbuf
*m
)
231 struct ieee80211com
*ic
= vap0
->iv_ic
;
232 struct ieee80211_radiotap_header
*rh
= ic
->ic_rh
;
235 KASSERT(rh
!= NULL
, ("no rx radiotap header"));
236 len
= le16toh(rh
->it_len
);
238 if (vap0
->iv_flags_ext
& IEEE80211_FEXT_BPF
)
239 bpf_mtap2(vap0
->iv_rawbpf
, rh
, len
, m
);
241 * Spam monitor mode vaps with unicast frames. Multicast
242 * frames are handled by passing through ieee80211_input_all
243 * which distributes copies to the monitor mode vaps.
245 if (ic
->ic_montaps
!= 0 && (m
->m_flags
& M_BCAST
) == 0)
246 spam_vaps(vap0
, m
, rh
, len
);
250 * Dispatch radiotap data for a packet received outside the normal
251 * rx processing path; this is used, for example, to handle frames
252 * received with errors that would otherwise be dropped.
255 ieee80211_radiotap_rx_all(struct ieee80211com
*ic
, struct mbuf
*m
)
257 struct ieee80211_radiotap_header
*rh
= ic
->ic_rh
;
258 int len
= le16toh(rh
->it_len
);
259 struct ieee80211vap
*vap
;
262 TAILQ_FOREACH(vap
, &ic
->ic_vaps
, iv_next
) {
263 if (ieee80211_radiotap_active_vap(vap
) &&
264 vap
->iv_state
!= IEEE80211_S_INIT
)
265 bpf_mtap2(vap
->iv_rawbpf
, rh
, len
, m
);
270 * Return the offset of the specified item in the radiotap
271 * header description. If the item is not present or is not
272 * known -1 is returned.
275 radiotap_offset(struct ieee80211_radiotap_header
*rh
,
276 int n_vendor_attributes
, int item
)
278 static const struct {
281 [IEEE80211_RADIOTAP_TSFT
] = {
282 .align
= sizeof(uint64_t),
283 .width
= sizeof(uint64_t),
285 [IEEE80211_RADIOTAP_FLAGS
] = {
286 .align
= sizeof(uint8_t),
287 .width
= sizeof(uint8_t),
289 [IEEE80211_RADIOTAP_RATE
] = {
290 .align
= sizeof(uint8_t),
291 .width
= sizeof(uint8_t),
293 [IEEE80211_RADIOTAP_CHANNEL
] = {
294 .align
= sizeof(uint16_t),
295 .width
= 2*sizeof(uint16_t),
297 [IEEE80211_RADIOTAP_FHSS
] = {
298 .align
= sizeof(uint16_t),
299 .width
= sizeof(uint16_t),
301 [IEEE80211_RADIOTAP_DBM_ANTSIGNAL
] = {
302 .align
= sizeof(uint8_t),
303 .width
= sizeof(uint8_t),
305 [IEEE80211_RADIOTAP_DBM_ANTNOISE
] = {
306 .align
= sizeof(uint8_t),
307 .width
= sizeof(uint8_t),
309 [IEEE80211_RADIOTAP_LOCK_QUALITY
] = {
310 .align
= sizeof(uint16_t),
311 .width
= sizeof(uint16_t),
313 [IEEE80211_RADIOTAP_TX_ATTENUATION
] = {
314 .align
= sizeof(uint16_t),
315 .width
= sizeof(uint16_t),
317 [IEEE80211_RADIOTAP_DB_TX_ATTENUATION
] = {
318 .align
= sizeof(uint16_t),
319 .width
= sizeof(uint16_t),
321 [IEEE80211_RADIOTAP_DBM_TX_POWER
] = {
322 .align
= sizeof(uint8_t),
323 .width
= sizeof(uint8_t),
325 [IEEE80211_RADIOTAP_ANTENNA
] = {
326 .align
= sizeof(uint8_t),
327 .width
= sizeof(uint8_t),
329 [IEEE80211_RADIOTAP_DB_ANTSIGNAL
] = {
330 .align
= sizeof(uint8_t),
331 .width
= sizeof(uint8_t),
333 [IEEE80211_RADIOTAP_DB_ANTNOISE
] = {
334 .align
= sizeof(uint8_t),
335 .width
= sizeof(uint8_t),
337 [IEEE80211_RADIOTAP_XCHANNEL
] = {
338 .align
= sizeof(uint32_t),
339 .width
= 2*sizeof(uint32_t),
341 [IEEE80211_RADIOTAP_MCS
] = {
342 .align
= sizeof(uint8_t),
343 .width
= 3*sizeof(uint8_t),
346 uint32_t present
= le32toh(rh
->it_present
);
349 off
= sizeof(struct ieee80211_radiotap_header
);
350 off
+= n_vendor_attributes
* (sizeof(uint32_t));
352 for (i
= 0; i
< IEEE80211_RADIOTAP_EXT
; i
++) {
353 if ((present
& (1<<i
)) == 0)
355 if (items
[i
].align
== 0) {
356 /* NB: unidentified element, don't guess */
357 printf("%s: unknown item %d\n", __func__
, i
);
360 off
= roundup2(off
, items
[i
].align
);
362 if (off
+ items
[i
].width
> le16toh(rh
->it_len
)) {
363 /* NB: item does not fit in header data */
364 printf("%s: item %d not in header data, "
365 "off %d width %zu len %d\n", __func__
, i
,
366 off
, items
[i
].width
, le16toh(rh
->it_len
));
371 off
+= items
[i
].width
;