Subject: RFC: 802.11 radio capture header
To: None <tech-net@netbsd.org>
From: David Young <dyoung@pobox.com>
List: tech-net
Date: 08/02/2003 01:19:39
--VbJkn9YxBvnuCH5J
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

For your review, I have attached the header file
(sys/net/if_ieee80211radiotap.h) defining a generic 802.11 radio
capture format. I have also attached patches containing my reference
implementation for wi(4).

If I do not hear any objections to this format on tech-net@ or on
tcpdump-workers@tcpdump.org, I will commit the wi patches next weekend.

The idea behind this capture format is that

* it is generic: it is suitable for an, atw, awi, wi, and future
  drivers (Atheros, Atmel, Realtek)

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

* 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 highly informative: the units and meaning of 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: an existing sniffer
  app such as bsd-airtools provides can be adapted to use this format,
  and then all radios (ADMtek, Atheros) will be supported; 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
dyoung@ojctech.com      Urbana, IL * (217) 278-3933

--VbJkn9YxBvnuCH5J
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="if_ieee80211radiotap.h"

/*	$NetBSD: $	*/

/*-
 * 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.
 */
#ifndef _NET_IF_IEEE80211RADIOTAP_H_
#define _NET_IF_IEEE80211RADIOTAP_H_

/* 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.
 */

/* 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 /* _NET_IF_IEEE80211RADIOTAP_H_ */

--VbJkn9YxBvnuCH5J
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=cap-diffs

Index: wi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wi.c,v
retrieving revision 1.132
diff -u -r1.132 wi.c
--- wi.c	2003/07/06 20:01:17	1.132
+++ wi.c	2003/08/02 06:02:40
@@ -93,6 +93,7 @@
 #include <net/if_media.h>
 #include <net/if_ether.h>
 #include <net/if_ieee80211.h>
+#include <net/if_ieee80211radiotap.h>
 
 #if NBPFILTER > 0
 #include <net/bpf.h>
@@ -378,6 +380,11 @@
 	ic->ic_media.ifm_status = wi_media_status;
 	ic->ic_media.ifm_change = wi_media_change;
 
+#if NBPFILTER > 0
+	bpfattach2(ifp, DLT_IEEE802_11_RADIO,
+	    sizeof(struct ieee80211_frame) + 64, &sc->sc_drvbpf);
+#endif
+
 	/* Attach is successful. */
 	sc->sc_attached = 1;
 
@@ -842,22 +858,33 @@
 			}
 			frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT);
 		}
 		m_copydata(m0, 0, sizeof(struct ieee80211_frame),
 		    (caddr_t)&frmhdr.wi_whdr);
 		m_adj(m0, sizeof(struct ieee80211_frame));
 		frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len);
 #if NBPFILTER > 0
 		if (sc->sc_drvbpf) {
 			struct mbuf mb;
+			union {
+				struct wi_tx_radiotap_header	wttap;
+				u_int8_t			pad[64];
+			} u;
+
+			/* XXX endianness */
+			memset(&u, 0, sizeof(u));
+			u.wttap.wt_ihdr.it_len = sizeof(u);
+			u.wttap.wt_rate = frmhdr.wi_tx_rate / 5;
+			u.wttap.wt_chan = ic->ic_bss.ni_chan;
+			u.wttap.wt_ihdr.it_present = WI_TX_RADIOTAP_PRESENT;
+			if (frmhdr.wi_tx_rate == 0)
+				u.wttap.wt_ihdr.it_present &=
+				    ~(1 << IEEE80211_RADIOTAP_RATE);
+			/* TBD u.wttap.wt_flags */
 
 			M_COPY_PKTHDR(&mb, m0);
-			mb.m_data = (caddr_t)&frmhdr;
-			mb.m_len = sizeof(frmhdr);
+			mb.m_data = (caddr_t)&u;
+			mb.m_len = u.wttap.wt_ihdr.it_len;
 			mb.m_next = m0;
 			mb.m_pkthdr.len += mb.m_len;
 			bpf_mtap(sc->sc_drvbpf, &mb);
 		}
 #endif
 		if (IFF_DUMPPKTS(ifp))
 			wi_dump_pkt(&frmhdr, ni, -1);
 		fid = sc->sc_txd[cur].d_fid;
@@ -1259,12 +1326,27 @@
 #if NBPFILTER > 0
 	if (sc->sc_drvbpf) {
 		struct mbuf mb;
+		union {
+			struct wi_rx_radiotap_header	wrtap;
+			u_int8_t			pad[64];
+		} u;
+
+		/* XXX endianness */
+		memset(&u, 0, sizeof(u));
+		u.wrtap.wr_ihdr.it_len = sizeof(u);
+		u.wrtap.wr_ihdr.it_present = WI_RX_RADIOTAP_PRESENT0;
+		u.wrtap.wr_present1 = WI_RX_RADIOTAP_PRESENT1;
+		u.wrtap.wr_rate = frmhdr.wi_rx_rate / 5;
+		u.wrtap.wr_chan = ic->ic_bss.ni_chan;
+		u.wrtap.wr_antsignal = WI_RSSI_TO_DBM(sc, frmhdr.wi_rx_signal);
+		u.wrtap.wr_antnoise = WI_RSSI_TO_DBM(sc, frmhdr.wi_rx_silence);
+		/* TBD u.wrtap.wr_flags */
+		u.wrtap.wr_time =
+		    (frmhdr.wi_rx_tstamp1 << 16) | frmhdr.wi_rx_tstamp0;
 
 		M_COPY_PKTHDR(&mb, m);
-		mb.m_data = (caddr_t)&frmhdr;
-		frmhdr.wi_rx_signal = WI_RSSI_TO_DBM(sc, frmhdr.wi_rx_signal);
-		frmhdr.wi_rx_silence = WI_RSSI_TO_DBM(sc, frmhdr.wi_rx_silence);
-		mb.m_len = (char *)&frmhdr.wi_whdr - (char *)&frmhdr;
+		mb.m_data = (caddr_t)&u;
+		mb.m_len = u.wrtap.wr_ihdr.it_len;
 		mb.m_next = m;
 		mb.m_pkthdr.len += mb.m_len;
 		bpf_mtap(sc->sc_drvbpf, &mb);
Index: wireg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wireg.h,v
retrieving revision 1.45
diff -u -r1.45 wireg.h
--- wireg.h	2003/05/13 08:35:58	1.45
+++ wireg.h	2003/08/02 06:02:41
@@ -578,3 +584,39 @@
 
 /* Limit on the number of AIDs handled in the PRISM2-based Host AP mode. */
 #define WI_MAX_AID		256
+
+/* Radio capture format for Prism. */
+
+#define WI_RX_RADIOTAP_PRESENT0	((1 << IEEE80211_RADIOTAP_FLAGS) | \
+				 (1 << IEEE80211_RADIOTAP_RATE) | \
+				 (1 << IEEE80211_RADIOTAP_CHANNEL) | \
+				 (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | \
+				 (1 << IEEE80211_RADIOTAP_DB_ANTNOISE) | \
+				 (1 << IEEE80211_RADIOTAP_EXT))
+
+#define WI_RX_RADIOTAP_PRESENT1	(1 << (IEEE80211_RADIOTAP_TIME - 32))
+
+struct wi_rx_radiotap_header {
+	struct ieee80211_radiotap_header	wr_ihdr;
+	u_int32_t				wr_present1;
+	u_int16_t				wr_flags;
+	u_int16_t				wr_rate;
+	u_int16_t				wr_chan;
+	u_int16_t				wr_antsignal;
+	u_int16_t				wr_antnoise;
+	u_int32_t				wr_time;
+};
+
+#define WI_TX_RADIOTAP_PRESENT	((1 << IEEE80211_RADIOTAP_FLAGS) | \
+				 (1 << IEEE80211_RADIOTAP_RATE) | \
+				 (1 << IEEE80211_RADIOTAP_CHANNEL))
+
+struct wi_tx_radiotap_header {
+	struct ieee80211_radiotap_header	wt_ihdr;
+	u_int16_t				wt_flags;
+	u_int16_t				wt_rate;
+	u_int16_t				wt_chan;
+};
+
+#undef BIT
+

--VbJkn9YxBvnuCH5J--