15463c4a4SSam Leffler /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
45463c4a4SSam Leffler * Copyright (c) 2009 Sam Leffler, Errno Consulting
55463c4a4SSam Leffler * All rights reserved.
65463c4a4SSam Leffler *
75463c4a4SSam Leffler * Redistribution and use in source and binary forms, with or without
85463c4a4SSam Leffler * modification, are permitted provided that the following conditions
95463c4a4SSam Leffler * are met:
105463c4a4SSam Leffler * 1. Redistributions of source code must retain the above copyright
115463c4a4SSam Leffler * notice, this list of conditions and the following disclaimer.
125463c4a4SSam Leffler * 2. Redistributions in binary form must reproduce the above copyright
135463c4a4SSam Leffler * notice, this list of conditions and the following disclaimer in the
145463c4a4SSam Leffler * documentation and/or other materials provided with the distribution.
155463c4a4SSam Leffler *
165463c4a4SSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
175463c4a4SSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
185463c4a4SSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
195463c4a4SSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
205463c4a4SSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
215463c4a4SSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
225463c4a4SSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
235463c4a4SSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
245463c4a4SSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
255463c4a4SSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
265463c4a4SSam Leffler */
275463c4a4SSam Leffler
285463c4a4SSam Leffler #include <sys/cdefs.h>
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>
4576039bc8SGleb Smirnoff #include <net/if_var.h>
465463c4a4SSam Leffler #include <net/if_media.h>
47c3322cb9SGleb Smirnoff #include <net/ethernet.h>
485463c4a4SSam Leffler
495463c4a4SSam Leffler #include <net80211/ieee80211_var.h>
505463c4a4SSam Leffler
518a3860d5SAdrian Chadd static int radiotap_offset(struct ieee80211_radiotap_header *, int, int);
525463c4a4SSam Leffler
535463c4a4SSam Leffler 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)545463c4a4SSam Leffler ieee80211_radiotap_attach(struct ieee80211com *ic,
555463c4a4SSam Leffler struct ieee80211_radiotap_header *th, int tlen, uint32_t tx_radiotap,
565463c4a4SSam Leffler struct ieee80211_radiotap_header *rh, int rlen, uint32_t rx_radiotap)
575463c4a4SSam Leffler {
588a3860d5SAdrian Chadd ieee80211_radiotap_attachv(ic, th, tlen, 0, tx_radiotap,
598a3860d5SAdrian Chadd rh, rlen, 0, rx_radiotap);
608a3860d5SAdrian Chadd }
618a3860d5SAdrian Chadd
628a3860d5SAdrian Chadd void
ieee80211_radiotap_attachv(struct ieee80211com * ic,struct ieee80211_radiotap_header * th,int tlen,int n_tx_v,uint32_t tx_radiotap,struct ieee80211_radiotap_header * rh,int rlen,int n_rx_v,uint32_t rx_radiotap)638a3860d5SAdrian Chadd ieee80211_radiotap_attachv(struct ieee80211com *ic,
648a3860d5SAdrian Chadd struct ieee80211_radiotap_header *th,
658a3860d5SAdrian Chadd int tlen, int n_tx_v, uint32_t tx_radiotap,
668a3860d5SAdrian Chadd struct ieee80211_radiotap_header *rh,
678a3860d5SAdrian Chadd int rlen, int n_rx_v, uint32_t rx_radiotap)
688a3860d5SAdrian Chadd {
695463c4a4SSam Leffler #define B(_v) (1<<(_v))
705463c4a4SSam Leffler int off;
715463c4a4SSam Leffler
725463c4a4SSam Leffler th->it_len = htole16(roundup2(tlen, sizeof(uint32_t)));
735463c4a4SSam Leffler th->it_present = htole32(tx_radiotap);
745463c4a4SSam Leffler ic->ic_th = th;
755463c4a4SSam Leffler /* calculate offset to channel data */
765463c4a4SSam Leffler off = -1;
775463c4a4SSam Leffler if (tx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
788a3860d5SAdrian Chadd off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_CHANNEL);
795463c4a4SSam Leffler else if (tx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
808a3860d5SAdrian Chadd off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_XCHANNEL);
815463c4a4SSam Leffler if (off == -1) {
82c8f5794eSGleb Smirnoff ic_printf(ic, "%s: no tx channel, radiotap 0x%x\n", __func__,
83c8f5794eSGleb Smirnoff tx_radiotap);
845463c4a4SSam Leffler /* NB: we handle this case but data will have no chan spec */
855463c4a4SSam Leffler } else
865463c4a4SSam Leffler ic->ic_txchan = ((uint8_t *) th) + off;
875463c4a4SSam Leffler
885463c4a4SSam Leffler rh->it_len = htole16(roundup2(rlen, sizeof(uint32_t)));
895463c4a4SSam Leffler rh->it_present = htole32(rx_radiotap);
905463c4a4SSam Leffler ic->ic_rh = rh;
915463c4a4SSam Leffler /* calculate offset to channel data */
925463c4a4SSam Leffler off = -1;
935463c4a4SSam Leffler if (rx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
948a3860d5SAdrian Chadd off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_CHANNEL);
955463c4a4SSam Leffler else if (rx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
968a3860d5SAdrian Chadd off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_XCHANNEL);
975463c4a4SSam Leffler if (off == -1) {
98c8f5794eSGleb Smirnoff ic_printf(ic, "%s: no rx channel, radiotap 0x%x\n", __func__,
99c8f5794eSGleb Smirnoff rx_radiotap);
1005463c4a4SSam Leffler /* NB: we handle this case but data will have no chan spec */
1015463c4a4SSam Leffler } else
1025463c4a4SSam Leffler ic->ic_rxchan = ((uint8_t *) rh) + off;
1035463c4a4SSam Leffler #undef B
1045463c4a4SSam Leffler }
1055463c4a4SSam Leffler
1065463c4a4SSam Leffler void
ieee80211_radiotap_detach(struct ieee80211com * ic)1075463c4a4SSam Leffler ieee80211_radiotap_detach(struct ieee80211com *ic)
1085463c4a4SSam Leffler {
1095463c4a4SSam Leffler }
1105463c4a4SSam Leffler
1115463c4a4SSam Leffler void
ieee80211_radiotap_vattach(struct ieee80211vap * vap)1125463c4a4SSam Leffler ieee80211_radiotap_vattach(struct ieee80211vap *vap)
1135463c4a4SSam Leffler {
1145463c4a4SSam Leffler struct ieee80211com *ic = vap->iv_ic;
1155463c4a4SSam Leffler struct ieee80211_radiotap_header *th = ic->ic_th;
1165463c4a4SSam Leffler
117a6c3cf3eSSam Leffler if (th != NULL && ic->ic_rh != NULL) {
1185463c4a4SSam Leffler /* radiotap DLT for raw 802.11 frames */
1195463c4a4SSam Leffler bpfattach2(vap->iv_ifp, DLT_IEEE802_11_RADIO,
1205463c4a4SSam Leffler sizeof(struct ieee80211_frame) + le16toh(th->it_len),
1215463c4a4SSam Leffler &vap->iv_rawbpf);
1225463c4a4SSam Leffler }
123a6c3cf3eSSam Leffler }
1245463c4a4SSam Leffler
1255463c4a4SSam Leffler void
ieee80211_radiotap_vdetach(struct ieee80211vap * vap)1265463c4a4SSam Leffler ieee80211_radiotap_vdetach(struct ieee80211vap *vap)
1275463c4a4SSam Leffler {
128*34c98f40SZhenlei Huang /* NB: bpfdetach is called by ether_ifdetach and claims all taps */
1295463c4a4SSam Leffler }
1305463c4a4SSam Leffler
1315463c4a4SSam Leffler static void
set_channel(void * p,const struct ieee80211_channel * c)1325463c4a4SSam Leffler set_channel(void *p, const struct ieee80211_channel *c)
1335463c4a4SSam Leffler {
1345463c4a4SSam Leffler struct {
1355463c4a4SSam Leffler uint16_t freq;
1365463c4a4SSam Leffler uint16_t flags;
1375463c4a4SSam Leffler } *rc = p;
1385463c4a4SSam Leffler
1395463c4a4SSam Leffler rc->freq = htole16(c->ic_freq);
1405463c4a4SSam Leffler rc->flags = htole16(c->ic_flags);
1415463c4a4SSam Leffler }
1425463c4a4SSam Leffler
1435463c4a4SSam Leffler static void
set_xchannel(void * p,const struct ieee80211_channel * c)1445463c4a4SSam Leffler set_xchannel(void *p, const struct ieee80211_channel *c)
1455463c4a4SSam Leffler {
1465463c4a4SSam Leffler struct {
1475463c4a4SSam Leffler uint32_t flags;
1485463c4a4SSam Leffler uint16_t freq;
1495463c4a4SSam Leffler uint8_t ieee;
1505463c4a4SSam Leffler uint8_t maxpow;
1515463c4a4SSam Leffler } *rc = p;
1525463c4a4SSam Leffler
1535463c4a4SSam Leffler rc->flags = htole32(c->ic_flags);
1545463c4a4SSam Leffler rc->freq = htole16(c->ic_freq);
1555463c4a4SSam Leffler rc->ieee = c->ic_ieee;
1565463c4a4SSam Leffler rc->maxpow = c->ic_maxregpower;
1575463c4a4SSam Leffler }
1585463c4a4SSam Leffler
1595463c4a4SSam Leffler /*
1605463c4a4SSam Leffler * Update radiotap state on channel change.
1615463c4a4SSam Leffler */
1625463c4a4SSam Leffler void
ieee80211_radiotap_chan_change(struct ieee80211com * ic)1635463c4a4SSam Leffler ieee80211_radiotap_chan_change(struct ieee80211com *ic)
1645463c4a4SSam Leffler {
1655463c4a4SSam Leffler if (ic->ic_rxchan != NULL) {
1665463c4a4SSam Leffler struct ieee80211_radiotap_header *rh = ic->ic_rh;
1675463c4a4SSam Leffler
16886ede425SSam Leffler if (rh->it_present & htole32(1<<IEEE80211_RADIOTAP_XCHANNEL))
1695463c4a4SSam Leffler set_xchannel(ic->ic_rxchan, ic->ic_curchan);
17086ede425SSam Leffler else if (rh->it_present & htole32(1<<IEEE80211_RADIOTAP_CHANNEL))
1715463c4a4SSam Leffler set_channel(ic->ic_rxchan, ic->ic_curchan);
1725463c4a4SSam Leffler }
1735463c4a4SSam Leffler if (ic->ic_txchan != NULL) {
1745463c4a4SSam Leffler struct ieee80211_radiotap_header *th = ic->ic_th;
1755463c4a4SSam Leffler
17686ede425SSam Leffler if (th->it_present & htole32(1<<IEEE80211_RADIOTAP_XCHANNEL))
1775463c4a4SSam Leffler set_xchannel(ic->ic_txchan, ic->ic_curchan);
17886ede425SSam Leffler else if (th->it_present & htole32(1<<IEEE80211_RADIOTAP_CHANNEL))
1795463c4a4SSam Leffler set_channel(ic->ic_txchan, ic->ic_curchan);
1805463c4a4SSam Leffler }
1815463c4a4SSam Leffler }
1825463c4a4SSam Leffler
183e1cfcbcbSSam Leffler /*
184e1cfcbcbSSam Leffler * Distribute radiotap data (+packet) to all monitor mode
185e1cfcbcbSSam Leffler * vaps with an active tap other than vap0.
186e1cfcbcbSSam Leffler */
187e1cfcbcbSSam Leffler static void
spam_vaps(struct ieee80211vap * vap0,struct mbuf * m,struct ieee80211_radiotap_header * rh,int len)188e1cfcbcbSSam Leffler spam_vaps(struct ieee80211vap *vap0, struct mbuf *m,
189e1cfcbcbSSam Leffler struct ieee80211_radiotap_header *rh, int len)
190e1cfcbcbSSam Leffler {
191e1cfcbcbSSam Leffler struct ieee80211com *ic = vap0->iv_ic;
192e1cfcbcbSSam Leffler struct ieee80211vap *vap;
193e1cfcbcbSSam Leffler
194e1cfcbcbSSam Leffler TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
195e1cfcbcbSSam Leffler if (vap != vap0 &&
196e1cfcbcbSSam Leffler vap->iv_opmode == IEEE80211_M_MONITOR &&
197e1cfcbcbSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_BPF) &&
198e1cfcbcbSSam Leffler vap->iv_state != IEEE80211_S_INIT)
199e1cfcbcbSSam Leffler bpf_mtap2(vap->iv_rawbpf, rh, len, m);
200e1cfcbcbSSam Leffler }
201e1cfcbcbSSam Leffler }
2025463c4a4SSam Leffler
2035463c4a4SSam Leffler /*
2045463c4a4SSam Leffler * Dispatch radiotap data for transmitted packet.
2055463c4a4SSam Leffler */
2065463c4a4SSam Leffler void
ieee80211_radiotap_tx(struct ieee80211vap * vap0,struct mbuf * m)2075463c4a4SSam Leffler ieee80211_radiotap_tx(struct ieee80211vap *vap0, struct mbuf *m)
2085463c4a4SSam Leffler {
209e1cfcbcbSSam Leffler struct ieee80211com *ic = vap0->iv_ic;
210e1cfcbcbSSam Leffler struct ieee80211_radiotap_header *th = ic->ic_th;
211e1cfcbcbSSam Leffler int len;
212e1cfcbcbSSam Leffler
213e1cfcbcbSSam Leffler KASSERT(th != NULL, ("no tx radiotap header"));
214e1cfcbcbSSam Leffler len = le16toh(th->it_len);
215e1cfcbcbSSam Leffler
216e1cfcbcbSSam Leffler if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF)
217e1cfcbcbSSam Leffler bpf_mtap2(vap0->iv_rawbpf, th, len, m);
218e1cfcbcbSSam Leffler /*
219e1cfcbcbSSam Leffler * Spam monitor mode vaps.
220e1cfcbcbSSam Leffler */
221e1cfcbcbSSam Leffler if (ic->ic_montaps != 0)
222e1cfcbcbSSam Leffler spam_vaps(vap0, m, th, len);
2235463c4a4SSam Leffler }
2245463c4a4SSam Leffler
2255463c4a4SSam Leffler /*
2265463c4a4SSam Leffler * Dispatch radiotap data for received packet.
2275463c4a4SSam Leffler */
2285463c4a4SSam Leffler void
ieee80211_radiotap_rx(struct ieee80211vap * vap0,struct mbuf * m)2295463c4a4SSam Leffler ieee80211_radiotap_rx(struct ieee80211vap *vap0, struct mbuf *m)
2305463c4a4SSam Leffler {
231e1cfcbcbSSam Leffler struct ieee80211com *ic = vap0->iv_ic;
232e1cfcbcbSSam Leffler struct ieee80211_radiotap_header *rh = ic->ic_rh;
233e1cfcbcbSSam Leffler int len;
234e1cfcbcbSSam Leffler
235e1cfcbcbSSam Leffler KASSERT(rh != NULL, ("no rx radiotap header"));
236e1cfcbcbSSam Leffler len = le16toh(rh->it_len);
237e1cfcbcbSSam Leffler
238e1cfcbcbSSam Leffler if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF)
239e1cfcbcbSSam Leffler bpf_mtap2(vap0->iv_rawbpf, rh, len, m);
240e1cfcbcbSSam Leffler /*
241e1cfcbcbSSam Leffler * Spam monitor mode vaps with unicast frames. Multicast
242e1cfcbcbSSam Leffler * frames are handled by passing through ieee80211_input_all
243e1cfcbcbSSam Leffler * which distributes copies to the monitor mode vaps.
244e1cfcbcbSSam Leffler */
245e1cfcbcbSSam Leffler if (ic->ic_montaps != 0 && (m->m_flags & M_BCAST) == 0)
246e1cfcbcbSSam Leffler spam_vaps(vap0, m, rh, len);
2475463c4a4SSam Leffler }
2485463c4a4SSam Leffler
2495463c4a4SSam Leffler /*
2505463c4a4SSam Leffler * Dispatch radiotap data for a packet received outside the normal
2515463c4a4SSam Leffler * rx processing path; this is used, for example, to handle frames
2525463c4a4SSam Leffler * received with errors that would otherwise be dropped.
2535463c4a4SSam Leffler */
2545463c4a4SSam Leffler void
ieee80211_radiotap_rx_all(struct ieee80211com * ic,struct mbuf * m)2555463c4a4SSam Leffler ieee80211_radiotap_rx_all(struct ieee80211com *ic, struct mbuf *m)
2565463c4a4SSam Leffler {
2575463c4a4SSam Leffler struct ieee80211_radiotap_header *rh = ic->ic_rh;
2585463c4a4SSam Leffler int len = le16toh(rh->it_len);
2595463c4a4SSam Leffler struct ieee80211vap *vap;
2605463c4a4SSam Leffler
2615463c4a4SSam Leffler /* XXX locking? */
2625463c4a4SSam Leffler TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
263e1cfcbcbSSam Leffler if (ieee80211_radiotap_active_vap(vap) &&
264e1cfcbcbSSam Leffler vap->iv_state != IEEE80211_S_INIT)
2655463c4a4SSam Leffler bpf_mtap2(vap->iv_rawbpf, rh, len, m);
2665463c4a4SSam Leffler }
2675463c4a4SSam Leffler }
2685463c4a4SSam Leffler
2695463c4a4SSam Leffler /*
2705463c4a4SSam Leffler * Return the offset of the specified item in the radiotap
2715463c4a4SSam Leffler * header description. If the item is not present or is not
2725463c4a4SSam Leffler * known -1 is returned.
2735463c4a4SSam Leffler */
2745463c4a4SSam Leffler static int
radiotap_offset(struct ieee80211_radiotap_header * rh,int n_vendor_attributes,int item)2758a3860d5SAdrian Chadd radiotap_offset(struct ieee80211_radiotap_header *rh,
2768a3860d5SAdrian Chadd int n_vendor_attributes, int item)
2775463c4a4SSam Leffler {
2785463c4a4SSam Leffler static const struct {
2795463c4a4SSam Leffler size_t align, width;
2805463c4a4SSam Leffler } items[] = {
2815463c4a4SSam Leffler [IEEE80211_RADIOTAP_TSFT] = {
2825463c4a4SSam Leffler .align = sizeof(uint64_t),
2835463c4a4SSam Leffler .width = sizeof(uint64_t),
2845463c4a4SSam Leffler },
2855463c4a4SSam Leffler [IEEE80211_RADIOTAP_FLAGS] = {
2865463c4a4SSam Leffler .align = sizeof(uint8_t),
2875463c4a4SSam Leffler .width = sizeof(uint8_t),
2885463c4a4SSam Leffler },
2895463c4a4SSam Leffler [IEEE80211_RADIOTAP_RATE] = {
2905463c4a4SSam Leffler .align = sizeof(uint8_t),
2915463c4a4SSam Leffler .width = sizeof(uint8_t),
2925463c4a4SSam Leffler },
2935463c4a4SSam Leffler [IEEE80211_RADIOTAP_CHANNEL] = {
2945463c4a4SSam Leffler .align = sizeof(uint16_t),
2955463c4a4SSam Leffler .width = 2*sizeof(uint16_t),
2965463c4a4SSam Leffler },
2975463c4a4SSam Leffler [IEEE80211_RADIOTAP_FHSS] = {
2985463c4a4SSam Leffler .align = sizeof(uint16_t),
2995463c4a4SSam Leffler .width = sizeof(uint16_t),
3005463c4a4SSam Leffler },
3015463c4a4SSam Leffler [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = {
3025463c4a4SSam Leffler .align = sizeof(uint8_t),
3035463c4a4SSam Leffler .width = sizeof(uint8_t),
3045463c4a4SSam Leffler },
3055463c4a4SSam Leffler [IEEE80211_RADIOTAP_DBM_ANTNOISE] = {
3065463c4a4SSam Leffler .align = sizeof(uint8_t),
3075463c4a4SSam Leffler .width = sizeof(uint8_t),
3085463c4a4SSam Leffler },
3095463c4a4SSam Leffler [IEEE80211_RADIOTAP_LOCK_QUALITY] = {
3105463c4a4SSam Leffler .align = sizeof(uint16_t),
3115463c4a4SSam Leffler .width = sizeof(uint16_t),
3125463c4a4SSam Leffler },
3135463c4a4SSam Leffler [IEEE80211_RADIOTAP_TX_ATTENUATION] = {
3145463c4a4SSam Leffler .align = sizeof(uint16_t),
3155463c4a4SSam Leffler .width = sizeof(uint16_t),
3165463c4a4SSam Leffler },
3175463c4a4SSam Leffler [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = {
3185463c4a4SSam Leffler .align = sizeof(uint16_t),
3195463c4a4SSam Leffler .width = sizeof(uint16_t),
3205463c4a4SSam Leffler },
3215463c4a4SSam Leffler [IEEE80211_RADIOTAP_DBM_TX_POWER] = {
3225463c4a4SSam Leffler .align = sizeof(uint8_t),
3235463c4a4SSam Leffler .width = sizeof(uint8_t),
3245463c4a4SSam Leffler },
3255463c4a4SSam Leffler [IEEE80211_RADIOTAP_ANTENNA] = {
3265463c4a4SSam Leffler .align = sizeof(uint8_t),
3275463c4a4SSam Leffler .width = sizeof(uint8_t),
3285463c4a4SSam Leffler },
3295463c4a4SSam Leffler [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = {
3305463c4a4SSam Leffler .align = sizeof(uint8_t),
3315463c4a4SSam Leffler .width = sizeof(uint8_t),
3325463c4a4SSam Leffler },
3335463c4a4SSam Leffler [IEEE80211_RADIOTAP_DB_ANTNOISE] = {
3345463c4a4SSam Leffler .align = sizeof(uint8_t),
3355463c4a4SSam Leffler .width = sizeof(uint8_t),
3365463c4a4SSam Leffler },
3375463c4a4SSam Leffler [IEEE80211_RADIOTAP_XCHANNEL] = {
3385463c4a4SSam Leffler .align = sizeof(uint32_t),
3395463c4a4SSam Leffler .width = 2*sizeof(uint32_t),
3405463c4a4SSam Leffler },
341d8f609a9SAdrian Chadd [IEEE80211_RADIOTAP_MCS] = {
342d8f609a9SAdrian Chadd .align = sizeof(uint8_t),
343d8f609a9SAdrian Chadd .width = 3*sizeof(uint8_t),
344d8f609a9SAdrian Chadd },
3455463c4a4SSam Leffler };
3465463c4a4SSam Leffler uint32_t present = le32toh(rh->it_present);
3475463c4a4SSam Leffler int off, i;
3485463c4a4SSam Leffler
3495463c4a4SSam Leffler off = sizeof(struct ieee80211_radiotap_header);
3508a3860d5SAdrian Chadd off += n_vendor_attributes * (sizeof(uint32_t));
3518a3860d5SAdrian Chadd
3525463c4a4SSam Leffler for (i = 0; i < IEEE80211_RADIOTAP_EXT; i++) {
3535463c4a4SSam Leffler if ((present & (1<<i)) == 0)
3545463c4a4SSam Leffler continue;
3555463c4a4SSam Leffler if (items[i].align == 0) {
3565463c4a4SSam Leffler /* NB: unidentified element, don't guess */
3575463c4a4SSam Leffler printf("%s: unknown item %d\n", __func__, i);
3585463c4a4SSam Leffler return -1;
3595463c4a4SSam Leffler }
3605463c4a4SSam Leffler off = roundup2(off, items[i].align);
3615463c4a4SSam Leffler if (i == item) {
3625463c4a4SSam Leffler if (off + items[i].width > le16toh(rh->it_len)) {
3635463c4a4SSam Leffler /* NB: item does not fit in header data */
3645463c4a4SSam Leffler printf("%s: item %d not in header data, "
3655463c4a4SSam Leffler "off %d width %zu len %d\n", __func__, i,
3665463c4a4SSam Leffler off, items[i].width, le16toh(rh->it_len));
3675463c4a4SSam Leffler return -1;
3685463c4a4SSam Leffler }
3695463c4a4SSam Leffler return off;
3705463c4a4SSam Leffler }
3715463c4a4SSam Leffler off += items[i].width;
3725463c4a4SSam Leffler }
3735463c4a4SSam Leffler return -1;
3745463c4a4SSam Leffler }
375