The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net80211/ieee80211_radiotap.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 }

Cache object: e1197332ccca51e9179b875d84d3b918


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.