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

Cache object: 7fbd1f8f29f00373698b7506ecd66478


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