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