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

Cache object: 3d93a9ae35bc3358665d61f8b2f44f4d


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