Add the radiotap capture format to tcpdump.  radiotap is an extensible
capture format for 802.11 radio statistics such as signal strength,
rx/tx bit rate, and rx/tx channel.
diff --git a/Makefile.in b/Makefile.in
index 3acae8c..443f921 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -17,7 +17,7 @@
 #  WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 #  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 #
-# @(#) $Header: /tcpdump/master/tcpdump/Makefile.in,v 1.289 2004-07-27 17:04:20 hannes Exp $ (LBL)
+# @(#) $Header: /tcpdump/master/tcpdump/Makefile.in,v 1.290 2004-09-23 21:57:24 dyoung Exp $ (LBL)
 
 #
 # Various configurable paths (remember to edit Makefile.in, not Makefile)
@@ -65,7 +65,7 @@
 	@rm -f $@
 	$(CC) $(CFLAGS) -c $(srcdir)/$*.c
 
-CSRC =	addrtoname.c gmpls.c oui.c gmt2local.c ipproto.c l2vpn.c machdep.c parsenfsfh.c \
+CSRC =	addrtoname.c cpack.c gmpls.c oui.c gmt2local.c ipproto.c l2vpn.c machdep.c parsenfsfh.c \
 	print-802_11.c print-ap1394.c print-ah.c print-arcnet.c \
 	print-aodv.c print-arp.c print-ascii.c print-atalk.c print-atm.c \
 	print-beep.c print-bfd.c print-bgp.c print-bootp.c print-cdp.c \
@@ -97,7 +97,7 @@
 # We would like to say "OBJ = $(SRC:.c=.o)" but Ultrix's make cannot
 # hack the extra indirection
 OBJ =	$(CSRC:.c=.o) $(GENSRC:.c=.o) $(LOCALSRC:.c=.o) $(LIBOBJS)
-HDR =   addrtoname.h appletalk.h bootp.h decnet.h \
+HDR =   addrtoname.h appletalk.h bootp.h cpack.h decnet.h \
 	ethertype.h extract.h fddi.h gmt2local.h igrp.h interface.h \
 	ipx.h llc.h machdep.h mib.h nfsfh.h nfsv2.h ntp.h ospf.h \
 	setsignal.h \
diff --git a/print-802_11.c b/print-802_11.c
index d6050e4..795168e 100644
--- a/print-802_11.c
+++ b/print-802_11.c
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-802_11.c,v 1.29 2004-03-17 23:24:35 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/tcpdump/print-802_11.c,v 1.30 2004-09-23 21:57:25 dyoung Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -41,15 +41,20 @@
 
 #include "extract.h"
 
-#include "ieee802_11.h"
+#include "cpack.h"
 
+#include "ieee802_11.h"
+#include "ieee802_11_radio.h"
+
+#define PRINT_RATE(_sep, _r, _suf) \
+	printf("%s%2.1f%s", _sep, (.5 * ((_r) & 0x7f)), _suf)
 #define PRINT_RATES(p) \
 do { \
 	int z; \
 	const char *sep = " ["; \
 	for (z = 0; z < p.rates.length ; z++) { \
-		printf("%s%2.1f", sep, (.5 * (p.rates.rate[z] & 0x7f))); \
-		if (p.rates.rate[z] & 0x80) printf("*"); \
+		PRINT_RATE(sep, p.rates.rate[z], \
+			(p.rates.rate[z] & 0x80 ? "*" : "")); \
 		sep = " "; \
 	} \
 	if (p.rates.length != 0) \
@@ -919,9 +924,201 @@
 	return ieee802_11_print(p, h->len, h->caplen);
 }
 
+static int
+print_radiotap_field(struct cpack_state *s, u_int32_t bit)
+{
+	union {
+		int8_t		i8;
+		u_int8_t	u8;
+		int16_t		i16;
+		u_int16_t	u16;
+		u_int32_t	u32;
+		u_int64_t	u64;
+	} u, u2;
+	int rc;
+
+	switch (bit) {
+	case IEEE80211_RADIOTAP_FLAGS:
+	case IEEE80211_RADIOTAP_RATE:
+	case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
+	case IEEE80211_RADIOTAP_DB_ANTNOISE:
+	case IEEE80211_RADIOTAP_ANTENNA:
+		rc = cpack_uint8(s, &u.u8);
+		break;
+	case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
+	case IEEE80211_RADIOTAP_DBM_ANTNOISE:
+		rc = cpack_int8(s, &u.i8);
+		break;
+	case IEEE80211_RADIOTAP_CHANNEL:
+		rc = cpack_uint16(s, &u.u16);
+		if (rc != 0)
+			break;
+		rc = cpack_uint16(s, &u2.u16);
+		break;
+	case IEEE80211_RADIOTAP_FHSS:
+	case IEEE80211_RADIOTAP_LOCK_QUALITY:
+	case IEEE80211_RADIOTAP_TX_ATTENUATION:
+		rc = cpack_uint16(s, &u.u16);
+		break;
+	case IEEE80211_RADIOTAP_DB_TX_ATTENUATION:
+		rc = cpack_uint8(s, &u.u8);
+		break;
+	case IEEE80211_RADIOTAP_DBM_TX_POWER:
+		rc = cpack_uint8(s, &u.i8);
+		break;
+	case IEEE80211_RADIOTAP_TSFT:
+		rc = cpack_uint64(s, &u.u64);
+		break;
+	default:
+		/* this bit indicates a field whose
+		 * size we do not know, so we cannot
+		 * proceed.
+		 */
+		printf("[0x%08x] ", bit);
+		return -1;
+	}
+
+	if (rc != 0) {
+		printf("[|802.11]");
+		return rc;
+	}
+
+	switch (bit) {
+	case IEEE80211_RADIOTAP_CHANNEL:
+		printf("%u MHz ", u.u16);
+		if (u2.u16 != 0)
+			printf("(0x%04x) ", u2.u16);
+		break;
+	case IEEE80211_RADIOTAP_FHSS:
+		printf("fhset %d fhpat %d ", u.u16 & 0xff, (u.u16 >> 8) & 0xff);
+		break;
+	case IEEE80211_RADIOTAP_RATE:
+		PRINT_RATE("", u.u8, " Mb/s ");
+		break;
+	case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
+		printf("%ddB signal ", u.i8);
+		break;
+	case IEEE80211_RADIOTAP_DBM_ANTNOISE:
+		printf("%ddB noise ", u.i8);
+		break;
+	case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
+		printf("%ddB signal ", u.u8);
+		break;
+	case IEEE80211_RADIOTAP_DB_ANTNOISE:
+		printf("%ddB noise ", u.u8);
+		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.u8);
+		break;
+	case IEEE80211_RADIOTAP_DBM_TX_POWER:
+		printf("%ddBm tx power ", u.i8);
+		break;
+	case IEEE80211_RADIOTAP_FLAGS:
+		if (u.u8 & IEEE80211_RADIOTAP_F_CFP)
+			printf("cfp ");
+		if (u.u8 & IEEE80211_RADIOTAP_F_SHORTPRE)
+			printf("short preamble ");
+		if (u.u8 & IEEE80211_RADIOTAP_F_WEP)
+			printf("wep ");
+		if (u.u8 & IEEE80211_RADIOTAP_F_FRAG)
+			printf("fragmented ");
+		break;
+	case IEEE80211_RADIOTAP_ANTENNA:
+		printf("antenna %d ", u.u8);
+		break;
+	case IEEE80211_RADIOTAP_TSFT:
+		printf("%" PRIu64 "us tsft ", u.u64);
+		break;
+	}
+	return 0;
+}
+
 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)
+#define	IS_EXTENDED(__p)	\
+	    (EXTRACT_LE_32BITS(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0
+
+	struct cpack_state cpacker;
+	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;
+	u_int len;
+
+	if (caplen < sizeof(*hdr)) {
+		printf("[|802.11]");
+		return caplen;
+	}
+
+	hdr = (struct ieee80211_radiotap_header *)p;
+
+	len = EXTRACT_LE_16BITS(&hdr->it_len);
+
+	if (caplen < len) {
+		printf("[|802.11]");
+		return caplen;
+	}
+	for (last_presentp = &hdr->it_present;
+	     IS_EXTENDED(last_presentp) &&
+	     (u_char*)(last_presentp + 1) <= p + len;
+	     last_presentp++);
+
+	/* are there more bitmap extensions than bytes in header? */
+	if (IS_EXTENDED(last_presentp)) {
+		printf("[|802.11]");
+		return caplen;
+	}
+
+	iter = (u_char*)(last_presentp + 1);
+
+	if (cpack_init(&cpacker, (u_int8_t*)iter, len - (iter - p)) != 0) {
+		/* XXX */
+		printf("[|802.11]");
+		return caplen;
+	}
+
+	for (bit0 = 0, presentp = &hdr->it_present; presentp <= last_presentp;
+	     presentp++, bit0 += 32) {
+		for (present = EXTRACT_LE_32BITS(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);
+
+			if (print_radiotap_field(&cpacker, bit) != 0)
+				goto out;
+		}
+	}
+out:
+	return len + ieee802_11_print(p + len, length - len, caplen - len);
+#undef BITNO_32
+#undef BITNO_16
+#undef BITNO_8
+#undef BITNO_4
+#undef BITNO_2
+#undef BIT
+}
+
+static u_int
+ieee802_11_avs_radio_print(const u_char *p, u_int length, u_int caplen)
+{
 	u_int32_t caphdr_len;
 
 	caphdr_len = EXTRACT_32BITS(p + 4);
@@ -972,7 +1169,7 @@
 	}
 
 	if (EXTRACT_32BITS(p) == WLANCAP_MAGIC_COOKIE_V1)
-		return ieee802_11_radio_print(p, length, caplen);
+		return ieee802_11_avs_radio_print(p, length, caplen);
 
 	if (caplen < PRISM_HDR_LEN) {
 		printf("[|802.11]");