1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2009 Sam Leffler, Errno Consulting 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 /* 30 * IEEE 802.11 radiotap support. 31 */ 32 #include "opt_wlan.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/mbuf.h> 37 #include <sys/malloc.h> 38 #include <sys/endian.h> 39 #include <sys/kernel.h> 40 41 #include <sys/socket.h> 42 43 #include <net/bpf.h> 44 #include <net/if.h> 45 #include <net/if_var.h> 46 #include <net/if_media.h> 47 #include <net/ethernet.h> 48 49 #include <net80211/ieee80211_var.h> 50 51 static int radiotap_offset(struct ieee80211_radiotap_header *, int, int); 52 53 void 54 ieee80211_radiotap_attach(struct ieee80211com *ic, 55 struct ieee80211_radiotap_header *th, int tlen, uint32_t tx_radiotap, 56 struct ieee80211_radiotap_header *rh, int rlen, uint32_t rx_radiotap) 57 { 58 ieee80211_radiotap_attachv(ic, th, tlen, 0, tx_radiotap, 59 rh, rlen, 0, rx_radiotap); 60 } 61 62 void 63 ieee80211_radiotap_attachv(struct ieee80211com *ic, 64 struct ieee80211_radiotap_header *th, 65 int tlen, int n_tx_v, uint32_t tx_radiotap, 66 struct ieee80211_radiotap_header *rh, 67 int rlen, int n_rx_v, uint32_t rx_radiotap) 68 { 69 #define B(_v) (1<<(_v)) 70 int off; 71 72 th->it_len = htole16(roundup2(tlen, sizeof(uint32_t))); 73 th->it_present = htole32(tx_radiotap); 74 ic->ic_th = th; 75 /* calculate offset to channel data */ 76 off = -1; 77 if (tx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL)) 78 off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_CHANNEL); 79 else if (tx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL)) 80 off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_XCHANNEL); 81 if (off == -1) { 82 ic_printf(ic, "%s: no tx channel, radiotap 0x%x\n", __func__, 83 tx_radiotap); 84 /* NB: we handle this case but data will have no chan spec */ 85 } else 86 ic->ic_txchan = ((uint8_t *) th) + off; 87 88 rh->it_len = htole16(roundup2(rlen, sizeof(uint32_t))); 89 rh->it_present = htole32(rx_radiotap); 90 ic->ic_rh = rh; 91 /* calculate offset to channel data */ 92 off = -1; 93 if (rx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL)) 94 off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_CHANNEL); 95 else if (rx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL)) 96 off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_XCHANNEL); 97 if (off == -1) { 98 ic_printf(ic, "%s: no rx channel, radiotap 0x%x\n", __func__, 99 rx_radiotap); 100 /* NB: we handle this case but data will have no chan spec */ 101 } else 102 ic->ic_rxchan = ((uint8_t *) rh) + off; 103 #undef B 104 } 105 106 void 107 ieee80211_radiotap_detach(struct ieee80211com *ic) 108 { 109 } 110 111 void 112 ieee80211_radiotap_vattach(struct ieee80211vap *vap) 113 { 114 struct ieee80211com *ic = vap->iv_ic; 115 struct ieee80211_radiotap_header *th = ic->ic_th; 116 117 if (th != NULL && ic->ic_rh != NULL) { 118 /* radiotap DLT for raw 802.11 frames */ 119 bpfattach2(vap->iv_ifp, DLT_IEEE802_11_RADIO, 120 sizeof(struct ieee80211_frame) + le16toh(th->it_len), 121 &vap->iv_rawbpf); 122 } 123 } 124 125 void 126 ieee80211_radiotap_vdetach(struct ieee80211vap *vap) 127 { 128 /* NB: bpfattach is called by ether_ifdetach and claims all taps */ 129 } 130 131 static void 132 set_channel(void *p, const struct ieee80211_channel *c) 133 { 134 struct { 135 uint16_t freq; 136 uint16_t flags; 137 } *rc = p; 138 139 rc->freq = htole16(c->ic_freq); 140 rc->flags = htole16(c->ic_flags); 141 } 142 143 static void 144 set_xchannel(void *p, const struct ieee80211_channel *c) 145 { 146 struct { 147 uint32_t flags; 148 uint16_t freq; 149 uint8_t ieee; 150 uint8_t maxpow; 151 } *rc = p; 152 153 rc->flags = htole32(c->ic_flags); 154 rc->freq = htole16(c->ic_freq); 155 rc->ieee = c->ic_ieee; 156 rc->maxpow = c->ic_maxregpower; 157 } 158 159 /* 160 * Update radiotap state on channel change. 161 */ 162 void 163 ieee80211_radiotap_chan_change(struct ieee80211com *ic) 164 { 165 if (ic->ic_rxchan != NULL) { 166 struct ieee80211_radiotap_header *rh = ic->ic_rh; 167 168 if (rh->it_present & htole32(1<<IEEE80211_RADIOTAP_XCHANNEL)) 169 set_xchannel(ic->ic_rxchan, ic->ic_curchan); 170 else if (rh->it_present & htole32(1<<IEEE80211_RADIOTAP_CHANNEL)) 171 set_channel(ic->ic_rxchan, ic->ic_curchan); 172 } 173 if (ic->ic_txchan != NULL) { 174 struct ieee80211_radiotap_header *th = ic->ic_th; 175 176 if (th->it_present & htole32(1<<IEEE80211_RADIOTAP_XCHANNEL)) 177 set_xchannel(ic->ic_txchan, ic->ic_curchan); 178 else if (th->it_present & htole32(1<<IEEE80211_RADIOTAP_CHANNEL)) 179 set_channel(ic->ic_txchan, ic->ic_curchan); 180 } 181 } 182 183 /* 184 * Distribute radiotap data (+packet) to all monitor mode 185 * vaps with an active tap other than vap0. 186 */ 187 static void 188 spam_vaps(struct ieee80211vap *vap0, struct mbuf *m, 189 struct ieee80211_radiotap_header *rh, int len) 190 { 191 struct ieee80211com *ic = vap0->iv_ic; 192 struct ieee80211vap *vap; 193 194 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 195 if (vap != vap0 && 196 vap->iv_opmode == IEEE80211_M_MONITOR && 197 (vap->iv_flags_ext & IEEE80211_FEXT_BPF) && 198 vap->iv_state != IEEE80211_S_INIT) 199 bpf_mtap2(vap->iv_rawbpf, rh, len, m); 200 } 201 } 202 203 /* 204 * Dispatch radiotap data for transmitted packet. 205 */ 206 void 207 ieee80211_radiotap_tx(struct ieee80211vap *vap0, struct mbuf *m) 208 { 209 struct ieee80211com *ic = vap0->iv_ic; 210 struct ieee80211_radiotap_header *th = ic->ic_th; 211 int len; 212 213 KASSERT(th != NULL, ("no tx radiotap header")); 214 len = le16toh(th->it_len); 215 216 if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF) 217 bpf_mtap2(vap0->iv_rawbpf, th, len, m); 218 /* 219 * Spam monitor mode vaps. 220 */ 221 if (ic->ic_montaps != 0) 222 spam_vaps(vap0, m, th, len); 223 } 224 225 /* 226 * Dispatch radiotap data for received packet. 227 */ 228 void 229 ieee80211_radiotap_rx(struct ieee80211vap *vap0, struct mbuf *m) 230 { 231 struct ieee80211com *ic = vap0->iv_ic; 232 struct ieee80211_radiotap_header *rh = ic->ic_rh; 233 int len; 234 235 KASSERT(rh != NULL, ("no rx radiotap header")); 236 len = le16toh(rh->it_len); 237 238 if (vap0->iv_flags_ext & IEEE80211_FEXT_BPF) 239 bpf_mtap2(vap0->iv_rawbpf, rh, len, m); 240 /* 241 * Spam monitor mode vaps with unicast frames. Multicast 242 * frames are handled by passing through ieee80211_input_all 243 * which distributes copies to the monitor mode vaps. 244 */ 245 if (ic->ic_montaps != 0 && (m->m_flags & M_BCAST) == 0) 246 spam_vaps(vap0, m, rh, len); 247 } 248 249 /* 250 * Dispatch radiotap data for a packet received outside the normal 251 * rx processing path; this is used, for example, to handle frames 252 * received with errors that would otherwise be dropped. 253 */ 254 void 255 ieee80211_radiotap_rx_all(struct ieee80211com *ic, struct mbuf *m) 256 { 257 struct ieee80211_radiotap_header *rh = ic->ic_rh; 258 int len = le16toh(rh->it_len); 259 struct ieee80211vap *vap; 260 261 /* XXX locking? */ 262 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 263 if (ieee80211_radiotap_active_vap(vap) && 264 vap->iv_state != IEEE80211_S_INIT) 265 bpf_mtap2(vap->iv_rawbpf, rh, len, m); 266 } 267 } 268 269 /* 270 * Return the offset of the specified item in the radiotap 271 * header description. If the item is not present or is not 272 * known -1 is returned. 273 */ 274 static int 275 radiotap_offset(struct ieee80211_radiotap_header *rh, 276 int n_vendor_attributes, int item) 277 { 278 static const struct { 279 size_t align, width; 280 } items[] = { 281 [IEEE80211_RADIOTAP_TSFT] = { 282 .align = sizeof(uint64_t), 283 .width = sizeof(uint64_t), 284 }, 285 [IEEE80211_RADIOTAP_FLAGS] = { 286 .align = sizeof(uint8_t), 287 .width = sizeof(uint8_t), 288 }, 289 [IEEE80211_RADIOTAP_RATE] = { 290 .align = sizeof(uint8_t), 291 .width = sizeof(uint8_t), 292 }, 293 [IEEE80211_RADIOTAP_CHANNEL] = { 294 .align = sizeof(uint16_t), 295 .width = 2*sizeof(uint16_t), 296 }, 297 [IEEE80211_RADIOTAP_FHSS] = { 298 .align = sizeof(uint16_t), 299 .width = sizeof(uint16_t), 300 }, 301 [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { 302 .align = sizeof(uint8_t), 303 .width = sizeof(uint8_t), 304 }, 305 [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { 306 .align = sizeof(uint8_t), 307 .width = sizeof(uint8_t), 308 }, 309 [IEEE80211_RADIOTAP_LOCK_QUALITY] = { 310 .align = sizeof(uint16_t), 311 .width = sizeof(uint16_t), 312 }, 313 [IEEE80211_RADIOTAP_TX_ATTENUATION] = { 314 .align = sizeof(uint16_t), 315 .width = sizeof(uint16_t), 316 }, 317 [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { 318 .align = sizeof(uint16_t), 319 .width = sizeof(uint16_t), 320 }, 321 [IEEE80211_RADIOTAP_DBM_TX_POWER] = { 322 .align = sizeof(uint8_t), 323 .width = sizeof(uint8_t), 324 }, 325 [IEEE80211_RADIOTAP_ANTENNA] = { 326 .align = sizeof(uint8_t), 327 .width = sizeof(uint8_t), 328 }, 329 [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { 330 .align = sizeof(uint8_t), 331 .width = sizeof(uint8_t), 332 }, 333 [IEEE80211_RADIOTAP_DB_ANTNOISE] = { 334 .align = sizeof(uint8_t), 335 .width = sizeof(uint8_t), 336 }, 337 [IEEE80211_RADIOTAP_XCHANNEL] = { 338 .align = sizeof(uint32_t), 339 .width = 2*sizeof(uint32_t), 340 }, 341 [IEEE80211_RADIOTAP_MCS] = { 342 .align = sizeof(uint8_t), 343 .width = 3*sizeof(uint8_t), 344 }, 345 }; 346 uint32_t present = le32toh(rh->it_present); 347 int off, i; 348 349 off = sizeof(struct ieee80211_radiotap_header); 350 off += n_vendor_attributes * (sizeof(uint32_t)); 351 352 for (i = 0; i < IEEE80211_RADIOTAP_EXT; i++) { 353 if ((present & (1<<i)) == 0) 354 continue; 355 if (items[i].align == 0) { 356 /* NB: unidentified element, don't guess */ 357 printf("%s: unknown item %d\n", __func__, i); 358 return -1; 359 } 360 off = roundup2(off, items[i].align); 361 if (i == item) { 362 if (off + items[i].width > le16toh(rh->it_len)) { 363 /* NB: item does not fit in header data */ 364 printf("%s: item %d not in header data, " 365 "off %d width %zu len %d\n", __func__, i, 366 off, items[i].width, le16toh(rh->it_len)); 367 return -1; 368 } 369 return off; 370 } 371 off += items[i].width; 372 } 373 return -1; 374 } 375