/* * 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 <tins/config.h> #if !defined(TINS_DOT11_DOT11_H) && defined(TINS_HAVE_DOT11) #define TINS_DOT11_DOT11_H #include <tins/pdu.h> #include <tins/pdu_option.h> #include <tins/small_uint.h> #include <tins/hw_address.h> #include <tins/endianness.h> #include <tins/cxxstd.h> #include <tins/macros.h> namespace Tins { namespace Memory { class InputMemoryStream; class OutputMemoryStream; } // Memory class RSNInformation; /** * \brief Class representing an 802.11 frame. */ class TINS_API Dot11 : public PDU { public: /** * The type used to store hardware addresses. */ typedef HWAddress<6> address_type; /** * \brief IEEE 802.11 options struct. */ typedef PDUOption<uint8_t, Dot11> option; /** * The type used to store tagged options. */ typedef std::vector<option> options_type; /** * \brief This PDU's flag. */ static const PDU::PDUType pdu_flag = PDU::DOT11; /** * \brief Broadcast hardware address. */ static const address_type BROADCAST; /** * The endianness used by Dot11. */ static const endian_type endianness = LE; /** * \brief Enum for the different types of 802.11 frames. * */ enum Types { MANAGEMENT = 0, CONTROL = 1, DATA = 2 }; /** * \brief Enum for the different types of tagged options. */ enum OptionTypes { SSID, SUPPORTED_RATES, FH_SET, DS_SET, CF_SET, TIM, IBSS_SET, COUNTRY, HOPPING_PATTERN_PARAMS, HOPPING_PATTERN_TABLE, REQUEST_INFORMATION, BSS_LOAD, EDCA, TSPEC, TCLAS, SCHEDULE, CHALLENGE_TEXT, POWER_CONSTRAINT = 32, POWER_CAPABILITY, TPC_REQUEST, TPC_REPORT, SUPPORTED_CHANNELS, CHANNEL_SWITCH, MEASUREMENT_REQUEST, MEASUREMENT_REPORT, QUIET, IBSS_DFS, ERP_INFORMATION, TS_DELAY, TCLAS_PROCESSING, HT_CAPABILITY, QOS_CAPABILITY, RSN = 48, EXT_SUPPORTED_RATES = 50, AP_CHANNEL_REPORT, NEIGHBOR_REPORT, RCPI, MOBILITY_DOMAIN_MDE, FAST_BSS_TRANSITION_FTE, TIMEOUT_INTERVAL, RIC_DATA_RDE, DSE_REG_LOC, SUPPORTED_OP_CLASSES, EXT_CH_SWITCH_ANNOUNCEMENT, HT_OPERATION, SEC_CH_OFFSET, BSS_AVG_ACCESS_DELAY, ANTENNA, RSNI, MEASUREMENT_PILOT_TRANSMISSION, BSS_AVAIL_ADMISSION_CAPACITY, BSS_AC_ACCESS_DELAY, TIME_ADVERTISEMENT, RM_ENABLED_CAP, MULTIPLE_BSSID, BSS_2040_COEX, BSS_2040_INTOLERANT_CH_REPORT, OVERLAPPING_BSS_SCAN_PARAM, RIC_DESCRIPTOR, MGMT_MIC, EVENT_REQ = 78, EVENT_REPORT, DIAG_REQ, DIAG_REPORT, LOCATION_PARAMS, NONTRANSMITTED_BSSID_CAP, SSID_LIST, MULTIPLE_BSSID_INDEX, FMS_DESCRIPTOR, FMS_REQ, FMS_RESP, QOS_TRAFFIC_CAP, BSS_MAX_IDLE_PERIOD, TFS_REQ, TFS_RESP, WNM_SLEEP_MODE, TIM_BROADCAST_REQ, TIM_BROADCAST_RESP, COLLOCATED_INTERFERENCE_REPORT, CH_USAGE, TIME_ZONE, DMS_REQ, DMS_RESP, LINK_ID, WAKEUP_SCHEDULE, CH_SWITCH_TIMING, PTI_CONTROL, TPU_BUFFER_STATUS, INTERWORKING, ADVERTISEMENT_PROTOCOL, EXPEDITED_BANDWIDTH_REQ, QOS_MAP, ROAMING_CONSORTIUM, EMERG_ALERT_ID, MESH_CONFIG, MESH_ID, MESH_LINK_METRIC_REPORT, CONGESTION_NOTIFICATION, MESH_PEERING_MGMT, MESH_CH_SWITCH_PARAMS, MESH_AWAKE_WINDOW, BEACON_TIMING, MCCAOP_SETUP_REQ, MCCAOP_SETUP_REPLY, MCCAOP_ADVERTISEMENT, MCCAOP_TEARDOWN, GANN, RANN, EXT_CAP, PREQ = 130, PREP, PERR, PXU = 137, PXUC, AUTH_MESH_PEER_EX, MIC, DEST_URI, UAPSD_COEX, DMG_WAKEUP_SCHEDULE, EXT_SCHEDULE, STA_AVAIL, DMG_TSPEC, NEXT_DMG_ATI, DMG_CAP, DMG_OP = 151, DMG_BSS_PARAM_CHG, DMG_BEAM_REFINEMENT, CH_MEASUREMENT_FEEDBACK, AWAKE_WINDOW = 157, MULTIBAND, ADDBA_ESXT, NEXTPCP_LIST, PCP_HANDOVER, DMG_LINK_MARGIN, SWITCHING_STREAM, SESSION_TRANSITION, DYNAMIC_TONE_PAIRING_REPORT, CLUSTER_REPORT, RELAY_CAP, RELAY_TRANSFER_PARAM_SET, BEAMLINK_MAINTENANCE, MULTIPLE_MAC_SUBLAYERS, UPID, DMG_LINK_ADAPTATION_ACK, MCCAOP_ADV_OVERVIEW = 174, QUIET_PERIOD_REQ, QUIET_PERIOD_RESP = 177, QMF_POLICY = 181, ECAPC_POLICY = 182, CLUSTER_TIME_OFFSET, INTRA_ACCESS_CAT_PRIORITY, SCS_DESCRIPTOR, QLOAD_REPORT, HCCA_TXOP_UPDATE_COUNT, HIGHER_LAYER_STREAM_ID, GCR_GROUP_ADDR, ANTENNA_SECTOR_ID_PATTERN, VHT_CAP, VHT_OP, EXT_BSS_LOAD, WIDE_BANDWIDTH_CH_SWITCH, TRANSMIT_POWER_ENVELOPE, CH_SWITCH_WRAPPER, AID, QUIET_CHANNEL, OP_MODE_NOTIFY, UPSIM, REDUCED_NEIGHBOR_REPORT, TVHT_OP, DEV_LOC = 204, WHITE_SPACE_MAP, FINE_TUNING_MEASUREMENT_PARAMS, VENDOR_SPECIFIC = 221 }; /** * \brief Enum for the different subtypes of 802.11 management frames. * */ enum ManagementSubtypes { ASSOC_REQ = 0, ASSOC_RESP = 1, REASSOC_REQ = 2, REASSOC_RESP = 3, PROBE_REQ = 4, PROBE_RESP = 5, BEACON = 8, ATIM = 9, DISASSOC = 10, AUTH = 11, DEAUTH = 12 }; /** * \brief Enum for the different subtypes of 802.11 control frames. * */ enum ControlSubtypes { BLOCK_ACK_REQ = 8, BLOCK_ACK = 9, PS = 10, RTS = 11, CTS = 12, ACK = 13, CF_END = 14, CF_END_ACK = 15 }; /** * \brief Enum fro the different subtypes of 802.11 data frames. * */ enum DataSubtypes { DATA_DATA = 0, DATA_CF_ACK = 1, DATA_CF_POLL = 2, DATA_CF_ACK_POLL = 3, DATA_NULL = 4, CF_ACK = 5, CF_POLL = 6, CF_ACK_POLL = 7, QOS_DATA_DATA = 8, QOS_DATA_CF_ACK = 9, QOS_DATA_CF_POLL = 10, QOS_DATA_CF_ACK_POLL = 11, QOS_DATA_NULL = 12 }; /** * \brief Constructs an 802.11 PDU. * * \param dst_hw_addr The destination hardware address. */ Dot11(const address_type& dst_hw_addr = address_type()); /** * \brief Constructs 802.11 PDU from a buffer and adds all * identifiable PDUs found in the buffer as children of this one. * * If the next PDU is not recognized, then a RawPDU is used. * * If there is not enough size for a 802.11 header in the * buffer, a malformed_packet exception is thrown. * * \param buffer The buffer from which this PDU will be constructed. * \param total_sz The total size of the buffer. */ Dot11(const uint8_t* buffer, uint32_t total_sz); /** * \brief Getter for the protocol version field. * * \return The stored protocol version field. */ small_uint<2> protocol() const { return header_.control.protocol; } /** * \brief Getter for the Type field. * * \return The stored Type field. */ small_uint<2> type() const { return header_.control.type; } /** * \brief Getter for the Subtype field. * * \return The stored Subtype field. */ small_uint<4> subtype() const { return header_.control.subtype; } /** * \brief Getter for the To-DS field. * * \return The stored To-DS field. */ small_uint<1> to_ds() const { return header_.control.to_ds; } /** * \brief Getter for the From-DS field. * * \return The stored From-DS field. */ small_uint<1> from_ds() const { return header_.control.from_ds; } /** * \brief Getter for the More-Frag field. * * \return The stored More-Frag field. */ small_uint<1> more_frag() const { return header_.control.more_frag; } /** * \brief Getter for the Retry field. * * \return The stored Retry field. */ small_uint<1> retry() const { return header_.control.retry; } /** * \brief Getter for the Power-Management field. * * \return The stored Power-Management field. */ small_uint<1> power_mgmt() const { return header_.control.power_mgmt; } /** * \brief Getter for the More Data field. * * \return The stored More Data field. */ small_uint<1> more_data() const { return header_.control.more_data; } /** * \brief Getter for the WEP field. * * \return The stored WEP field. */ small_uint<1> wep() const { return header_.control.wep; } /** * \brief Getter for the Order field. * * \return The stored Order field. */ small_uint<1> order() const { return header_.control.order; } /** * \brief Getter for the Duration-ID field. * * \return The stored Duration-ID field. */ uint16_t duration_id() const { return Endian::le_to_host(header_.duration_id); } /** * \brief Getter for the first address. * * \return The stored first address. */ address_type addr1() const { return header_.addr1; } // Setters /** * \brief Setter for the protocol version field. * * \param new_proto The new protocol version field value. */ void protocol(small_uint<2> new_proto); /** * \brief Setter for the type field. * * \param new_type The new type field value. */ void type(small_uint<2> new_type); /** * \brief Setter for the subtype field. * * \param new_subtype The new subtype field value. */ void subtype(small_uint<4> new_subtype); /** * \brief Setter for the To-DS field. * * \param new_value The new To-DS field value. */ void to_ds(small_uint<1> new_value); /** * \brief Setter for the From-DS field. * * \param new_value The new From-DS field value. */ void from_ds(small_uint<1> new_value); /** * \brief Setter for the More-Frag field. * * \param new_value The new More-Frag field value. */ void more_frag(small_uint<1> new_value); /** * \brief Setter for the Retry field. * * \param new_value The new Retry field value. */ void retry(small_uint<1> new_value); /** * \brief Setter for the Power-Management field. * * \param new_value The new Power-Management field value. */ void power_mgmt(small_uint<1> new_value); /** * \brief Setter for the More Data field. * * \param new_value The new More Data field value. */ void more_data(small_uint<1> new_value); /** * \brief Setter for the WEP field. * * \param new_value The new WEP field value. */ void wep(small_uint<1> new_value); /** * \brief Setter for the Order field. * * \param new_value The new Order field value. */ void order(small_uint<1> new_value); /** * \brief Setter for the Duration-ID field. * * \param new_duration_id The new Duration-ID field value. */ void duration_id(uint16_t new_duration_id); /** * \brief Setter for the first address. * * \param new_addr1 The new first address. */ void addr1(const address_type& new_addr1); /* Virtual methods */ /** * \brief Returns the 802.11 frame's header length. * * \return An uint32_t with the header's size. * \sa PDU::header_size() */ uint32_t header_size() const; #ifndef _WIN32 /** * \sa PDU::send() */ void send(PacketSender& sender, const NetworkInterface& iface); #endif // _WIN32 /** * \brief Adds a new option to this Dot11 PDU. * \param opt The option to be added. */ void add_option(const option& opt); #if TINS_IS_CXX11 /** * \brief Adds a new option to this Dot11 PDU. * * The option is move-constructed * * \param opt The option to be added. */ void add_option(option &&opt) { internal_add_option(opt); options_.push_back(std::move(opt)); } #endif /** * \brief Removes a Dot11 option. * * If there are multiple options of the given type, only the first one * will be removed. * * \param type The type of the option to be removed. * \return true if the option was removed, false otherwise. */ bool remove_option(OptionTypes type); /** * \brief Looks up a tagged option in the option list. * * The returned pointer <b>must not</b> be free'd. * * \param type The option identifier. * \return The option found, or 0 if no such option has been set. */ const option* search_option(OptionTypes type) const; /** * \brief Getter for the PDU's type. * \sa PDU::pdu_type */ PDUType pdu_type() const { return pdu_flag; } /** * \sa PDU::clone */ Dot11* clone() const { return new Dot11(*this); } /** * \brief Check whether this PDU matches the specified flag. * \param flag The flag to match * \sa PDU::matches_flag */ bool matches_flag(PDUType flag) const { return flag == pdu_flag; } /** * \brief Getter for the option list. * * \return The options list. */ const options_type& options() const { return options_; } /** * \brief Allocates an Dot11 PDU from a buffer. * * This can be used somehow as a "virtual constructor". This * method instantiates the appropriate subclass of Dot11 from the * given buffer. * * The allocated class' type will be figured out from the * information provided in the buffer. * * \param buffer The buffer from which to take the PDU data. * \param total_sz The total size of the buffer. * \return The allocated Dot11 PDU. */ static Dot11* from_bytes(const uint8_t* buffer, uint32_t total_sz); protected: virtual void write_ext_header(Memory::OutputMemoryStream& stream); virtual void write_fixed_parameters(Memory::OutputMemoryStream& stream); void parse_tagged_parameters(Memory::InputMemoryStream& stream); void add_tagged_option(OptionTypes opt, uint8_t len, const uint8_t* val); protected: /** * Struct that represents the 802.11 header */ TINS_BEGIN_PACK struct dot11_header { TINS_BEGIN_PACK struct { #if TINS_IS_LITTLE_ENDIAN uint16_t protocol:2, type:2, subtype:4, to_ds:1, from_ds:1, more_frag:1, retry:1, power_mgmt:1, more_data:1, wep:1, order:1; #elif TINS_IS_BIG_ENDIAN uint16_t subtype:4, type:2, protocol:2, order:1, wep:1, more_data:1, power_mgmt:1, retry:1, more_frag:1, from_ds:1, to_ds:1; #endif } TINS_END_PACK control; uint16_t duration_id; uint8_t addr1[address_type::address_size]; } TINS_END_PACK; private: Dot11(const dot11_header* header_ptr); void internal_add_option(const option& opt); void write_serialization(uint8_t* buffer, uint32_t total_sz); options_type::const_iterator search_option_iterator(OptionTypes type) const; options_type::iterator search_option_iterator(OptionTypes type); dot11_header header_; uint32_t options_size_; options_type options_; }; } // Tins #endif // TINS_DOT11_DOT11_H