1753c7e08SAugustin Cavalier /*-
286021fd4SAugustin Cavalier * SPDX-License-Identifier: BSD-2-Clause
38244a9baSAugustin Cavalier *
4753c7e08SAugustin Cavalier * Copyright (c) 2009 Sam Leffler, Errno Consulting
5753c7e08SAugustin Cavalier * All rights reserved.
6753c7e08SAugustin Cavalier *
7753c7e08SAugustin Cavalier * Redistribution and use in source and binary forms, with or without
8753c7e08SAugustin Cavalier * modification, are permitted provided that the following conditions
9753c7e08SAugustin Cavalier * are met:
10753c7e08SAugustin Cavalier * 1. Redistributions of source code must retain the above copyright
11753c7e08SAugustin Cavalier * notice, this list of conditions and the following disclaimer.
12753c7e08SAugustin Cavalier * 2. Redistributions in binary form must reproduce the above copyright
13753c7e08SAugustin Cavalier * notice, this list of conditions and the following disclaimer in the
14753c7e08SAugustin Cavalier * documentation and/or other materials provided with the distribution.
15753c7e08SAugustin Cavalier *
16753c7e08SAugustin Cavalier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17753c7e08SAugustin Cavalier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18753c7e08SAugustin Cavalier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19753c7e08SAugustin Cavalier * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20753c7e08SAugustin Cavalier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21753c7e08SAugustin Cavalier * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22753c7e08SAugustin Cavalier * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23753c7e08SAugustin Cavalier * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24753c7e08SAugustin Cavalier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25753c7e08SAugustin Cavalier * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26753c7e08SAugustin Cavalier */
27753c7e08SAugustin Cavalier
28753c7e08SAugustin Cavalier #include <sys/cdefs.h>
29753c7e08SAugustin Cavalier /*
30753c7e08SAugustin Cavalier * IEEE 802.11 radiotap support.
31753c7e08SAugustin Cavalier */
32753c7e08SAugustin Cavalier #include "opt_wlan.h"
33753c7e08SAugustin Cavalier
34753c7e08SAugustin Cavalier #include <sys/param.h>
35753c7e08SAugustin Cavalier #include <sys/systm.h>
36753c7e08SAugustin Cavalier #include <sys/mbuf.h>
37753c7e08SAugustin Cavalier #include <sys/malloc.h>
38753c7e08SAugustin Cavalier #include <sys/endian.h>
39753c7e08SAugustin Cavalier #include <sys/kernel.h>
40753c7e08SAugustin Cavalier
41753c7e08SAugustin Cavalier #include <sys/socket.h>
42753c7e08SAugustin Cavalier
43753c7e08SAugustin Cavalier #include <net/bpf.h>
44753c7e08SAugustin Cavalier #include <net/if.h>
45753c7e08SAugustin Cavalier #include <net/if_var.h>
46753c7e08SAugustin Cavalier #include <net/if_media.h>
47753c7e08SAugustin Cavalier #include <net/ethernet.h>
48753c7e08SAugustin Cavalier
49753c7e08SAugustin Cavalier #include <net80211/ieee80211_var.h>
50753c7e08SAugustin Cavalier
51753c7e08SAugustin Cavalier static int radiotap_offset(struct ieee80211_radiotap_header *, int, int);
52753c7e08SAugustin Cavalier
53753c7e08SAugustin Cavalier 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)54753c7e08SAugustin Cavalier ieee80211_radiotap_attach(struct ieee80211com *ic,
55753c7e08SAugustin Cavalier struct ieee80211_radiotap_header *th, int tlen, uint32_t tx_radiotap,
56753c7e08SAugustin Cavalier struct ieee80211_radiotap_header *rh, int rlen, uint32_t rx_radiotap)
57753c7e08SAugustin Cavalier {
58753c7e08SAugustin Cavalier ieee80211_radiotap_attachv(ic, th, tlen, 0, tx_radiotap,
59753c7e08SAugustin Cavalier rh, rlen, 0, rx_radiotap);
60753c7e08SAugustin Cavalier }
61753c7e08SAugustin Cavalier
62753c7e08SAugustin Cavalier 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)63753c7e08SAugustin Cavalier ieee80211_radiotap_attachv(struct ieee80211com *ic,
64753c7e08SAugustin Cavalier struct ieee80211_radiotap_header *th,
65753c7e08SAugustin Cavalier int tlen, int n_tx_v, uint32_t tx_radiotap,
66753c7e08SAugustin Cavalier struct ieee80211_radiotap_header *rh,
67753c7e08SAugustin Cavalier int rlen, int n_rx_v, uint32_t rx_radiotap)
68753c7e08SAugustin Cavalier {
69753c7e08SAugustin Cavalier #define B(_v) (1<<(_v))
70753c7e08SAugustin Cavalier int off;
71753c7e08SAugustin Cavalier
72753c7e08SAugustin Cavalier th->it_len = htole16(roundup2(tlen, sizeof(uint32_t)));
73753c7e08SAugustin Cavalier th->it_present = htole32(tx_radiotap);
74753c7e08SAugustin Cavalier ic->ic_th = th;
75753c7e08SAugustin Cavalier /* calculate offset to channel data */
76753c7e08SAugustin Cavalier off = -1;
77753c7e08SAugustin Cavalier if (tx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
78753c7e08SAugustin Cavalier off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_CHANNEL);
79753c7e08SAugustin Cavalier else if (tx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
80753c7e08SAugustin Cavalier off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_XCHANNEL);
81753c7e08SAugustin Cavalier if (off == -1) {
82753c7e08SAugustin Cavalier ic_printf(ic, "%s: no tx channel, radiotap 0x%x\n", __func__,
83753c7e08SAugustin Cavalier tx_radiotap);
84753c7e08SAugustin Cavalier /* NB: we handle this case but data will have no chan spec */
85753c7e08SAugustin Cavalier } else
86753c7e08SAugustin Cavalier ic->ic_txchan = ((uint8_t *) th) + off;
87753c7e08SAugustin Cavalier
88753c7e08SAugustin Cavalier rh->it_len = htole16(roundup2(rlen, sizeof(uint32_t)));
89753c7e08SAugustin Cavalier rh->it_present = htole32(rx_radiotap);
90753c7e08SAugustin Cavalier ic->ic_rh = rh;
91753c7e08SAugustin Cavalier /* calculate offset to channel data */
92753c7e08SAugustin Cavalier off = -1;
93753c7e08SAugustin Cavalier if (rx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
94753c7e08SAugustin Cavalier off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_CHANNEL);
95753c7e08SAugustin Cavalier else if (rx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
96753c7e08SAugustin Cavalier off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_XCHANNEL);
97753c7e08SAugustin Cavalier if (off == -1) {
98753c7e08SAugustin Cavalier ic_printf(ic, "%s: no rx channel, radiotap 0x%x\n", __func__,
99753c7e08SAugustin Cavalier rx_radiotap);
100753c7e08SAugustin Cavalier /* NB: we handle this case but data will have no chan spec */
101753c7e08SAugustin Cavalier } else
102753c7e08SAugustin Cavalier ic->ic_rxchan = ((uint8_t *) rh) + off;
103753c7e08SAugustin Cavalier #undef B
104753c7e08SAugustin Cavalier }
105753c7e08SAugustin Cavalier
106753c7e08SAugustin Cavalier void
ieee80211_radiotap_detach(struct ieee80211com * ic)107753c7e08SAugustin Cavalier ieee80211_radiotap_detach(struct ieee80211com *ic)
108753c7e08SAugustin Cavalier {
109753c7e08SAugustin Cavalier }
110753c7e08SAugustin Cavalier
111753c7e08SAugustin Cavalier void
ieee80211_radiotap_vattach(struct ieee80211vap * vap)112753c7e08SAugustin Cavalier ieee80211_radiotap_vattach(struct ieee80211vap *vap)
113753c7e08SAugustin Cavalier {
114753c7e08SAugustin Cavalier struct ieee80211com *ic = vap->iv_ic;
115753c7e08SAugustin Cavalier struct ieee80211_radiotap_header *th = ic->ic_th;
116753c7e08SAugustin Cavalier
117753c7e08SAugustin Cavalier if (th != NULL && ic->ic_rh != NULL) {
118753c7e08SAugustin Cavalier /* radiotap DLT for raw 802.11 frames */
119753c7e08SAugustin Cavalier bpfattach2(vap->iv_ifp, DLT_IEEE802_11_RADIO,
120753c7e08SAugustin Cavalier sizeof(struct ieee80211_frame) + le16toh(th->it_len),
121753c7e08SAugustin Cavalier &vap->iv_rawbpf);
122753c7e08SAugustin Cavalier }
123753c7e08SAugustin Cavalier }
124753c7e08SAugustin Cavalier
125753c7e08SAugustin Cavalier void
ieee80211_radiotap_vdetach(struct ieee80211vap * vap)126753c7e08SAugustin Cavalier ieee80211_radiotap_vdetach(struct ieee80211vap *vap)
127753c7e08SAugustin Cavalier {
128*da3ca318SAugustin Cavalier /* NB: bpfdetach is called by ether_ifdetach and claims all taps */
129753c7e08SAugustin Cavalier }
130753c7e08SAugustin Cavalier
131753c7e08SAugustin Cavalier static void
set_channel(void * p,const struct ieee80211_channel * c)132753c7e08SAugustin Cavalier set_channel(void *p, const struct ieee80211_channel *c)
133753c7e08SAugustin Cavalier {
134753c7e08SAugustin Cavalier struct {
135753c7e08SAugustin Cavalier uint16_t freq;
136753c7e08SAugustin Cavalier uint16_t flags;
137753c7e08SAugustin Cavalier } *rc = p;
138753c7e08SAugustin Cavalier
139753c7e08SAugustin Cavalier rc->freq = htole16(c->ic_freq);
140753c7e08SAugustin Cavalier rc->flags = htole16(c->ic_flags);
141753c7e08SAugustin Cavalier }
142753c7e08SAugustin Cavalier
143753c7e08SAugustin Cavalier static void
set_xchannel(void * p,const struct ieee80211_channel * c)144753c7e08SAugustin Cavalier set_xchannel(void *p, const struct ieee80211_channel *c)
145753c7e08SAugustin Cavalier {
146753c7e08SAugustin Cavalier struct {
147753c7e08SAugustin Cavalier uint32_t flags;
148753c7e08SAugustin Cavalier uint16_t freq;
149753c7e08SAugustin Cavalier uint8_t ieee;
150753c7e08SAugustin Cavalier uint8_t maxpow;
151753c7e08SAugustin Cavalier } *rc = p;
152753c7e08SAugustin Cavalier
153753c7e08SAugustin Cavalier rc->flags = htole32(c->ic_flags);
154753c7e08SAugustin Cavalier rc->freq = htole16(c->ic_freq);
155753c7e08SAugustin Cavalier rc->ieee = c->ic_ieee;
156753c7e08SAugustin Cavalier rc->maxpow = c->ic_maxregpower;
157753c7e08SAugustin Cavalier }
158753c7e08SAugustin Cavalier
159753c7e08SAugustin Cavalier /*
160753c7e08SAugustin Cavalier * Update radiotap state on channel change.
161753c7e08SAugustin Cavalier */
162753c7e08SAugustin Cavalier void
ieee80211_radiotap_chan_change(struct ieee80211com * ic)163753c7e08SAugustin Cavalier ieee80211_radiotap_chan_change(struct ieee80211com *ic)
164753c7e08SAugustin Cavalier {
165753c7e08SAugustin Cavalier if (ic->ic_rxchan != NULL) {
166753c7e08SAugustin Cavalier struct ieee80211_radiotap_header *rh = ic->ic_rh;
167753c7e08SAugustin Cavalier
168753c7e08SAugustin Cavalier if (rh->it_present & htole32(1<<IEEE80211_RADIOTAP_XCHANNEL))
169753c7e08SAugustin Cavalier set_xchannel(ic->ic_rxchan, ic->ic_curchan);
170753c7e08SAugustin Cavalier else if (rh->it_present & htole32(1<<IEEE80211_RADIOTAP_CHANNEL))
171753c7e08SAugustin Cavalier set_channel(ic->ic_rxchan, ic->ic_curchan);
172753c7e08SAugustin Cavalier }
173753c7e08SAugustin Cavalier if (ic->ic_txchan != NULL) {
174753c7e08SAugustin Cavalier struct ieee80211_radiotap_header *th = ic->ic_th;
175753c7e08SAugustin Cavalier
176753c7e08SAugustin Cavalier if (th->it_present & htole32(1<<IEEE80211_RADIOTAP_XCHANNEL))
177753c7e08SAugustin Cavalier set_xchannel(ic->ic_txchan, ic->ic_curchan);
178753c7e08SAugustin Cavalier else if (th->it_present & htole32(1<<IEEE80211_RADIOTAP_CHANNEL))
179753c7e08SAugustin Cavalier set_channel(ic->ic_txchan, ic->ic_curchan);
180753c7e08SAugustin Cavalier }
181753c7e08SAugustin Cavalier }
182753c7e08SAugustin Cavalier
183753c7e08SAugustin Cavalier /*
184753c7e08SAugustin Cavalier * Distribute radiotap data (+packet) to all monitor mode
185753c7e08SAugustin Cavalier * vaps with an active tap other than vap0.
186753c7e08SAugustin Cavalier */
187753c7e08SAugustin Cavalier static void
spam_vaps(struct ieee80211vap * vap0,struct mbuf * m,struct ieee80211_radiotap_header * rh,int len)188753c7e08SAugustin Cavalier spam_vaps(struct ieee80211vap *vap0, struct mbuf *m,
189753c7e08SAugustin Cavalier struct ieee80211_radiotap_header *rh, int len)
190753c7e08SAugustin Cavalier {
191753c7e08SAugustin Cavalier struct ieee80211com *ic = vap0->iv_ic;
192753c7e08SAugustin Cavalier struct ieee80211vap *vap;
193753c7e08SAugustin Cavalier
194753c7e08SAugustin Cavalier TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
195753c7e08SAugustin Cavalier if (vap != vap0 &&
196753c7e08SAugustin Cavalier vap->iv_opmode == IEEE80211_M_MONITOR &&
197753c7e08SAugustin Cavalier (vap->iv_flags_ext & IEEE80211_FEXT_BPF) &&
198753c7e08SAugustin Cavalier vap->iv_state != IEEE80211_S_INIT)
199753c7e08SAugustin Cavalier bpf_mtap2(vap->iv_rawbpf, rh, len, m);
200753c7e08SAugustin Cavalier }
201753c7e08SAugustin Cavalier }
202753c7e08SAugustin Cavalier
203753c7e08SAugustin Cavalier /*
204753c7e08SAugustin Cavalier * Dispatch radiotap data for transmitted packet.
205753c7e08SAugustin Cavalier */
206753c7e08SAugustin Cavalier void
ieee80211_radiotap_tx(struct ieee80211vap * vap0,struct mbuf * m)207753c7e08SAugustin Cavalier ieee80211_radiotap_tx(struct ieee80211vap *vap0, struct mbuf *m)
208753c7e08SAugustin Cavalier {
209753c7e08SAugustin Cavalier struct ieee80211com *ic = vap0->iv_ic;
210753c7e08SAugustin Cavalier struct ieee80211_radiotap_header *th = ic->ic_th;
211753c7e08SAugustin Cavalier int len;
212753c7e08SAugustin Cavalier
213753c7e08SAugustin Cavalier KASSERT(th != NULL, ("no tx radiotap header"));
214753c7e08SAugustin Cavalier len = le16toh(th->it_len);
215753c7e08SAugustin Cavalier
216753c7e08SAugustin Cavalier if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF)
217753c7e08SAugustin Cavalier bpf_mtap2(vap0->iv_rawbpf, th, len, m);
218753c7e08SAugustin Cavalier /*
219753c7e08SAugustin Cavalier * Spam monitor mode vaps.
220753c7e08SAugustin Cavalier */
221753c7e08SAugustin Cavalier if (ic->ic_montaps != 0)
222753c7e08SAugustin Cavalier spam_vaps(vap0, m, th, len);
223753c7e08SAugustin Cavalier }
224753c7e08SAugustin Cavalier
225753c7e08SAugustin Cavalier /*
226753c7e08SAugustin Cavalier * Dispatch radiotap data for received packet.
227753c7e08SAugustin Cavalier */
228753c7e08SAugustin Cavalier void
ieee80211_radiotap_rx(struct ieee80211vap * vap0,struct mbuf * m)229753c7e08SAugustin Cavalier ieee80211_radiotap_rx(struct ieee80211vap *vap0, struct mbuf *m)
230753c7e08SAugustin Cavalier {
231753c7e08SAugustin Cavalier struct ieee80211com *ic = vap0->iv_ic;
232753c7e08SAugustin Cavalier struct ieee80211_radiotap_header *rh = ic->ic_rh;
233753c7e08SAugustin Cavalier int len;
234753c7e08SAugustin Cavalier
235753c7e08SAugustin Cavalier KASSERT(rh != NULL, ("no rx radiotap header"));
236753c7e08SAugustin Cavalier len = le16toh(rh->it_len);
237753c7e08SAugustin Cavalier
238753c7e08SAugustin Cavalier if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF)
239753c7e08SAugustin Cavalier bpf_mtap2(vap0->iv_rawbpf, rh, len, m);
240753c7e08SAugustin Cavalier /*
241753c7e08SAugustin Cavalier * Spam monitor mode vaps with unicast frames. Multicast
242753c7e08SAugustin Cavalier * frames are handled by passing through ieee80211_input_all
243753c7e08SAugustin Cavalier * which distributes copies to the monitor mode vaps.
244753c7e08SAugustin Cavalier */
245753c7e08SAugustin Cavalier if (ic->ic_montaps != 0 && (m->m_flags & M_BCAST) == 0)
246753c7e08SAugustin Cavalier spam_vaps(vap0, m, rh, len);
247753c7e08SAugustin Cavalier }
248753c7e08SAugustin Cavalier
249753c7e08SAugustin Cavalier /*
250753c7e08SAugustin Cavalier * Dispatch radiotap data for a packet received outside the normal
251753c7e08SAugustin Cavalier * rx processing path; this is used, for example, to handle frames
252753c7e08SAugustin Cavalier * received with errors that would otherwise be dropped.
253753c7e08SAugustin Cavalier */
254753c7e08SAugustin Cavalier void
ieee80211_radiotap_rx_all(struct ieee80211com * ic,struct mbuf * m)255753c7e08SAugustin Cavalier ieee80211_radiotap_rx_all(struct ieee80211com *ic, struct mbuf *m)
256753c7e08SAugustin Cavalier {
257753c7e08SAugustin Cavalier struct ieee80211_radiotap_header *rh = ic->ic_rh;
258753c7e08SAugustin Cavalier int len = le16toh(rh->it_len);
259753c7e08SAugustin Cavalier struct ieee80211vap *vap;
260753c7e08SAugustin Cavalier
261753c7e08SAugustin Cavalier /* XXX locking? */
262753c7e08SAugustin Cavalier TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
263753c7e08SAugustin Cavalier if (ieee80211_radiotap_active_vap(vap) &&
264753c7e08SAugustin Cavalier vap->iv_state != IEEE80211_S_INIT)
265753c7e08SAugustin Cavalier bpf_mtap2(vap->iv_rawbpf, rh, len, m);
266753c7e08SAugustin Cavalier }
267753c7e08SAugustin Cavalier }
268753c7e08SAugustin Cavalier
269753c7e08SAugustin Cavalier /*
270753c7e08SAugustin Cavalier * Return the offset of the specified item in the radiotap
271753c7e08SAugustin Cavalier * header description. If the item is not present or is not
272753c7e08SAugustin Cavalier * known -1 is returned.
273753c7e08SAugustin Cavalier */
274753c7e08SAugustin Cavalier static int
radiotap_offset(struct ieee80211_radiotap_header * rh,int n_vendor_attributes,int item)275753c7e08SAugustin Cavalier radiotap_offset(struct ieee80211_radiotap_header *rh,
276753c7e08SAugustin Cavalier int n_vendor_attributes, int item)
277753c7e08SAugustin Cavalier {
278753c7e08SAugustin Cavalier static const struct {
279753c7e08SAugustin Cavalier size_t align, width;
280753c7e08SAugustin Cavalier } items[] = {
281753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_TSFT] = {
282753c7e08SAugustin Cavalier .align = sizeof(uint64_t),
283753c7e08SAugustin Cavalier .width = sizeof(uint64_t),
284753c7e08SAugustin Cavalier },
285753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_FLAGS] = {
286753c7e08SAugustin Cavalier .align = sizeof(uint8_t),
287753c7e08SAugustin Cavalier .width = sizeof(uint8_t),
288753c7e08SAugustin Cavalier },
289753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_RATE] = {
290753c7e08SAugustin Cavalier .align = sizeof(uint8_t),
291753c7e08SAugustin Cavalier .width = sizeof(uint8_t),
292753c7e08SAugustin Cavalier },
293753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_CHANNEL] = {
294753c7e08SAugustin Cavalier .align = sizeof(uint16_t),
295753c7e08SAugustin Cavalier .width = 2*sizeof(uint16_t),
296753c7e08SAugustin Cavalier },
297753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_FHSS] = {
298753c7e08SAugustin Cavalier .align = sizeof(uint16_t),
299753c7e08SAugustin Cavalier .width = sizeof(uint16_t),
300753c7e08SAugustin Cavalier },
301753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = {
302753c7e08SAugustin Cavalier .align = sizeof(uint8_t),
303753c7e08SAugustin Cavalier .width = sizeof(uint8_t),
304753c7e08SAugustin Cavalier },
305753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_DBM_ANTNOISE] = {
306753c7e08SAugustin Cavalier .align = sizeof(uint8_t),
307753c7e08SAugustin Cavalier .width = sizeof(uint8_t),
308753c7e08SAugustin Cavalier },
309753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_LOCK_QUALITY] = {
310753c7e08SAugustin Cavalier .align = sizeof(uint16_t),
311753c7e08SAugustin Cavalier .width = sizeof(uint16_t),
312753c7e08SAugustin Cavalier },
313753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_TX_ATTENUATION] = {
314753c7e08SAugustin Cavalier .align = sizeof(uint16_t),
315753c7e08SAugustin Cavalier .width = sizeof(uint16_t),
316753c7e08SAugustin Cavalier },
317753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = {
318753c7e08SAugustin Cavalier .align = sizeof(uint16_t),
319753c7e08SAugustin Cavalier .width = sizeof(uint16_t),
320753c7e08SAugustin Cavalier },
321753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_DBM_TX_POWER] = {
322753c7e08SAugustin Cavalier .align = sizeof(uint8_t),
323753c7e08SAugustin Cavalier .width = sizeof(uint8_t),
324753c7e08SAugustin Cavalier },
325753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_ANTENNA] = {
326753c7e08SAugustin Cavalier .align = sizeof(uint8_t),
327753c7e08SAugustin Cavalier .width = sizeof(uint8_t),
328753c7e08SAugustin Cavalier },
329753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = {
330753c7e08SAugustin Cavalier .align = sizeof(uint8_t),
331753c7e08SAugustin Cavalier .width = sizeof(uint8_t),
332753c7e08SAugustin Cavalier },
333753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_DB_ANTNOISE] = {
334753c7e08SAugustin Cavalier .align = sizeof(uint8_t),
335753c7e08SAugustin Cavalier .width = sizeof(uint8_t),
336753c7e08SAugustin Cavalier },
337753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_XCHANNEL] = {
338753c7e08SAugustin Cavalier .align = sizeof(uint32_t),
339753c7e08SAugustin Cavalier .width = 2*sizeof(uint32_t),
340753c7e08SAugustin Cavalier },
341753c7e08SAugustin Cavalier [IEEE80211_RADIOTAP_MCS] = {
342753c7e08SAugustin Cavalier .align = sizeof(uint8_t),
343753c7e08SAugustin Cavalier .width = 3*sizeof(uint8_t),
344753c7e08SAugustin Cavalier },
345753c7e08SAugustin Cavalier };
346753c7e08SAugustin Cavalier uint32_t present = le32toh(rh->it_present);
347753c7e08SAugustin Cavalier int off, i;
348753c7e08SAugustin Cavalier
349753c7e08SAugustin Cavalier off = sizeof(struct ieee80211_radiotap_header);
350753c7e08SAugustin Cavalier off += n_vendor_attributes * (sizeof(uint32_t));
351753c7e08SAugustin Cavalier
352753c7e08SAugustin Cavalier for (i = 0; i < IEEE80211_RADIOTAP_EXT; i++) {
353753c7e08SAugustin Cavalier if ((present & (1<<i)) == 0)
354753c7e08SAugustin Cavalier continue;
355753c7e08SAugustin Cavalier if (items[i].align == 0) {
356753c7e08SAugustin Cavalier /* NB: unidentified element, don't guess */
357753c7e08SAugustin Cavalier printf("%s: unknown item %d\n", __func__, i);
358753c7e08SAugustin Cavalier return -1;
359753c7e08SAugustin Cavalier }
360753c7e08SAugustin Cavalier off = roundup2(off, items[i].align);
361753c7e08SAugustin Cavalier if (i == item) {
362753c7e08SAugustin Cavalier if (off + items[i].width > le16toh(rh->it_len)) {
363753c7e08SAugustin Cavalier /* NB: item does not fit in header data */
364753c7e08SAugustin Cavalier printf("%s: item %d not in header data, "
365753c7e08SAugustin Cavalier "off %d width %zu len %d\n", __func__, i,
366753c7e08SAugustin Cavalier off, items[i].width, le16toh(rh->it_len));
367753c7e08SAugustin Cavalier return -1;
368753c7e08SAugustin Cavalier }
369753c7e08SAugustin Cavalier return off;
370753c7e08SAugustin Cavalier }
371753c7e08SAugustin Cavalier off += items[i].width;
372753c7e08SAugustin Cavalier }
373753c7e08SAugustin Cavalier return -1;
374753c7e08SAugustin Cavalier }
375