From 7af1ec0984a359d39321e72a10afecb7b798df95 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Tue, 23 May 2017 19:07:49 -0700 Subject: [PATCH] Add some useful member functions to RadioTapParser --- include/tins/utils/radiotap_parser.h | 44 ++++++++++++++++++++++++- src/utils/radiotap_parser.cpp | 49 ++++++++++++++++++++-------- 2 files changed, 79 insertions(+), 14 deletions(-) diff --git a/include/tins/utils/radiotap_parser.h b/include/tins/utils/radiotap_parser.h index 4afd980..9a08b85 100644 --- a/include/tins/utils/radiotap_parser.h +++ b/include/tins/utils/radiotap_parser.h @@ -58,7 +58,25 @@ public: UNKNOWN_NS }; - typedef PDUOption option; + typedef PDUOption option; + + /** + * Represents the size and alignment of each RadioTap field + */ + struct FieldMetadata { + uint32_t size; + uint32_t alignment; + }; + + /** + * Contains metadata for each data field in RadioTap + */ + static const FieldMetadata RADIOTAP_METADATA[]; + + /** + * Represents the maximum bit we have information for + */ + static const uint32_t MAX_RADIOTAP_FIELD; /** * \brief Constructs a RadioTap parser around a payload @@ -78,6 +96,13 @@ public: */ NamespaceType current_namespace() const; + /** + * \brief Gets a 0 index based namespace index. + * + * This index will be incremented every time a new namespace is found + */ + uint32_t current_namespace_index() const; + /** * Gets the current field being parsed */ @@ -103,10 +128,27 @@ public: */ bool advance_field(); + /** + * \brief Skips all fields until the provided one is found + * + * This will effectively move the current option pointer until the field is + * found or the end of the options list is reached + * + * \return true iff the field was foudn + */ + bool skip_to_field(RadioTap::PresentFlags flag); + /** * Indicates whether this RadioTap options buffer contains any fields set */ bool has_fields() const; + + /** + * \brief Indicates whether the provided field is set. + * + * This will look the field up in all flag sets and not just the current one + */ + bool has_field(RadioTap::PresentFlags flag) const; private: const uint8_t* find_options_start() const; bool advance_to_next_field(bool start_from_zero); diff --git a/src/utils/radiotap_parser.cpp b/src/utils/radiotap_parser.cpp index 677064c..058655a 100644 --- a/src/utils/radiotap_parser.cpp +++ b/src/utils/radiotap_parser.cpp @@ -35,12 +35,7 @@ using std::vector; namespace Tins { namespace Utils { -struct FieldMetadata { - uint32_t size; - uint32_t alignment; -}; - -static const FieldMetadata RADIOTAP_METADATA[] = { +const RadioTapParser::FieldMetadata RadioTapParser::RADIOTAP_METADATA[] = { { 8, 8 }, /// TSFT { 1, 1 }, // FLAGS { 1, 1 }, // RATE @@ -63,7 +58,8 @@ static const FieldMetadata RADIOTAP_METADATA[] = { { 3, 1 }, // MCS }; -static const uint32_t BIT_LIMIT = sizeof(RADIOTAP_METADATA) / sizeof(FieldMetadata) + 1; +const uint32_t RadioTapParser::MAX_RADIOTAP_FIELD = sizeof(RADIOTAP_METADATA) / + sizeof(FieldMetadata) + 1; #if TINS_IS_LITTLE_ENDIAN TINS_BEGIN_PACK @@ -141,7 +137,7 @@ void align_buffer(const uint8_t* buffer_start, const uint8_t*& buffer, uint32_t } RadioTapParser::RadioTapParser(const vector& buffer) -: current_namespace_(RADIOTAP_NS), current_bit_(BIT_LIMIT), namespace_index_(0) { +: current_namespace_(RADIOTAP_NS), current_bit_(MAX_RADIOTAP_FIELD), namespace_index_(0) { if (buffer.empty()) { start_ = 0; end_ = 0; @@ -160,6 +156,10 @@ RadioTapParser::NamespaceType RadioTapParser::current_namespace() const { return current_namespace_; } +uint32_t RadioTapParser::current_namespace_index() const { + return namespace_index_; +} + RadioTap::PresentFlags RadioTapParser::current_field() const { return static_cast(1 << current_bit_); } @@ -178,7 +178,7 @@ const uint8_t* RadioTapParser::current_option_ptr() const { bool RadioTapParser::advance_field() { // If we have no buffer to parse, then we can't advance - if (start_ == 0 || current_bit_ == BIT_LIMIT) { + if (start_ == 0 || current_bit_ == MAX_RADIOTAP_FIELD) { return false; } // If we manage to advance the field, return true @@ -186,7 +186,7 @@ bool RadioTapParser::advance_field() { return true; } // We finished iterating the current namespace (if any). Reset our bit - current_bit_ = BIT_LIMIT; + current_bit_ = MAX_RADIOTAP_FIELD; // Otherwise, let's try advancing the namespace. If we fail, then we failed if (!advance_to_next_namespace()) { return false; @@ -195,8 +195,31 @@ bool RadioTapParser::advance_field() { return advance_to_next_field(true /* start from 0*/); } +bool RadioTapParser::skip_to_field(RadioTap::PresentFlags flag) { + while (has_fields() && current_field() != flag) { + advance_field(); + } + return has_fields(); +} + bool RadioTapParser::has_fields() const { - return current_bit_ != BIT_LIMIT; + return current_bit_ != MAX_RADIOTAP_FIELD; +} + +bool RadioTapParser::has_field(RadioTap::PresentFlags flag) const { + const uint8_t* ptr = start_; + while (ptr + sizeof(uint32_t) < end_) { + const RadioTapFlags* flags = (const RadioTapFlags*)ptr; + if (is_field_set(flag, flags)) { + return true; + } + if (!flags->ext) { + break; + } + // Jump to the next flags field + ptr += sizeof(uint32_t); + } + return false; } const uint8_t* RadioTapParser::find_options_start() const { @@ -227,10 +250,10 @@ bool RadioTapParser::advance_to_next_field(bool start_from_zero) { current_ptr_ += RADIOTAP_METADATA[current_bit_].size; bit = current_bit_ + 1; } - while (!is_field_set(1 << bit, flags) && bit < BIT_LIMIT) { + while (!is_field_set(1 << bit, flags) && bit < MAX_RADIOTAP_FIELD) { bit++; } - if (bit < BIT_LIMIT) { + if (bit < MAX_RADIOTAP_FIELD) { const uint8_t* radiotap_start = start_ - sizeof(uint32_t); // Skip and align the buffer align_buffer(radiotap_start, current_ptr_, end_ - radiotap_start,