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