diff --git a/epan/dissectors/packet-ieee80211-radiotap-defs.h b/epan/dissectors/packet-ieee80211-radiotap-defs.h index 950077815e1a..f90bd35278cc 100644 --- a/epan/dissectors/packet-ieee80211-radiotap-defs.h +++ b/epan/dissectors/packet-ieee80211-radiotap-defs.h @@ -200,6 +200,7 @@ enum ieee80211_radiotap_type { IEEE80211_RAFIOTAP_HE_MU_USER = 25, IEEE80211_RADIOTAP_0_LENGTH_PSDU = 26, IEEE80211_RADIOTAP_L_SIG = 27, + IEEE80211_RADIOTAP_TLVS = 28, /* valid in every it_present bitmap, even vendor namespaces */ IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, @@ -207,9 +208,11 @@ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_EXT = 31 }; -/* not (yet) defined Radiotap present flag */ -/* Bit 25 and 28 are not defined (in binary : 0001 0010 0000 0000 0000 0000 0000 0000 */ -#define IEEE80211_RADIOTAP_NOTDEFINED 0x10000000 +struct ieee80211_radiotap_tlv { + guint16 type; + guint16 datalen; + guint8 data[]; +}; /* Channel flags. */ /* 0x00000001 through 0x00000008 undefined (reserved?) */ diff --git a/epan/dissectors/packet-ieee80211-radiotap-iter.c b/epan/dissectors/packet-ieee80211-radiotap-iter.c index fe4066525287..f757a3d0db61 100644 --- a/epan/dissectors/packet-ieee80211-radiotap-iter.c +++ b/epan/dissectors/packet-ieee80211-radiotap-iter.c @@ -142,6 +142,7 @@ int ieee80211_radiotap_iterator_init( iterator->_vns = vns; iterator->current_namespace = &radiotap_ns; iterator->is_radiotap_ns = 1; + iterator->tlv_mode = 0; #ifdef RADIOTAP_SUPPORT_OVERRIDES iterator->n_overrides = 0; iterator->overrides = NULL; @@ -164,6 +165,13 @@ int ieee80211_radiotap_iterator_init( /* XXX - we should report an expert info here */ if (!ITERATOR_VALID(iterator, sizeof(guint32))) return -EINVAL; + + /* XXX - we should report an expert info here */ + if ((get_unaligned_le32(iterator->_arg) & + (1U << IEEE80211_RADIOTAP_TLVS)) && + (get_unaligned_le32(iterator->_arg) & + (1U << IEEE80211_RADIOTAP_EXT))) + return -EINVAL; } iterator->_arg += sizeof(guint32); @@ -253,6 +261,46 @@ static int find_override(struct ieee80211_radiotap_iterator *iterator, int ieee80211_radiotap_iterator_next( struct ieee80211_radiotap_iterator *iterator) { + if (iterator->tlv_mode) { + struct ieee80211_radiotap_tlv *tlv; + guint32 size; + +#define TLV_LEN_ALIGN(x) ((x + 3) & ~3) + size = sizeof(*tlv) + TLV_LEN_ALIGN(iterator->this_arg_size); + + /* + * We know that without the alignment padding it was valid, so + * ignore arbitrary padding and return that we finished if no + * further TLV could fit. + */ + if (!ITERATOR_VALID(iterator, size)) + return -ENOENT; + + /* move to next entry */ + iterator->_arg += sizeof(*tlv) + TLV_LEN_ALIGN(iterator->this_arg_size); + +return_tlv: + /* and check again if we reached the end */ + if (!ITERATOR_VALID(iterator, 1)) + return -ENOENT; + + /* if it's not the end but a new TLV won't fit - error out */ + if (!ITERATOR_VALID(iterator, sizeof(*tlv))) + return -EINVAL; + + tlv = (struct ieee80211_radiotap_tlv *)iterator->_arg; + + iterator->this_arg_index = get_unaligned_le16(&tlv->type); + iterator->this_arg_size = get_unaligned_le16(&tlv->datalen); + iterator->this_arg = tlv->data; + iterator->is_radiotap_ns = + iterator->this_arg_index != IEEE80211_RADIOTAP_VENDOR_NAMESPACE; + + if (!ITERATOR_VALID(iterator, sizeof(*tlv) + iterator->this_arg_size)) + return -EINVAL; + return 0; + } + while (1) { int hit = 0; int pad, align, size, subns; @@ -268,6 +316,10 @@ int ieee80211_radiotap_iterator_next( /* get alignment/size of data */ switch (iterator->_arg_index % 32) { + case IEEE80211_RADIOTAP_TLVS: + align = 4; + size = 0; + break; case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: case IEEE80211_RADIOTAP_EXT: align = 1; @@ -344,6 +396,9 @@ int ieee80211_radiotap_iterator_next( iterator->_next_ns_data = iterator->_arg + size + vnslen; if (!iterator->current_namespace) size += vnslen; + } else if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_TLVS) { + iterator->tlv_mode = 1; + goto return_tlv; } /* diff --git a/epan/dissectors/packet-ieee80211-radiotap-iter.h b/epan/dissectors/packet-ieee80211-radiotap-iter.h index 74f5316c6f26..88da8c25e19c 100644 --- a/epan/dissectors/packet-ieee80211-radiotap-iter.h +++ b/epan/dissectors/packet-ieee80211-radiotap-iter.h @@ -89,6 +89,7 @@ struct ieee80211_radiotap_iterator { int this_arg_size; int is_radiotap_ns; + int tlv_mode; int _max_length; int _arg_index; diff --git a/epan/dissectors/packet-ieee80211-radiotap.c b/epan/dissectors/packet-ieee80211-radiotap.c index 4efcd77d60be..122083e42946 100644 --- a/epan/dissectors/packet-ieee80211-radiotap.c +++ b/epan/dissectors/packet-ieee80211-radiotap.c @@ -38,6 +38,12 @@ static int hf_radiotap_version = -1; static int hf_radiotap_pad = -1; static int hf_radiotap_length = -1; static int hf_radiotap_present = -1; + +static int hf_radiotap_tlv = -1; +static int hf_radiotap_tlv_type = -1; +static int hf_radiotap_tlv_datalen = -1; +static int hf_radiotap_unknown_tlv_data = -1; + static int hf_radiotap_mactime = -1; /* static int hf_radiotap_channel = -1; */ static int hf_radiotap_channel_frequency = -1; @@ -92,6 +98,7 @@ static int hf_radiotap_vendor_ns = -1; static int hf_radiotap_ven_oui = -1; static int hf_radiotap_ven_subns = -1; static int hf_radiotap_ven_skip = -1; +static int hf_radiotap_ven_item = -1; static int hf_radiotap_ven_data = -1; static int hf_radiotap_mcs = -1; static int hf_radiotap_mcs_known = -1; @@ -182,7 +189,7 @@ static int hf_radiotap_present_he = -1; static int hf_radiotap_present_he_mu = -1; static int hf_radiotap_present_0_length_psdu = -1; static int hf_radiotap_present_l_sig = -1; -static int hf_radiotap_present_reserved = -1; +static int hf_radiotap_present_tlv = -1; static int hf_radiotap_present_rtap_ns = -1; static int hf_radiotap_present_vendor_ns = -1; static int hf_radiotap_present_ext = -1; @@ -349,6 +356,7 @@ static int hf_radiotap_l_sig_rate = -1; static int hf_radiotap_l_sig_length = -1; static gint ett_radiotap = -1; +static gint ett_radiotap_tlv = -1; static gint ett_radiotap_present = -1; static gint ett_radiotap_present_word = -1; static gint ett_radiotap_flags = -1; @@ -383,7 +391,6 @@ static gint ett_radiotap_l_sig_data_2 = -1; static expert_field ei_radiotap_invalid_header_length = EI_INIT; static expert_field ei_radiotap_data_past_header = EI_INIT; -static expert_field ei_radiotap_present_reserved = EI_INIT; static expert_field ei_radiotap_present = EI_INIT; static expert_field ei_radiotap_invalid_data_rate = EI_INIT; @@ -2276,17 +2283,10 @@ dissect_radiotap(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* u proto_tree_add_item(present_word_tree, hf_radiotap_present_l_sig, tvb, offset + 4, 4, ENC_LITTLE_ENDIAN); - - ti = proto_tree_add_item(present_word_tree, - hf_radiotap_present_reserved, tvb, + proto_tree_add_item(present_word_tree, + hf_radiotap_present_tlv, tvb, offset + 4, 4, ENC_LITTLE_ENDIAN); } - /* Check if Reserved/Not Defined is not "zero" */ - if(bmap & IEEE80211_RADIOTAP_NOTDEFINED) - { - expert_add_info(pinfo, present_word_item, - &ei_radiotap_present_reserved); - } always_bits: if (tree) { proto_tree_add_item(present_word_tree, @@ -2302,8 +2302,30 @@ dissect_radiotap(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* u } while (!(err = ieee80211_radiotap_iterator_next(&iter))) { + proto_tree *item_tree = radiotap_tree; + offset = (int)((guchar *) iter.this_arg - (guchar *) data); + if (iter.tlv_mode) { + proto_item *tlvi; + + offset -= sizeof(struct ieee80211_radiotap_tlv); + + tlvi = proto_tree_add_bytes_format_value(radiotap_tree, hf_radiotap_tlv, + tvb, offset, + iter.this_arg_size + sizeof(struct ieee80211_radiotap_tlv), + NULL, + "Radiotap Item %u", + iter.this_arg_index); + item_tree = proto_item_add_subtree(tlvi, ett_radiotap_tlv); + proto_tree_add_item(item_tree, hf_radiotap_tlv_type, + tvb, offset + 0, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(item_tree, hf_radiotap_tlv_datalen, + tvb, offset + 2, 2, ENC_LITTLE_ENDIAN); + + offset += sizeof(struct ieee80211_radiotap_tlv); + } + if (iter.this_arg_index == IEEE80211_RADIOTAP_VENDOR_NAMESPACE && tree) { proto_tree *ven_tree; @@ -2314,7 +2336,7 @@ dissect_radiotap(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* u manuf_name = tvb_get_manuf_name(tvb, offset); subns = tvb_get_guint8(tvb, offset+3); - vt = proto_tree_add_bytes_format_value(radiotap_tree, + vt = proto_tree_add_bytes_format_value(item_tree, hf_radiotap_vendor_ns, tvb, offset, iter.this_arg_size, @@ -2332,11 +2354,19 @@ dissect_radiotap(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* u tvb, offset, 3, ENC_BIG_ENDIAN); proto_tree_add_item(ven_tree, hf_radiotap_ven_subns, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN); - proto_tree_add_item(ven_tree, hf_radiotap_ven_skip, tvb, - offset + 4, 2, ENC_LITTLE_ENDIAN); - proto_tree_add_item(ven_tree, hf_radiotap_ven_data, tvb, - offset + 6, iter.this_arg_size - 6, - ENC_NA); + if (iter.tlv_mode) { + proto_tree_add_item(ven_tree, hf_radiotap_ven_item, tvb, + offset + 4, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(ven_tree, hf_radiotap_ven_data, tvb, + offset + 8, iter.this_arg_size - 8, + ENC_NA); + } else { + proto_tree_add_item(ven_tree, hf_radiotap_ven_skip, tvb, + offset + 4, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(ven_tree, hf_radiotap_ven_data, tvb, + offset + 6, iter.this_arg_size - 6, + ENC_NA); + } } if (!iter.is_radiotap_ns) @@ -2345,89 +2375,89 @@ dissect_radiotap(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* u switch (iter.this_arg_index) { case IEEE80211_RADIOTAP_TSFT: - dissect_radiotap_tsft(tvb, pinfo, radiotap_tree, offset, + dissect_radiotap_tsft(tvb, pinfo, item_tree, offset, &phdr); break; case IEEE80211_RADIOTAP_FLAGS: have_rflags = TRUE; - dissect_radiotap_flags(tvb, pinfo, radiotap_tree, offset, + dissect_radiotap_flags(tvb, pinfo, item_tree, offset, &rflags, &phdr); break; case IEEE80211_RADIOTAP_RATE: - dissect_radiotap_rate(tvb, pinfo, radiotap_tree, offset, + dissect_radiotap_rate(tvb, pinfo, item_tree, offset, &phdr); break; case IEEE80211_RADIOTAP_CHANNEL: - dissect_radiotap_channel(tvb, pinfo, radiotap_tree, offset, + dissect_radiotap_channel(tvb, pinfo, item_tree, offset, rflags, have_rflags, &phdr); break; case IEEE80211_RADIOTAP_FHSS: - dissect_radiotap_fhss(tvb, pinfo, radiotap_tree, offset, + dissect_radiotap_fhss(tvb, pinfo, item_tree, offset, &phdr); break; case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: - dissect_radiotap_dbm_antsignal(tvb, pinfo, radiotap_tree, + dissect_radiotap_dbm_antsignal(tvb, pinfo, item_tree, offset, &phdr); break; case IEEE80211_RADIOTAP_DBM_ANTNOISE: - dissect_radiotap_dbm_antnoise(tvb, pinfo, radiotap_tree, + dissect_radiotap_dbm_antnoise(tvb, pinfo, item_tree, offset, &phdr); break; case IEEE80211_RADIOTAP_LOCK_QUALITY: - proto_tree_add_item(radiotap_tree, + proto_tree_add_item(item_tree, hf_radiotap_quality, tvb, offset, 2, ENC_LITTLE_ENDIAN); break; case IEEE80211_RADIOTAP_TX_ATTENUATION: - proto_tree_add_item(radiotap_tree, + proto_tree_add_item(item_tree, hf_radiotap_tx_attenuation, tvb, offset, 2, ENC_LITTLE_ENDIAN); break; case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: - proto_tree_add_item(radiotap_tree, + proto_tree_add_item(item_tree, hf_radiotap_db_tx_attenuation, tvb, offset, 2, ENC_LITTLE_ENDIAN); break; case IEEE80211_RADIOTAP_DBM_TX_POWER: - proto_tree_add_item(radiotap_tree, + proto_tree_add_item(item_tree, hf_radiotap_txpower, tvb, offset, 1, ENC_NA); break; case IEEE80211_RADIOTAP_ANTENNA: - proto_tree_add_item(radiotap_tree, + proto_tree_add_item(item_tree, hf_radiotap_antenna, tvb, offset, 1, ENC_NA); break; case IEEE80211_RADIOTAP_DB_ANTSIGNAL: - dissect_radiotap_db_antsignal(tvb, pinfo, radiotap_tree, + dissect_radiotap_db_antsignal(tvb, pinfo, item_tree, offset, &phdr); break; case IEEE80211_RADIOTAP_DB_ANTNOISE: - dissect_radiotap_db_antnoise(tvb, pinfo, radiotap_tree, + dissect_radiotap_db_antnoise(tvb, pinfo, item_tree, offset, &phdr); break; case IEEE80211_RADIOTAP_RX_FLAGS: - dissect_radiotap_rx_flags(tvb, pinfo, radiotap_tree, + dissect_radiotap_rx_flags(tvb, pinfo, item_tree, offset, &hdr_fcs_ti, &hdr_fcs_offset, &sent_fcs); break; case IEEE80211_RADIOTAP_XCHANNEL: - dissect_radiotap_xchannel(tvb, pinfo, radiotap_tree, + dissect_radiotap_xchannel(tvb, pinfo, item_tree, offset, rflags, have_rflags, &phdr); break; @@ -2523,7 +2553,7 @@ dissect_radiotap(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* u NULL }; - it = proto_tree_add_item(radiotap_tree, hf_radiotap_mcs, + it = proto_tree_add_item(item_tree, hf_radiotap_mcs, tvb, offset, 3, ENC_NA); mcs_tree = proto_item_add_subtree(it, ett_radiotap_mcs); @@ -2579,7 +2609,7 @@ dissect_radiotap(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* u float rate = ieee80211_htrate(mcs, bandwidth, gi_length); col_add_fstr(pinfo->cinfo, COL_TX_RATE, "%.1f", rate); if (tree) { - rate_ti = proto_tree_add_float_format(radiotap_tree, + rate_ti = proto_tree_add_float_format(item_tree, hf_radiotap_datarate, tvb, offset, 3, rate, "Data Rate: %.1f Mb/s", rate); @@ -2604,7 +2634,7 @@ dissect_radiotap(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* u phdr.aggregate_flags |= PHDR_802_11_A_MPDU_DELIM_CRC_ERROR; if (tree) { - it = proto_tree_add_item(radiotap_tree, hf_radiotap_ampdu, + it = proto_tree_add_item(item_tree, hf_radiotap_ampdu, tvb, offset, 8, ENC_NA); ampdu_tree = proto_item_add_subtree(it, ett_radiotap_ampdu); @@ -2665,7 +2695,7 @@ dissect_radiotap(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* u } vht_flags = tvb_get_guint8(tvb, offset + 2); if (tree) { - it_root = proto_tree_add_item(radiotap_tree, hf_radiotap_vht, + it_root = proto_tree_add_item(item_tree, hf_radiotap_vht, tvb, offset, 12, ENC_NA); vht_tree = proto_item_add_subtree(it_root, ett_radiotap_vht); it = proto_tree_add_item(vht_tree, hf_radiotap_vht_known, @@ -2857,22 +2887,29 @@ dissect_radiotap(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* u break; } case IEEE80211_RADIOTAP_TIMESTAMP: { - dissect_radiotap_timestamp(tvb, pinfo, radiotap_tree, + dissect_radiotap_timestamp(tvb, pinfo, item_tree, offset, &phdr); break; } case IEEE80211_RADIOTAP_HE: - dissect_radiotap_he_info(tvb, pinfo, radiotap_tree, offset); + dissect_radiotap_he_info(tvb, pinfo, item_tree, offset); break; case IEEE80211_RADIOTAP_HE_MU: - dissect_radiotap_he_mu_info(tvb, pinfo, radiotap_tree, offset); + dissect_radiotap_he_mu_info(tvb, pinfo, item_tree, offset); break; case IEEE80211_RADIOTAP_0_LENGTH_PSDU: - dissect_radiotap_0_length_psdu(tvb, pinfo, radiotap_tree, offset, &phdr); + dissect_radiotap_0_length_psdu(tvb, pinfo, item_tree, offset, &phdr); zero_length_psdu = TRUE; break; case IEEE80211_RADIOTAP_L_SIG: - dissect_radiotap_l_sig(tvb, pinfo, radiotap_tree, offset); + dissect_radiotap_l_sig(tvb, pinfo, item_tree, offset); + break; + case IEEE80211_RADIOTAP_TLVS: + /* used for padding */ + break; + default: + proto_tree_add_item(item_tree, hf_radiotap_unknown_tlv_data, tvb, + offset, iter.this_arg_size, ENC_NA); break; } } @@ -2971,6 +3008,26 @@ void proto_register_radiotap(void) FT_UINT32, BASE_HEX, NULL, 0x0, "Word from present flags bitmask", HFILL}}, + {&hf_radiotap_tlv, + {"TLV", "radiotap.tlv", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL}}, + + {&hf_radiotap_tlv_type, + {"TLV type", "radiotap.tlv.type", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL}}, + + {&hf_radiotap_tlv_datalen, + {"TLV datalen", "radiotap.tlv.datalen", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL}}, + + {&hf_radiotap_unknown_tlv_data, + {"unknown TLV data", "radiotap.tlv.unknown_data", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL}}, + #define RADIOTAP_MASK(name) BIT(IEEE80211_RADIOTAP_ ##name) /* Boolean 'present' flags */ @@ -3099,10 +3156,10 @@ void proto_register_radiotap(void) FT_BOOLEAN, 32, TFS(&tfs_present_absent), RADIOTAP_MASK(L_SIG), "Specifies whther or not the L-SIG field is present", HFILL}}, - {&hf_radiotap_present_reserved, - {"Reserved", "radiotap.present.reserved", - FT_UINT32, BASE_HEX, NULL, IEEE80211_RADIOTAP_NOTDEFINED, - "Not (yet) defined present flags (Must be zero)", HFILL}}, + {&hf_radiotap_present_tlv, + {"TLVs", "radiotap.present.tlv", + FT_BOOLEAN, 32, TFS(&tfs_present_absent), RADIOTAP_MASK(TLVS), + "Specifies switch to TLV fields", HFILL}}, {&hf_radiotap_present_rtap_ns, {"Radiotap NS next", "radiotap.present.rtap_ns", @@ -3827,6 +3884,11 @@ void proto_register_radiotap(void) FT_UINT16, BASE_DEC, NULL, 0x0, "Length of vendor-specified data", HFILL}}, + {&hf_radiotap_ven_item, + {"Vendor data item type", "radiotap.vendor_data_item_type", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Item type of vendor-specific data", HFILL}}, + {&hf_radiotap_ven_data, {"Vendor data", "radiotap.vendor_data", FT_NONE, BASE_NONE, NULL, 0x0, @@ -4558,6 +4620,7 @@ void proto_register_radiotap(void) }; static gint *ett[] = { &ett_radiotap, + &ett_radiotap_tlv, &ett_radiotap_present, &ett_radiotap_present_word, &ett_radiotap_flags, @@ -4593,7 +4656,6 @@ void proto_register_radiotap(void) static ei_register_info ei[] = { { &ei_radiotap_invalid_header_length, { "radiotap.length.invalid", PI_MALFORMED, PI_ERROR, "The radiotap header length is less than 8 bytes", EXPFILL }}, { &ei_radiotap_present, { "radiotap.present.radiotap_and_vendor", PI_MALFORMED, PI_ERROR, "Both radiotap and vendor namespace specified in bitmask word", EXPFILL }}, - { &ei_radiotap_present_reserved, { "radiotap.present.reserved.unknown", PI_UNDECODED, PI_NOTE, "Unknown Radiotap fields, code not implemented, Please check radiotap documentation, Contact Wireshark developers if you want this supported", EXPFILL }}, { &ei_radiotap_data_past_header, { "radiotap.data_past_header", PI_MALFORMED, PI_ERROR, "Radiotap data goes past the end of the radiotap header", EXPFILL }}, { &ei_radiotap_invalid_data_rate, { "radiotap.vht.datarate.invalid", PI_PROTOCOL, PI_WARN, "Data rate invalid", EXPFILL }}, };