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