/* * Copyright (c) 2017, Matias Fontanini * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #if !defined(TINS_RADIOTAP_PARSER_H) && defined(TINS_HAVE_DOT11) #define TINS_RADIOTAP_PARSER_H #include #include #include #include namespace Tins { namespace Utils { struct RadioTapFlags; /** * \brief Allows parsing RadioTap options * * RadioTap is a somehow tricky protocol to be parsed, as it has ordered flags, * alignment between options, etc. This class allows parsing options in a RadioTap * header without much trouble. */ class RadioTapParser { public: /** * Represents the RadioTap namespace currently being parsed */ enum NamespaceType { RADIOTAP_NS, VENDOR_NS, UNKNOWN_NS }; /** * 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 * * Note that the payload is not copied, hence it must be kept in * scope while the parser is still being used. * * The buffer should contain an entire RadioTap header, with optionally * extra data at the end, which will be ignored. * * \param buffer The buffer to be parsed */ RadioTapParser(const std::vector& buffer); /** * Gets the current namespace being parsed */ 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 */ RadioTap::PresentFlags current_field() const; /** * Gets the option the parsed is currently pointing at */ RadioTap::option current_option(); /** * \brief Gets the pointer at which the current option is located * * A past-the-end pointer may be returned in case of malformed input or * end of data. Its validity must be checked (e.g. using * \ref RadioTapParser.has_fields) before dereference. */ const uint8_t* current_option_ptr() const; /** * \brief Advances to the next option * * If there's a namespace change, this will handle that as well. * * \return true iff advancing was successfull (e.g. false if we reached * the end of the header) */ bool advance_field(); /** * \brief Advances to the next namespace * * \return true iff advancing was successfull (e.g. false if we're currently * in the last namespace) */ bool advance_namespace(); /** * Gets the current namespace's flags */ RadioTap::PresentFlags namespace_flags() const; /** * \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_first_field(); bool advance_to_next_field(); bool skip_current_field(); bool advance_to_next_namespace(); const RadioTapFlags* get_flags_ptr() const; void load_current_flags(); bool is_field_set(uint32_t bit, const RadioTapFlags* flags) const; const uint8_t* start_; const uint8_t* end_; const uint8_t* current_ptr_; uint64_t current_bit_; uint32_t current_flags_; uint32_t namespace_index_; NamespaceType current_namespace_; }; } // Utils } // Tins #endif // TINS_RADIOTAP_PARSER_H