xref: /freebsd/sys/net80211/ieee80211_radiotap.c (revision 86ede425f2b45ccb1e9d43aab4248449898a34e7)
15463c4a4SSam Leffler /*-
25463c4a4SSam Leffler  * Copyright (c) 2009 Sam Leffler, Errno Consulting
35463c4a4SSam Leffler  * All rights reserved.
45463c4a4SSam Leffler  *
55463c4a4SSam Leffler  * Redistribution and use in source and binary forms, with or without
65463c4a4SSam Leffler  * modification, are permitted provided that the following conditions
75463c4a4SSam Leffler  * are met:
85463c4a4SSam Leffler  * 1. Redistributions of source code must retain the above copyright
95463c4a4SSam Leffler  *    notice, this list of conditions and the following disclaimer.
105463c4a4SSam Leffler  * 2. Redistributions in binary form must reproduce the above copyright
115463c4a4SSam Leffler  *    notice, this list of conditions and the following disclaimer in the
125463c4a4SSam Leffler  *    documentation and/or other materials provided with the distribution.
135463c4a4SSam Leffler  *
145463c4a4SSam Leffler  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
155463c4a4SSam Leffler  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
165463c4a4SSam Leffler  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
175463c4a4SSam Leffler  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
185463c4a4SSam Leffler  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
195463c4a4SSam Leffler  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
205463c4a4SSam Leffler  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
215463c4a4SSam Leffler  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
225463c4a4SSam Leffler  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
235463c4a4SSam Leffler  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
245463c4a4SSam Leffler  */
255463c4a4SSam Leffler 
265463c4a4SSam Leffler #include <sys/cdefs.h>
275463c4a4SSam Leffler __FBSDID("$FreeBSD$");
285463c4a4SSam Leffler 
295463c4a4SSam Leffler /*
305463c4a4SSam Leffler  * IEEE 802.11 radiotap support.
315463c4a4SSam Leffler  */
325463c4a4SSam Leffler #include "opt_wlan.h"
335463c4a4SSam Leffler 
345463c4a4SSam Leffler #include <sys/param.h>
355463c4a4SSam Leffler #include <sys/systm.h>
365463c4a4SSam Leffler #include <sys/mbuf.h>
375463c4a4SSam Leffler #include <sys/malloc.h>
385463c4a4SSam Leffler #include <sys/endian.h>
395463c4a4SSam Leffler #include <sys/kernel.h>
405463c4a4SSam Leffler 
415463c4a4SSam Leffler #include <sys/socket.h>
425463c4a4SSam Leffler 
435463c4a4SSam Leffler #include <net/bpf.h>
445463c4a4SSam Leffler #include <net/if.h>
455463c4a4SSam Leffler #include <net/if_llc.h>
465463c4a4SSam Leffler #include <net/if_media.h>
475463c4a4SSam Leffler 
485463c4a4SSam Leffler #include <net80211/ieee80211_var.h>
495463c4a4SSam Leffler 
505463c4a4SSam Leffler static int radiotap_offset(struct ieee80211_radiotap_header *, int);
515463c4a4SSam Leffler 
525463c4a4SSam Leffler void
535463c4a4SSam Leffler ieee80211_radiotap_attach(struct ieee80211com *ic,
545463c4a4SSam Leffler 	struct ieee80211_radiotap_header *th, int tlen, uint32_t tx_radiotap,
555463c4a4SSam Leffler 	struct ieee80211_radiotap_header *rh, int rlen, uint32_t rx_radiotap)
565463c4a4SSam Leffler {
575463c4a4SSam Leffler #define	B(_v)	(1<<(_v))
585463c4a4SSam Leffler 	int off;
595463c4a4SSam Leffler 
605463c4a4SSam Leffler 	th->it_len = htole16(roundup2(tlen, sizeof(uint32_t)));
615463c4a4SSam Leffler 	th->it_present = htole32(tx_radiotap);
625463c4a4SSam Leffler 	ic->ic_th = th;
635463c4a4SSam Leffler 	/* calculate offset to channel data */
645463c4a4SSam Leffler 	off = -1;
655463c4a4SSam Leffler 	if (tx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
665463c4a4SSam Leffler 		off = radiotap_offset(th, IEEE80211_RADIOTAP_CHANNEL);
675463c4a4SSam Leffler 	else if (tx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
685463c4a4SSam Leffler 		off = radiotap_offset(th, IEEE80211_RADIOTAP_XCHANNEL);
695463c4a4SSam Leffler 	if (off == -1) {
705463c4a4SSam Leffler 		if_printf(ic->ic_ifp, "%s: no tx channel, radiotap 0x%x",
715463c4a4SSam Leffler 		    __func__, tx_radiotap);
725463c4a4SSam Leffler 		/* NB: we handle this case but data will have no chan spec */
735463c4a4SSam Leffler 	} else
745463c4a4SSam Leffler 		ic->ic_txchan = ((uint8_t *) th) + off;
755463c4a4SSam Leffler 
765463c4a4SSam Leffler 	rh->it_len = htole16(roundup2(rlen, sizeof(uint32_t)));
775463c4a4SSam Leffler 	rh->it_present = htole32(rx_radiotap);
785463c4a4SSam Leffler 	ic->ic_rh = rh;
795463c4a4SSam Leffler 	/* calculate offset to channel data */
805463c4a4SSam Leffler 	off = -1;
815463c4a4SSam Leffler 	if (rx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
825463c4a4SSam Leffler 		off = radiotap_offset(rh, IEEE80211_RADIOTAP_CHANNEL);
835463c4a4SSam Leffler 	else if (rx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
845463c4a4SSam Leffler 		off = radiotap_offset(rh, IEEE80211_RADIOTAP_XCHANNEL);
855463c4a4SSam Leffler 	if (off == -1) {
865463c4a4SSam Leffler 		if_printf(ic->ic_ifp, "%s: no rx channel, radiotap 0x%x",
875463c4a4SSam Leffler 		    __func__, rx_radiotap);
885463c4a4SSam Leffler 		/* NB: we handle this case but data will have no chan spec */
895463c4a4SSam Leffler 	} else
905463c4a4SSam Leffler 		ic->ic_rxchan = ((uint8_t *) rh) + off;
915463c4a4SSam Leffler #undef B
925463c4a4SSam Leffler }
935463c4a4SSam Leffler 
945463c4a4SSam Leffler void
955463c4a4SSam Leffler ieee80211_radiotap_detach(struct ieee80211com *ic)
965463c4a4SSam Leffler {
975463c4a4SSam Leffler }
985463c4a4SSam Leffler 
995463c4a4SSam Leffler void
1005463c4a4SSam Leffler ieee80211_radiotap_vattach(struct ieee80211vap *vap)
1015463c4a4SSam Leffler {
1025463c4a4SSam Leffler 	struct ieee80211com *ic = vap->iv_ic;
1035463c4a4SSam Leffler 	struct ieee80211_radiotap_header *th = ic->ic_th;
1045463c4a4SSam Leffler 
105a6c3cf3eSSam Leffler 	if (th != NULL && ic->ic_rh != NULL) {
1065463c4a4SSam Leffler 		/* radiotap DLT for raw 802.11 frames */
1075463c4a4SSam Leffler 		bpfattach2(vap->iv_ifp, DLT_IEEE802_11_RADIO,
1085463c4a4SSam Leffler 		    sizeof(struct ieee80211_frame) + le16toh(th->it_len),
1095463c4a4SSam Leffler 		    &vap->iv_rawbpf);
1105463c4a4SSam Leffler 	}
111a6c3cf3eSSam Leffler }
1125463c4a4SSam Leffler 
1135463c4a4SSam Leffler void
1145463c4a4SSam Leffler ieee80211_radiotap_vdetach(struct ieee80211vap *vap)
1155463c4a4SSam Leffler {
1165463c4a4SSam Leffler 	/* NB: bpfattach is called by ether_ifdetach and claims all taps */
1175463c4a4SSam Leffler }
1185463c4a4SSam Leffler 
1195463c4a4SSam Leffler static void
1205463c4a4SSam Leffler set_channel(void *p, const struct ieee80211_channel *c)
1215463c4a4SSam Leffler {
1225463c4a4SSam Leffler 	struct {
1235463c4a4SSam Leffler 		uint16_t	freq;
1245463c4a4SSam Leffler 		uint16_t	flags;
1255463c4a4SSam Leffler 	} *rc = p;
1265463c4a4SSam Leffler 
1275463c4a4SSam Leffler 	rc->freq = htole16(c->ic_freq);
1285463c4a4SSam Leffler 	rc->flags = htole16(c->ic_flags);
1295463c4a4SSam Leffler }
1305463c4a4SSam Leffler 
1315463c4a4SSam Leffler static void
1325463c4a4SSam Leffler set_xchannel(void *p, const struct ieee80211_channel *c)
1335463c4a4SSam Leffler {
1345463c4a4SSam Leffler 	struct {
1355463c4a4SSam Leffler 		uint32_t	flags;
1365463c4a4SSam Leffler 		uint16_t	freq;
1375463c4a4SSam Leffler 		uint8_t		ieee;
1385463c4a4SSam Leffler 		uint8_t		maxpow;
1395463c4a4SSam Leffler 	} *rc = p;
1405463c4a4SSam Leffler 
1415463c4a4SSam Leffler 	rc->flags = htole32(c->ic_flags);
1425463c4a4SSam Leffler 	rc->freq = htole16(c->ic_freq);
1435463c4a4SSam Leffler 	rc->ieee = c->ic_ieee;
1445463c4a4SSam Leffler 	rc->maxpow = c->ic_maxregpower;
1455463c4a4SSam Leffler }
1465463c4a4SSam Leffler 
1475463c4a4SSam Leffler /*
1485463c4a4SSam Leffler  * Update radiotap state on channel change.
1495463c4a4SSam Leffler  */
1505463c4a4SSam Leffler void
1515463c4a4SSam Leffler ieee80211_radiotap_chan_change(struct ieee80211com *ic)
1525463c4a4SSam Leffler {
1535463c4a4SSam Leffler 	if (ic->ic_rxchan != NULL) {
1545463c4a4SSam Leffler 		struct ieee80211_radiotap_header *rh = ic->ic_rh;
1555463c4a4SSam Leffler 
15686ede425SSam Leffler 		if (rh->it_present & htole32(1<<IEEE80211_RADIOTAP_XCHANNEL))
1575463c4a4SSam Leffler 			set_xchannel(ic->ic_rxchan, ic->ic_curchan);
15886ede425SSam Leffler 		else if (rh->it_present & htole32(1<<IEEE80211_RADIOTAP_CHANNEL))
1595463c4a4SSam Leffler 			set_channel(ic->ic_rxchan, ic->ic_curchan);
1605463c4a4SSam Leffler 	}
1615463c4a4SSam Leffler 	if (ic->ic_txchan != NULL) {
1625463c4a4SSam Leffler 		struct ieee80211_radiotap_header *th = ic->ic_th;
1635463c4a4SSam Leffler 
16486ede425SSam Leffler 		if (th->it_present & htole32(1<<IEEE80211_RADIOTAP_XCHANNEL))
1655463c4a4SSam Leffler 			set_xchannel(ic->ic_txchan, ic->ic_curchan);
16686ede425SSam Leffler 		else if (th->it_present & htole32(1<<IEEE80211_RADIOTAP_CHANNEL))
1675463c4a4SSam Leffler 			set_channel(ic->ic_txchan, ic->ic_curchan);
1685463c4a4SSam Leffler 	}
1695463c4a4SSam Leffler }
1705463c4a4SSam Leffler 
171e1cfcbcbSSam Leffler #if 0
1725463c4a4SSam Leffler static void
1735463c4a4SSam Leffler dispatch_radiotap(struct ieee80211vap *vap0, struct mbuf *m,
1745463c4a4SSam Leffler 	struct ieee80211_radiotap_header *rh)
1755463c4a4SSam Leffler {
1765463c4a4SSam Leffler 	struct ieee80211com *ic = vap0->iv_ic;
1775463c4a4SSam Leffler 	int len = le16toh(rh->it_len);
1785463c4a4SSam Leffler 
179e1cfcbcbSSam Leffler 	if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF)
1805463c4a4SSam Leffler 		bpf_mtap2(vap0->iv_rawbpf, rh, len, m);
181e1cfcbcbSSam Leffler 	/*
182e1cfcbcbSSam Leffler 	 * Spam monitor mode vaps with unicast frames.  Multicast
183e1cfcbcbSSam Leffler 	 * frames are handled by passing through ieee80211_input_all
184e1cfcbcbSSam Leffler 	 * which distributes copies to the monitor mode vaps to be
185e1cfcbcbSSam Leffler 	 * processed above.
186e1cfcbcbSSam Leffler 	 */
187e1cfcbcbSSam Leffler 	if (ic->ic_montaps != 0 && (m->m_flags & M_BCAST) == 0) {
1885463c4a4SSam Leffler 		struct ieee80211vap *vap;
1895463c4a4SSam Leffler 		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
190e1cfcbcbSSam Leffler 			if (vap != vap0 &&
191e1cfcbcbSSam Leffler 			    vap->iv_opmode == IEEE80211_M_MONITOR &&
192e1cfcbcbSSam Leffler 			    (vap->iv_flags_ext & IEEE80211_FEXT_BPF) &&
193e1cfcbcbSSam Leffler 			    vap->iv_state != IEEE80211_S_INIT)
1945463c4a4SSam Leffler 				bpf_mtap2(vap->iv_rawbpf, rh, len, m);
1955463c4a4SSam Leffler 		}
1965463c4a4SSam Leffler 	}
1975463c4a4SSam Leffler }
198e1cfcbcbSSam Leffler #endif
199e1cfcbcbSSam Leffler 
200e1cfcbcbSSam Leffler /*
201e1cfcbcbSSam Leffler  * Distribute radiotap data (+packet) to all monitor mode
202e1cfcbcbSSam Leffler  * vaps with an active tap other than vap0.
203e1cfcbcbSSam Leffler  */
204e1cfcbcbSSam Leffler static void
205e1cfcbcbSSam Leffler spam_vaps(struct ieee80211vap *vap0, struct mbuf *m,
206e1cfcbcbSSam Leffler 	struct ieee80211_radiotap_header *rh, int len)
207e1cfcbcbSSam Leffler {
208e1cfcbcbSSam Leffler 	struct ieee80211com *ic = vap0->iv_ic;
209e1cfcbcbSSam Leffler 	struct ieee80211vap *vap;
210e1cfcbcbSSam Leffler 
211e1cfcbcbSSam Leffler 	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
212e1cfcbcbSSam Leffler 		if (vap != vap0 &&
213e1cfcbcbSSam Leffler 		    vap->iv_opmode == IEEE80211_M_MONITOR &&
214e1cfcbcbSSam Leffler 		    (vap->iv_flags_ext & IEEE80211_FEXT_BPF) &&
215e1cfcbcbSSam Leffler 		    vap->iv_state != IEEE80211_S_INIT)
216e1cfcbcbSSam Leffler 			bpf_mtap2(vap->iv_rawbpf, rh, len, m);
217e1cfcbcbSSam Leffler 	}
218e1cfcbcbSSam Leffler }
2195463c4a4SSam Leffler 
2205463c4a4SSam Leffler /*
2215463c4a4SSam Leffler  * Dispatch radiotap data for transmitted packet.
2225463c4a4SSam Leffler  */
2235463c4a4SSam Leffler void
2245463c4a4SSam Leffler ieee80211_radiotap_tx(struct ieee80211vap *vap0, struct mbuf *m)
2255463c4a4SSam Leffler {
226e1cfcbcbSSam Leffler 	struct ieee80211com *ic = vap0->iv_ic;
227e1cfcbcbSSam Leffler 	struct ieee80211_radiotap_header *th = ic->ic_th;
228e1cfcbcbSSam Leffler 	int len;
229e1cfcbcbSSam Leffler 
230e1cfcbcbSSam Leffler 	KASSERT(th != NULL, ("no tx radiotap header"));
231e1cfcbcbSSam Leffler 	len = le16toh(th->it_len);
232e1cfcbcbSSam Leffler 
233e1cfcbcbSSam Leffler 	if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF)
234e1cfcbcbSSam Leffler 		bpf_mtap2(vap0->iv_rawbpf, th, len, m);
235e1cfcbcbSSam Leffler 	/*
236e1cfcbcbSSam Leffler 	 * Spam monitor mode vaps.
237e1cfcbcbSSam Leffler 	 */
238e1cfcbcbSSam Leffler 	if (ic->ic_montaps != 0)
239e1cfcbcbSSam Leffler 		spam_vaps(vap0, m, th, len);
2405463c4a4SSam Leffler }
2415463c4a4SSam Leffler 
2425463c4a4SSam Leffler /*
2435463c4a4SSam Leffler  * Dispatch radiotap data for received packet.
2445463c4a4SSam Leffler  */
2455463c4a4SSam Leffler void
2465463c4a4SSam Leffler ieee80211_radiotap_rx(struct ieee80211vap *vap0, struct mbuf *m)
2475463c4a4SSam Leffler {
248e1cfcbcbSSam Leffler 	struct ieee80211com *ic = vap0->iv_ic;
249e1cfcbcbSSam Leffler 	struct ieee80211_radiotap_header *rh = ic->ic_rh;
250e1cfcbcbSSam Leffler 	int len;
251e1cfcbcbSSam Leffler 
252e1cfcbcbSSam Leffler 	KASSERT(rh != NULL, ("no rx radiotap header"));
253e1cfcbcbSSam Leffler 	len = le16toh(rh->it_len);
254e1cfcbcbSSam Leffler 
255e1cfcbcbSSam Leffler 	if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF)
256e1cfcbcbSSam Leffler 		bpf_mtap2(vap0->iv_rawbpf, rh, len, m);
257e1cfcbcbSSam Leffler 	/*
258e1cfcbcbSSam Leffler 	 * Spam monitor mode vaps with unicast frames.  Multicast
259e1cfcbcbSSam Leffler 	 * frames are handled by passing through ieee80211_input_all
260e1cfcbcbSSam Leffler 	 * which distributes copies to the monitor mode vaps.
261e1cfcbcbSSam Leffler 	 */
262e1cfcbcbSSam Leffler 	if (ic->ic_montaps != 0 && (m->m_flags & M_BCAST) == 0)
263e1cfcbcbSSam Leffler 		spam_vaps(vap0, m, rh, len);
2645463c4a4SSam Leffler }
2655463c4a4SSam Leffler 
2665463c4a4SSam Leffler /*
2675463c4a4SSam Leffler  * Dispatch radiotap data for a packet received outside the normal
2685463c4a4SSam Leffler  * rx processing path; this is used, for example, to handle frames
2695463c4a4SSam Leffler  * received with errors that would otherwise be dropped.
2705463c4a4SSam Leffler  */
2715463c4a4SSam Leffler void
2725463c4a4SSam Leffler ieee80211_radiotap_rx_all(struct ieee80211com *ic, struct mbuf *m)
2735463c4a4SSam Leffler {
2745463c4a4SSam Leffler 	struct ieee80211_radiotap_header *rh = ic->ic_rh;
2755463c4a4SSam Leffler 	int len = le16toh(rh->it_len);
2765463c4a4SSam Leffler 	struct ieee80211vap *vap;
2775463c4a4SSam Leffler 
2785463c4a4SSam Leffler 	/* XXX locking? */
2795463c4a4SSam Leffler 	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
280e1cfcbcbSSam Leffler 		if (ieee80211_radiotap_active_vap(vap) &&
281e1cfcbcbSSam Leffler 		    vap->iv_state != IEEE80211_S_INIT)
2825463c4a4SSam Leffler 			bpf_mtap2(vap->iv_rawbpf, rh, len, m);
2835463c4a4SSam Leffler 	}
2845463c4a4SSam Leffler }
2855463c4a4SSam Leffler 
2865463c4a4SSam Leffler /*
2875463c4a4SSam Leffler  * Return the offset of the specified item in the radiotap
2885463c4a4SSam Leffler  * header description.  If the item is not present or is not
2895463c4a4SSam Leffler  * known -1 is returned.
2905463c4a4SSam Leffler  */
2915463c4a4SSam Leffler static int
2925463c4a4SSam Leffler radiotap_offset(struct ieee80211_radiotap_header *rh, int item)
2935463c4a4SSam Leffler {
2945463c4a4SSam Leffler 	static const struct {
2955463c4a4SSam Leffler 		size_t	align, width;
2965463c4a4SSam Leffler 	} items[] = {
2975463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_TSFT] = {
2985463c4a4SSam Leffler 		    .align	= sizeof(uint64_t),
2995463c4a4SSam Leffler 		    .width	= sizeof(uint64_t),
3005463c4a4SSam Leffler 		},
3015463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_FLAGS] = {
3025463c4a4SSam Leffler 		    .align	= sizeof(uint8_t),
3035463c4a4SSam Leffler 		    .width	= sizeof(uint8_t),
3045463c4a4SSam Leffler 		},
3055463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_RATE] = {
3065463c4a4SSam Leffler 		    .align	= sizeof(uint8_t),
3075463c4a4SSam Leffler 		    .width	= sizeof(uint8_t),
3085463c4a4SSam Leffler 		},
3095463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_CHANNEL] = {
3105463c4a4SSam Leffler 		    .align	= sizeof(uint16_t),
3115463c4a4SSam Leffler 		    .width	= 2*sizeof(uint16_t),
3125463c4a4SSam Leffler 		},
3135463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_FHSS] = {
3145463c4a4SSam Leffler 		    .align	= sizeof(uint16_t),
3155463c4a4SSam Leffler 		    .width	= sizeof(uint16_t),
3165463c4a4SSam Leffler 		},
3175463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = {
3185463c4a4SSam Leffler 		    .align	= sizeof(uint8_t),
3195463c4a4SSam Leffler 		    .width	= sizeof(uint8_t),
3205463c4a4SSam Leffler 		},
3215463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_DBM_ANTNOISE] = {
3225463c4a4SSam Leffler 		    .align	= sizeof(uint8_t),
3235463c4a4SSam Leffler 		    .width	= sizeof(uint8_t),
3245463c4a4SSam Leffler 		},
3255463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_LOCK_QUALITY] = {
3265463c4a4SSam Leffler 		    .align	= sizeof(uint16_t),
3275463c4a4SSam Leffler 		    .width	= sizeof(uint16_t),
3285463c4a4SSam Leffler 		},
3295463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_TX_ATTENUATION] = {
3305463c4a4SSam Leffler 		    .align	= sizeof(uint16_t),
3315463c4a4SSam Leffler 		    .width	= sizeof(uint16_t),
3325463c4a4SSam Leffler 		},
3335463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = {
3345463c4a4SSam Leffler 		    .align	= sizeof(uint16_t),
3355463c4a4SSam Leffler 		    .width	= sizeof(uint16_t),
3365463c4a4SSam Leffler 		},
3375463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_DBM_TX_POWER] = {
3385463c4a4SSam Leffler 		    .align	= sizeof(uint8_t),
3395463c4a4SSam Leffler 		    .width	= sizeof(uint8_t),
3405463c4a4SSam Leffler 		},
3415463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_ANTENNA] = {
3425463c4a4SSam Leffler 		    .align	= sizeof(uint8_t),
3435463c4a4SSam Leffler 		    .width	= sizeof(uint8_t),
3445463c4a4SSam Leffler 		},
3455463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_DB_ANTSIGNAL] = {
3465463c4a4SSam Leffler 		    .align	= sizeof(uint8_t),
3475463c4a4SSam Leffler 		    .width	= sizeof(uint8_t),
3485463c4a4SSam Leffler 		},
3495463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_DB_ANTNOISE] = {
3505463c4a4SSam Leffler 		    .align	= sizeof(uint8_t),
3515463c4a4SSam Leffler 		    .width	= sizeof(uint8_t),
3525463c4a4SSam Leffler 		},
3535463c4a4SSam Leffler 		[IEEE80211_RADIOTAP_XCHANNEL] = {
3545463c4a4SSam Leffler 		    .align	= sizeof(uint32_t),
3555463c4a4SSam Leffler 		    .width	= 2*sizeof(uint32_t),
3565463c4a4SSam Leffler 		},
3575463c4a4SSam Leffler 	};
3585463c4a4SSam Leffler 	uint32_t present = le32toh(rh->it_present);
3595463c4a4SSam Leffler 	int off, i;
3605463c4a4SSam Leffler 
3615463c4a4SSam Leffler 	off = sizeof(struct ieee80211_radiotap_header);
3625463c4a4SSam Leffler 	for (i = 0; i < IEEE80211_RADIOTAP_EXT; i++) {
3635463c4a4SSam Leffler 		if ((present & (1<<i)) == 0)
3645463c4a4SSam Leffler 			continue;
3655463c4a4SSam Leffler 		if (items[i].align == 0) {
3665463c4a4SSam Leffler 			/* NB: unidentified element, don't guess */
3675463c4a4SSam Leffler 			printf("%s: unknown item %d\n", __func__, i);
3685463c4a4SSam Leffler 			return -1;
3695463c4a4SSam Leffler 		}
3705463c4a4SSam Leffler 		off = roundup2(off, items[i].align);
3715463c4a4SSam Leffler 		if (i == item) {
3725463c4a4SSam Leffler 			if (off + items[i].width > le16toh(rh->it_len)) {
3735463c4a4SSam Leffler 				/* NB: item does not fit in header data */
3745463c4a4SSam Leffler 				printf("%s: item %d not in header data, "
3755463c4a4SSam Leffler 				    "off %d width %zu len %d\n", __func__, i,
3765463c4a4SSam Leffler 				    off, items[i].width, le16toh(rh->it_len));
3775463c4a4SSam Leffler 				return -1;
3785463c4a4SSam Leffler 			}
3795463c4a4SSam Leffler 			return off;
3805463c4a4SSam Leffler 		}
3815463c4a4SSam Leffler 		off += items[i].width;
3825463c4a4SSam Leffler 	}
3835463c4a4SSam Leffler 	return -1;
3845463c4a4SSam Leffler }
385