I have attached the header file (ieee802_11_radio.h) defining an improved
(IMHO) generic 802.11 radio capture format. I have also attached patches
containing my implementation for tcpdump. Please consider this format
for adoption by tcpdump.

The idea behind this capture format is that

* it is generic: it suits radios parts by Cisco/Aironet, ADMtek,
  AMD 79c930, Prism 2.x, TI, Atheros, Atmel, and Realtek.

* it is extensible: if new hardware provides useful new radio
  information, you can add them to this capture format without breaking
  existing parsers for the capture format.

* it conserves bandwidth: the capture header length can vary
  with the content of the header; drivers can take advantage when
  libpcap finally groks variable-length headers. 

* it is more informative than previous radio headers: the units and
  meaning for each field are rigidly specified; fields can be left out
  which are meaningless in context (e.g., Rx signal strength can be left
  out of transmitted frames)

* it supports advanced wireless applications: existing sniffer
  apps (dsniffer, kismet) can be adapted to use this format, for universal
  radio support; wireless routers algorithms can monitor a link and assign
  costs based on S/N ratio or on peers' data rate; stations can share
  S/N information with each other to support improved rate adaptation;
  and so on.

Here is an example capture:

> sudo ./tcpdump -ne -y ieee802_11_radio -s 256 -i wi0
Password:
tcpdump: data link type ieee802_11_radio
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wi0, link-type 127, capture size 256 bytes
01:17:58.503262 2.0 Mb/s -64dB signal -73dB noise 2762646109us mactime 
BSSID:00:05:5d:da:ac:a8 DA:00:05:5d:da:ac:a8 SA:00:30:65:15:46:38 Authentication (Open 
System)-1: Succesful
01:17:58.503292 2.0 Mb/s BSSID:00:05:5d:da:ac:a8 DA:00:30:65:15:46:38 
SA:00:05:5d:da:ac:a8 Authentication (Open System)-2: 
01:17:58.505034 2.0 Mb/s -64dB signal -73dB noise 2876613213us mactime 
BSSID:00:05:5d:da:ac:a8 DA:00:05:5d:da:ac:a8 SA:00:30:65:15:46:38 Assoc Request (ojc) 
[1.0 2.0 5.5 11.0 Mbit]
01:17:58.505051 2.0 Mb/s BSSID:00:05:5d:da:ac:a8 DA:00:30:65:15:46:38 
SA:00:05:5d:da:ac:a8 Assoc Response AID(1) :: Succesful
01:17:59.033918 2.0 Mb/s -64dB signal -73dB noise 3153437285us mactime 
BSSID:00:05:5d:da:ac:a8 SA:00:30:65:15:46:38 DA:00:05:5d:da:ac:a8 LLC, dsap 0xaa, ssap 
0xaa, cmd 0x03, IP 192.168.1.109 > 192.168.1.1: icmp 64: echo request seq 2660
01:17:59.034024 2.0 Mb/s DA:00:30:65:15:46:38 BSSID:00:05:5d:da:ac:a8 
SA:00:05:5d:da:ac:a8 LLC, dsap 0xaa, ssap 0xaa, cmd 0x03, IP 192.168.1.1 > 
192.168.1.109: icmp 64: echo reply seq 2660
01:17:59.627226 2.0 Mb/s -64dB signal -73dB noise 3309281902us mactime 
BSSID:00:05:5d:da:ac:a8 SA:00:30:65:15:46:38 DA:ff:ff:ff:ff:ff:ff LLC, dsap 0xaa, ssap 
0xaa, cmd 0x03, IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 
00:30:65:15:46:38, length: 303
01:17:59.630303 2.0 Mb/s DA:00:30:65:15:46:38 BSSID:00:05:5d:da:ac:a8 
SA:00:05:5d:da:ac:a8 LLC, dsap 0xaa, ssap 0xaa, cmd 0x03, IP 192.168.1.1.67 > 
192.168.1.109.68: BOOTP/DHCP, Reply, length: 300
01:18:00.034279 2.0 Mb/s -64dB signal -73dB noise 4287079028us mactime 
BSSID:00:05:5d:da:ac:a8 SA:00:30:65:15:46:38 DA:00:05:5d:da:ac:a8 LLC, dsap 0xaa, ssap 
0xaa, cmd 0x03, IP 192.168.1.109 > 192.168.1.1: icmp 64: echo request seq 2661
01:18:00.034373 2.0 Mb/s DA:00:30:65:15:46:38 BSSID:00:05:5d:da:ac:a8 
SA:00:05:5d:da:ac:a8 LLC, dsap 0xaa, ssap 0xaa, cmd 0x03, IP 192.168.1.1 > 
192.168.1.109: icmp 64: echo reply seq 2661

Dave

-- 
David Young             OJC Technologies
[EMAIL PROTECTED]      Urbana, IL * (217) 278-3933
? ieee802_11_radio.h
Index: extract.h
===================================================================
RCS file: /tcpdump/master/tcpdump/extract.h,v
retrieving revision 1.19
diff -u -r1.19 extract.h
--- extract.h   11 Dec 2002 07:13:51 -0000      1.19
+++ extract.h   2 Aug 2003 21:46:00 -0000
@@ -96,3 +96,12 @@
                     (u_int32_t)*((const u_int8_t *)(p) + 2) << 16 | \
                     (u_int32_t)*((const u_int8_t *)(p) + 1) << 8 | \
                     (u_int32_t)*((const u_int8_t *)(p) + 0)))
+#define EXTRACT_LE_64BITS(p) \
+       ((u_int64_t)((u_int64_t)*((const u_int8_t *)(p) + 7) << 56 | \
+                    (u_int64_t)*((const u_int8_t *)(p) + 6) << 48 | \
+                    (u_int64_t)*((const u_int8_t *)(p) + 5) << 40 | \
+                    (u_int64_t)*((const u_int8_t *)(p) + 4) << 32 | \
+                    (u_int64_t)*((const u_int8_t *)(p) + 3) << 24 | \
+                    (u_int64_t)*((const u_int8_t *)(p) + 2) << 16 | \
+                    (u_int64_t)*((const u_int8_t *)(p) + 1) << 8 | \
+                    (u_int64_t)*((const u_int8_t *)(p) + 0)))
Index: print-802_11.c
===================================================================
RCS file: /tcpdump/master/tcpdump/print-802_11.c,v
retrieving revision 1.22
diff -u -r1.22 print-802_11.c
--- print-802_11.c      22 Jul 2003 17:36:57 -0000      1.22
+++ print-802_11.c      2 Aug 2003 21:46:00 -0000
@@ -42,6 +42,11 @@
 #include "extract.h"
 
 #include "ieee802_11.h"
+#ifdef HAVE_IEEE80211RADIOTAP_H
+#include <net/if_ieee80211radiotap.h>
+#else
+#include "ieee802_11_radio.h"
+#endif
 
 #define PRINT_RATES(p) \
 do { \
@@ -927,6 +932,155 @@
 static u_int
 ieee802_11_radio_print(const u_char *p, u_int length, u_int caplen)
 {
+#define BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x)))
+#define BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x)))
+#define BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x)))
+#define BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x)))
+#define BITNO_2(x) (((x) & 2) ? 1 : 0)
+#define BIT(n) (1 << n)
+
+       union {
+               int16_t         i16;
+               u_int16_t       u16;
+               u_int32_t       u32;
+               u_int64_t       u64;
+       } u;
+       struct ieee80211_radiotap_header *hdr;
+       u_int32_t present, next_present;
+       u_int32_t *presentp, *last_presentp;
+       enum ieee80211_radiotap_type bit;
+       int bit0;
+       const u_char *iter;
+
+       if (caplen < sizeof(*hdr)) {
+               printf("[|802.11]");
+               return caplen;
+       }
+
+       hdr = (struct ieee80211_radiotap_header *)p;
+
+       if (caplen < hdr->it_len) {
+               printf("[|802.11]");
+               return caplen;
+       }
+
+       for (last_presentp = &hdr->it_present;
+            (*last_presentp & BIT(IEEE80211_RADIOTAP_EXT)) != 0 &&
+            (u_char*)(last_presentp + 1) <= p + hdr->it_len;
+            last_presentp++);
+
+       /* are there more bitmap extensions than bytes in header? */
+       if ((*last_presentp & BIT(IEEE80211_RADIOTAP_EXT)) != 0) {
+               printf("[|802.11]");
+               return caplen;
+       }
+
+       iter = (u_char*)(last_presentp + 1);
+
+       for (bit0 = 0, presentp = &hdr->it_present; presentp <= last_presentp;
+            presentp++, bit0 += 32) {
+               for (present = *presentp; present; present = next_present) {
+                       /* clear the least significant bit that is set */
+                       next_present = present & (present - 1);
+
+                       /* extract the least significant bit that is set */
+                       bit = bit0 + BITNO_32(present ^ next_present);
+
+                       switch (bit) {
+                       case IEEE80211_RADIOTAP_RATE:
+                       case IEEE80211_RADIOTAP_CHANNEL:
+                       case IEEE80211_RADIOTAP_FHSS:
+                       case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
+                       case IEEE80211_RADIOTAP_DB_ANTNOISE:
+                       case IEEE80211_RADIOTAP_LOCK_QUALITY:
+                       case IEEE80211_RADIOTAP_TX_ATTENUATION:
+                       case IEEE80211_RADIOTAP_DB_TX_ATTENUATION:
+                       case IEEE80211_RADIOTAP_DBM_TX_POWER:
+                       case IEEE80211_RADIOTAP_FLAGS:
+                       case IEEE80211_RADIOTAP_ANTENNA:
+                               u.u16 = EXTRACT_LE_16BITS(iter);
+                               iter += sizeof(u.u16);
+                               break;
+                       case IEEE80211_RADIOTAP_TIME:
+                               u.u32 = EXTRACT_LE_32BITS(iter);
+                               iter += sizeof(u.u32);
+                               break;
+                       case IEEE80211_RADIOTAP_TSFT:
+                               u.u64 = EXTRACT_LE_64BITS(iter);
+                               iter += sizeof(u.u64);
+                               break;
+                       default:
+                               continue;
+                       }
+
+                       switch (bit) {
+                       case IEEE80211_RADIOTAP_CHANNEL:
+                               printf("ch %d ", u.u16);
+                               break;
+                       case IEEE80211_RADIOTAP_FHSS:
+                               printf("fhset %d fhpat %d ", u.u16 & 0xff,
+                                      (u.u16 >> 8) & 0xff);
+                               break;
+                       case IEEE80211_RADIOTAP_RATE:
+                               printf("%d.%d Mb/s ", u.u16 / 2,
+                                      (u.u16 * 5) % 10);
+                               break;
+                       case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
+                               printf("%ddB signal ", u.i16);
+                               break;
+                       case IEEE80211_RADIOTAP_DB_ANTNOISE:
+                               printf("%ddB noise ", u.i16);
+                               break;
+                       case IEEE80211_RADIOTAP_LOCK_QUALITY:
+                               printf("%u sq ", u.u16);
+                               break;
+                       case IEEE80211_RADIOTAP_TX_ATTENUATION:
+                               printf("%d tx power ", -(int)u.u16);
+                               break;
+                       case IEEE80211_RADIOTAP_DB_TX_ATTENUATION:
+                               printf("%ddB tx power ", -(int)u.u16);
+                               break;
+                       case IEEE80211_RADIOTAP_DBM_TX_POWER:
+                               printf("%ddBm tx power ", u.u16);
+                               break;
+                       case IEEE80211_RADIOTAP_FLAGS:
+                               if (u.u16 & IEEE80211_RADIOTAP_F_CFP)
+                                       printf("cfp ");
+                               if (u.u16 & IEEE80211_RADIOTAP_F_SHORTPRE)
+                                       printf("short preamble ");
+                               if (u.u16 & IEEE80211_RADIOTAP_F_WEP)
+                                       printf("wep ");
+                               if (u.u16 & IEEE80211_RADIOTAP_F_FRAG)
+                                       printf("fragmented ");
+                               break;
+                       case IEEE80211_RADIOTAP_ANTENNA:
+                               printf("antenna %d ", u.u16);
+                               break;
+                       case IEEE80211_RADIOTAP_TIME:
+                               printf("%uus mactime ", u.u32);
+                               break;
+                       case IEEE80211_RADIOTAP_TSFT:
+                               printf("%" PRIu64 "us tsft ", u.u64);
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       return hdr->it_len + ieee802_11_print(p + hdr->it_len,
+           length - hdr->it_len, caplen - hdr->it_len);
+#undef BITNO_32
+#undef BITNO_16
+#undef BITNO_8
+#undef BITNO_4
+#undef BITNO_2
+#undef BIT
+}
+
+static u_int
+ieee802_11_linux_radio_print(const u_char *p, u_int length, u_int caplen)
+{
        u_int32_t caphdr_len;
 
        caphdr_len = EXTRACT_32BITS(p + 4);
@@ -977,7 +1131,7 @@
        }
 
        if (EXTRACT_32BITS(p) == WLANCAP_MAGIC_COOKIE_V1)
-               return ieee802_11_radio_print(p, length, caplen);
+               return ieee802_11_linux_radio_print(p, length, caplen);
 
        if (caplen < PRISM_HDR_LEN) {
                printf("[|802.11]");
/* $Header: $ */

/*-
 * Copyright (c) 2003, 2004 David Young.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of David Young may not be used to endorse or promote
 *    products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DAVID
 * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 */

/* A generic radio capture format is desirable. There is one for
 * Linux, but it is neither rigidly defined (there were not even
 * units given for some fields) nor easily extensible.
 *
 * I suggest the following extensible radio capture format. It is
 * based on a bitmap indicating which fields are present.
 *
 * I am trying to describe precisely what the application programmer
 * should expect in the following, and for that reason I tell the
 * units and origin of each measurement (where it applies), or else I
 * use sufficiently weaselly language ("is a monotonically nondecreasing
 * function of...") that I cannot set false expectations for lawyerly
 * readers.
 */

#ifndef _IEEE802_11_RADIO_H_
#define _IEEE802_11_RADIO_H_

/* The radio capture header precedes the 802.11 header. */
struct ieee80211_radiotap_header {
        u_int8_t        it_version;     /* Version 0. Only increases
                                         * for drastic changes,
                                         * introduction of compatible
                                         * new LTVs does not count.
                                         */
        u_int8_t        it_pad;
        u_int16_t       it_len;         /* length of the whole
                                         * header in bytes, including
                                         * it_version, it_pad,
                                         * it_len, and LTVs.
                                         */
        u_int32_t       it_present;     /* A bitmap telling which
                                         * fields are present. Set bit 31
                                         * (0x80000000) to extend the
                                         * bitmap by another 32 bits.
                                         * Additional extensions are made
                                         * by setting bit 31.
                                         */
};

/* Name                                 Data type       Units
 * ----                                 ---------       -----
 *
 * IEEE80211_RADIOTAP_CHANNEL           u_int16_t       MHz
 *
 *      Tx/Rx channel number (for DSSS/OFDM/PBCC PHY)
 *
 * IEEE80211_RADIOTAP_FHSS              u_int16_t       see below
 *
 *      For frequency-hopping radios, the hop set (first byte)
 *      and pattern (second byte).
 *
 * IEEE80211_RADIOTAP_RATE              u_int16_t       100kb/s
 *
 *      Tx/Rx data rate
 *
 * IEEE80211_RADIOTAP_DB_ANTSIGNAL      int16_t         decibel (dB)
 *              
 *      RF signal power at the antenna, measured from a fixed,
 *      arbitrary reference point.
 *
 * IEEE80211_RADIOTAP_DB_ANTNOISE       int16_t         decibel (dB)
 *
 *      RF noise power at the antenna in decibels from an arbitrary,
 *      fixed reference point.
 *
 * IEEE80211_RADIOTAP_BARKER_CODE_LOCK  u_int16_t       unitless
 *
 *      Quality of Barker code lock. Unitless. Monotonically
 *      nondecreasing with "better" lock strength. Called "Signal
 *      Quality" in datasheets.  (Is there a standard way to measure
 *      this?)
 *
 * IEEE80211_RADIOTAP_TX_ATTENUATION    u_int16_t       unitless
 *
 *      Transmit power expressed as unitless distance from max
 *      power set at factory calibration.  0 is max power.
 *      Monotonically nondecreasing with lower power levels.
 *
 * IEEE80211_RADIOTAP_DB_TX_ATTENUATION u_int16_t       decibels (dB)
 *
 *      Transmit power expressed as decibel distance from max power
 *      set at factory calibration.  0 is max power.  Monotonically
 *      nondecreasing with lower power levels.
 *
 * IEEE80211_RADIOTAP_DBM_TX_POWER      u_int16_t       decibels from
 *                                                      milliwatt (dBm)
 *
 *      Transmit power expressed as dBm (decibels from a 1 milliwatt
 *      reference). This is the absolute power level measured at
 *      the antenna port.
 *
 * IEEE80211_RADIOTAP_TSFT              u_int64_t       microseconds
 *
 *      Value in microseconds of the MAC's 64-bit 802.11 Time
 *      Synchronization Function timer when the first bit of the
 *      MPDU arrived at the MAC. For received frames, only.
 *      Little-endian byte order.
 *
 * IEEE80211_RADIOTAP_FLAGS             u_int16_t       bitmap
 *
 *      Properties of transmitted and received frames. See flags
 *      defined below.
 *
 * IEEE80211_RADIOTAP_TIME              u_int32_t       microseconds
 *
 *      For radios that provide it: packet arrival time in
 *      microseconds. Prism hardware will provide this, but it is
 *      not known whether it marks the first or the last bit of
 *      the frame. Nor is it known where that bit has arrived
 *      (antenna, modem, MAC?) when the time is measured.
 *
 * IEEE80211_RADIOTAP_ANTENNA           u_int16_t       antenna index
 *
 *      Unitless indication of the Rx/Tx antenna for this packet.
 *      The first antenna is antenna 0.
 */
enum ieee80211_radiotap_type {
        IEEE80211_RADIOTAP_PAD = 0,
        IEEE80211_RADIOTAP_FLAGS = 1,
        IEEE80211_RADIOTAP_RATE = 2,
        IEEE80211_RADIOTAP_CHANNEL = 3,
        IEEE80211_RADIOTAP_FHSS = 4,
        IEEE80211_RADIOTAP_DB_ANTSIGNAL = 5,
        IEEE80211_RADIOTAP_DB_ANTNOISE = 6,
        IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
        IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
        IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
        IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
        IEEE80211_RADIOTAP_ANTENNA = 11,
        IEEE80211_RADIOTAP_TSFT = 12,
        IEEE80211_RADIOTAP_EXT = 31,
        IEEE80211_RADIOTAP_TIME = 32
};

/* For IEEE80211_RADIOTAP_FLAGS */
#define IEEE80211_RADIOTAP_F_CFP        0x0001  /* sent/received
                                                 * during CFP
                                                 */
#define IEEE80211_RADIOTAP_F_SHORTPRE   0x0002  /* sent/received
                                                 * with short
                                                 * preamble
                                                 */
#define IEEE80211_RADIOTAP_F_WEP        0x0004  /* sent/received
                                                 * with WEP encryption
                                                 */
#define IEEE80211_RADIOTAP_F_FRAG       0x0008  /* sent/received
                                                 * with fragmentation
                                                 */

#endif /* _IEEE802_11_RADIO_H_ */

Reply via email to