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