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