summaryrefslogtreecommitdiff
path: root/print-802_11.c
diff options
context:
space:
mode:
Diffstat (limited to 'print-802_11.c')
-rw-r--r--print-802_11.c917
1 files changed, 701 insertions, 216 deletions
diff --git a/print-802_11.c b/print-802_11.c
index 835d21bd3741f..088840ab13848 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.47.2.2 2007-12-29 23:25:28 guy Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/tcpdump/print-802_11.c,v 1.49 2007-12-29 23:25:02 guy Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
@@ -47,93 +47,206 @@ static const char rcsid[] _U_ =
#include "ieee802_11_radio.h"
#define PRINT_SSID(p) \
- switch (p.ssid_status) { \
- case TRUNCATED: \
- return 0; \
- case PRESENT: \
+ if (p.ssid_present) { \
printf(" ("); \
fn_print(p.ssid.ssid, NULL); \
printf(")"); \
- break; \
- case NOT_PRESENT: \
- break; \
}
#define PRINT_RATE(_sep, _r, _suf) \
printf("%s%2.1f%s", _sep, (.5 * ((_r) & 0x7f)), _suf)
#define PRINT_RATES(p) \
- switch (p.rates_status) { \
- case TRUNCATED: \
- return 0; \
- case PRESENT: \
- do { \
- int z; \
- const char *sep = " ["; \
- for (z = 0; z < p.rates.length ; z++) { \
- PRINT_RATE(sep, p.rates.rate[z], \
- (p.rates.rate[z] & 0x80 ? "*" : "")); \
- sep = " "; \
- } \
- if (p.rates.length != 0) \
- printf(" Mbit]"); \
- } while (0); \
- break; \
- case NOT_PRESENT: \
- break; \
+ if (p.rates_present) { \
+ int z; \
+ const char *sep = " ["; \
+ for (z = 0; z < p.rates.length ; z++) { \
+ PRINT_RATE(sep, p.rates.rate[z], \
+ (p.rates.rate[z] & 0x80 ? "*" : "")); \
+ sep = " "; \
+ } \
+ if (p.rates.length != 0) \
+ printf(" Mbit]"); \
}
#define PRINT_DS_CHANNEL(p) \
- switch (p.ds_status) { \
- case TRUNCATED: \
- return 0; \
- case PRESENT: \
+ if (p.ds_present) \
printf(" CH: %u", p.ds.channel); \
- break; \
- case NOT_PRESENT: \
- break; \
- } \
printf("%s", \
CAPABILITY_PRIVACY(p.capability_info) ? ", PRIVACY" : "" );
+static const int ieee80211_htrates[16] = {
+ 13, /* IFM_IEEE80211_MCS0 */
+ 26, /* IFM_IEEE80211_MCS1 */
+ 39, /* IFM_IEEE80211_MCS2 */
+ 52, /* IFM_IEEE80211_MCS3 */
+ 78, /* IFM_IEEE80211_MCS4 */
+ 104, /* IFM_IEEE80211_MCS5 */
+ 117, /* IFM_IEEE80211_MCS6 */
+ 130, /* IFM_IEEE80211_MCS7 */
+ 26, /* IFM_IEEE80211_MCS8 */
+ 52, /* IFM_IEEE80211_MCS9 */
+ 78, /* IFM_IEEE80211_MCS10 */
+ 104, /* IFM_IEEE80211_MCS11 */
+ 156, /* IFM_IEEE80211_MCS12 */
+ 208, /* IFM_IEEE80211_MCS13 */
+ 234, /* IFM_IEEE80211_MCS14 */
+ 260, /* IFM_IEEE80211_MCS15 */
+};
+#define PRINT_HT_RATE(_sep, _r, _suf) \
+ printf("%s%.1f%s", _sep, (.5 * ieee80211_htrates[(_r) & 0xf]), _suf)
+
static const char *auth_alg_text[]={"Open System","Shared Key","EAP"};
#define NUM_AUTH_ALGS (sizeof auth_alg_text / sizeof auth_alg_text[0])
static const char *status_text[] = {
- "Succesful", /* 0 */
- "Unspecified failure", /* 1 */
- "Reserved", /* 2 */
- "Reserved", /* 3 */
- "Reserved", /* 4 */
- "Reserved", /* 5 */
- "Reserved", /* 6 */
- "Reserved", /* 7 */
- "Reserved", /* 8 */
- "Reserved", /* 9 */
- "Cannot Support all requested capabilities in the Capability Information field", /* 10 */
- "Reassociation denied due to inability to confirm that association exists", /* 11 */
- "Association denied due to reason outside the scope of the standard", /* 12 */
- "Responding station does not support the specified authentication algorithm ", /* 13 */
- "Received an Authentication frame with authentication transaction " \
- "sequence number out of expected sequence", /* 14 */
- "Authentication rejected because of challenge failure", /* 15 */
- "Authentication rejected due to timeout waiting for next frame in sequence", /* 16 */
- "Association denied because AP is unable to handle additional associated stations", /* 17 */
- "Association denied due to requesting station not supporting all of the " \
- "data rates in BSSBasicRateSet parameter", /* 18 */
+ "Succesful", /* 0 */
+ "Unspecified failure", /* 1 */
+ "Reserved", /* 2 */
+ "Reserved", /* 3 */
+ "Reserved", /* 4 */
+ "Reserved", /* 5 */
+ "Reserved", /* 6 */
+ "Reserved", /* 7 */
+ "Reserved", /* 8 */
+ "Reserved", /* 9 */
+ "Cannot Support all requested capabilities in the Capability "
+ "Information field", /* 10 */
+ "Reassociation denied due to inability to confirm that association "
+ "exists", /* 11 */
+ "Association denied due to reason outside the scope of the "
+ "standard", /* 12 */
+ "Responding station does not support the specified authentication "
+ "algorithm ", /* 13 */
+ "Received an Authentication frame with authentication transaction "
+ "sequence number out of expected sequence", /* 14 */
+ "Authentication rejected because of challenge failure", /* 15 */
+ "Authentication rejected due to timeout waiting for next frame in "
+ "sequence", /* 16 */
+ "Association denied because AP is unable to handle additional"
+ "associated stations", /* 17 */
+ "Association denied due to requesting station not supporting all of "
+ "the data rates in BSSBasicRateSet parameter", /* 18 */
+ "Association denied due to requesting station not supporting "
+ "short preamble operation", /* 19 */
+ "Association denied due to requesting station not supporting "
+ "PBCC encoding", /* 20 */
+ "Association denied due to requesting station not supporting "
+ "channel agility", /* 21 */
+ "Association request rejected because Spectrum Management "
+ "capability is required", /* 22 */
+ "Association request rejected because the information in the "
+ "Power Capability element is unacceptable", /* 23 */
+ "Association request rejected because the information in the "
+ "Supported Channels element is unacceptable", /* 24 */
+ "Association denied due to requesting station not supporting "
+ "short slot operation", /* 25 */
+ "Association denied due to requesting station not supporting "
+ "DSSS-OFDM operation", /* 26 */
+ "Association denied because the requested STA does not support HT "
+ "features", /* 27 */
+ "Reserved", /* 28 */
+ "Association denied because the requested STA does not support "
+ "the PCO transition time required by the AP", /* 29 */
+ "Reserved", /* 30 */
+ "Reserved", /* 31 */
+ "Unspecified, QoS-related failure", /* 32 */
+ "Association denied due to QAP having insufficient bandwidth "
+ "to handle another QSTA", /* 33 */
+ "Association denied due to excessive frame loss rates and/or "
+ "poor conditions on current operating channel", /* 34 */
+ "Association (with QBSS) denied due to requesting station not "
+ "supporting the QoS facility", /* 35 */
+ "Association denied due to requesting station not supporting "
+ "Block Ack", /* 36 */
+ "The request has been declined", /* 37 */
+ "The request has not been successful as one or more parameters "
+ "have invalid values", /* 38 */
+ "The TS has not been created because the request cannot be honored. "
+ "However, a suggested TSPEC is provided so that the initiating QSTA"
+ "may attempt to set another TS with the suggested changes to the "
+ "TSPEC", /* 39 */
+ "Invalid Information Element", /* 40 */
+ "Group Cipher is not valid", /* 41 */
+ "Pairwise Cipher is not valid", /* 42 */
+ "AKMP is not valid", /* 43 */
+ "Unsupported RSN IE version", /* 44 */
+ "Invalid RSN IE Capabilities", /* 45 */
+ "Cipher suite is rejected per security policy", /* 46 */
+ "The TS has not been created. However, the HC may be capable of "
+ "creating a TS, in response to a request, after the time indicated "
+ "in the TS Delay element", /* 47 */
+ "Direct Link is not allowed in the BSS by policy", /* 48 */
+ "Destination STA is not present within this QBSS.", /* 49 */
+ "The Destination STA is not a QSTA.", /* 50 */
+
};
#define NUM_STATUSES (sizeof status_text / sizeof status_text[0])
static const char *reason_text[] = {
- "Reserved", /* 0 */
- "Unspecified reason", /* 1 */
- "Previous authentication no longer valid", /* 2 */
- "Deauthenticated because sending station is leaving (or has left) IBSS or ESS", /* 3 */
- "Disassociated due to inactivity", /* 4 */
- "Disassociated because AP is unable to handle all currently associated stations", /* 5 */
+ "Reserved", /* 0 */
+ "Unspecified reason", /* 1 */
+ "Previous authentication no longer valid", /* 2 */
+ "Deauthenticated because sending station is leaving (or has left) "
+ "IBSS or ESS", /* 3 */
+ "Disassociated due to inactivity", /* 4 */
+ "Disassociated because AP is unable to handle all currently "
+ " associated stations", /* 5 */
"Class 2 frame received from nonauthenticated station", /* 6 */
- "Class 3 frame received from nonassociated station", /* 7 */
- "Disassociated because sending station is leaving (or has left) BSS", /* 8 */
- "Station requesting (re)association is not authenticated with responding station", /* 9 */
+ "Class 3 frame received from nonassociated station", /* 7 */
+ "Disassociated because sending station is leaving "
+ "(or has left) BSS", /* 8 */
+ "Station requesting (re)association is not authenticated with "
+ "responding station", /* 9 */
+ "Disassociated because the information in the Power Capability "
+ "element is unacceptable", /* 10 */
+ "Disassociated because the information in the SupportedChannels "
+ "element is unacceptable", /* 11 */
+ "Invalid Information Element", /* 12 */
+ "Reserved", /* 13 */
+ "Michael MIC failure", /* 14 */
+ "4-Way Handshake timeout", /* 15 */
+ "Group key update timeout", /* 16 */
+ "Information element in 4-Way Handshake different from (Re)Association"
+ "Request/Probe Response/Beacon", /* 17 */
+ "Group Cipher is not valid", /* 18 */
+ "AKMP is not valid", /* 20 */
+ "Unsupported RSN IE version", /* 21 */
+ "Invalid RSN IE Capabilities", /* 22 */
+ "IEEE 802.1X Authentication failed", /* 23 */
+ "Cipher suite is rejected per security policy", /* 24 */
+ "Reserved", /* 25 */
+ "Reserved", /* 26 */
+ "Reserved", /* 27 */
+ "Reserved", /* 28 */
+ "Reserved", /* 29 */
+ "Reserved", /* 30 */
+ "TS deleted because QoS AP lacks sufficient bandwidth for this "
+ "QoS STA due to a change in BSS service characteristics or "
+ "operational mode (e.g. an HT BSS change from 40 MHz channel "
+ "to 20 MHz channel)", /* 31 */
+ "Disassociated for unspecified, QoS-related reason", /* 32 */
+ "Disassociated because QoS AP lacks sufficient bandwidth for this "
+ "QoS STA", /* 33 */
+ "Disassociated because of excessive number of frames that need to be "
+ "acknowledged, but are not acknowledged for AP transmissions "
+ "and/or poor channel conditions", /* 34 */
+ "Disassociated because STA is transmitting outside the limits "
+ "of its TXOPs", /* 35 */
+ "Requested from peer STA as the STA is leaving the BSS "
+ "(or resetting)", /* 36 */
+ "Requested from peer STA as it does not want to use the "
+ "mechanism", /* 37 */
+ "Requested from peer STA as the STA received frames using the "
+ "mechanism for which a set up is required", /* 38 */
+ "Requested from peer STA due to time out", /* 39 */
+ "Reserved", /* 40 */
+ "Reserved", /* 41 */
+ "Reserved", /* 42 */
+ "Reserved", /* 43 */
+ "Reserved", /* 44 */
+ "Peer STA does not support the requested cipher suite", /* 45 */
+ "Association denied due to requesting STA not supporting HT "
+ "features", /* 46 */
};
#define NUM_REASONS (sizeof reason_text / sizeof reason_text[0])
@@ -152,141 +265,240 @@ wep_print(const u_char *p)
return 1;
}
-static void
-parse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset)
+static int
+parse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset,
+ u_int length)
{
+ struct ssid_t ssid;
+ struct challenge_t challenge;
+ struct rates_t rates;
+ struct ds_t ds;
+ struct cf_t cf;
+ struct tim_t tim;
+
/*
* We haven't seen any elements yet.
*/
- pbody->challenge_status = NOT_PRESENT;
- pbody->ssid_status = NOT_PRESENT;
- pbody->rates_status = NOT_PRESENT;
- pbody->ds_status = NOT_PRESENT;
- pbody->cf_status = NOT_PRESENT;
- pbody->tim_status = NOT_PRESENT;
-
- for (;;) {
+ pbody->challenge_present = 0;
+ pbody->ssid_present = 0;
+ pbody->rates_present = 0;
+ pbody->ds_present = 0;
+ pbody->cf_present = 0;
+ pbody->tim_present = 0;
+
+ while (length != 0) {
if (!TTEST2(*(p + offset), 1))
- return;
+ return 0;
+ if (length < 1)
+ return 0;
switch (*(p + offset)) {
case E_SSID:
- /* Present, possibly truncated */
- pbody->ssid_status = TRUNCATED;
if (!TTEST2(*(p + offset), 2))
- return;
- memcpy(&pbody->ssid, p + offset, 2);
+ return 0;
+ if (length < 2)
+ return 0;
+ memcpy(&ssid, p + offset, 2);
offset += 2;
- if (pbody->ssid.length != 0) {
- if (pbody->ssid.length >
- sizeof(pbody->ssid.ssid) - 1)
- return;
- if (!TTEST2(*(p + offset), pbody->ssid.length))
- return;
- memcpy(&pbody->ssid.ssid, p + offset,
- pbody->ssid.length);
- offset += pbody->ssid.length;
+ length -= 2;
+ if (ssid.length != 0) {
+ if (ssid.length > sizeof(ssid.ssid) - 1)
+ return 0;
+ if (!TTEST2(*(p + offset), ssid.length))
+ return 0;
+ if (length < ssid.length)
+ return 0;
+ memcpy(&ssid.ssid, p + offset, ssid.length);
+ offset += ssid.length;
+ length -= ssid.length;
+ }
+ ssid.ssid[ssid.length] = '\0';
+ /*
+ * Present and not truncated.
+ *
+ * If we haven't already seen an SSID IE,
+ * copy this one, otherwise ignore this one,
+ * so we later report the first one we saw.
+ */
+ if (!pbody->ssid_present) {
+ pbody->ssid = ssid;
+ pbody->ssid_present = 1;
}
- pbody->ssid.ssid[pbody->ssid.length] = '\0';
- /* Present and not truncated */
- pbody->ssid_status = PRESENT;
break;
case E_CHALLENGE:
- /* Present, possibly truncated */
- pbody->challenge_status = TRUNCATED;
if (!TTEST2(*(p + offset), 2))
- return;
- memcpy(&pbody->challenge, p + offset, 2);
+ return 0;
+ if (length < 2)
+ return 0;
+ memcpy(&challenge, p + offset, 2);
offset += 2;
- if (pbody->challenge.length != 0) {
- if (pbody->challenge.length >
- sizeof(pbody->challenge.text) - 1)
- return;
- if (!TTEST2(*(p + offset), pbody->challenge.length))
- return;
- memcpy(&pbody->challenge.text, p + offset,
- pbody->challenge.length);
- offset += pbody->challenge.length;
+ length -= 2;
+ if (challenge.length != 0) {
+ if (challenge.length >
+ sizeof(challenge.text) - 1)
+ return 0;
+ if (!TTEST2(*(p + offset), challenge.length))
+ return 0;
+ if (length < challenge.length)
+ return 0;
+ memcpy(&challenge.text, p + offset,
+ challenge.length);
+ offset += challenge.length;
+ length -= challenge.length;
+ }
+ challenge.text[challenge.length] = '\0';
+ /*
+ * Present and not truncated.
+ *
+ * If we haven't already seen a challenge IE,
+ * copy this one, otherwise ignore this one,
+ * so we later report the first one we saw.
+ */
+ if (!pbody->challenge_present) {
+ pbody->challenge = challenge;
+ pbody->challenge_present = 1;
}
- pbody->challenge.text[pbody->challenge.length] = '\0';
- /* Present and not truncated */
- pbody->challenge_status = PRESENT;
break;
case E_RATES:
- /* Present, possibly truncated */
- pbody->rates_status = TRUNCATED;
if (!TTEST2(*(p + offset), 2))
- return;
- memcpy(&(pbody->rates), p + offset, 2);
+ return 0;
+ if (length < 2)
+ return 0;
+ memcpy(&rates, p + offset, 2);
offset += 2;
- if (pbody->rates.length != 0) {
- if (pbody->rates.length > sizeof pbody->rates.rate)
- return;
- if (!TTEST2(*(p + offset), pbody->rates.length))
- return;
- memcpy(&pbody->rates.rate, p + offset,
- pbody->rates.length);
- offset += pbody->rates.length;
+ length -= 2;
+ if (rates.length != 0) {
+ if (rates.length > sizeof rates.rate)
+ return 0;
+ if (!TTEST2(*(p + offset), rates.length))
+ return 0;
+ if (length < rates.length)
+ return 0;
+ memcpy(&rates.rate, p + offset, rates.length);
+ offset += rates.length;
+ length -= rates.length;
+ }
+ /*
+ * Present and not truncated.
+ *
+ * If we haven't already seen a rates IE,
+ * copy this one if it's not zero-length,
+ * otherwise ignore this one, so we later
+ * report the first one we saw.
+ *
+ * We ignore zero-length rates IEs as some
+ * devices seem to put a zero-length rates
+ * IE, followed by an SSID IE, followed by
+ * a non-zero-length rates IE into frames,
+ * even though IEEE Std 802.11-2007 doesn't
+ * seem to indicate that a zero-length rates
+ * IE is valid.
+ */
+ if (!pbody->rates_present && rates.length != 0) {
+ pbody->rates = rates;
+ pbody->rates_present = 1;
}
- /* Present and not truncated */
- pbody->rates_status = PRESENT;
break;
case E_DS:
- /* Present, possibly truncated */
- pbody->ds_status = TRUNCATED;
if (!TTEST2(*(p + offset), 3))
- return;
- memcpy(&pbody->ds, p + offset, 3);
+ return 0;
+ if (length < 3)
+ return 0;
+ memcpy(&ds, p + offset, 3);
offset += 3;
- /* Present and not truncated */
- pbody->ds_status = PRESENT;
+ length -= 3;
+ /*
+ * Present and not truncated.
+ *
+ * If we haven't already seen a DS IE,
+ * copy this one, otherwise ignore this one,
+ * so we later report the first one we saw.
+ */
+ if (!pbody->ds_present) {
+ pbody->ds = ds;
+ pbody->ds_present = 1;
+ }
break;
case E_CF:
- /* Present, possibly truncated */
- pbody->cf_status = TRUNCATED;
if (!TTEST2(*(p + offset), 8))
- return;
- memcpy(&pbody->cf, p + offset, 8);
+ return 0;
+ if (length < 8)
+ return 0;
+ memcpy(&cf, p + offset, 8);
offset += 8;
- /* Present and not truncated */
- pbody->cf_status = PRESENT;
+ length -= 8;
+ /*
+ * Present and not truncated.
+ *
+ * If we haven't already seen a CF IE,
+ * copy this one, otherwise ignore this one,
+ * so we later report the first one we saw.
+ */
+ if (!pbody->cf_present) {
+ pbody->cf = cf;
+ pbody->cf_present = 1;
+ }
break;
case E_TIM:
- /* Present, possibly truncated */
- pbody->tim_status = TRUNCATED;
if (!TTEST2(*(p + offset), 2))
- return;
- memcpy(&pbody->tim, p + offset, 2);
+ return 0;
+ if (length < 2)
+ return 0;
+ memcpy(&tim, p + offset, 2);
offset += 2;
+ length -= 2;
if (!TTEST2(*(p + offset), 3))
- return;
- memcpy(&pbody->tim.count, p + offset, 3);
+ return 0;
+ if (length < 3)
+ return 0;
+ memcpy(&tim.count, p + offset, 3);
offset += 3;
+ length -= 3;
- if (pbody->tim.length <= 3)
+ if (tim.length <= 3)
break;
- if (pbody->tim.length - 3 > (int)sizeof pbody->tim.bitmap)
- return;
- if (!TTEST2(*(p + offset), pbody->tim.length - 3))
- return;
- memcpy(pbody->tim.bitmap, p + (pbody->tim.length - 3),
- (pbody->tim.length - 3));
- offset += pbody->tim.length - 3;
- /* Present and not truncated */
- pbody->tim_status = PRESENT;
+ if (tim.length - 3 > (int)sizeof tim.bitmap)
+ return 0;
+ if (!TTEST2(*(p + offset), tim.length - 3))
+ return 0;
+ if (length < (u_int)(tim.length - 3))
+ return 0;
+ memcpy(tim.bitmap, p + (tim.length - 3),
+ (tim.length - 3));
+ offset += tim.length - 3;
+ length -= tim.length - 3;
+ /*
+ * Present and not truncated.
+ *
+ * If we haven't already seen a TIM IE,
+ * copy this one, otherwise ignore this one,
+ * so we later report the first one we saw.
+ */
+ if (!pbody->tim_present) {
+ pbody->tim = tim;
+ pbody->tim_present = 1;
+ }
break;
default:
#if 0
printf("(1) unhandled element_id (%d) ",
- *(p + offset) );
+ *(p + offset));
#endif
if (!TTEST2(*(p + offset), 2))
- return;
+ return 0;
+ if (length < 2)
+ return 0;
if (!TTEST2(*(p + offset + 2), *(p + offset + 1)))
- return;
+ return 0;
+ if (length < (u_int)(*(p + offset + 1) + 2))
+ return 0;
offset += *(p + offset + 1) + 2;
+ length -= *(p + offset + 1) + 2;
break;
}
}
+
+ /* No problems found. */
+ return 1;
}
/*********************************************************************************
@@ -294,24 +506,31 @@ parse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset)
*********************************************************************************/
static int
-handle_beacon(const u_char *p)
+handle_beacon(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
+ int ret;
memset(&pbody, 0, sizeof(pbody));
if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
IEEE802_11_CAPINFO_LEN))
return 0;
+ if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
+ IEEE802_11_CAPINFO_LEN)
+ return 0;
memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
offset += IEEE802_11_TSTAMP_LEN;
+ length -= IEEE802_11_TSTAMP_LEN;
pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_BCNINT_LEN;
+ length -= IEEE802_11_BCNINT_LEN;
pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_CAPINFO_LEN;
+ length -= IEEE802_11_CAPINFO_LEN;
- parse_elements(&pbody, p, offset);
+ ret = parse_elements(&pbody, p, offset, length);
PRINT_SSID(pbody);
PRINT_RATES(pbody);
@@ -319,50 +538,62 @@ handle_beacon(const u_char *p)
CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS");
PRINT_DS_CHANNEL(pbody);
- return 1;
+ return ret;
}
static int
-handle_assoc_request(const u_char *p)
+handle_assoc_request(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
+ int ret;
memset(&pbody, 0, sizeof(pbody));
if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN))
return 0;
+ if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN)
+ return 0;
pbody.capability_info = EXTRACT_LE_16BITS(p);
offset += IEEE802_11_CAPINFO_LEN;
+ length -= IEEE802_11_CAPINFO_LEN;
pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_LISTENINT_LEN;
+ length -= IEEE802_11_LISTENINT_LEN;
- parse_elements(&pbody, p, offset);
+ ret = parse_elements(&pbody, p, offset, length);
PRINT_SSID(pbody);
PRINT_RATES(pbody);
- return 1;
+ return ret;
}
static int
-handle_assoc_response(const u_char *p)
+handle_assoc_response(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
+ int ret;
memset(&pbody, 0, sizeof(pbody));
if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
IEEE802_11_AID_LEN))
return 0;
+ if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
+ IEEE802_11_AID_LEN)
+ return 0;
pbody.capability_info = EXTRACT_LE_16BITS(p);
offset += IEEE802_11_CAPINFO_LEN;
+ length -= IEEE802_11_CAPINFO_LEN;
pbody.status_code = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_STATUS_LEN;
+ length -= IEEE802_11_STATUS_LEN;
pbody.aid = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_AID_LEN;
+ length -= IEEE802_11_AID_LEN;
- parse_elements(&pbody, p, offset);
+ ret = parse_elements(&pbody, p, offset, length);
printf(" AID(%x) :%s: %s", ((u_int16_t)(pbody.aid << 2 )) >> 2 ,
CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "",
@@ -370,84 +601,98 @@ handle_assoc_response(const u_char *p)
? status_text[pbody.status_code]
: "n/a"));
- return 1;
+ return ret;
}
static int
-handle_reassoc_request(const u_char *p)
+handle_reassoc_request(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
+ int ret;
memset(&pbody, 0, sizeof(pbody));
if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
IEEE802_11_AP_LEN))
return 0;
+ if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
+ IEEE802_11_AP_LEN)
+ return 0;
pbody.capability_info = EXTRACT_LE_16BITS(p);
offset += IEEE802_11_CAPINFO_LEN;
+ length -= IEEE802_11_CAPINFO_LEN;
pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_LISTENINT_LEN;
+ length -= IEEE802_11_LISTENINT_LEN;
memcpy(&pbody.ap, p+offset, IEEE802_11_AP_LEN);
offset += IEEE802_11_AP_LEN;
+ length -= IEEE802_11_AP_LEN;
- parse_elements(&pbody, p, offset);
+ ret = parse_elements(&pbody, p, offset, length);
PRINT_SSID(pbody);
printf(" AP : %s", etheraddr_string( pbody.ap ));
- return 1;
+ return ret;
}
static int
-handle_reassoc_response(const u_char *p)
+handle_reassoc_response(const u_char *p, u_int length)
{
/* Same as a Association Reponse */
- return handle_assoc_response(p);
+ return handle_assoc_response(p, length);
}
static int
-handle_probe_request(const u_char *p)
+handle_probe_request(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
+ int ret;
memset(&pbody, 0, sizeof(pbody));
- parse_elements(&pbody, p, offset);
+ ret = parse_elements(&pbody, p, offset, length);
PRINT_SSID(pbody);
PRINT_RATES(pbody);
- return 1;
+ return ret;
}
static int
-handle_probe_response(const u_char *p)
+handle_probe_response(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
+ int ret;
memset(&pbody, 0, sizeof(pbody));
if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
IEEE802_11_CAPINFO_LEN))
return 0;
-
+ if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
+ IEEE802_11_CAPINFO_LEN)
+ return 0;
memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
offset += IEEE802_11_TSTAMP_LEN;
+ length -= IEEE802_11_TSTAMP_LEN;
pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_BCNINT_LEN;
+ length -= IEEE802_11_BCNINT_LEN;
pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
offset += IEEE802_11_CAPINFO_LEN;
+ length -= IEEE802_11_CAPINFO_LEN;
- parse_elements(&pbody, p, offset);
+ ret = parse_elements(&pbody, p, offset, length);
PRINT_SSID(pbody);
PRINT_RATES(pbody);
PRINT_DS_CHANNEL(pbody);
- return 1;
+ return ret;
}
static int
@@ -458,7 +703,7 @@ handle_atim(void)
}
static int
-handle_disassoc(const u_char *p)
+handle_disassoc(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
@@ -466,6 +711,8 @@ handle_disassoc(const u_char *p)
if (!TTEST2(*p, IEEE802_11_REASON_LEN))
return 0;
+ if (length < IEEE802_11_REASON_LEN)
+ return 0;
pbody.reason_code = EXTRACT_LE_16BITS(p);
printf(": %s",
@@ -477,23 +724,29 @@ handle_disassoc(const u_char *p)
}
static int
-handle_auth(const u_char *p)
+handle_auth(const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
+ int ret;
memset(&pbody, 0, sizeof(pbody));
if (!TTEST2(*p, 6))
return 0;
+ if (length < 6)
+ return 0;
pbody.auth_alg = EXTRACT_LE_16BITS(p);
offset += 2;
+ length -= 2;
pbody.auth_trans_seq_num = EXTRACT_LE_16BITS(p + offset);
offset += 2;
+ length -= 2;
pbody.status_code = EXTRACT_LE_16BITS(p + offset);
offset += 2;
+ length -= 2;
- parse_elements(&pbody, p, offset);
+ ret = parse_elements(&pbody, p, offset, length);
if ((pbody.auth_alg == 1) &&
((pbody.auth_trans_seq_num == 2) ||
@@ -507,7 +760,7 @@ handle_auth(const u_char *p)
? ((pbody.status_code < NUM_STATUSES)
? status_text[pbody.status_code]
: "n/a") : ""));
- return 1;
+ return ret;
}
printf(" (%s)-%x: %s",
(pbody.auth_alg < NUM_AUTH_ALGS)
@@ -520,11 +773,11 @@ handle_auth(const u_char *p)
: "n/a")
: "");
- return 1;
+ return ret;
}
static int
-handle_deauth(const struct mgmt_header_t *pmh, const u_char *p)
+handle_deauth(const struct mgmt_header_t *pmh, const u_char *p, u_int length)
{
struct mgmt_body_t pbody;
int offset = 0;
@@ -534,8 +787,11 @@ handle_deauth(const struct mgmt_header_t *pmh, const u_char *p)
if (!TTEST2(*p, IEEE802_11_REASON_LEN))
return 0;
+ if (length < IEEE802_11_REASON_LEN)
+ return 0;
pbody.reason_code = EXTRACT_LE_16BITS(p);
offset += IEEE802_11_REASON_LEN;
+ length -= IEEE802_11_REASON_LEN;
reason = (pbody.reason_code < NUM_REASONS)
? reason_text[pbody.reason_code]
@@ -549,6 +805,68 @@ handle_deauth(const struct mgmt_header_t *pmh, const u_char *p)
return 1;
}
+#define PRINT_HT_ACTION(v) (\
+ (v) == 0 ? printf("TxChWidth") : \
+ (v) == 1 ? printf("MIMOPwrSave") : \
+ printf("Act#%d", (v)) \
+)
+#define PRINT_BA_ACTION(v) (\
+ (v) == 0 ? printf("ADDBA Request") : \
+ (v) == 1 ? printf("ADDBA Response") : \
+ (v) == 2 ? printf("DELBA") : \
+ printf("Act#%d", (v)) \
+)
+#define PRINT_MESHLINK_ACTION(v) (\
+ (v) == 0 ? printf("Request") : \
+ (v) == 1 ? printf("Report") : \
+ printf("Act#%d", (v)) \
+)
+#define PRINT_MESHPEERING_ACTION(v) (\
+ (v) == 0 ? printf("Open") : \
+ (v) == 1 ? printf("Confirm") : \
+ (v) == 2 ? printf("Close") : \
+ printf("Act#%d", (v)) \
+)
+#define PRINT_MESHPATH_ACTION(v) (\
+ (v) == 0 ? printf("Request") : \
+ (v) == 1 ? printf("Report") : \
+ (v) == 2 ? printf("Error") : \
+ (v) == 3 ? printf("RootAnnouncement") : \
+ printf("Act#%d", (v)) \
+)
+
+static int
+handle_action(const struct mgmt_header_t *pmh, const u_char *p, u_int length)
+{
+ if (!TTEST2(*p, 2))
+ return 0;
+ if (length < 2)
+ return 0;
+ if (eflag) {
+ printf(": ");
+ } else {
+ printf(" (%s): ", etheraddr_string(pmh->sa));
+ }
+ switch (p[0]) {
+ case 0: printf("Spectrum Management Act#%d", p[1]); break;
+ case 1: printf("QoS Act#%d", p[1]); break;
+ case 2: printf("DLS Act#%d", p[1]); break;
+ case 3: printf("BA "); PRINT_BA_ACTION(p[1]); break;
+ case 7: printf("HT "); PRINT_HT_ACTION(p[1]); break;
+ case 13: printf("MeshLMetric "); PRINT_MESHLINK_ACTION(p[1]); break;
+ case 15: printf("Interwork Act#%d", p[1]); break;
+ case 16: printf("Resource Act#%d", p[1]); break;
+ case 17: printf("Proxy Act#%d", p[1]); break;
+ case 30: printf("MeshPeering "); PRINT_MESHPEERING_ACTION(p[1]); break;
+ case 32: printf("MeshPath "); PRINT_MESHPATH_ACTION(p[1]); break;
+ case 127: printf("Vendor Act#%d", p[1]); break;
+ default:
+ printf("Reserved(%d) Act#%d", p[0], p[1]);
+ break;
+ }
+ return 1;
+}
+
/*********************************************************************************
* Print Body funcs
@@ -557,36 +875,36 @@ handle_deauth(const struct mgmt_header_t *pmh, const u_char *p)
static int
mgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh,
- const u_char *p)
+ const u_char *p, u_int length)
{
switch (FC_SUBTYPE(fc)) {
case ST_ASSOC_REQUEST:
printf("Assoc Request");
- return handle_assoc_request(p);
+ return handle_assoc_request(p, length);
case ST_ASSOC_RESPONSE:
printf("Assoc Response");
- return handle_assoc_response(p);
+ return handle_assoc_response(p, length);
case ST_REASSOC_REQUEST:
printf("ReAssoc Request");
- return handle_reassoc_request(p);
+ return handle_reassoc_request(p, length);
case ST_REASSOC_RESPONSE:
printf("ReAssoc Response");
- return handle_reassoc_response(p);
+ return handle_reassoc_response(p, length);
case ST_PROBE_REQUEST:
printf("Probe Request");
- return handle_probe_request(p);
+ return handle_probe_request(p, length);
case ST_PROBE_RESPONSE:
printf("Probe Response");
- return handle_probe_response(p);
+ return handle_probe_response(p, length);
case ST_BEACON:
printf("Beacon");
- return handle_beacon(p);
+ return handle_beacon(p, length);
case ST_ATIM:
printf("ATIM");
return handle_atim();
case ST_DISASSOC:
printf("Disassociation");
- return handle_disassoc(p);
+ return handle_disassoc(p, length);
case ST_AUTH:
printf("Authentication");
if (!TTEST2(*p, 3))
@@ -595,10 +913,14 @@ mgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh,
printf("Authentication (Shared-Key)-3 ");
return wep_print(p);
}
- return handle_auth(p);
+ return handle_auth(p, length);
case ST_DEAUTH:
printf("DeAuthentication");
- return handle_deauth(pmh, p);
+ return handle_deauth(pmh, p, length);
+ break;
+ case ST_ACTION:
+ printf("Action");
+ return handle_action(pmh, p, length);
break;
default:
printf("Unhandled Management subtype(%x)",
@@ -616,6 +938,29 @@ static int
ctrl_body_print(u_int16_t fc, const u_char *p)
{
switch (FC_SUBTYPE(fc)) {
+ case CTRL_CONTROL_WRAPPER:
+ printf("Control Wrapper");
+ /* XXX - requires special handling */
+ break;
+ case CTRL_BAR:
+ printf("BAR");
+ if (!TTEST2(*p, CTRL_BAR_HDRLEN))
+ return 0;
+ if (!eflag)
+ printf(" RA:%s TA:%s CTL(%x) SEQ(%u) ",
+ etheraddr_string(((const struct ctrl_bar_t *)p)->ra),
+ etheraddr_string(((const struct ctrl_bar_t *)p)->ta),
+ EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->ctl)),
+ EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->seq)));
+ break;
+ case CTRL_BA:
+ printf("BA");
+ if (!TTEST2(*p, CTRL_BA_HDRLEN))
+ return 0;
+ if (!eflag)
+ printf(" RA:%s ",
+ etheraddr_string(((const struct ctrl_ba_t *)p)->ra));
+ break;
case CTRL_PS_POLL:
printf("Power Save-Poll");
if (!TTEST2(*p, CTRL_PS_POLL_HDRLEN))
@@ -789,6 +1134,17 @@ ctrl_header_print(u_int16_t fc, const u_char *p, const u_int8_t **srcp,
return;
switch (FC_SUBTYPE(fc)) {
+ case CTRL_BAR:
+ printf(" RA:%s TA:%s CTL(%x) SEQ(%u) ",
+ etheraddr_string(((const struct ctrl_bar_t *)p)->ra),
+ etheraddr_string(((const struct ctrl_bar_t *)p)->ta),
+ EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->ctl)),
+ EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->seq)));
+ break;
+ case CTRL_BA:
+ printf("RA:%s ",
+ etheraddr_string(((const struct ctrl_ba_t *)p)->ra));
+ break;
case CTRL_PS_POLL:
printf("BSSID:%s TA:%s ",
etheraddr_string(((const struct ctrl_ps_poll_t *)p)->bssid),
@@ -833,6 +1189,8 @@ extract_header_length(u_int16_t fc)
return MGMT_HDRLEN;
case T_CTRL:
switch (FC_SUBTYPE(fc)) {
+ case CTRL_BAR:
+ return CTRL_BAR_HDRLEN;
case CTRL_PS_POLL:
return CTRL_PS_POLL_HDRLEN;
case CTRL_RTS:
@@ -859,14 +1217,20 @@ extract_header_length(u_int16_t fc)
}
}
+static int
+extract_mesh_header_length(const u_char *p)
+{
+ return (p[0] &~ 3) ? 0 : 6*(1 + (p[0] & 3));
+}
+
/*
* Print the 802.11 MAC header if eflag is set, and set "*srcp" and "*dstp"
* to point to the source and destination MAC addresses in any case if
* "srcp" and "dstp" aren't null.
*/
-static inline void
-ieee_802_11_hdr_print(u_int16_t fc, const u_char *p, const u_int8_t **srcp,
- const u_int8_t **dstp)
+static void
+ieee_802_11_hdr_print(u_int16_t fc, const u_char *p, u_int hdrlen,
+ u_int meshdrlen, const u_int8_t **srcp, const u_int8_t **dstp)
{
if (vflag) {
if (FC_MORE_DATA(fc))
@@ -886,6 +1250,21 @@ ieee_802_11_hdr_print(u_int16_t fc, const u_char *p, const u_int8_t **srcp,
EXTRACT_LE_16BITS(
&((const struct mgmt_header_t *)p)->duration));
}
+ if (meshdrlen != 0) {
+ const struct meshcntl_t *mc =
+ (const struct meshcntl_t *)&p[hdrlen - meshdrlen];
+ int ae = mc->flags & 3;
+
+ printf("MeshData (AE %d TTL %u seq %u", ae, mc->ttl,
+ EXTRACT_LE_32BITS(mc->seq));
+ if (ae > 0)
+ printf(" A4:%s", etheraddr_string(mc->addr4));
+ if (ae > 1)
+ printf(" A5:%s", etheraddr_string(mc->addr5));
+ if (ae > 2)
+ printf(" A6:%s", etheraddr_string(mc->addr6));
+ printf(") ");
+ }
switch (FC_TYPE(fc)) {
case T_MGMT:
@@ -911,29 +1290,50 @@ ieee_802_11_hdr_print(u_int16_t fc, const u_char *p, const u_int8_t **srcp,
#endif
static u_int
-ieee802_11_print(const u_char *p, u_int length, u_int caplen, int pad)
+ieee802_11_print(const u_char *p, u_int length, u_int orig_caplen, int pad,
+ u_int fcslen)
{
u_int16_t fc;
- u_int hdrlen;
+ u_int caplen, hdrlen, meshdrlen;
const u_int8_t *src, *dst;
u_short extracted_ethertype;
- if (caplen < IEEE802_11_FC_LEN) {
+ caplen = orig_caplen;
+ /* Remove FCS, if present */
+ if (length < fcslen) {
printf("[|802.11]");
return caplen;
}
+ length -= fcslen;
+ if (caplen > length) {
+ /* Amount of FCS in actual packet data, if any */
+ fcslen = caplen - length;
+ caplen -= fcslen;
+ snapend -= fcslen;
+ }
+
+ if (caplen < IEEE802_11_FC_LEN) {
+ printf("[|802.11]");
+ return orig_caplen;
+ }
fc = EXTRACT_LE_16BITS(p);
hdrlen = extract_header_length(fc);
if (pad)
hdrlen = roundup2(hdrlen, 4);
+ if (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) {
printf("[|802.11]");
return hdrlen;
}
- ieee_802_11_hdr_print(fc, p, &src, &dst);
+ ieee_802_11_hdr_print(fc, p, hdrlen, meshdrlen, &src, &dst);
/*
* Go past the 802.11 header.
@@ -945,7 +1345,7 @@ ieee802_11_print(const u_char *p, u_int length, u_int caplen, int pad)
switch (FC_TYPE(fc)) {
case T_MGMT:
if (!mgmt_body_print(fc,
- (const struct mgmt_header_t *)(p - hdrlen), p)) {
+ (const struct mgmt_header_t *)(p - hdrlen), p, length)) {
printf("[|802.11]");
return hdrlen;
}
@@ -972,8 +1372,8 @@ ieee802_11_print(const u_char *p, u_int length, u_int caplen, int pad)
* handle intelligently
*/
if (!eflag)
- ieee_802_11_hdr_print(fc, p - hdrlen, NULL,
- NULL);
+ ieee_802_11_hdr_print(fc, p - hdrlen, hdrlen,
+ meshdrlen, NULL, NULL);
if (extracted_ethertype)
printf("(LLC %s) ",
etherproto_string(
@@ -999,11 +1399,69 @@ ieee802_11_print(const u_char *p, u_int length, u_int caplen, int pad)
u_int
ieee802_11_if_print(const struct pcap_pkthdr *h, const u_char *p)
{
- return ieee802_11_print(p, h->len, h->caplen, 0);
+ return ieee802_11_print(p, h->len, h->caplen, 0, 0);
+}
+
+#define IEEE80211_CHAN_FHSS \
+ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK)
+#define IEEE80211_CHAN_A \
+ (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
+#define IEEE80211_CHAN_B \
+ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
+#define IEEE80211_CHAN_PUREG \
+ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
+#define IEEE80211_CHAN_G \
+ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
+
+#define IS_CHAN_FHSS(flags) \
+ ((flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS)
+#define IS_CHAN_A(flags) \
+ ((flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)
+#define IS_CHAN_B(flags) \
+ ((flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)
+#define IS_CHAN_PUREG(flags) \
+ ((flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG)
+#define IS_CHAN_G(flags) \
+ ((flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
+#define IS_CHAN_ANYG(flags) \
+ (IS_CHAN_PUREG(flags) || IS_CHAN_G(flags))
+
+static void
+print_chaninfo(int freq, int flags)
+{
+ printf("%u MHz", freq);
+ if (IS_CHAN_FHSS(flags))
+ printf(" FHSS");
+ if (IS_CHAN_A(flags)) {
+ if (flags & IEEE80211_CHAN_HALF)
+ printf(" 11a/10Mhz");
+ else if (flags & IEEE80211_CHAN_QUARTER)
+ printf(" 11a/5Mhz");
+ else
+ printf(" 11a");
+ }
+ if (IS_CHAN_ANYG(flags)) {
+ if (flags & IEEE80211_CHAN_HALF)
+ printf(" 11g/10Mhz");
+ else if (flags & IEEE80211_CHAN_QUARTER)
+ printf(" 11g/5Mhz");
+ else
+ printf(" 11g");
+ } else if (IS_CHAN_B(flags))
+ printf(" 11b");
+ if (flags & IEEE80211_CHAN_TURBO)
+ printf(" Turbo");
+ if (flags & IEEE80211_CHAN_HT20)
+ printf(" ht/20");
+ else if (flags & IEEE80211_CHAN_HT40D)
+ printf(" ht/40-");
+ else if (flags & IEEE80211_CHAN_HT40U)
+ printf(" ht/40+");
+ printf(" ");
}
static int
-print_radiotap_field(struct cpack_state *s, u_int32_t bit, int *pad)
+print_radiotap_field(struct cpack_state *s, u_int32_t bit, u_int8_t *flags)
{
union {
int8_t i8;
@@ -1012,14 +1470,13 @@ print_radiotap_field(struct cpack_state *s, u_int32_t bit, int *pad)
u_int16_t u16;
u_int32_t u32;
u_int64_t u64;
- } u, u2;
+ } u, u2, u3, u4;
int rc;
switch (bit) {
case IEEE80211_RADIOTAP_FLAGS:
rc = cpack_uint8(s, &u.u8);
- if (u.u8 & IEEE80211_RADIOTAP_F_DATAPAD)
- *pad = 1;
+ *flags = u.u8;
break;
case IEEE80211_RADIOTAP_RATE:
case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
@@ -1051,12 +1508,24 @@ print_radiotap_field(struct cpack_state *s, u_int32_t bit, int *pad)
case IEEE80211_RADIOTAP_TSFT:
rc = cpack_uint64(s, &u.u64);
break;
+ case IEEE80211_RADIOTAP_XCHANNEL:
+ 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;
default:
/* this bit indicates a field whose
* size we do not know, so we cannot
- * proceed.
+ * proceed. Just print the bit number.
*/
- printf("[0x%08x] ", bit);
+ printf("[bit %u] ", bit);
return -1;
}
@@ -1067,15 +1536,16 @@ print_radiotap_field(struct cpack_state *s, u_int32_t bit, int *pad)
switch (bit) {
case IEEE80211_RADIOTAP_CHANNEL:
- printf("%u MHz ", u.u16);
- if (u2.u16 != 0)
- printf("(0x%04x) ", u2.u16);
+ print_chaninfo(u.u16, 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 ");
+ if (u.u8 & 0x80)
+ PRINT_HT_RATE("", u.u8, " Mb/s ");
+ else
+ PRINT_RATE("", u.u8, " Mb/s ");
break;
case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
printf("%ddB signal ", u.i8);
@@ -1119,6 +1589,9 @@ print_radiotap_field(struct cpack_state *s, u_int32_t bit, int *pad)
case IEEE80211_RADIOTAP_TSFT:
printf("%" PRIu64 "us tsft ", u.u64);
break;
+ case IEEE80211_RADIOTAP_XCHANNEL:
+ print_chaninfo(u2.u16, u.u32);
+ break;
}
return 0;
}
@@ -1131,7 +1604,7 @@ ieee802_11_radio_print(const u_char *p, u_int length, u_int caplen)
#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 BIT(n) (1U << n)
#define IS_EXTENDED(__p) \
(EXTRACT_LE_32BITS(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0
@@ -1143,7 +1616,9 @@ ieee802_11_radio_print(const u_char *p, u_int length, u_int caplen)
int bit0;
const u_char *iter;
u_int len;
+ u_int8_t flags;
int pad;
+ u_int fcslen;
if (caplen < sizeof(*hdr)) {
printf("[|802.11]");
@@ -1177,8 +1652,12 @@ ieee802_11_radio_print(const u_char *p, u_int length, u_int caplen)
return caplen;
}
+ /* Assume no flags */
+ flags = 0;
/* Assume no Atheros padding between 802.11 header and body */
pad = 0;
+ /* Assume no FCS at end of frame */
+ fcslen = 0;
for (bit0 = 0, presentp = &hdr->it_present; presentp <= last_presentp;
presentp++, bit0 += 32) {
for (present = EXTRACT_LE_32BITS(presentp); present;
@@ -1190,12 +1669,18 @@ ieee802_11_radio_print(const u_char *p, u_int length, u_int caplen)
bit = (enum ieee80211_radiotap_type)
(bit0 + BITNO_32(present ^ next_present));
- if (print_radiotap_field(&cpacker, bit, &pad) != 0)
+ if (print_radiotap_field(&cpacker, bit, &flags) != 0)
goto out;
}
}
+
+ if (flags & IEEE80211_RADIOTAP_F_DATAPAD)
+ pad = 1; /* Atheros padding */
+ if (flags & IEEE80211_RADIOTAP_F_FCS)
+ fcslen = 4; /* FCS at end of packet */
out:
- return len + ieee802_11_print(p + len, length - len, caplen - len, pad);
+ return len + ieee802_11_print(p + len, length - len, caplen - len, pad,
+ fcslen);
#undef BITNO_32
#undef BITNO_16
#undef BITNO_8
@@ -1231,7 +1716,7 @@ ieee802_11_avs_radio_print(const u_char *p, u_int length, u_int caplen)
}
return caphdr_len + ieee802_11_print(p + caphdr_len,
- length - caphdr_len, caplen - caphdr_len, 0);
+ length - caphdr_len, caplen - caphdr_len, 0, 0);
}
#define PRISM_HDR_LEN 144
@@ -1276,7 +1761,7 @@ prism_if_print(const struct pcap_pkthdr *h, const u_char *p)
}
return PRISM_HDR_LEN + ieee802_11_print(p + PRISM_HDR_LEN,
- length - PRISM_HDR_LEN, caplen - PRISM_HDR_LEN, 0);
+ length - PRISM_HDR_LEN, caplen - PRISM_HDR_LEN, 0, 0);
}
/*