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