xref: /haiku/src/libs/compat/freebsd_wlan/net80211/ieee80211_radiotap.c (revision 753c7e0805fa38e422339966ddc4d6d71944a040)
1*753c7e08SAugustin Cavalier /*-
2*753c7e08SAugustin Cavalier  * Copyright (c) 2009 Sam Leffler, Errno Consulting
3*753c7e08SAugustin Cavalier  * All rights reserved.
4*753c7e08SAugustin Cavalier  *
5*753c7e08SAugustin Cavalier  * Redistribution and use in source and binary forms, with or without
6*753c7e08SAugustin Cavalier  * modification, are permitted provided that the following conditions
7*753c7e08SAugustin Cavalier  * are met:
8*753c7e08SAugustin Cavalier  * 1. Redistributions of source code must retain the above copyright
9*753c7e08SAugustin Cavalier  *    notice, this list of conditions and the following disclaimer.
10*753c7e08SAugustin Cavalier  * 2. Redistributions in binary form must reproduce the above copyright
11*753c7e08SAugustin Cavalier  *    notice, this list of conditions and the following disclaimer in the
12*753c7e08SAugustin Cavalier  *    documentation and/or other materials provided with the distribution.
13*753c7e08SAugustin Cavalier  *
14*753c7e08SAugustin Cavalier  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15*753c7e08SAugustin Cavalier  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16*753c7e08SAugustin Cavalier  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17*753c7e08SAugustin Cavalier  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18*753c7e08SAugustin Cavalier  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19*753c7e08SAugustin Cavalier  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20*753c7e08SAugustin Cavalier  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21*753c7e08SAugustin Cavalier  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22*753c7e08SAugustin Cavalier  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23*753c7e08SAugustin Cavalier  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*753c7e08SAugustin Cavalier  */
25*753c7e08SAugustin Cavalier 
26*753c7e08SAugustin Cavalier #include <sys/cdefs.h>
27*753c7e08SAugustin Cavalier __FBSDID("$FreeBSD: releng/11.1/sys/net80211/ieee80211_radiotap.c 283530 2015-05-25 14:54:10Z glebius $");
28*753c7e08SAugustin Cavalier 
29*753c7e08SAugustin Cavalier /*
30*753c7e08SAugustin Cavalier  * IEEE 802.11 radiotap support.
31*753c7e08SAugustin Cavalier  */
32*753c7e08SAugustin Cavalier #include "opt_wlan.h"
33*753c7e08SAugustin Cavalier 
34*753c7e08SAugustin Cavalier #include <sys/param.h>
35*753c7e08SAugustin Cavalier #include <sys/systm.h>
36*753c7e08SAugustin Cavalier #include <sys/mbuf.h>
37*753c7e08SAugustin Cavalier #include <sys/malloc.h>
38*753c7e08SAugustin Cavalier #include <sys/endian.h>
39*753c7e08SAugustin Cavalier #include <sys/kernel.h>
40*753c7e08SAugustin Cavalier 
41*753c7e08SAugustin Cavalier #include <sys/socket.h>
42*753c7e08SAugustin Cavalier 
43*753c7e08SAugustin Cavalier #include <net/bpf.h>
44*753c7e08SAugustin Cavalier #include <net/if.h>
45*753c7e08SAugustin Cavalier #include <net/if_var.h>
46*753c7e08SAugustin Cavalier #include <net/if_media.h>
47*753c7e08SAugustin Cavalier #include <net/ethernet.h>
48*753c7e08SAugustin Cavalier 
49*753c7e08SAugustin Cavalier #include <net80211/ieee80211_var.h>
50*753c7e08SAugustin Cavalier 
51*753c7e08SAugustin Cavalier static int radiotap_offset(struct ieee80211_radiotap_header *, int, int);
52*753c7e08SAugustin Cavalier 
53*753c7e08SAugustin Cavalier void
54*753c7e08SAugustin Cavalier ieee80211_radiotap_attach(struct ieee80211com *ic,
55*753c7e08SAugustin Cavalier 	struct ieee80211_radiotap_header *th, int tlen, uint32_t tx_radiotap,
56*753c7e08SAugustin Cavalier 	struct ieee80211_radiotap_header *rh, int rlen, uint32_t rx_radiotap)
57*753c7e08SAugustin Cavalier {
58*753c7e08SAugustin Cavalier 	ieee80211_radiotap_attachv(ic, th, tlen, 0, tx_radiotap,
59*753c7e08SAugustin Cavalier 	    rh, rlen, 0, rx_radiotap);
60*753c7e08SAugustin Cavalier }
61*753c7e08SAugustin Cavalier 
62*753c7e08SAugustin Cavalier void
63*753c7e08SAugustin Cavalier ieee80211_radiotap_attachv(struct ieee80211com *ic,
64*753c7e08SAugustin Cavalier 	struct ieee80211_radiotap_header *th,
65*753c7e08SAugustin Cavalier 	int tlen, int n_tx_v, uint32_t tx_radiotap,
66*753c7e08SAugustin Cavalier 	struct ieee80211_radiotap_header *rh,
67*753c7e08SAugustin Cavalier 	int rlen, int n_rx_v, uint32_t rx_radiotap)
68*753c7e08SAugustin Cavalier {
69*753c7e08SAugustin Cavalier #define	B(_v)	(1<<(_v))
70*753c7e08SAugustin Cavalier 	int off;
71*753c7e08SAugustin Cavalier 
72*753c7e08SAugustin Cavalier 	th->it_len = htole16(roundup2(tlen, sizeof(uint32_t)));
73*753c7e08SAugustin Cavalier 	th->it_present = htole32(tx_radiotap);
74*753c7e08SAugustin Cavalier 	ic->ic_th = th;
75*753c7e08SAugustin Cavalier 	/* calculate offset to channel data */
76*753c7e08SAugustin Cavalier 	off = -1;
77*753c7e08SAugustin Cavalier 	if (tx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
78*753c7e08SAugustin Cavalier 		off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_CHANNEL);
79*753c7e08SAugustin Cavalier 	else if (tx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
80*753c7e08SAugustin Cavalier 		off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_XCHANNEL);
81*753c7e08SAugustin Cavalier 	if (off == -1) {
82*753c7e08SAugustin Cavalier 		ic_printf(ic, "%s: no tx channel, radiotap 0x%x\n", __func__,
83*753c7e08SAugustin Cavalier 		    tx_radiotap);
84*753c7e08SAugustin Cavalier 		/* NB: we handle this case but data will have no chan spec */
85*753c7e08SAugustin Cavalier 	} else
86*753c7e08SAugustin Cavalier 		ic->ic_txchan = ((uint8_t *) th) + off;
87*753c7e08SAugustin Cavalier 
88*753c7e08SAugustin Cavalier 	rh->it_len = htole16(roundup2(rlen, sizeof(uint32_t)));
89*753c7e08SAugustin Cavalier 	rh->it_present = htole32(rx_radiotap);
90*753c7e08SAugustin Cavalier 	ic->ic_rh = rh;
91*753c7e08SAugustin Cavalier 	/* calculate offset to channel data */
92*753c7e08SAugustin Cavalier 	off = -1;
93*753c7e08SAugustin Cavalier 	if (rx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
94*753c7e08SAugustin Cavalier 		off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_CHANNEL);
95*753c7e08SAugustin Cavalier 	else if (rx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
96*753c7e08SAugustin Cavalier 		off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_XCHANNEL);
97*753c7e08SAugustin Cavalier 	if (off == -1) {
98*753c7e08SAugustin Cavalier 		ic_printf(ic, "%s: no rx channel, radiotap 0x%x\n", __func__,
99*753c7e08SAugustin Cavalier 		    rx_radiotap);
100*753c7e08SAugustin Cavalier 		/* NB: we handle this case but data will have no chan spec */
101*753c7e08SAugustin Cavalier 	} else
102*753c7e08SAugustin Cavalier 		ic->ic_rxchan = ((uint8_t *) rh) + off;
103*753c7e08SAugustin Cavalier #undef B
104*753c7e08SAugustin Cavalier }
105*753c7e08SAugustin Cavalier 
106*753c7e08SAugustin Cavalier void
107*753c7e08SAugustin Cavalier ieee80211_radiotap_detach(struct ieee80211com *ic)
108*753c7e08SAugustin Cavalier {
109*753c7e08SAugustin Cavalier }
110*753c7e08SAugustin Cavalier 
111*753c7e08SAugustin Cavalier void
112*753c7e08SAugustin Cavalier ieee80211_radiotap_vattach(struct ieee80211vap *vap)
113*753c7e08SAugustin Cavalier {
114*753c7e08SAugustin Cavalier 	struct ieee80211com *ic = vap->iv_ic;
115*753c7e08SAugustin Cavalier 	struct ieee80211_radiotap_header *th = ic->ic_th;
116*753c7e08SAugustin Cavalier 
117*753c7e08SAugustin Cavalier 	if (th != NULL && ic->ic_rh != NULL) {
118*753c7e08SAugustin Cavalier 		/* radiotap DLT for raw 802.11 frames */
119*753c7e08SAugustin Cavalier 		bpfattach2(vap->iv_ifp, DLT_IEEE802_11_RADIO,
120*753c7e08SAugustin Cavalier 		    sizeof(struct ieee80211_frame) + le16toh(th->it_len),
121*753c7e08SAugustin Cavalier 		    &vap->iv_rawbpf);
122*753c7e08SAugustin Cavalier 	}
123*753c7e08SAugustin Cavalier }
124*753c7e08SAugustin Cavalier 
125*753c7e08SAugustin Cavalier void
126*753c7e08SAugustin Cavalier ieee80211_radiotap_vdetach(struct ieee80211vap *vap)
127*753c7e08SAugustin Cavalier {
128*753c7e08SAugustin Cavalier 	/* NB: bpfattach is called by ether_ifdetach and claims all taps */
129*753c7e08SAugustin Cavalier }
130*753c7e08SAugustin Cavalier 
131*753c7e08SAugustin Cavalier static void
132*753c7e08SAugustin Cavalier set_channel(void *p, const struct ieee80211_channel *c)
133*753c7e08SAugustin Cavalier {
134*753c7e08SAugustin Cavalier 	struct {
135*753c7e08SAugustin Cavalier 		uint16_t	freq;
136*753c7e08SAugustin Cavalier 		uint16_t	flags;
137*753c7e08SAugustin Cavalier 	} *rc = p;
138*753c7e08SAugustin Cavalier 
139*753c7e08SAugustin Cavalier 	rc->freq = htole16(c->ic_freq);
140*753c7e08SAugustin Cavalier 	rc->flags = htole16(c->ic_flags);
141*753c7e08SAugustin Cavalier }
142*753c7e08SAugustin Cavalier 
143*753c7e08SAugustin Cavalier static void
144*753c7e08SAugustin Cavalier set_xchannel(void *p, const struct ieee80211_channel *c)
145*753c7e08SAugustin Cavalier {
146*753c7e08SAugustin Cavalier 	struct {
147*753c7e08SAugustin Cavalier 		uint32_t	flags;
148*753c7e08SAugustin Cavalier 		uint16_t	freq;
149*753c7e08SAugustin Cavalier 		uint8_t		ieee;
150*753c7e08SAugustin Cavalier 		uint8_t		maxpow;
151*753c7e08SAugustin Cavalier 	} *rc = p;
152*753c7e08SAugustin Cavalier 
153*753c7e08SAugustin Cavalier 	rc->flags = htole32(c->ic_flags);
154*753c7e08SAugustin Cavalier 	rc->freq = htole16(c->ic_freq);
155*753c7e08SAugustin Cavalier 	rc->ieee = c->ic_ieee;
156*753c7e08SAugustin Cavalier 	rc->maxpow = c->ic_maxregpower;
157*753c7e08SAugustin Cavalier }
158*753c7e08SAugustin Cavalier 
159*753c7e08SAugustin Cavalier /*
160*753c7e08SAugustin Cavalier  * Update radiotap state on channel change.
161*753c7e08SAugustin Cavalier  */
162*753c7e08SAugustin Cavalier void
163*753c7e08SAugustin Cavalier ieee80211_radiotap_chan_change(struct ieee80211com *ic)
164*753c7e08SAugustin Cavalier {
165*753c7e08SAugustin Cavalier 	if (ic->ic_rxchan != NULL) {
166*753c7e08SAugustin Cavalier 		struct ieee80211_radiotap_header *rh = ic->ic_rh;
167*753c7e08SAugustin Cavalier 
168*753c7e08SAugustin Cavalier 		if (rh->it_present & htole32(1<<IEEE80211_RADIOTAP_XCHANNEL))
169*753c7e08SAugustin Cavalier 			set_xchannel(ic->ic_rxchan, ic->ic_curchan);
170*753c7e08SAugustin Cavalier 		else if (rh->it_present & htole32(1<<IEEE80211_RADIOTAP_CHANNEL))
171*753c7e08SAugustin Cavalier 			set_channel(ic->ic_rxchan, ic->ic_curchan);
172*753c7e08SAugustin Cavalier 	}
173*753c7e08SAugustin Cavalier 	if (ic->ic_txchan != NULL) {
174*753c7e08SAugustin Cavalier 		struct ieee80211_radiotap_header *th = ic->ic_th;
175*753c7e08SAugustin Cavalier 
176*753c7e08SAugustin Cavalier 		if (th->it_present & htole32(1<<IEEE80211_RADIOTAP_XCHANNEL))
177*753c7e08SAugustin Cavalier 			set_xchannel(ic->ic_txchan, ic->ic_curchan);
178*753c7e08SAugustin Cavalier 		else if (th->it_present & htole32(1<<IEEE80211_RADIOTAP_CHANNEL))
179*753c7e08SAugustin Cavalier 			set_channel(ic->ic_txchan, ic->ic_curchan);
180*753c7e08SAugustin Cavalier 	}
181*753c7e08SAugustin Cavalier }
182*753c7e08SAugustin Cavalier 
183*753c7e08SAugustin Cavalier /*
184*753c7e08SAugustin Cavalier  * Distribute radiotap data (+packet) to all monitor mode
185*753c7e08SAugustin Cavalier  * vaps with an active tap other than vap0.
186*753c7e08SAugustin Cavalier  */
187*753c7e08SAugustin Cavalier static void
188*753c7e08SAugustin Cavalier spam_vaps(struct ieee80211vap *vap0, struct mbuf *m,
189*753c7e08SAugustin Cavalier 	struct ieee80211_radiotap_header *rh, int len)
190*753c7e08SAugustin Cavalier {
191*753c7e08SAugustin Cavalier 	struct ieee80211com *ic = vap0->iv_ic;
192*753c7e08SAugustin Cavalier 	struct ieee80211vap *vap;
193*753c7e08SAugustin Cavalier 
194*753c7e08SAugustin Cavalier 	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
195*753c7e08SAugustin Cavalier 		if (vap != vap0 &&
196*753c7e08SAugustin Cavalier 		    vap->iv_opmode == IEEE80211_M_MONITOR &&
197*753c7e08SAugustin Cavalier 		    (vap->iv_flags_ext & IEEE80211_FEXT_BPF) &&
198*753c7e08SAugustin Cavalier 		    vap->iv_state != IEEE80211_S_INIT)
199*753c7e08SAugustin Cavalier 			bpf_mtap2(vap->iv_rawbpf, rh, len, m);
200*753c7e08SAugustin Cavalier 	}
201*753c7e08SAugustin Cavalier }
202*753c7e08SAugustin Cavalier 
203*753c7e08SAugustin Cavalier /*
204*753c7e08SAugustin Cavalier  * Dispatch radiotap data for transmitted packet.
205*753c7e08SAugustin Cavalier  */
206*753c7e08SAugustin Cavalier void
207*753c7e08SAugustin Cavalier ieee80211_radiotap_tx(struct ieee80211vap *vap0, struct mbuf *m)
208*753c7e08SAugustin Cavalier {
209*753c7e08SAugustin Cavalier 	struct ieee80211com *ic = vap0->iv_ic;
210*753c7e08SAugustin Cavalier 	struct ieee80211_radiotap_header *th = ic->ic_th;
211*753c7e08SAugustin Cavalier 	int len;
212*753c7e08SAugustin Cavalier 
213*753c7e08SAugustin Cavalier 	KASSERT(th != NULL, ("no tx radiotap header"));
214*753c7e08SAugustin Cavalier 	len = le16toh(th->it_len);
215*753c7e08SAugustin Cavalier 
216*753c7e08SAugustin Cavalier 	if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF)
217*753c7e08SAugustin Cavalier 		bpf_mtap2(vap0->iv_rawbpf, th, len, m);
218*753c7e08SAugustin Cavalier 	/*
219*753c7e08SAugustin Cavalier 	 * Spam monitor mode vaps.
220*753c7e08SAugustin Cavalier 	 */
221*753c7e08SAugustin Cavalier 	if (ic->ic_montaps != 0)
222*753c7e08SAugustin Cavalier 		spam_vaps(vap0, m, th, len);
223*753c7e08SAugustin Cavalier }
224*753c7e08SAugustin Cavalier 
225*753c7e08SAugustin Cavalier /*
226*753c7e08SAugustin Cavalier  * Dispatch radiotap data for received packet.
227*753c7e08SAugustin Cavalier  */
228*753c7e08SAugustin Cavalier void
229*753c7e08SAugustin Cavalier ieee80211_radiotap_rx(struct ieee80211vap *vap0, struct mbuf *m)
230*753c7e08SAugustin Cavalier {
231*753c7e08SAugustin Cavalier 	struct ieee80211com *ic = vap0->iv_ic;
232*753c7e08SAugustin Cavalier 	struct ieee80211_radiotap_header *rh = ic->ic_rh;
233*753c7e08SAugustin Cavalier 	int len;
234*753c7e08SAugustin Cavalier 
235*753c7e08SAugustin Cavalier 	KASSERT(rh != NULL, ("no rx radiotap header"));
236*753c7e08SAugustin Cavalier 	len = le16toh(rh->it_len);
237*753c7e08SAugustin Cavalier 
238*753c7e08SAugustin Cavalier 	if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF)
239*753c7e08SAugustin Cavalier 		bpf_mtap2(vap0->iv_rawbpf, rh, len, m);
240*753c7e08SAugustin Cavalier 	/*
241*753c7e08SAugustin Cavalier 	 * Spam monitor mode vaps with unicast frames.  Multicast
242*753c7e08SAugustin Cavalier 	 * frames are handled by passing through ieee80211_input_all
243*753c7e08SAugustin Cavalier 	 * which distributes copies to the monitor mode vaps.
244*753c7e08SAugustin Cavalier 	 */
245*753c7e08SAugustin Cavalier 	if (ic->ic_montaps != 0 && (m->m_flags & M_BCAST) == 0)
246*753c7e08SAugustin Cavalier 		spam_vaps(vap0, m, rh, len);
247*753c7e08SAugustin Cavalier }
248*753c7e08SAugustin Cavalier 
249*753c7e08SAugustin Cavalier /*
250*753c7e08SAugustin Cavalier  * Dispatch radiotap data for a packet received outside the normal
251*753c7e08SAugustin Cavalier  * rx processing path; this is used, for example, to handle frames
252*753c7e08SAugustin Cavalier  * received with errors that would otherwise be dropped.
253*753c7e08SAugustin Cavalier  */
254*753c7e08SAugustin Cavalier void
255*753c7e08SAugustin Cavalier ieee80211_radiotap_rx_all(struct ieee80211com *ic, struct mbuf *m)
256*753c7e08SAugustin Cavalier {
257*753c7e08SAugustin Cavalier 	struct ieee80211_radiotap_header *rh = ic->ic_rh;
258*753c7e08SAugustin Cavalier 	int len = le16toh(rh->it_len);
259*753c7e08SAugustin Cavalier 	struct ieee80211vap *vap;
260*753c7e08SAugustin Cavalier 
261*753c7e08SAugustin Cavalier 	/* XXX locking? */
262*753c7e08SAugustin Cavalier 	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
263*753c7e08SAugustin Cavalier 		if (ieee80211_radiotap_active_vap(vap) &&
264*753c7e08SAugustin Cavalier 		    vap->iv_state != IEEE80211_S_INIT)
265*753c7e08SAugustin Cavalier 			bpf_mtap2(vap->iv_rawbpf, rh, len, m);
266*753c7e08SAugustin Cavalier 	}
267*753c7e08SAugustin Cavalier }
268*753c7e08SAugustin Cavalier 
269*753c7e08SAugustin Cavalier /*
270*753c7e08SAugustin Cavalier  * Return the offset of the specified item in the radiotap
271*753c7e08SAugustin Cavalier  * header description.  If the item is not present or is not
272*753c7e08SAugustin Cavalier  * known -1 is returned.
273*753c7e08SAugustin Cavalier  */
274*753c7e08SAugustin Cavalier static int
275*753c7e08SAugustin Cavalier radiotap_offset(struct ieee80211_radiotap_header *rh,
276*753c7e08SAugustin Cavalier     int n_vendor_attributes, int item)
277*753c7e08SAugustin Cavalier {
278*753c7e08SAugustin Cavalier 	static const struct {
279*753c7e08SAugustin Cavalier 		size_t	align, width;
280*753c7e08SAugustin Cavalier 	} items[] = {
281*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_TSFT] = {
282*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint64_t),
283*753c7e08SAugustin Cavalier 		    .width	= sizeof(uint64_t),
284*753c7e08SAugustin Cavalier 		},
285*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_FLAGS] = {
286*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint8_t),
287*753c7e08SAugustin Cavalier 		    .width	= sizeof(uint8_t),
288*753c7e08SAugustin Cavalier 		},
289*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_RATE] = {
290*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint8_t),
291*753c7e08SAugustin Cavalier 		    .width	= sizeof(uint8_t),
292*753c7e08SAugustin Cavalier 		},
293*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_CHANNEL] = {
294*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint16_t),
295*753c7e08SAugustin Cavalier 		    .width	= 2*sizeof(uint16_t),
296*753c7e08SAugustin Cavalier 		},
297*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_FHSS] = {
298*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint16_t),
299*753c7e08SAugustin Cavalier 		    .width	= sizeof(uint16_t),
300*753c7e08SAugustin Cavalier 		},
301*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = {
302*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint8_t),
303*753c7e08SAugustin Cavalier 		    .width	= sizeof(uint8_t),
304*753c7e08SAugustin Cavalier 		},
305*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_DBM_ANTNOISE] = {
306*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint8_t),
307*753c7e08SAugustin Cavalier 		    .width	= sizeof(uint8_t),
308*753c7e08SAugustin Cavalier 		},
309*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_LOCK_QUALITY] = {
310*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint16_t),
311*753c7e08SAugustin Cavalier 		    .width	= sizeof(uint16_t),
312*753c7e08SAugustin Cavalier 		},
313*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_TX_ATTENUATION] = {
314*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint16_t),
315*753c7e08SAugustin Cavalier 		    .width	= sizeof(uint16_t),
316*753c7e08SAugustin Cavalier 		},
317*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = {
318*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint16_t),
319*753c7e08SAugustin Cavalier 		    .width	= sizeof(uint16_t),
320*753c7e08SAugustin Cavalier 		},
321*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_DBM_TX_POWER] = {
322*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint8_t),
323*753c7e08SAugustin Cavalier 		    .width	= sizeof(uint8_t),
324*753c7e08SAugustin Cavalier 		},
325*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_ANTENNA] = {
326*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint8_t),
327*753c7e08SAugustin Cavalier 		    .width	= sizeof(uint8_t),
328*753c7e08SAugustin Cavalier 		},
329*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_DB_ANTSIGNAL] = {
330*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint8_t),
331*753c7e08SAugustin Cavalier 		    .width	= sizeof(uint8_t),
332*753c7e08SAugustin Cavalier 		},
333*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_DB_ANTNOISE] = {
334*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint8_t),
335*753c7e08SAugustin Cavalier 		    .width	= sizeof(uint8_t),
336*753c7e08SAugustin Cavalier 		},
337*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_XCHANNEL] = {
338*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint32_t),
339*753c7e08SAugustin Cavalier 		    .width	= 2*sizeof(uint32_t),
340*753c7e08SAugustin Cavalier 		},
341*753c7e08SAugustin Cavalier 		[IEEE80211_RADIOTAP_MCS] = {
342*753c7e08SAugustin Cavalier 		    .align	= sizeof(uint8_t),
343*753c7e08SAugustin Cavalier 		    .width	= 3*sizeof(uint8_t),
344*753c7e08SAugustin Cavalier 		},
345*753c7e08SAugustin Cavalier 	};
346*753c7e08SAugustin Cavalier 	uint32_t present = le32toh(rh->it_present);
347*753c7e08SAugustin Cavalier 	int off, i;
348*753c7e08SAugustin Cavalier 
349*753c7e08SAugustin Cavalier 	off = sizeof(struct ieee80211_radiotap_header);
350*753c7e08SAugustin Cavalier 	off += n_vendor_attributes * (sizeof(uint32_t));
351*753c7e08SAugustin Cavalier 
352*753c7e08SAugustin Cavalier 	for (i = 0; i < IEEE80211_RADIOTAP_EXT; i++) {
353*753c7e08SAugustin Cavalier 		if ((present & (1<<i)) == 0)
354*753c7e08SAugustin Cavalier 			continue;
355*753c7e08SAugustin Cavalier 		if (items[i].align == 0) {
356*753c7e08SAugustin Cavalier 			/* NB: unidentified element, don't guess */
357*753c7e08SAugustin Cavalier 			printf("%s: unknown item %d\n", __func__, i);
358*753c7e08SAugustin Cavalier 			return -1;
359*753c7e08SAugustin Cavalier 		}
360*753c7e08SAugustin Cavalier 		off = roundup2(off, items[i].align);
361*753c7e08SAugustin Cavalier 		if (i == item) {
362*753c7e08SAugustin Cavalier 			if (off + items[i].width > le16toh(rh->it_len)) {
363*753c7e08SAugustin Cavalier 				/* NB: item does not fit in header data */
364*753c7e08SAugustin Cavalier 				printf("%s: item %d not in header data, "
365*753c7e08SAugustin Cavalier 				    "off %d width %zu len %d\n", __func__, i,
366*753c7e08SAugustin Cavalier 				    off, items[i].width, le16toh(rh->it_len));
367*753c7e08SAugustin Cavalier 				return -1;
368*753c7e08SAugustin Cavalier 			}
369*753c7e08SAugustin Cavalier 			return off;
370*753c7e08SAugustin Cavalier 		}
371*753c7e08SAugustin Cavalier 		off += items[i].width;
372*753c7e08SAugustin Cavalier 	}
373*753c7e08SAugustin Cavalier 	return -1;
374*753c7e08SAugustin Cavalier }
375