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

Cache object: 14202929eecdfe9a16ea296e340cbfce


[ 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.