X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/1ac906f1747fed56bcad0c24c4ce351aeb9360a8..refs/pull/471/head:/print-802_11.c diff --git a/print-802_11.c b/print-802_11.c index 489aec4e..02e8cb2e 100644 --- a/print-802_11.c +++ b/print-802_11.c @@ -24,11 +24,11 @@ #include "config.h" #endif -#include +#include #include -#include "interface.h" +#include "netdissect.h" #include "addrtoname.h" #include "extract.h" @@ -168,7 +168,7 @@ static const struct tok ctrl_str[] = { #define FC_RETRY(fc) ((fc) & 0x0800) #define FC_POWER_MGMT(fc) ((fc) & 0x1000) #define FC_MORE_DATA(fc) ((fc) & 0x2000) -#define FC_WEP(fc) ((fc) & 0x4000) +#define FC_PROTECTED(fc) ((fc) & 0x4000) #define FC_ORDER(fc) ((fc) & 0x8000) struct mgmt_header_t { @@ -397,310 +397,6 @@ struct meshcntl_t { #define IV_PAD(iv) (((iv) >> 24) & 0x3F) #define IV_KEYID(iv) (((iv) >> 30) & 0x03) -/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ -/* NetBSD: ieee802_11_radio.h,v 1.2 2006/02/26 03:04:03 dyoung Exp */ - -/*- - * 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. It must be - * rigidly defined (e.g., units for fields should be given), - * and easily extensible. - * - * The following is an 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. - * - * Note well: all radiotap fields are little-endian. - */ -struct ieee80211_radiotap_header { - uint8_t it_version; /* Version 0. Only increases - * for drastic changes, - * introduction of compatible - * new fields does not count. - */ - uint8_t it_pad; - uint16_t it_len; /* length of the whole - * header in bytes, including - * it_version, it_pad, - * it_len, and data fields. - */ - uint32_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_TSFT uint64_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. - * - * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap - * - * Tx/Rx frequency in MHz, followed by flags (see below). - * Note that IEEE80211_RADIOTAP_XCHANNEL must be used to - * represent an HT channel as there is not enough room in - * the flags word. - * - * IEEE80211_RADIOTAP_FHSS uint16_t see below - * - * For frequency-hopping radios, the hop set (first byte) - * and pattern (second byte). - * - * IEEE80211_RADIOTAP_RATE uint8_t 500kb/s or index - * - * Tx/Rx data rate. If bit 0x80 is set then it represents an - * an MCS index and not an IEEE rate. - * - * IEEE80211_RADIOTAP_DBM_ANTSIGNAL int8_t decibels from - * one milliwatt (dBm) - * - * RF signal power at the antenna, decibel difference from - * one milliwatt. - * - * IEEE80211_RADIOTAP_DBM_ANTNOISE int8_t decibels from - * one milliwatt (dBm) - * - * RF noise power at the antenna, decibel difference from one - * milliwatt. - * - * IEEE80211_RADIOTAP_DB_ANTSIGNAL uint8_t decibel (dB) - * - * RF signal power at the antenna, decibel difference from an - * arbitrary, fixed reference. - * - * IEEE80211_RADIOTAP_DB_ANTNOISE uint8_t decibel (dB) - * - * RF noise power at the antenna, decibel difference from an - * arbitrary, fixed reference point. - * - * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_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 uint16_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 uint16_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 int8_t decibels from - * one 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_FLAGS uint8_t bitmap - * - * Properties of transmitted and received frames. See flags - * defined below. - * - * IEEE80211_RADIOTAP_ANTENNA uint8_t antenna index - * - * Unitless indication of the Rx/Tx antenna for this packet. - * The first antenna is antenna 0. - * - * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap - * - * Properties of received frames. See flags defined below. - * - * IEEE80211_RADIOTAP_XCHANNEL uint32_t bitmap - * uint16_t MHz - * uint8_t channel number - * uint8_t .5 dBm - * - * Extended channel specification: flags (see below) followed by - * frequency in MHz, the corresponding IEEE channel number, and - * finally the maximum regulatory transmit power cap in .5 dBm - * units. This property supersedes IEEE80211_RADIOTAP_CHANNEL - * and only one of the two should be present. - * - * IEEE80211_RADIOTAP_MCS uint8_t known - * uint8_t flags - * uint8_t mcs - * - * Bitset indicating which fields have known values, followed - * by bitset of flag values, followed by the MCS rate index as - * in IEEE 802.11n. - * - * IEEE80211_RADIOTAP_VENDOR_NAMESPACE - * uint8_t OUI[3] - * uint8_t subspace - * uint16_t length - * - * The Vendor Namespace Field contains three sub-fields. The first - * sub-field is 3 bytes long. It contains the vendor's IEEE 802 - * Organizationally Unique Identifier (OUI). The fourth byte is a - * vendor-specific "namespace selector." - * - */ -enum ieee80211_radiotap_type { - IEEE80211_RADIOTAP_TSFT = 0, - IEEE80211_RADIOTAP_FLAGS = 1, - IEEE80211_RADIOTAP_RATE = 2, - IEEE80211_RADIOTAP_CHANNEL = 3, - IEEE80211_RADIOTAP_FHSS = 4, - IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, - IEEE80211_RADIOTAP_DBM_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_DB_ANTSIGNAL = 12, - IEEE80211_RADIOTAP_DB_ANTNOISE = 13, - IEEE80211_RADIOTAP_RX_FLAGS = 14, - /* NB: gap for netbsd definitions */ - IEEE80211_RADIOTAP_XCHANNEL = 18, - IEEE80211_RADIOTAP_MCS = 19, - IEEE80211_RADIOTAP_NAMESPACE = 29, - IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30, - IEEE80211_RADIOTAP_EXT = 31 -}; - -/* channel attributes */ -#define IEEE80211_CHAN_TURBO 0x00010 /* Turbo channel */ -#define IEEE80211_CHAN_CCK 0x00020 /* CCK channel */ -#define IEEE80211_CHAN_OFDM 0x00040 /* OFDM channel */ -#define IEEE80211_CHAN_2GHZ 0x00080 /* 2 GHz spectrum channel. */ -#define IEEE80211_CHAN_5GHZ 0x00100 /* 5 GHz spectrum channel */ -#define IEEE80211_CHAN_PASSIVE 0x00200 /* Only passive scan allowed */ -#define IEEE80211_CHAN_DYN 0x00400 /* Dynamic CCK-OFDM channel */ -#define IEEE80211_CHAN_GFSK 0x00800 /* GFSK channel (FHSS PHY) */ -#define IEEE80211_CHAN_GSM 0x01000 /* 900 MHz spectrum channel */ -#define IEEE80211_CHAN_STURBO 0x02000 /* 11a static turbo channel only */ -#define IEEE80211_CHAN_HALF 0x04000 /* Half rate channel */ -#define IEEE80211_CHAN_QUARTER 0x08000 /* Quarter rate channel */ -#define IEEE80211_CHAN_HT20 0x10000 /* HT 20 channel */ -#define IEEE80211_CHAN_HT40U 0x20000 /* HT 40 channel w/ ext above */ -#define IEEE80211_CHAN_HT40D 0x40000 /* HT 40 channel w/ ext below */ - -/* Useful combinations of channel characteristics, borrowed from Ethereal */ -#define IEEE80211_CHAN_A \ - (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) -#define IEEE80211_CHAN_B \ - (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK) -#define IEEE80211_CHAN_G \ - (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN) -#define IEEE80211_CHAN_TA \ - (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO) -#define IEEE80211_CHAN_TG \ - (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN | IEEE80211_CHAN_TURBO) - - -/* For IEEE80211_RADIOTAP_FLAGS */ -#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received - * during CFP - */ -#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received - * with short - * preamble - */ -#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received - * with WEP encryption - */ -#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received - * with fragmentation - */ -#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ -#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between - * 802.11 header and payload - * (to 32-bit boundary) - */ -#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* does not pass FCS check */ - -/* For IEEE80211_RADIOTAP_RX_FLAGS */ -#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ -#define IEEE80211_RADIOTAP_F_RX_PLCP_CRC 0x0002 /* frame failed PLCP CRC check */ - -/* For IEEE80211_RADIOTAP_MCS known */ -#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN 0x01 -#define IEEE80211_RADIOTAP_MCS_MCS_INDEX_KNOWN 0x02 /* MCS index field */ -#define IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN 0x04 -#define IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN 0x08 -#define IEEE80211_RADIOTAP_MCS_FEC_TYPE_KNOWN 0x10 -#define IEEE80211_RADIOTAP_MCS_STBC_KNOWN 0x20 - -/* For IEEE80211_RADIOTAP_MCS flags */ -#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK 0x03 -#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20 0 -#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_40 1 -#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20L 2 -#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20U 3 -#define IEEE80211_RADIOTAP_MCS_SHORT_GI 0x04 /* short guard interval */ -#define IEEE80211_RADIOTAP_MCS_HT_GREENFIELD 0x08 -#define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10 -#define IEEE80211_RADIOTAP_MCS_STBC_MASK 0x60 -#define IEEE80211_RADIOTAP_MCS_STBC_1 1 -#define IEEE80211_RADIOTAP_MCS_STBC_2 2 -#define IEEE80211_RADIOTAP_MCS_STBC_3 3 -#define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5 - -static const char tstr[] = "[|802.11]"; - -/* Radiotap state */ -/* This is used to save state when parsing/processing parameters */ -struct radiotap_state -{ - uint32_t present; - - uint8_t rate; -}; - #define PRINT_SSID(p) \ if (p.ssid_present) { \ ND_PRINT((ndo, " (")); \ @@ -1290,7 +986,7 @@ wep_print(netdissect_options *ndo, return 0; iv = EXTRACT_LE_32BITS(p); - ND_PRINT((ndo, "Data IV:%3x Pad %x KeyID %x", IV_IV(iv), IV_PAD(iv), + ND_PRINT((ndo, " IV:%3x Pad %x KeyID %x", IV_IV(iv), IV_PAD(iv), IV_KEYID(iv))); return 1; @@ -1808,7 +1504,7 @@ handle_auth(netdissect_options *ndo, static int handle_deauth(netdissect_options *ndo, - const struct mgmt_header_t *pmh, const u_char *p, u_int length) + const uint8_t *src, const u_char *p, u_int length) { struct mgmt_body_t pbody; const char *reason = NULL; @@ -1828,7 +1524,7 @@ handle_deauth(netdissect_options *ndo, if (ndo->ndo_eflag) { ND_PRINT((ndo, ": %s", reason)); } else { - ND_PRINT((ndo, " (%s): %s", etheraddr_string(ndo, pmh->sa), reason)); + ND_PRINT((ndo, " (%s): %s", etheraddr_string(ndo, src), reason)); } return 1; } @@ -1893,7 +1589,7 @@ handle_deauth(netdissect_options *ndo, static int handle_action(netdissect_options *ndo, - const struct mgmt_header_t *pmh, const u_char *p, u_int length) + const uint8_t *src, const u_char *p, u_int length) { if (!ND_TTEST2(*p, 2)) return 0; @@ -1902,7 +1598,7 @@ handle_action(netdissect_options *ndo, if (ndo->ndo_eflag) { ND_PRINT((ndo, ": ")); } else { - ND_PRINT((ndo, " (%s): ", etheraddr_string(ndo, pmh->sa))); + ND_PRINT((ndo, " (%s): ", etheraddr_string(ndo, src))); } switch (p[0]) { case 0: ND_PRINT((ndo, "Spectrum Management Act#%d", p[1])); break; @@ -1933,10 +1629,13 @@ handle_action(netdissect_options *ndo, static int mgmt_body_print(netdissect_options *ndo, - uint16_t fc, const struct mgmt_header_t *pmh, - const u_char *p, u_int length) + uint16_t fc, const uint8_t *src, const u_char *p, u_int length) { ND_PRINT((ndo, "%s", tok2str(st_str, "Unhandled Management subtype(%x)", FC_SUBTYPE(fc)))); + + /* There may be a problem w/ AP not having this bit set */ + if (FC_PROTECTED(fc)) + return wep_print(ndo, p); switch (FC_SUBTYPE(fc)) { case ST_ASSOC_REQUEST: return handle_assoc_request(ndo, p, length); @@ -1957,17 +1656,11 @@ mgmt_body_print(netdissect_options *ndo, case ST_DISASSOC: return handle_disassoc(ndo, p, length); case ST_AUTH: - if (!ND_TTEST2(*p, 3)) - return 0; - if ((p[0] == 0 ) && (p[1] == 0) && (p[2] == 0)) { - ND_PRINT((ndo, "Authentication (Shared-Key)-3 ")); - return wep_print(ndo, p); - } return handle_auth(ndo, p, length); case ST_DEAUTH: - return handle_deauth(ndo, pmh, p, length); + return handle_deauth(ndo, src, p, length); case ST_ACTION: - return handle_action(ndo, pmh, p, length); + return handle_action(ndo, src, p, length); default: return 1; } @@ -2071,18 +1764,26 @@ get_data_src_dst_mac(uint16_t fc, const u_char *p, const uint8_t **srcp, #define ADDR3 (p + 16) #define ADDR4 (p + 24) - if (!FC_TO_DS(fc) && !FC_FROM_DS(fc)) { - *srcp = ADDR2; - *dstp = ADDR1; - } else if (!FC_TO_DS(fc) && FC_FROM_DS(fc)) { - *srcp = ADDR3; - *dstp = ADDR1; - } else if (FC_TO_DS(fc) && !FC_FROM_DS(fc)) { - *srcp = ADDR2; - *dstp = ADDR3; - } else if (FC_TO_DS(fc) && FC_FROM_DS(fc)) { - *srcp = ADDR4; - *dstp = ADDR3; + if (!FC_TO_DS(fc)) { + if (!FC_FROM_DS(fc)) { + /* not To DS and not From DS */ + *srcp = ADDR2; + *dstp = ADDR1; + } else { + /* not To DS and From DS */ + *srcp = ADDR3; + *dstp = ADDR1; + } + } else { + if (!FC_FROM_DS(fc)) { + /* From DS and not To DS */ + *srcp = ADDR2; + *dstp = ADDR3; + } else { + /* To DS and From DS */ + *srcp = ADDR4; + *dstp = ADDR3; + } } #undef ADDR1 @@ -2091,6 +1792,17 @@ get_data_src_dst_mac(uint16_t fc, const u_char *p, const uint8_t **srcp, #undef ADDR4 } +static void +get_mgmt_src_dst_mac(const u_char *p, const uint8_t **srcp, const uint8_t **dstp) +{ + const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p; + + if (srcp != NULL) + *srcp = hp->sa; + if (dstp != NULL) + *dstp = hp->da; +} + /* * Print Header funcs */ @@ -2274,8 +1986,8 @@ ieee_802_11_hdr_print(netdissect_options *ndo, ND_PRINT((ndo, "Retry ")); if (FC_ORDER(fc)) ND_PRINT((ndo, "Strictly Ordered ")); - if (FC_WEP(fc)) - ND_PRINT((ndo, "WEP Encrypted ")); + if (FC_PROTECTED(fc)) + ND_PRINT((ndo, "Protected ")); if (FC_TYPE(fc) != T_CTRL || FC_SUBTYPE(fc) != CTRL_PS_POLL) ND_PRINT((ndo, "%dus ", EXTRACT_LE_16BITS( @@ -2299,152 +2011,496 @@ ieee_802_11_hdr_print(netdissect_options *ndo, switch (FC_TYPE(fc)) { case T_MGMT: - mgmt_header_print(ndo, p); + mgmt_header_print(ndo, p); + break; + case T_CTRL: + ctrl_header_print(ndo, fc, p); + break; + case T_DATA: + data_header_print(ndo, fc, p); + break; + default: + break; + } +} + +#ifndef roundup2 +#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ +#endif + +static const char tstr[] = "[|802.11]"; + +static u_int +ieee802_11_print(netdissect_options *ndo, + const u_char *p, u_int length, u_int orig_caplen, int pad, + u_int fcslen) +{ + uint16_t fc; + u_int caplen, hdrlen, meshdrlen; + const uint8_t *src, *dst; + int llc_hdrlen; + + caplen = orig_caplen; + /* Remove FCS, if present */ + if (length < fcslen) { + ND_PRINT((ndo, "%s", tstr)); + return caplen; + } + length -= fcslen; + if (caplen > length) { + /* Amount of FCS in actual packet data, if any */ + fcslen = caplen - length; + caplen -= fcslen; + ndo->ndo_snapend -= fcslen; + } + + if (caplen < IEEE802_11_FC_LEN) { + ND_PRINT((ndo, "%s", tstr)); + return orig_caplen; + } + + fc = EXTRACT_LE_16BITS(p); + hdrlen = extract_header_length(ndo, fc); + if (hdrlen == 0) { + /* Unknown frame type or control frame subtype; quit. */ + return (0); + } + if (pad) + hdrlen = roundup2(hdrlen, 4); + if (ndo->ndo_Hflag && FC_TYPE(fc) == T_DATA && + DATA_FRAME_IS_QOS(FC_SUBTYPE(fc))) { + meshdrlen = extract_mesh_header_length(p+hdrlen); + hdrlen += meshdrlen; + } else + meshdrlen = 0; + + if (caplen < hdrlen) { + ND_PRINT((ndo, "%s", tstr)); + return hdrlen; + } + + if (ndo->ndo_eflag) + ieee_802_11_hdr_print(ndo, fc, p, hdrlen, meshdrlen); + + /* + * Go past the 802.11 header. + */ + length -= hdrlen; + caplen -= hdrlen; + p += hdrlen; + + switch (FC_TYPE(fc)) { + case T_MGMT: + get_mgmt_src_dst_mac(p - hdrlen, &src, &dst); + if (!mgmt_body_print(ndo, fc, src, p, length)) { + ND_PRINT((ndo, "%s", tstr)); + return hdrlen; + } break; case T_CTRL: - ctrl_header_print(ndo, fc, p); + if (!ctrl_body_print(ndo, fc, p - hdrlen)) { + ND_PRINT((ndo, "%s", tstr)); + return hdrlen; + } break; case T_DATA: - data_header_print(ndo, fc, p); + if (DATA_FRAME_IS_NULL(FC_SUBTYPE(fc))) + return hdrlen; /* no-data frame */ + /* There may be a problem w/ AP not having this bit set */ + if (FC_PROTECTED(fc)) { + ND_PRINT((ndo, "Data")); + if (!wep_print(ndo, p)) { + ND_PRINT((ndo, "%s", tstr)); + return hdrlen; + } + } else { + get_data_src_dst_mac(fc, p - hdrlen, &src, &dst); + llc_hdrlen = llc_print(ndo, p, length, caplen, src, dst); + if (llc_hdrlen < 0) { + /* + * Some kinds of LLC packet we cannot + * handle intelligently + */ + if (!ndo->ndo_suppress_default_print) + ND_DEFAULTPRINT(p, caplen); + llc_hdrlen = -llc_hdrlen; + } + hdrlen += llc_hdrlen; + } break; default: + /* We shouldn't get here - we should already have quit */ break; } -} -#ifndef roundup2 -#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ -#endif + return hdrlen; +} -static u_int -ieee802_11_print(netdissect_options *ndo, - const u_char *p, u_int length, u_int orig_caplen, int pad, - u_int fcslen) +/* + * This is the top level routine of the printer. 'p' points + * to the 802.11 header of the packet, 'h->ts' is the timestamp, + * 'h->len' is the length of the packet off the wire, and 'h->caplen' + * is the number of bytes actually captured. + */ +u_int +ieee802_11_if_print(netdissect_options *ndo, + const struct pcap_pkthdr *h, const u_char *p) { - uint16_t fc; - u_int caplen, hdrlen, meshdrlen; - const uint8_t *src, *dst; - u_short extracted_ethertype; + return ieee802_11_print(ndo, p, h->len, h->caplen, 0, 0); +} + + +/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ +/* NetBSD: ieee802_11_radio.h,v 1.2 2006/02/26 03:04:03 dyoung Exp */ + +/*- + * 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. It must be + * rigidly defined (e.g., units for fields should be given), + * and easily extensible. + * + * The following is an 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. + * + * Note well: all radiotap fields are little-endian. + */ +struct ieee80211_radiotap_header { + uint8_t it_version; /* Version 0. Only increases + * for drastic changes, + * introduction of compatible + * new fields does not count. + */ + uint8_t it_pad; + uint16_t it_len; /* length of the whole + * header in bytes, including + * it_version, it_pad, + * it_len, and data fields. + */ + uint32_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_TSFT uint64_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. + * + * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap + * + * Tx/Rx frequency in MHz, followed by flags (see below). + * Note that IEEE80211_RADIOTAP_XCHANNEL must be used to + * represent an HT channel as there is not enough room in + * the flags word. + * + * IEEE80211_RADIOTAP_FHSS uint16_t see below + * + * For frequency-hopping radios, the hop set (first byte) + * and pattern (second byte). + * + * IEEE80211_RADIOTAP_RATE uint8_t 500kb/s or index + * + * Tx/Rx data rate. If bit 0x80 is set then it represents an + * an MCS index and not an IEEE rate. + * + * IEEE80211_RADIOTAP_DBM_ANTSIGNAL int8_t decibels from + * one milliwatt (dBm) + * + * RF signal power at the antenna, decibel difference from + * one milliwatt. + * + * IEEE80211_RADIOTAP_DBM_ANTNOISE int8_t decibels from + * one milliwatt (dBm) + * + * RF noise power at the antenna, decibel difference from one + * milliwatt. + * + * IEEE80211_RADIOTAP_DB_ANTSIGNAL uint8_t decibel (dB) + * + * RF signal power at the antenna, decibel difference from an + * arbitrary, fixed reference. + * + * IEEE80211_RADIOTAP_DB_ANTNOISE uint8_t decibel (dB) + * + * RF noise power at the antenna, decibel difference from an + * arbitrary, fixed reference point. + * + * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_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 uint16_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 uint16_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 int8_t decibels from + * one 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_FLAGS uint8_t bitmap + * + * Properties of transmitted and received frames. See flags + * defined below. + * + * IEEE80211_RADIOTAP_ANTENNA uint8_t antenna index + * + * Unitless indication of the Rx/Tx antenna for this packet. + * The first antenna is antenna 0. + * + * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap + * + * Properties of received frames. See flags defined below. + * + * IEEE80211_RADIOTAP_XCHANNEL uint32_t bitmap + * uint16_t MHz + * uint8_t channel number + * uint8_t .5 dBm + * + * Extended channel specification: flags (see below) followed by + * frequency in MHz, the corresponding IEEE channel number, and + * finally the maximum regulatory transmit power cap in .5 dBm + * units. This property supersedes IEEE80211_RADIOTAP_CHANNEL + * and only one of the two should be present. + * + * IEEE80211_RADIOTAP_MCS uint8_t known + * uint8_t flags + * uint8_t mcs + * + * Bitset indicating which fields have known values, followed + * by bitset of flag values, followed by the MCS rate index as + * in IEEE 802.11n. + * + * + * IEEE80211_RADIOTAP_AMPDU_STATUS u32, u16, u8, u8 unitless + * + * Contains the AMPDU information for the subframe. + * + * IEEE80211_RADIOTAP_VHT u16, u8, u8, u8[4], u8, u8, u16 + * + * Contains VHT information about this frame. + * + * IEEE80211_RADIOTAP_VENDOR_NAMESPACE + * uint8_t OUI[3] + * uint8_t subspace + * uint16_t length + * + * The Vendor Namespace Field contains three sub-fields. The first + * sub-field is 3 bytes long. It contains the vendor's IEEE 802 + * Organizationally Unique Identifier (OUI). The fourth byte is a + * vendor-specific "namespace selector." + * + */ +enum ieee80211_radiotap_type { + IEEE80211_RADIOTAP_TSFT = 0, + IEEE80211_RADIOTAP_FLAGS = 1, + IEEE80211_RADIOTAP_RATE = 2, + IEEE80211_RADIOTAP_CHANNEL = 3, + IEEE80211_RADIOTAP_FHSS = 4, + IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, + IEEE80211_RADIOTAP_DBM_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_DB_ANTSIGNAL = 12, + IEEE80211_RADIOTAP_DB_ANTNOISE = 13, + IEEE80211_RADIOTAP_RX_FLAGS = 14, + /* NB: gap for netbsd definitions */ + IEEE80211_RADIOTAP_XCHANNEL = 18, + IEEE80211_RADIOTAP_MCS = 19, + IEEE80211_RADIOTAP_AMPDU_STATUS = 20, + IEEE80211_RADIOTAP_VHT = 21, + IEEE80211_RADIOTAP_NAMESPACE = 29, + IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30, + IEEE80211_RADIOTAP_EXT = 31 +}; - caplen = orig_caplen; - /* Remove FCS, if present */ - if (length < fcslen) { - ND_PRINT((ndo, "%s", tstr)); - return caplen; - } - length -= fcslen; - if (caplen > length) { - /* Amount of FCS in actual packet data, if any */ - fcslen = caplen - length; - caplen -= fcslen; - ndo->ndo_snapend -= fcslen; - } +/* channel attributes */ +#define IEEE80211_CHAN_TURBO 0x00010 /* Turbo channel */ +#define IEEE80211_CHAN_CCK 0x00020 /* CCK channel */ +#define IEEE80211_CHAN_OFDM 0x00040 /* OFDM channel */ +#define IEEE80211_CHAN_2GHZ 0x00080 /* 2 GHz spectrum channel. */ +#define IEEE80211_CHAN_5GHZ 0x00100 /* 5 GHz spectrum channel */ +#define IEEE80211_CHAN_PASSIVE 0x00200 /* Only passive scan allowed */ +#define IEEE80211_CHAN_DYN 0x00400 /* Dynamic CCK-OFDM channel */ +#define IEEE80211_CHAN_GFSK 0x00800 /* GFSK channel (FHSS PHY) */ +#define IEEE80211_CHAN_GSM 0x01000 /* 900 MHz spectrum channel */ +#define IEEE80211_CHAN_STURBO 0x02000 /* 11a static turbo channel only */ +#define IEEE80211_CHAN_HALF 0x04000 /* Half rate channel */ +#define IEEE80211_CHAN_QUARTER 0x08000 /* Quarter rate channel */ +#define IEEE80211_CHAN_HT20 0x10000 /* HT 20 channel */ +#define IEEE80211_CHAN_HT40U 0x20000 /* HT 40 channel w/ ext above */ +#define IEEE80211_CHAN_HT40D 0x40000 /* HT 40 channel w/ ext below */ - if (caplen < IEEE802_11_FC_LEN) { - ND_PRINT((ndo, "%s", tstr)); - return orig_caplen; - } +/* Useful combinations of channel characteristics, borrowed from Ethereal */ +#define IEEE80211_CHAN_A \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) +#define IEEE80211_CHAN_B \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK) +#define IEEE80211_CHAN_G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN) +#define IEEE80211_CHAN_TA \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO) +#define IEEE80211_CHAN_TG \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN | IEEE80211_CHAN_TURBO) - fc = EXTRACT_LE_16BITS(p); - hdrlen = extract_header_length(ndo, fc); - if (hdrlen == 0) { - /* Unknown frame type or control frame subtype; quit. */ - return (0); - } - if (pad) - hdrlen = roundup2(hdrlen, 4); - if (ndo->ndo_Hflag && FC_TYPE(fc) == T_DATA && - DATA_FRAME_IS_QOS(FC_SUBTYPE(fc))) { - meshdrlen = extract_mesh_header_length(p+hdrlen); - hdrlen += meshdrlen; - } else - meshdrlen = 0; - if (caplen < hdrlen) { - ND_PRINT((ndo, "%s", tstr)); - return hdrlen; - } +/* For IEEE80211_RADIOTAP_FLAGS */ +#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received + * during CFP + */ +#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received + * with short + * preamble + */ +#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received + * with WEP encryption + */ +#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received + * with fragmentation + */ +#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ +#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between + * 802.11 header and payload + * (to 32-bit boundary) + */ +#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* does not pass FCS check */ - if (ndo->ndo_eflag) - ieee_802_11_hdr_print(ndo, fc, p, hdrlen, meshdrlen); +/* For IEEE80211_RADIOTAP_RX_FLAGS */ +#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ +#define IEEE80211_RADIOTAP_F_RX_PLCP_CRC 0x0002 /* frame failed PLCP CRC check */ - /* - * Go past the 802.11 header. - */ - length -= hdrlen; - caplen -= hdrlen; - p += hdrlen; +/* For IEEE80211_RADIOTAP_MCS known */ +#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN 0x01 +#define IEEE80211_RADIOTAP_MCS_MCS_INDEX_KNOWN 0x02 /* MCS index field */ +#define IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN 0x04 +#define IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN 0x08 +#define IEEE80211_RADIOTAP_MCS_FEC_TYPE_KNOWN 0x10 +#define IEEE80211_RADIOTAP_MCS_STBC_KNOWN 0x20 +#define IEEE80211_RADIOTAP_MCS_NESS_KNOWN 0x40 +#define IEEE80211_RADIOTAP_MCS_NESS_BIT_1 0x80 - switch (FC_TYPE(fc)) { - case T_MGMT: - if (FC_WEP(fc)) { - if (!ndo->ndo_eflag) - ND_PRINT((ndo, "WEP Encrypted ")); - } - if (!mgmt_body_print(ndo, fc, - (const struct mgmt_header_t *)(p - hdrlen), p, length)) { - ND_PRINT((ndo, "%s", tstr)); - return hdrlen; - } - break; - case T_CTRL: - if (!ctrl_body_print(ndo, fc, p - hdrlen)) { - ND_PRINT((ndo, "%s", tstr)); - return hdrlen; - } - break; - case T_DATA: - if (DATA_FRAME_IS_NULL(FC_SUBTYPE(fc))) - return hdrlen; /* no-data frame */ - /* There may be a problem w/ AP not having this bit set */ - if (FC_WEP(fc)) { - if (!ndo->ndo_eflag) - ND_PRINT((ndo, "WEP Encrypted ")); - if (!wep_print(ndo, p)) { - ND_PRINT((ndo, "%s", tstr)); - return hdrlen; - } - } else { - get_data_src_dst_mac(fc, p - hdrlen, &src, &dst); - if (llc_print(ndo, p, length, caplen, dst, src, - &extracted_ethertype) == 0) { - /* - * Some kinds of LLC packet we cannot - * handle intelligently - */ - if (!ndo->ndo_eflag) { - ieee_802_11_hdr_print(ndo, fc, p - hdrlen, - hdrlen, meshdrlen); - } - if (extracted_ethertype) - ND_PRINT((ndo, "(LLC %s) ", - etherproto_string( - htons(extracted_ethertype)))); - if (!ndo->ndo_suppress_default_print) - ND_DEFAULTPRINT(p, caplen); - } - } - break; - default: - /* We shouldn't get here - we should already have quit */ - break; - } +/* For IEEE80211_RADIOTAP_MCS flags */ +#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK 0x03 +#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20 0 +#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_40 1 +#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20L 2 +#define IEEE80211_RADIOTAP_MCS_BANDWIDTH_20U 3 +#define IEEE80211_RADIOTAP_MCS_SHORT_GI 0x04 /* short guard interval */ +#define IEEE80211_RADIOTAP_MCS_HT_GREENFIELD 0x08 +#define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10 +#define IEEE80211_RADIOTAP_MCS_STBC_MASK 0x60 +#define IEEE80211_RADIOTAP_MCS_STBC_1 1 +#define IEEE80211_RADIOTAP_MCS_STBC_2 2 +#define IEEE80211_RADIOTAP_MCS_STBC_3 3 +#define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5 +#define IEEE80211_RADIOTAP_MCS_NESS_BIT_0 0x80 + +/* For IEEE80211_RADIOTAP_AMPDU_STATUS */ +#define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001 +#define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN 0x0002 +#define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN 0x0004 +#define IEEE80211_RADIOTAP_AMPDU_IS_LAST 0x0008 +#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010 +#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020 + +/* For IEEE80211_RADIOTAP_VHT known */ +#define IEEE80211_RADIOTAP_VHT_STBC_KNOWN 0x0001 +#define IEEE80211_RADIOTAP_VHT_TXOP_PS_NA_KNOWN 0x0002 +#define IEEE80211_RADIOTAP_VHT_GUARD_INTERVAL_KNOWN 0x0004 +#define IEEE80211_RADIOTAP_VHT_SGI_NSYM_DIS_KNOWN 0x0008 +#define IEEE80211_RADIOTAP_VHT_LDPC_EXTRA_OFDM_SYM_KNOWN 0x0010 +#define IEEE80211_RADIOTAP_VHT_BEAMFORMED_KNOWN 0x0020 +#define IEEE80211_RADIOTAP_VHT_BANDWIDTH_KNOWN 0x0040 +#define IEEE80211_RADIOTAP_VHT_GROUP_ID_KNOWN 0x0080 +#define IEEE80211_RADIOTAP_VHT_PARTIAL_AID_KNOWN 0x0100 + +/* For IEEE80211_RADIOTAP_VHT flags */ +#define IEEE80211_RADIOTAP_VHT_STBC 0x01 +#define IEEE80211_RADIOTAP_VHT_TXOP_PS_NA 0x02 +#define IEEE80211_RADIOTAP_VHT_SHORT_GI 0x04 +#define IEEE80211_RADIOTAP_VHT_SGI_NSYM_M10_9 0x08 +#define IEEE80211_RADIOTAP_VHT_LDPC_EXTRA_OFDM_SYM 0x10 +#define IEEE80211_RADIOTAP_VHT_BEAMFORMED 0x20 + +#define IEEE80211_RADIOTAP_VHT_BANDWIDTH_MASK 0x1f + +#define IEEE80211_RADIOTAP_VHT_NSS_MASK 0x0f +#define IEEE80211_RADIOTAP_VHT_MCS_MASK 0xf0 +#define IEEE80211_RADIOTAP_VHT_MCS_SHIFT 4 + +#define IEEE80211_RADIOTAP_CODING_LDPC_USERn 0x01 - return hdrlen; -} -/* - * This is the top level routine of the printer. 'p' points - * to the 802.11 header of the packet, 'h->ts' is the timestamp, - * 'h->len' is the length of the packet off the wire, and 'h->caplen' - * is the number of bytes actually captured. - */ -u_int -ieee802_11_if_print(netdissect_options *ndo, - const struct pcap_pkthdr *h, const u_char *p) +/* Radiotap state */ +/* This is used to save state when parsing/processing parameters */ +struct radiotap_state { - return ieee802_11_print(ndo, p, h->len, h->caplen, 0, 0); -} + uint32_t present; + + uint8_t rate; +}; #define IEEE80211_CHAN_FHSS \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK) @@ -2472,30 +2528,41 @@ ieee802_11_if_print(netdissect_options *ndo, static void print_chaninfo(netdissect_options *ndo, - int freq, int flags) + int freq, int flags, int presentflags) { ND_PRINT((ndo, "%u MHz", freq)); - if (IS_CHAN_FHSS(flags)) - ND_PRINT((ndo, " FHSS")); - if (IS_CHAN_A(flags)) { - if (flags & IEEE80211_CHAN_HALF) - ND_PRINT((ndo, " 11a/10Mhz")); - else if (flags & IEEE80211_CHAN_QUARTER) - ND_PRINT((ndo, " 11a/5Mhz")); - else - ND_PRINT((ndo, " 11a")); + if (presentflags & (1 << IEEE80211_RADIOTAP_MCS)) { + /* + * We have the MCS field, so this is 11n, regardless + * of what the channel flags say. + */ + ND_PRINT((ndo, " 11n")); + } else { + if (IS_CHAN_FHSS(flags)) + ND_PRINT((ndo, " FHSS")); + if (IS_CHAN_A(flags)) { + if (flags & IEEE80211_CHAN_HALF) + ND_PRINT((ndo, " 11a/10Mhz")); + else if (flags & IEEE80211_CHAN_QUARTER) + ND_PRINT((ndo, " 11a/5Mhz")); + else + ND_PRINT((ndo, " 11a")); + } + if (IS_CHAN_ANYG(flags)) { + if (flags & IEEE80211_CHAN_HALF) + ND_PRINT((ndo, " 11g/10Mhz")); + else if (flags & IEEE80211_CHAN_QUARTER) + ND_PRINT((ndo, " 11g/5Mhz")); + else + ND_PRINT((ndo, " 11g")); + } else if (IS_CHAN_B(flags)) + ND_PRINT((ndo, " 11b")); + if (flags & IEEE80211_CHAN_TURBO) + ND_PRINT((ndo, " Turbo")); } - if (IS_CHAN_ANYG(flags)) { - if (flags & IEEE80211_CHAN_HALF) - ND_PRINT((ndo, " 11g/10Mhz")); - else if (flags & IEEE80211_CHAN_QUARTER) - ND_PRINT((ndo, " 11g/5Mhz")); - else - ND_PRINT((ndo, " 11g")); - } else if (IS_CHAN_B(flags)) - ND_PRINT((ndo, " 11b")); - if (flags & IEEE80211_CHAN_TURBO) - ND_PRINT((ndo, " Turbo")); + /* + * These apply to 11n. + */ if (flags & IEEE80211_CHAN_HT20) ND_PRINT((ndo, " ht/20")); else if (flags & IEEE80211_CHAN_HT40D) @@ -2517,7 +2584,9 @@ print_radiotap_field(netdissect_options *ndo, uint16_t u16; uint32_t u32; uint64_t u64; - } u, u2, u3, u4; + } u, u2, u3, u4, u5, u6; + uint8_t mcs_nss[4]; + u_int i; int rc; switch (bit) { @@ -2586,6 +2655,42 @@ print_radiotap_field(netdissect_options *ndo, break; rc = cpack_uint8(s, &u3.u8); break; + case IEEE80211_RADIOTAP_AMPDU_STATUS: + rc = cpack_uint32(s, &u.u32); + if (rc != 0) + break; + rc = cpack_uint16(s, &u2.u16); + if (rc != 0) + break; + rc = cpack_uint8(s, &u3.u8); + if (rc != 0) + break; + rc = cpack_uint8(s, &u4.u8); + break; + case IEEE80211_RADIOTAP_VHT: + rc = cpack_uint16(s, &u.u16); + if (rc != 0) + break; + rc = cpack_uint8(s, &u2.u8); + if (rc != 0) + break; + rc = cpack_uint8(s, &u3.u8); + if (rc != 0) + goto fail; + for (i = 0; i < 4; i++) { + rc = cpack_uint8(s, &mcs_nss[i]); + if (rc != 0) + goto fail; + } + rc = cpack_uint8(s, &u4.u8); + if (rc != 0) + break; + rc = cpack_uint8(s, &u5.u8); + if (rc != 0) + goto fail; + rc = cpack_uint16(s, &u6.u16); + fail: + break; case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: { uint8_t vns[3]; uint16_t length; @@ -2641,7 +2746,7 @@ print_radiotap_field(netdissect_options *ndo, */ if (presentflags & (1 << IEEE80211_RADIOTAP_XCHANNEL)) break; - print_chaninfo(ndo, u.u16, u2.u16); + print_chaninfo(ndo, u.u16, u2.u16, presentflags); break; case IEEE80211_RADIOTAP_FHSS: ND_PRINT((ndo, "fhset %d fhpat %d ", u.u16 & 0xff, (u.u16 >> 8) & 0xff)); @@ -2690,10 +2795,10 @@ print_radiotap_field(netdissect_options *ndo, ND_PRINT((ndo, "%2.1f Mb/s ", .5 * u.u8)); break; case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: - ND_PRINT((ndo, "%ddB signal ", u.i8)); + ND_PRINT((ndo, "%ddBm signal ", u.i8)); break; case IEEE80211_RADIOTAP_DBM_ANTNOISE: - ND_PRINT((ndo, "%ddB noise ", u.i8)); + ND_PRINT((ndo, "%ddBm noise ", u.i8)); break; case IEEE80211_RADIOTAP_DB_ANTSIGNAL: ND_PRINT((ndo, "%ddB signal ", u.u8)); @@ -2735,10 +2840,10 @@ print_radiotap_field(netdissect_options *ndo, /* Do nothing for now */ break; case IEEE80211_RADIOTAP_XCHANNEL: - print_chaninfo(ndo, u2.u16, u.u32); + print_chaninfo(ndo, u2.u16, u.u32, presentflags); break; case IEEE80211_RADIOTAP_MCS: { - static const char *bandwidth[4] = { + static const char *ht_bandwidth[4] = { "20 MHz", "40 MHz", "20 MHz (L)", @@ -2795,12 +2900,12 @@ print_radiotap_field(netdissect_options *ndo, } if (u.u8 & IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN) { ND_PRINT((ndo, "%s ", - bandwidth[u2.u8 & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK])); + ht_bandwidth[u2.u8 & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK])); } if (u.u8 & IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN) { ND_PRINT((ndo, "%s GI ", (u2.u8 & IEEE80211_RADIOTAP_MCS_SHORT_GI) ? - "short" : "lon")); + "short" : "long")); } if (u.u8 & IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN) { ND_PRINT((ndo, "%s ", @@ -2817,6 +2922,68 @@ print_radiotap_field(netdissect_options *ndo, (u2.u8 & IEEE80211_RADIOTAP_MCS_STBC_MASK) >> IEEE80211_RADIOTAP_MCS_STBC_SHIFT)); } + break; + } + case IEEE80211_RADIOTAP_AMPDU_STATUS: + break; + case IEEE80211_RADIOTAP_VHT: { + static const char *vht_bandwidth[32] = { + "20 MHz", + "40 MHz", + "20 MHz (L)", + "20 MHz (U)", + "80 MHz", + "80 MHz (L)", + "80 MHz (U)", + "80 MHz (LL)", + "80 MHz (LU)", + "80 MHz (UL)", + "80 MHz (UU)", + "160 MHz", + "160 MHz (L)", + "160 MHz (U)", + "160 MHz (LL)", + "160 MHz (LU)", + "160 MHz (UL)", + "160 MHz (UU)", + "160 MHz (LLL)", + "160 MHz (LLU)", + "160 MHz (LUL)", + "160 MHz (UUU)", + "160 MHz (ULL)", + "160 MHz (ULU)", + "160 MHz (UUL)", + "160 MHz (UUU)", + "unknown (26)", + "unknown (27)", + "unknown (28)", + "unknown (29)", + "unknown (30)", + "unknown (31)" + }; + + for (i = 0; i < 4; i++) { + u_int nss, mcs; + nss = mcs_nss[i] & IEEE80211_RADIOTAP_VHT_NSS_MASK; + mcs = (mcs_nss[i] & IEEE80211_RADIOTAP_VHT_MCS_MASK) >> IEEE80211_RADIOTAP_VHT_MCS_SHIFT; + + if (nss == 0) + continue; + + ND_PRINT((ndo, "User %u MCS %u ", i, mcs)); + ND_PRINT((ndo, "%s FEC ", + (u4.u8 & (IEEE80211_RADIOTAP_CODING_LDPC_USERn << i)) ? + "LDPC" : "BCC")); + } + if (u.u16 & IEEE80211_RADIOTAP_VHT_BANDWIDTH_KNOWN) { + ND_PRINT((ndo, "%s ", + vht_bandwidth[u3.u8 & IEEE80211_RADIOTAP_VHT_BANDWIDTH_MASK])); + } + if (u.u16 & IEEE80211_RADIOTAP_VHT_GUARD_INTERVAL_KNOWN) { + ND_PRINT((ndo, "%s GI ", + (u2.u8 & IEEE80211_RADIOTAP_VHT_SHORT_GI) ? + "short" : "long")); + } break; } } @@ -2837,10 +3004,10 @@ ieee802_11_radio_print(netdissect_options *ndo, (EXTRACT_LE_32BITS(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0 struct cpack_state cpacker; - struct ieee80211_radiotap_header *hdr; + const struct ieee80211_radiotap_header *hdr; uint32_t present, next_present; uint32_t presentflags = 0; - uint32_t *presentp, *last_presentp; + const uint32_t *presentp, *last_presentp; enum ieee80211_radiotap_type bit; int bit0; u_int len; @@ -2854,7 +3021,7 @@ ieee802_11_radio_print(netdissect_options *ndo, return caplen; } - hdr = (struct ieee80211_radiotap_header *)p; + hdr = (const struct ieee80211_radiotap_header *)p; len = EXTRACT_LE_16BITS(&hdr->it_len); @@ -2862,11 +3029,11 @@ ieee802_11_radio_print(netdissect_options *ndo, ND_PRINT((ndo, "%s", tstr)); return caplen; } - cpack_init(&cpacker, (uint8_t *)hdr, len); /* align against header start */ + cpack_init(&cpacker, (const uint8_t *)hdr, len); /* align against header start */ cpack_advance(&cpacker, sizeof(*hdr)); /* includes the 1st bitmap */ for (last_presentp = &hdr->it_present; IS_EXTENDED(last_presentp) && - (u_char*)(last_presentp + 1) <= p + len; + (const u_char*)(last_presentp + 1) <= p + len; last_presentp++) cpack_advance(&cpacker, sizeof(hdr->it_present)); /* more bitmaps */