X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/9678a1c75d3ee56b351b636e077fbe3c95b96a81..9f957a5883cb4c5c99cefa71b42fc9d2d27d73e1:/print-802_11.c diff --git a/print-802_11.c b/print-802_11.c index d8116474..2d8b16e9 100644 --- a/print-802_11.c +++ b/print-802_11.c @@ -20,6 +20,8 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ +/* \summary: IEEE 802.11 printer */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -982,9 +984,9 @@ wep_print(netdissect_options *ndo, { uint32_t iv; - if (!ND_TTEST2(*p, IEEE802_11_IV_LEN + IEEE802_11_KID_LEN)) + if (!ND_TTEST_LEN(p, IEEE802_11_IV_LEN + IEEE802_11_KID_LEN)) return 0; - iv = EXTRACT_LE_32BITS(p); + iv = EXTRACT_LE_U_4(p); ND_PRINT((ndo, " IV:%3x Pad %x KeyID %x", IV_IV(iv), IV_PAD(iv), IV_KEYID(iv))); @@ -1017,19 +1019,19 @@ parse_elements(netdissect_options *ndo, while (length != 0) { /* Make sure we at least have the element ID and length. */ - if (!ND_TTEST2(*(p + offset), 2)) + if (!ND_TTEST_2(p + offset)) return 0; if (length < 2) return 0; - elementlen = *(p + offset + 1); + elementlen = EXTRACT_U_1(p + offset + 1); /* Make sure we have the entire element. */ - if (!ND_TTEST2(*(p + offset + 2), elementlen)) + if (!ND_TTEST_LEN(p + offset + 2, elementlen)) return 0; if (length < elementlen + 2) return 0; - switch (*(p + offset)) { + switch (EXTRACT_U_1(p + offset)) { case E_SSID: memcpy(&ssid, p + offset, 2); offset += 2; @@ -1037,10 +1039,6 @@ parse_elements(netdissect_options *ndo, if (ssid.length != 0) { if (ssid.length > sizeof(ssid.ssid) - 1) return 0; - if (!ND_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; @@ -1066,10 +1064,6 @@ parse_elements(netdissect_options *ndo, if (challenge.length > sizeof(challenge.text) - 1) return 0; - if (!ND_TTEST2(*(p + offset), challenge.length)) - return 0; - if (length < challenge.length) - return 0; memcpy(&challenge.text, p + offset, challenge.length); offset += challenge.length; @@ -1095,10 +1089,6 @@ parse_elements(netdissect_options *ndo, if (rates.length != 0) { if (rates.length > sizeof rates.rate) return 0; - if (!ND_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; @@ -1133,7 +1123,7 @@ parse_elements(netdissect_options *ndo, length -= ds.length; break; } - ds.channel = *(p + offset); + ds.channel = EXTRACT_U_1(p + offset); offset += 1; length -= 1; /* @@ -1176,19 +1166,18 @@ parse_elements(netdissect_options *ndo, memcpy(&tim, p + offset, 2); offset += 2; length -= 2; - if (tim.length <= 3) { + if (tim.length <= 3U) { offset += tim.length; length -= tim.length; break; } - if (tim.length - 3 > (int)sizeof tim.bitmap) + if (tim.length - 3U > sizeof tim.bitmap) return 0; memcpy(&tim.count, p + offset, 3); offset += 3; length -= 3; - memcpy(tim.bitmap, p + (tim.length - 3), - (tim.length - 3)); + memcpy(tim.bitmap, p + offset, tim.length - 3); offset += tim.length - 3; length -= tim.length - 3; /* @@ -1232,8 +1221,7 @@ handle_beacon(netdissect_options *ndo, memset(&pbody, 0, sizeof(pbody)); - if (!ND_TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN + - IEEE802_11_CAPINFO_LEN)) + if (!ND_TTEST_LEN(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) @@ -1241,10 +1229,10 @@ handle_beacon(netdissect_options *ndo, 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); + pbody.beacon_interval = EXTRACT_LE_U_2(p + offset); offset += IEEE802_11_BCNINT_LEN; length -= IEEE802_11_BCNINT_LEN; - pbody.capability_info = EXTRACT_LE_16BITS(p+offset); + pbody.capability_info = EXTRACT_LE_U_2(p + offset); offset += IEEE802_11_CAPINFO_LEN; length -= IEEE802_11_CAPINFO_LEN; @@ -1269,14 +1257,14 @@ handle_assoc_request(netdissect_options *ndo, memset(&pbody, 0, sizeof(pbody)); - if (!ND_TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN)) + if (!ND_TTEST_LEN(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); + pbody.capability_info = EXTRACT_LE_U_2(p); offset += IEEE802_11_CAPINFO_LEN; length -= IEEE802_11_CAPINFO_LEN; - pbody.listen_interval = EXTRACT_LE_16BITS(p+offset); + pbody.listen_interval = EXTRACT_LE_U_2(p + offset); offset += IEEE802_11_LISTENINT_LEN; length -= IEEE802_11_LISTENINT_LEN; @@ -1297,19 +1285,18 @@ handle_assoc_response(netdissect_options *ndo, memset(&pbody, 0, sizeof(pbody)); - if (!ND_TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN + - IEEE802_11_AID_LEN)) + if (!ND_TTEST_LEN(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); + pbody.capability_info = EXTRACT_LE_U_2(p); offset += IEEE802_11_CAPINFO_LEN; length -= IEEE802_11_CAPINFO_LEN; - pbody.status_code = EXTRACT_LE_16BITS(p+offset); + pbody.status_code = EXTRACT_LE_U_2(p + offset); offset += IEEE802_11_STATUS_LEN; length -= IEEE802_11_STATUS_LEN; - pbody.aid = EXTRACT_LE_16BITS(p+offset); + pbody.aid = EXTRACT_LE_U_2(p + offset); offset += IEEE802_11_AID_LEN; length -= IEEE802_11_AID_LEN; @@ -1334,16 +1321,15 @@ handle_reassoc_request(netdissect_options *ndo, memset(&pbody, 0, sizeof(pbody)); - if (!ND_TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN + - IEEE802_11_AP_LEN)) + if (!ND_TTEST_LEN(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); + pbody.capability_info = EXTRACT_LE_U_2(p); offset += IEEE802_11_CAPINFO_LEN; length -= IEEE802_11_CAPINFO_LEN; - pbody.listen_interval = EXTRACT_LE_16BITS(p+offset); + pbody.listen_interval = EXTRACT_LE_U_2(p + offset); offset += IEEE802_11_LISTENINT_LEN; length -= IEEE802_11_LISTENINT_LEN; memcpy(&pbody.ap, p+offset, IEEE802_11_AP_LEN); @@ -1394,8 +1380,7 @@ handle_probe_response(netdissect_options *ndo, memset(&pbody, 0, sizeof(pbody)); - if (!ND_TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN + - IEEE802_11_CAPINFO_LEN)) + if (!ND_TTEST_LEN(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) @@ -1403,10 +1388,10 @@ handle_probe_response(netdissect_options *ndo, 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); + pbody.beacon_interval = EXTRACT_LE_U_2(p + offset); offset += IEEE802_11_BCNINT_LEN; length -= IEEE802_11_BCNINT_LEN; - pbody.capability_info = EXTRACT_LE_16BITS(p+offset); + pbody.capability_info = EXTRACT_LE_U_2(p + offset); offset += IEEE802_11_CAPINFO_LEN; length -= IEEE802_11_CAPINFO_LEN; @@ -1434,11 +1419,11 @@ handle_disassoc(netdissect_options *ndo, memset(&pbody, 0, sizeof(pbody)); - if (!ND_TTEST2(*p, IEEE802_11_REASON_LEN)) + if (!ND_TTEST_LEN(p, IEEE802_11_REASON_LEN)) return 0; if (length < IEEE802_11_REASON_LEN) return 0; - pbody.reason_code = EXTRACT_LE_16BITS(p); + pbody.reason_code = EXTRACT_LE_U_2(p); ND_PRINT((ndo, ": %s", (pbody.reason_code < NUM_REASONS) @@ -1458,17 +1443,17 @@ handle_auth(netdissect_options *ndo, memset(&pbody, 0, sizeof(pbody)); - if (!ND_TTEST2(*p, 6)) + if (!ND_TTEST_6(p)) return 0; if (length < 6) return 0; - pbody.auth_alg = EXTRACT_LE_16BITS(p); + pbody.auth_alg = EXTRACT_LE_U_2(p); offset += 2; length -= 2; - pbody.auth_trans_seq_num = EXTRACT_LE_16BITS(p + offset); + pbody.auth_trans_seq_num = EXTRACT_LE_U_2(p + offset); offset += 2; length -= 2; - pbody.status_code = EXTRACT_LE_16BITS(p + offset); + pbody.status_code = EXTRACT_LE_U_2(p + offset); offset += 2; length -= 2; @@ -1511,11 +1496,11 @@ handle_deauth(netdissect_options *ndo, memset(&pbody, 0, sizeof(pbody)); - if (!ND_TTEST2(*p, IEEE802_11_REASON_LEN)) + if (!ND_TTEST_LEN(p, IEEE802_11_REASON_LEN)) return 0; if (length < IEEE802_11_REASON_LEN) return 0; - pbody.reason_code = EXTRACT_LE_16BITS(p); + pbody.reason_code = EXTRACT_LE_U_2(p); reason = (pbody.reason_code < NUM_REASONS) ? reason_text[pbody.reason_code] @@ -1591,7 +1576,7 @@ static int handle_action(netdissect_options *ndo, const uint8_t *src, const u_char *p, u_int length) { - if (!ND_TTEST2(*p, 2)) + if (!ND_TTEST_2(p)) return 0; if (length < 2) return 0; @@ -1600,22 +1585,22 @@ handle_action(netdissect_options *ndo, } else { ND_PRINT((ndo, " (%s): ", etheraddr_string(ndo, src))); } - switch (p[0]) { - case 0: ND_PRINT((ndo, "Spectrum Management Act#%d", p[1])); break; - case 1: ND_PRINT((ndo, "QoS Act#%d", p[1])); break; - case 2: ND_PRINT((ndo, "DLS Act#%d", p[1])); break; - case 3: ND_PRINT((ndo, "BA ")); PRINT_BA_ACTION(p[1]); break; - case 7: ND_PRINT((ndo, "HT ")); PRINT_HT_ACTION(p[1]); break; - case 13: ND_PRINT((ndo, "MeshAction ")); PRINT_MESH_ACTION(p[1]); break; + switch (EXTRACT_U_1(p)) { + case 0: ND_PRINT((ndo, "Spectrum Management Act#%d", EXTRACT_U_1(p + 1))); break; + case 1: ND_PRINT((ndo, "QoS Act#%d", EXTRACT_U_1(p + 1))); break; + case 2: ND_PRINT((ndo, "DLS Act#%d", EXTRACT_U_1(p + 1))); break; + case 3: ND_PRINT((ndo, "BA ")); PRINT_BA_ACTION(EXTRACT_U_1(p + 1)); break; + case 7: ND_PRINT((ndo, "HT ")); PRINT_HT_ACTION(EXTRACT_U_1(p + 1)); break; + case 13: ND_PRINT((ndo, "MeshAction ")); PRINT_MESH_ACTION(EXTRACT_U_1(p + 1)); break; case 14: ND_PRINT((ndo, "MultiohopAction ")); - PRINT_MULTIHOP_ACTION(p[1]); break; + PRINT_MULTIHOP_ACTION(EXTRACT_U_1(p + 1)); break; case 15: ND_PRINT((ndo, "SelfprotectAction ")); - PRINT_SELFPROT_ACTION(p[1]); break; - case 127: ND_PRINT((ndo, "Vendor Act#%d", p[1])); break; + PRINT_SELFPROT_ACTION(EXTRACT_U_1(p + 1)); break; + case 127: ND_PRINT((ndo, "Vendor Act#%d", EXTRACT_U_1(p + 1))); break; default: - ND_PRINT((ndo, "Reserved(%d) Act#%d", p[0], p[1])); + ND_PRINT((ndo, "Reserved(%d) Act#%d", EXTRACT_U_1(p), EXTRACT_U_1(p + 1))); break; } return 1; @@ -1681,58 +1666,58 @@ ctrl_body_print(netdissect_options *ndo, /* XXX - requires special handling */ break; case CTRL_BAR: - if (!ND_TTEST2(*p, CTRL_BAR_HDRLEN)) + if (!ND_TTEST_LEN(p, CTRL_BAR_HDRLEN)) return 0; if (!ndo->ndo_eflag) ND_PRINT((ndo, " RA:%s TA:%s CTL(%x) SEQ(%u) ", etheraddr_string(ndo, ((const struct ctrl_bar_hdr_t *)p)->ra), etheraddr_string(ndo, ((const struct ctrl_bar_hdr_t *)p)->ta), - EXTRACT_LE_16BITS(&(((const struct ctrl_bar_hdr_t *)p)->ctl)), - EXTRACT_LE_16BITS(&(((const struct ctrl_bar_hdr_t *)p)->seq)))); + EXTRACT_LE_U_2(&(((const struct ctrl_bar_hdr_t *)p)->ctl)), + EXTRACT_LE_U_2(&(((const struct ctrl_bar_hdr_t *)p)->seq)))); break; case CTRL_BA: - if (!ND_TTEST2(*p, CTRL_BA_HDRLEN)) + if (!ND_TTEST_LEN(p, CTRL_BA_HDRLEN)) return 0; if (!ndo->ndo_eflag) ND_PRINT((ndo, " RA:%s ", etheraddr_string(ndo, ((const struct ctrl_ba_hdr_t *)p)->ra))); break; case CTRL_PS_POLL: - if (!ND_TTEST2(*p, CTRL_PS_POLL_HDRLEN)) + if (!ND_TTEST_LEN(p, CTRL_PS_POLL_HDRLEN)) return 0; ND_PRINT((ndo, " AID(%x)", - EXTRACT_LE_16BITS(&(((const struct ctrl_ps_poll_hdr_t *)p)->aid)))); + EXTRACT_LE_U_2(&(((const struct ctrl_ps_poll_hdr_t *)p)->aid)))); break; case CTRL_RTS: - if (!ND_TTEST2(*p, CTRL_RTS_HDRLEN)) + if (!ND_TTEST_LEN(p, CTRL_RTS_HDRLEN)) return 0; if (!ndo->ndo_eflag) ND_PRINT((ndo, " TA:%s ", etheraddr_string(ndo, ((const struct ctrl_rts_hdr_t *)p)->ta))); break; case CTRL_CTS: - if (!ND_TTEST2(*p, CTRL_CTS_HDRLEN)) + if (!ND_TTEST_LEN(p, CTRL_CTS_HDRLEN)) return 0; if (!ndo->ndo_eflag) ND_PRINT((ndo, " RA:%s ", etheraddr_string(ndo, ((const struct ctrl_cts_hdr_t *)p)->ra))); break; case CTRL_ACK: - if (!ND_TTEST2(*p, CTRL_ACK_HDRLEN)) + if (!ND_TTEST_LEN(p, CTRL_ACK_HDRLEN)) return 0; if (!ndo->ndo_eflag) ND_PRINT((ndo, " RA:%s ", etheraddr_string(ndo, ((const struct ctrl_ack_hdr_t *)p)->ra))); break; case CTRL_CF_END: - if (!ND_TTEST2(*p, CTRL_END_HDRLEN)) + if (!ND_TTEST_LEN(p, CTRL_END_HDRLEN)) return 0; if (!ndo->ndo_eflag) ND_PRINT((ndo, " RA:%s ", etheraddr_string(ndo, ((const struct ctrl_end_hdr_t *)p)->ra))); break; case CTRL_END_ACK: - if (!ND_TTEST2(*p, CTRL_END_ACK_HDRLEN)) + if (!ND_TTEST_LEN(p, CTRL_END_ACK_HDRLEN)) return 0; if (!ndo->ndo_eflag) ND_PRINT((ndo, " RA:%s ", @@ -1876,8 +1861,8 @@ ctrl_header_print(netdissect_options *ndo, uint16_t fc, const u_char *p) ND_PRINT((ndo, " RA:%s TA:%s CTL(%x) SEQ(%u) ", etheraddr_string(ndo, ((const struct ctrl_bar_hdr_t *)p)->ra), etheraddr_string(ndo, ((const struct ctrl_bar_hdr_t *)p)->ta), - EXTRACT_LE_16BITS(&(((const struct ctrl_bar_hdr_t *)p)->ctl)), - EXTRACT_LE_16BITS(&(((const struct ctrl_bar_hdr_t *)p)->seq)))); + EXTRACT_LE_U_2(&(((const struct ctrl_bar_hdr_t *)p)->ctl)), + EXTRACT_LE_U_2(&(((const struct ctrl_bar_hdr_t *)p)->seq)))); break; case CTRL_BA: ND_PRINT((ndo, "RA:%s ", @@ -1964,7 +1949,7 @@ extract_header_length(netdissect_options *ndo, static int extract_mesh_header_length(const u_char *p) { - return (p[0] &~ 3) ? 0 : 6*(1 + (p[0] & 3)); + return (EXTRACT_U_1(p) &~ 3) ? 0 : 6*(1 + (EXTRACT_U_1(p) & 3)); } /* @@ -1990,16 +1975,15 @@ ieee_802_11_hdr_print(netdissect_options *ndo, ND_PRINT((ndo, "Protected ")); if (FC_TYPE(fc) != T_CTRL || FC_SUBTYPE(fc) != CTRL_PS_POLL) ND_PRINT((ndo, "%dus ", - EXTRACT_LE_16BITS( - &((const struct mgmt_header_t *)p)->duration))); + EXTRACT_LE_U_2(&((const struct mgmt_header_t *)p)->duration))); } if (meshdrlen != 0) { const struct meshcntl_t *mc = - (const struct meshcntl_t *)&p[hdrlen - meshdrlen]; + (const struct meshcntl_t *)(p + hdrlen - meshdrlen); int ae = mc->flags & 3; ND_PRINT((ndo, "MeshData (AE %d TTL %u seq %u", ae, mc->ttl, - EXTRACT_LE_32BITS(mc->seq))); + EXTRACT_LE_U_4(mc->seq))); if (ae > 0) ND_PRINT((ndo, " A4:%s", etheraddr_string(ndo, mc->addr4))); if (ae > 1) @@ -2037,7 +2021,7 @@ ieee802_11_print(netdissect_options *ndo, { uint16_t fc; u_int caplen, hdrlen, meshdrlen; - const uint8_t *src, *dst; + struct lladdr_info src, dst; int llc_hdrlen; caplen = orig_caplen; @@ -2059,7 +2043,7 @@ ieee802_11_print(netdissect_options *ndo, return orig_caplen; } - fc = EXTRACT_LE_16BITS(p); + fc = EXTRACT_LE_U_2(p); hdrlen = extract_header_length(ndo, fc); if (hdrlen == 0) { /* Unknown frame type or control frame subtype; quit. */ @@ -2089,10 +2073,12 @@ ieee802_11_print(netdissect_options *ndo, caplen -= hdrlen; p += hdrlen; + src.addr_string = etheraddr_string; + dst.addr_string = etheraddr_string; 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)) { + get_mgmt_src_dst_mac(p - hdrlen, &src.addr, &dst.addr); + if (!mgmt_body_print(ndo, fc, src.addr, p, length)) { ND_PRINT((ndo, "%s", tstr)); return hdrlen; } @@ -2114,8 +2100,8 @@ ieee802_11_print(netdissect_options *ndo, return hdrlen; } } else { - get_data_src_dst_mac(fc, p - hdrlen, &src, &dst); - llc_hdrlen = llc_print(ndo, p, length, caplen, src, dst); + get_data_src_dst_mac(fc, p - hdrlen, &src.addr, &dst.addr); + llc_hdrlen = llc_print(ndo, p, length, caplen, &src, &dst); if (llc_hdrlen < 0) { /* * Some kinds of LLC packet we cannot @@ -2330,6 +2316,15 @@ struct ieee80211_radiotap_header { * 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 @@ -2360,6 +2355,8 @@ enum ieee80211_radiotap_type { /* 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 @@ -2427,6 +2424,8 @@ enum ieee80211_radiotap_type { #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 /* For IEEE80211_RADIOTAP_MCS flags */ #define IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK 0x03 @@ -2442,15 +2441,42 @@ enum ieee80211_radiotap_type { #define IEEE80211_RADIOTAP_MCS_STBC_2 2 #define IEEE80211_RADIOTAP_MCS_STBC_3 3 #define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5 - -/* Radiotap state */ -/* This is used to save state when parsing/processing parameters */ -struct radiotap_state -{ - uint32_t present; - - uint8_t rate; -}; +#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 #define IEEE80211_CHAN_FHSS \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK) @@ -2478,30 +2504,41 @@ struct radiotap_state static void print_chaninfo(netdissect_options *ndo, - int freq, int flags) + uint16_t 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) @@ -2513,146 +2550,50 @@ print_chaninfo(netdissect_options *ndo, static int print_radiotap_field(netdissect_options *ndo, - struct cpack_state *s, uint32_t bit, uint8_t *flags, - struct radiotap_state *state, uint32_t presentflags) + struct cpack_state *s, uint32_t bit, uint8_t *flagsp, + uint32_t presentflags) { - union { - int8_t i8; - uint8_t u8; - int16_t i16; - uint16_t u16; - uint32_t u32; - uint64_t u64; - } u, u2, u3, u4; + u_int i; int rc; switch (bit) { - case IEEE80211_RADIOTAP_FLAGS: - rc = cpack_uint8(s, &u.u8); - if (rc != 0) - break; - *flags = u.u8; - break; - case IEEE80211_RADIOTAP_RATE: - rc = cpack_uint8(s, &u.u8); - if (rc != 0) - break; - /* Save state rate */ - state->rate = u.u8; - break; - case IEEE80211_RADIOTAP_DB_ANTSIGNAL: - case IEEE80211_RADIOTAP_DB_ANTNOISE: - case IEEE80211_RADIOTAP_ANTENNA: - rc = cpack_uint8(s, &u.u8); - break; - case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: - case IEEE80211_RADIOTAP_DBM_ANTNOISE: - rc = cpack_int8(s, &u.i8); - break; - case IEEE80211_RADIOTAP_CHANNEL: - rc = cpack_uint16(s, &u.u16); - if (rc != 0) - break; - rc = cpack_uint16(s, &u2.u16); - break; - case IEEE80211_RADIOTAP_FHSS: - case IEEE80211_RADIOTAP_LOCK_QUALITY: - case IEEE80211_RADIOTAP_TX_ATTENUATION: - case IEEE80211_RADIOTAP_RX_FLAGS: - rc = cpack_uint16(s, &u.u16); - break; - case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: - rc = cpack_uint8(s, &u.u8); - break; - case IEEE80211_RADIOTAP_DBM_TX_POWER: - rc = cpack_int8(s, &u.i8); - break; - 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; - case IEEE80211_RADIOTAP_MCS: - rc = cpack_uint8(s, &u.u8); - if (rc != 0) - break; - rc = cpack_uint8(s, &u2.u8); + case IEEE80211_RADIOTAP_TSFT: { + uint64_t tsft; + + rc = cpack_uint64(s, &tsft); if (rc != 0) - break; - rc = cpack_uint8(s, &u3.u8); + goto trunc; + ND_PRINT((ndo, "%" PRIu64 "us tsft ", tsft)); break; - case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: { - uint8_t vns[3]; - uint16_t length; - uint8_t subspace; - - if ((cpack_align_and_reserve(s, 2)) == NULL) { - rc = -1; - break; } - rc = cpack_uint8(s, &vns[0]); - if (rc != 0) - break; - rc = cpack_uint8(s, &vns[1]); - if (rc != 0) - break; - rc = cpack_uint8(s, &vns[2]); - if (rc != 0) - break; - rc = cpack_uint8(s, &subspace); - if (rc != 0) - break; - rc = cpack_uint16(s, &length); - if (rc != 0) - break; + case IEEE80211_RADIOTAP_FLAGS: { + uint8_t flagsval; - /* Skip up to length */ - s->c_next += length; + rc = cpack_uint8(s, &flagsval); + if (rc != 0) + goto trunc; + *flagsp = flagsval; + if (flagsval & IEEE80211_RADIOTAP_F_CFP) + ND_PRINT((ndo, "cfp ")); + if (flagsval & IEEE80211_RADIOTAP_F_SHORTPRE) + ND_PRINT((ndo, "short preamble ")); + if (flagsval & IEEE80211_RADIOTAP_F_WEP) + ND_PRINT((ndo, "wep ")); + if (flagsval & IEEE80211_RADIOTAP_F_FRAG) + ND_PRINT((ndo, "fragmented ")); + if (flagsval & IEEE80211_RADIOTAP_F_BADFCS) + ND_PRINT((ndo, "bad-fcs ")); break; - } - default: - /* this bit indicates a field whose - * size we do not know, so we cannot - * proceed. Just print the bit number. - */ - ND_PRINT((ndo, "[bit %u] ", bit)); - return -1; - } - - if (rc != 0) { - ND_PRINT((ndo, "%s", tstr)); - return rc; - } + } - /* Preserve the state present flags */ - state->present = presentflags; + case IEEE80211_RADIOTAP_RATE: { + uint8_t rate; - switch (bit) { - case IEEE80211_RADIOTAP_CHANNEL: - /* - * If CHANNEL and XCHANNEL are both present, skip - * CHANNEL. - */ - if (presentflags & (1 << IEEE80211_RADIOTAP_XCHANNEL)) - break; - print_chaninfo(ndo, u.u16, u2.u16); - break; - case IEEE80211_RADIOTAP_FHSS: - ND_PRINT((ndo, "fhset %d fhpat %d ", u.u16 & 0xff, (u.u16 >> 8) & 0xff)); - break; - case IEEE80211_RADIOTAP_RATE: + rc = cpack_uint8(s, &rate); + if (rc != 0) + goto trunc; /* * XXX On FreeBSD rate & 0x80 means we have an MCS. On * Linux and AirPcap it does not. (What about @@ -2674,7 +2615,7 @@ print_radiotap_field(netdissect_options *ndo, * setting. Such rates do exist, e.g. 11n * MCS 7 at 20 MHz with a long guard interval. */ - if (u.u8 >= 0x80 && u.u8 <= 0x8f) { + if (rate >= 0x80 && rate <= 0x8f) { /* * XXX - we don't know the channel width * or guard interval length, so we can't @@ -2691,60 +2632,173 @@ print_radiotap_field(netdissect_options *ndo, * information from Flags, at least on * FreeBSD? */ - ND_PRINT((ndo, "MCS %u ", u.u8 & 0x7f)); + ND_PRINT((ndo, "MCS %u ", rate & 0x7f)); } else - ND_PRINT((ndo, "%2.1f Mb/s ", .5 * u.u8)); + ND_PRINT((ndo, "%2.1f Mb/s ", .5 * rate)); break; - case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: - ND_PRINT((ndo, "%ddBm signal ", u.i8)); + } + + case IEEE80211_RADIOTAP_CHANNEL: { + uint16_t frequency; + uint16_t flags; + + rc = cpack_uint16(s, &frequency); + if (rc != 0) + goto trunc; + rc = cpack_uint16(s, &flags); + if (rc != 0) + goto trunc; + /* + * If CHANNEL and XCHANNEL are both present, skip + * CHANNEL. + */ + if (presentflags & (1 << IEEE80211_RADIOTAP_XCHANNEL)) + break; + print_chaninfo(ndo, frequency, flags, presentflags); break; - case IEEE80211_RADIOTAP_DBM_ANTNOISE: - ND_PRINT((ndo, "%ddBm noise ", u.i8)); + } + + case IEEE80211_RADIOTAP_FHSS: { + uint8_t hopset; + uint8_t hoppat; + + rc = cpack_uint8(s, &hopset); + if (rc != 0) + goto trunc; + rc = cpack_uint8(s, &hoppat); + if (rc != 0) + goto trunc; + ND_PRINT((ndo, "fhset %d fhpat %d ", hopset, hoppat)); break; - case IEEE80211_RADIOTAP_DB_ANTSIGNAL: - ND_PRINT((ndo, "%ddB signal ", u.u8)); + } + + case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: { + int8_t dbm_antsignal; + + rc = cpack_int8(s, &dbm_antsignal); + if (rc != 0) + goto trunc; + ND_PRINT((ndo, "%ddBm signal ", dbm_antsignal)); break; - case IEEE80211_RADIOTAP_DB_ANTNOISE: - ND_PRINT((ndo, "%ddB noise ", u.u8)); + } + + case IEEE80211_RADIOTAP_DBM_ANTNOISE: { + int8_t dbm_antnoise; + + rc = cpack_int8(s, &dbm_antnoise); + if (rc != 0) + goto trunc; + ND_PRINT((ndo, "%ddBm noise ", dbm_antnoise)); break; - case IEEE80211_RADIOTAP_LOCK_QUALITY: - ND_PRINT((ndo, "%u sq ", u.u16)); + } + + case IEEE80211_RADIOTAP_LOCK_QUALITY: { + uint16_t lock_quality; + + rc = cpack_uint16(s, &lock_quality); + if (rc != 0) + goto trunc; + ND_PRINT((ndo, "%u sq ", lock_quality)); break; - case IEEE80211_RADIOTAP_TX_ATTENUATION: - ND_PRINT((ndo, "%d tx power ", -(int)u.u16)); + } + + case IEEE80211_RADIOTAP_TX_ATTENUATION: { + int16_t tx_attenuation; + + rc = cpack_int16(s, &tx_attenuation); + if (rc != 0) + goto trunc; + ND_PRINT((ndo, "%d tx power ", -tx_attenuation)); break; - case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: - ND_PRINT((ndo, "%ddB tx power ", -(int)u.u8)); + } + + case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: { + int8_t db_tx_attenuation; + + rc = cpack_int8(s, &db_tx_attenuation); + if (rc != 0) + goto trunc; + ND_PRINT((ndo, "%ddB tx attenuation ", -db_tx_attenuation)); break; - case IEEE80211_RADIOTAP_DBM_TX_POWER: - ND_PRINT((ndo, "%ddBm tx power ", u.i8)); + } + + case IEEE80211_RADIOTAP_DBM_TX_POWER: { + int8_t dbm_tx_power; + + rc = cpack_int8(s, &dbm_tx_power); + if (rc != 0) + goto trunc; + ND_PRINT((ndo, "%ddBm tx power ", dbm_tx_power)); break; - case IEEE80211_RADIOTAP_FLAGS: - if (u.u8 & IEEE80211_RADIOTAP_F_CFP) - ND_PRINT((ndo, "cfp ")); - if (u.u8 & IEEE80211_RADIOTAP_F_SHORTPRE) - ND_PRINT((ndo, "short preamble ")); - if (u.u8 & IEEE80211_RADIOTAP_F_WEP) - ND_PRINT((ndo, "wep ")); - if (u.u8 & IEEE80211_RADIOTAP_F_FRAG) - ND_PRINT((ndo, "fragmented ")); - if (u.u8 & IEEE80211_RADIOTAP_F_BADFCS) - ND_PRINT((ndo, "bad-fcs ")); + } + + case IEEE80211_RADIOTAP_ANTENNA: { + uint8_t antenna; + + rc = cpack_uint8(s, &antenna); + if (rc != 0) + goto trunc; + ND_PRINT((ndo, "antenna %u ", antenna)); break; - case IEEE80211_RADIOTAP_ANTENNA: - ND_PRINT((ndo, "antenna %d ", u.u8)); + } + + case IEEE80211_RADIOTAP_DB_ANTSIGNAL: { + uint8_t db_antsignal; + + rc = cpack_uint8(s, &db_antsignal); + if (rc != 0) + goto trunc; + ND_PRINT((ndo, "%ddB signal ", db_antsignal)); break; - case IEEE80211_RADIOTAP_TSFT: - ND_PRINT((ndo, "%" PRIu64 "us tsft ", u.u64)); + } + + case IEEE80211_RADIOTAP_DB_ANTNOISE: { + uint8_t db_antnoise; + + rc = cpack_uint8(s, &db_antnoise); + if (rc != 0) + goto trunc; + ND_PRINT((ndo, "%ddB noise ", db_antnoise)); break; - case IEEE80211_RADIOTAP_RX_FLAGS: + } + + case IEEE80211_RADIOTAP_RX_FLAGS: { + uint16_t rx_flags; + + rc = cpack_uint16(s, &rx_flags); + if (rc != 0) + goto trunc; /* Do nothing for now */ break; - case IEEE80211_RADIOTAP_XCHANNEL: - print_chaninfo(ndo, u2.u16, u.u32); + } + + case IEEE80211_RADIOTAP_XCHANNEL: { + uint32_t flags; + uint16_t frequency; + uint8_t channel; + uint8_t maxpower; + + rc = cpack_uint32(s, &flags); + if (rc != 0) + goto trunc; + rc = cpack_uint16(s, &frequency); + if (rc != 0) + goto trunc; + rc = cpack_uint8(s, &channel); + if (rc != 0) + goto trunc; + rc = cpack_uint8(s, &maxpower); + if (rc != 0) + goto trunc; + print_chaninfo(ndo, frequency, flags, presentflags); break; + } + case IEEE80211_RADIOTAP_MCS: { - static const char *bandwidth[4] = { + uint8_t known; + uint8_t flags; + uint8_t mcs_index; + static const char *ht_bandwidth[4] = { "20 MHz", "40 MHz", "20 MHz (L)", @@ -2752,15 +2806,24 @@ print_radiotap_field(netdissect_options *ndo, }; float htrate; - if (u.u8 & IEEE80211_RADIOTAP_MCS_MCS_INDEX_KNOWN) { + rc = cpack_uint8(s, &known); + if (rc != 0) + goto trunc; + rc = cpack_uint8(s, &flags); + if (rc != 0) + goto trunc; + rc = cpack_uint8(s, &mcs_index); + if (rc != 0) + goto trunc; + if (known & IEEE80211_RADIOTAP_MCS_MCS_INDEX_KNOWN) { /* * We know the MCS index. */ - if (u3.u8 <= MAX_MCS_INDEX) { + if (mcs_index <= MAX_MCS_INDEX) { /* * And it's in-range. */ - if (u.u8 & (IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN|IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN)) { + if (known & (IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN|IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN)) { /* * And we know both the bandwidth and * the guard interval, so we can look @@ -2768,9 +2831,9 @@ print_radiotap_field(netdissect_options *ndo, */ htrate = ieee80211_float_htrates \ - [u3.u8] \ - [((u2.u8 & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK) == IEEE80211_RADIOTAP_MCS_BANDWIDTH_40 ? 1 : 0)] \ - [((u2.u8 & IEEE80211_RADIOTAP_MCS_SHORT_GI) ? 1 : 0)]; + [mcs_index] \ + [((flags & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK) == IEEE80211_RADIOTAP_MCS_BANDWIDTH_40 ? 1 : 0)] \ + [((flags & IEEE80211_RADIOTAP_MCS_SHORT_GI) ? 1 : 0)]; } else { /* * We don't know both the bandwidth @@ -2790,70 +2853,240 @@ print_radiotap_field(netdissect_options *ndo, * We have the rate. * Print it. */ - ND_PRINT((ndo, "%.1f Mb/s MCS %u ", htrate, u3.u8)); + ND_PRINT((ndo, "%.1f Mb/s MCS %u ", htrate, mcs_index)); } else { /* * We at least have the MCS index. * Print it. */ - ND_PRINT((ndo, "MCS %u ", u3.u8)); + ND_PRINT((ndo, "MCS %u ", mcs_index)); } } - if (u.u8 & IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN) { + if (known & IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN) { ND_PRINT((ndo, "%s ", - bandwidth[u2.u8 & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK])); + ht_bandwidth[flags & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK])); } - if (u.u8 & IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN) { + if (known & IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN) { ND_PRINT((ndo, "%s GI ", - (u2.u8 & IEEE80211_RADIOTAP_MCS_SHORT_GI) ? - "short" : "lon")); + (flags & IEEE80211_RADIOTAP_MCS_SHORT_GI) ? + "short" : "long")); } - if (u.u8 & IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN) { + if (known & IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN) { ND_PRINT((ndo, "%s ", - (u2.u8 & IEEE80211_RADIOTAP_MCS_HT_GREENFIELD) ? + (flags & IEEE80211_RADIOTAP_MCS_HT_GREENFIELD) ? "greenfield" : "mixed")); } - if (u.u8 & IEEE80211_RADIOTAP_MCS_FEC_TYPE_KNOWN) { + if (known & IEEE80211_RADIOTAP_MCS_FEC_TYPE_KNOWN) { ND_PRINT((ndo, "%s FEC ", - (u2.u8 & IEEE80211_RADIOTAP_MCS_FEC_LDPC) ? + (flags & IEEE80211_RADIOTAP_MCS_FEC_LDPC) ? "LDPC" : "BCC")); } - if (u.u8 & IEEE80211_RADIOTAP_MCS_STBC_KNOWN) { + if (known & IEEE80211_RADIOTAP_MCS_STBC_KNOWN) { ND_PRINT((ndo, "RX-STBC%u ", - (u2.u8 & IEEE80211_RADIOTAP_MCS_STBC_MASK) >> IEEE80211_RADIOTAP_MCS_STBC_SHIFT)); + (flags & IEEE80211_RADIOTAP_MCS_STBC_MASK) >> IEEE80211_RADIOTAP_MCS_STBC_SHIFT)); + } + break; + } + + case IEEE80211_RADIOTAP_AMPDU_STATUS: { + uint32_t reference_num; + uint16_t flags; + uint8_t delim_crc; + uint8_t reserved; + + rc = cpack_uint32(s, &reference_num); + if (rc != 0) + goto trunc; + rc = cpack_uint16(s, &flags); + if (rc != 0) + goto trunc; + rc = cpack_uint8(s, &delim_crc); + if (rc != 0) + goto trunc; + rc = cpack_uint8(s, &reserved); + if (rc != 0) + goto trunc; + /* Do nothing for now */ + break; + } + + case IEEE80211_RADIOTAP_VHT: { + uint16_t known; + uint8_t flags; + uint8_t bandwidth; + uint8_t mcs_nss[4]; + uint8_t coding; + uint8_t group_id; + uint16_t partial_aid; + 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)" + }; + + rc = cpack_uint16(s, &known); + if (rc != 0) + goto trunc; + rc = cpack_uint8(s, &flags); + if (rc != 0) + goto trunc; + rc = cpack_uint8(s, &bandwidth); + if (rc != 0) + goto trunc; + for (i = 0; i < 4; i++) { + rc = cpack_uint8(s, &mcs_nss[i]); + if (rc != 0) + goto trunc; } + rc = cpack_uint8(s, &coding); + if (rc != 0) + goto trunc; + rc = cpack_uint8(s, &group_id); + if (rc != 0) + goto trunc; + rc = cpack_uint16(s, &partial_aid); + if (rc != 0) + goto trunc; + 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 ", + (coding & (IEEE80211_RADIOTAP_CODING_LDPC_USERn << i)) ? + "LDPC" : "BCC")); + } + if (known & IEEE80211_RADIOTAP_VHT_BANDWIDTH_KNOWN) { + ND_PRINT((ndo, "%s ", + vht_bandwidth[bandwidth & IEEE80211_RADIOTAP_VHT_BANDWIDTH_MASK])); + } + if (known & IEEE80211_RADIOTAP_VHT_GUARD_INTERVAL_KNOWN) { + ND_PRINT((ndo, "%s GI ", + (flags & IEEE80211_RADIOTAP_VHT_SHORT_GI) ? + "short" : "long")); + } break; } + + default: + /* this bit indicates a field whose + * size we do not know, so we cannot + * proceed. Just print the bit number. + */ + ND_PRINT((ndo, "[bit %u] ", bit)); + return -1; } + return 0; + +trunc: + ND_PRINT((ndo, "%s", tstr)); + return rc; } -static u_int -ieee802_11_radio_print(netdissect_options *ndo, - const u_char *p, u_int length, u_int caplen) + +static int +print_in_radiotap_namespace(netdissect_options *ndo, + struct cpack_state *s, uint8_t *flags, + uint32_t presentflags, int bit0) { #define BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x))) #define BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x))) #define BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x))) #define BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x))) #define BITNO_2(x) (((x) & 2) ? 1 : 0) + uint32_t present, next_present; + int bitno; + enum ieee80211_radiotap_type bit; + int rc; + + for (present = presentflags; present; present = next_present) { + /* + * Clear the least significant bit that is set. + */ + next_present = present & (present - 1); + + /* + * Get the bit number, within this presence word, + * of the remaining least significant bit that + * is set. + */ + bitno = BITNO_32(present ^ next_present); + + /* + * Stop if this is one of the "same meaning + * in all presence flags" bits. + */ + if (bitno >= IEEE80211_RADIOTAP_NAMESPACE) + break; + + /* + * Get the radiotap bit number of that bit. + */ + bit = (enum ieee80211_radiotap_type)(bit0 + bitno); + + rc = print_radiotap_field(ndo, s, bit, flags, presentflags); + if (rc != 0) + return rc; + } + + return 0; +} + +static u_int +ieee802_11_radio_print(netdissect_options *ndo, + const u_char *p, u_int length, u_int caplen) +{ #define BIT(n) (1U << n) #define IS_EXTENDED(__p) \ - (EXTRACT_LE_32BITS(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0 + (EXTRACT_LE_U_4(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0 struct cpack_state cpacker; const struct ieee80211_radiotap_header *hdr; - uint32_t present, next_present; - uint32_t presentflags = 0; + uint32_t presentflags; const uint32_t *presentp, *last_presentp; - enum ieee80211_radiotap_type bit; + int vendor_namespace; + uint8_t vendor_oui[3]; + uint8_t vendor_subnamespace; + uint16_t skip_length; int bit0; u_int len; uint8_t flags; int pad; u_int fcslen; - struct radiotap_state state; if (caplen < sizeof(*hdr)) { ND_PRINT((ndo, "%s", tstr)); @@ -2862,8 +3095,11 @@ ieee802_11_radio_print(netdissect_options *ndo, hdr = (const struct ieee80211_radiotap_header *)p; - len = EXTRACT_LE_16BITS(&hdr->it_len); + len = EXTRACT_LE_U_2(&hdr->it_len); + /* + * If we don't have the entire radiotap header, just give up. + */ if (caplen < len) { ND_PRINT((ndo, "%s", tstr)); return caplen; @@ -2871,45 +3107,144 @@ ieee802_11_radio_print(netdissect_options *ndo, 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) && - (const u_char*)(last_presentp + 1) <= p + len; + (const u_char*)(last_presentp + 1) <= p + len && + IS_EXTENDED(last_presentp); last_presentp++) cpack_advance(&cpacker, sizeof(hdr->it_present)); /* more bitmaps */ /* are there more bitmap extensions than bytes in header? */ - if (IS_EXTENDED(last_presentp)) { + if ((const u_char*)(last_presentp + 1) > p + len) { ND_PRINT((ndo, "%s", tstr)); return caplen; } + /* + * Start out at the beginning of the default radiotap namespace. + */ + bit0 = 0; + vendor_namespace = 0; + memset(vendor_oui, 0, 3); + vendor_subnamespace = 0; + skip_length = 0; /* 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) { - presentflags = EXTRACT_LE_32BITS(presentp); + for (presentp = &hdr->it_present; presentp <= last_presentp; + presentp++) { + presentflags = EXTRACT_LE_U_4(presentp); + + /* + * If this is a vendor namespace, we don't handle it. + */ + if (vendor_namespace) { + /* + * Skip past the stuff we don't understand. + * If we add support for any vendor namespaces, + * it'd be added here; use vendor_oui and + * vendor_subnamespace to interpret the fields. + */ + if (cpack_advance(&cpacker, skip_length) != 0) { + /* + * Ran out of space in the packet. + */ + break; + } + + /* + * We've skipped it all; nothing more to + * skip. + */ + skip_length = 0; + } else { + if (print_in_radiotap_namespace(ndo, &cpacker, + &flags, presentflags, bit0) != 0) { + /* + * Fatal error - can't process anything + * more in the radiotap header. + */ + break; + } + } - /* Clear state. */ - memset(&state, 0, sizeof(state)); + /* + * Handle the namespace switch bits; we've already handled + * the extension bit in all but the last word above. + */ + switch (presentflags & + (BIT(IEEE80211_RADIOTAP_NAMESPACE)|BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE))) { - for (present = EXTRACT_LE_32BITS(presentp); present; - present = next_present) { - /* clear the least significant bit that is set */ - next_present = present & (present - 1); + case 0: + /* + * We're not changing namespaces. + * advance to the next 32 bits in the current + * namespace. + */ + bit0 += 32; + break; - /* extract the least significant bit that is set */ - bit = (enum ieee80211_radiotap_type) - (bit0 + BITNO_32(present ^ next_present)); + case BIT(IEEE80211_RADIOTAP_NAMESPACE): + /* + * We're switching to the radiotap namespace. + * Reset the presence-bitmap index to 0, and + * reset the namespace to the default radiotap + * namespace. + */ + bit0 = 0; + vendor_namespace = 0; + memset(vendor_oui, 0, 3); + vendor_subnamespace = 0; + skip_length = 0; + break; - if (print_radiotap_field(ndo, &cpacker, bit, &flags, &state, presentflags) != 0) - goto out; + case BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE): + /* + * We're switching to a vendor namespace. + * Reset the presence-bitmap index to 0, + * note that we're in a vendor namespace, + * and fetch the fields of the Vendor Namespace + * item. + */ + bit0 = 0; + vendor_namespace = 1; + if ((cpack_align_and_reserve(&cpacker, 2)) == NULL) { + ND_PRINT((ndo, "%s", tstr)); + break; + } + if (cpack_uint8(&cpacker, &vendor_oui[0]) != 0) { + ND_PRINT((ndo, "%s", tstr)); + break; + } + if (cpack_uint8(&cpacker, &vendor_oui[1]) != 0) { + ND_PRINT((ndo, "%s", tstr)); + break; + } + if (cpack_uint8(&cpacker, &vendor_oui[2]) != 0) { + ND_PRINT((ndo, "%s", tstr)); + break; + } + if (cpack_uint8(&cpacker, &vendor_subnamespace) != 0) { + ND_PRINT((ndo, "%s", tstr)); + break; + } + if (cpack_uint16(&cpacker, &skip_length) != 0) { + ND_PRINT((ndo, "%s", tstr)); + break; + } + break; + + default: + /* + * Illegal combination. The behavior in this + * case is undefined by the radiotap spec; we + * just ignore both bits. + */ + break; } } -out: if (flags & IEEE80211_RADIOTAP_F_DATAPAD) pad = 1; /* Atheros padding */ if (flags & IEEE80211_RADIOTAP_F_FCS) @@ -2935,7 +3270,7 @@ ieee802_11_avs_radio_print(netdissect_options *ndo, return caplen; } - caphdr_len = EXTRACT_32BITS(p + 4); + caphdr_len = EXTRACT_BE_U_4(p + 4); if (caphdr_len < 8) { /* * Yow! The capture header length is claimed not @@ -2987,7 +3322,7 @@ prism_if_print(netdissect_options *ndo, return caplen; } - msgcode = EXTRACT_32BITS(p); + msgcode = EXTRACT_BE_U_4(p); if (msgcode == WLANCAP_MAGIC_COOKIE_V1 || msgcode == WLANCAP_MAGIC_COOKIE_V2) return ieee802_11_avs_radio_print(ndo, p, length, caplen);