diff options
Diffstat (limited to 'contrib/tcpdump/print-802_11.c')
-rw-r--r-- | contrib/tcpdump/print-802_11.c | 509 |
1 files changed, 331 insertions, 178 deletions
diff --git a/contrib/tcpdump/print-802_11.c b/contrib/tcpdump/print-802_11.c index bd89271..088840a 100644 --- a/contrib/tcpdump/print-802_11.c +++ b/contrib/tcpdump/print-802_11.c @@ -1,4 +1,3 @@ -/* $FreeBSD$ */ /* * Copyright (c) 2001 * Fortress Technologies, Inc. All rights reserved. @@ -23,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 @@ -48,51 +47,30 @@ 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" : "" ); @@ -287,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; } /********************************************************************************* @@ -429,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); @@ -454,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 " : "", @@ -505,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 @@ -593,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; @@ -601,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", @@ -612,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) || @@ -642,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) @@ -655,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; @@ -669,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] @@ -715,10 +836,12 @@ handle_deauth(const struct mgmt_header_t *pmh, const u_char *p) ) static int -handle_action(const struct mgmt_header_t *pmh, const u_char *p) +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 { @@ -752,36 +875,36 @@ handle_action(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)) @@ -790,14 +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); + return handle_action(pmh, p, length); break; default: printf("Unhandled Management subtype(%x)", @@ -815,6 +938,10 @@ 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)) @@ -1163,17 +1290,32 @@ ieee_802_11_hdr_print(u_int16_t fc, const u_char *p, u_int hdrlen, #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, meshdrlen; + 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); @@ -1203,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; } @@ -1257,7 +1399,7 @@ 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 \ @@ -1319,7 +1461,7 @@ print_chaninfo(int freq, int flags) } 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; @@ -1334,8 +1476,7 @@ print_radiotap_field(struct cpack_state *s, u_int32_t bit, int *pad) 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: @@ -1382,9 +1523,9 @@ print_radiotap_field(struct cpack_state *s, u_int32_t bit, int *pad) 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; } @@ -1463,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 @@ -1475,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]"); @@ -1509,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; @@ -1522,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 @@ -1563,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 @@ -1608,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); } /* |