diff --git a/include/ieee802-11.h b/include/ieee802-11.h index b263766..0e316d3 100644 --- a/include/ieee802-11.h +++ b/include/ieee802-11.h @@ -22,6 +22,7 @@ #ifndef __IEEE802_11_h #define __IEEE802_11_h +#include #include #include @@ -46,6 +47,45 @@ namespace Tins { CONTROL = 1, DATA = 2 }; + + /** + * \brief Enum for the different types of tagged options. + */ + enum TaggedOption { + SSID, + SUPPORTED_RATES, + FH_SET, + DS_SET, + CF_SET, + TIM, + BSS, + COUNTRY, + HOPPING_PATTERN_PARAMS, + HOPPING_PATTERN_TABLE, + REQUEST, + 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, + QOS_CAPABILITY = 46, + RSN = 48, + EXT_SUPPORTED_RATES = 50 + }; /** * \brief Enum for the different subtypes of 802.11 management frames. @@ -93,6 +133,35 @@ namespace Tins { CF_ACK_POLL = 7 }; + /** + * \brief IEEE 802.11 options struct. + */ + struct IEEE802_11_Option { + /** + * \brief The option number. + */ + uint8_t option; + /** + * \brief The value's length in bytes. + */ + uint8_t length; + /** + * \brief The option's value. + */ + uint8_t *value; + + /** + * \brief Creates an instance of IEEE802_11_Option. + * + * The option's value is copied, therefore the user should + * manually free any memory pointed by the "val" parameter. + * \param opt The option number. + * \param len The length of the option's value in bytes. + * \param val The option's value. + */ + IEEE802_11_Option(uint8_t opt, uint8_t len, const uint8_t *val); + }; + /** * \brief Constructor for creating a 802.11 PDU * @@ -137,7 +206,14 @@ namespace Tins { * \param total_sz The total size of the buffer. */ IEEE802_11(const uint8_t *buffer, uint32_t total_sz); - + + /** + * \brief IEEE802_11 destructor. + * + * Releases the memory allocated for tagged options. + */ + ~IEEE802_11(); + /** * \brief Getter for the protocol version. * @@ -410,12 +486,24 @@ namespace Tins { * \sa PDU::send() */ bool send(PacketSender* sender); + + /** + * \brief Adds a new option to this IEEE802_11 PDU. + * + * This copies the value buffer. + * \param opt The option identifier. + * \param len The length of the value field. + * \param val The value of this option. + */ + void add_tagged_option(TaggedOption opt, uint8_t len, const uint8_t *val); /** * \brief Getter for the PDU's type. * \sa PDU::pdu_type */ PDUType pdu_type() const { return PDU::IEEE802_11; } + protected: + virtual size_t write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) { return 0; } private: /** * Struct that represents the 802.11 header @@ -465,11 +553,14 @@ namespace Tins { } __attribute__((__packed__)); IEEE802_11(const ieee80211_header *header_ptr); - + void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); + + ieee80211_header _header; uint8_t _opt_addr[6]; - uint32_t _iface_index; + uint32_t _iface_index, _options_size; + std::list _options; }; diff --git a/src/dhcp.cpp b/src/dhcp.cpp index c64c75c..d26d44c 100644 --- a/src/dhcp.cpp +++ b/src/dhcp.cpp @@ -140,18 +140,22 @@ uint32_t Tins::DHCP::header_size() const { void Tins::DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { assert(total_sz >= header_size()); - uint8_t *result = new uint8_t[_size], *ptr = result + sizeof(uint32_t); - // Magic cookie - *((uint32_t*)result) = Utils::net_to_host_l(0x63825363); - for(std::list::const_iterator it = _options.begin(); it != _options.end(); ++it) { - *(ptr++) = it->option; - *(ptr++) = it->length; - std::memcpy(ptr, it->value, it->length); - ptr += it->length; + uint8_t *result = 0; + if(_size) { + result = new uint8_t[_size]; + uint8_t *ptr = result + sizeof(uint32_t); + // Magic cookie + *((uint32_t*)result) = Utils::net_to_host_l(0x63825363); + for(std::list::const_iterator it = _options.begin(); it != _options.end(); ++it) { + *(ptr++) = it->option; + *(ptr++) = it->length; + std::memcpy(ptr, it->value, it->length); + ptr += it->length; + } + // End of options + result[_size-1] = END; + vend(result, _size); } - // End of options - result[_size-1] = END; - vend(result, _size); BootP::write_serialization(buffer, total_sz, parent); delete[] result; } diff --git a/src/ieee802-11.cpp b/src/ieee802-11.cpp index 31355b8..a9c3014 100644 --- a/src/ieee802-11.cpp +++ b/src/ieee802-11.cpp @@ -35,7 +35,7 @@ using namespace std; -Tins::IEEE802_11::IEEE802_11(const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr, PDU* child) : PDU(ETHERTYPE_IP, child) { +Tins::IEEE802_11::IEEE802_11(const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr, PDU* child) : PDU(ETHERTYPE_IP, child), _options_size(0) { memset(&this->_header, 0, sizeof(ieee80211_header)); if(dst_hw_addr) this->dst_addr(dst_hw_addr); @@ -43,7 +43,7 @@ Tins::IEEE802_11::IEEE802_11(const uint8_t* dst_hw_addr, const uint8_t* src_hw_a this->src_addr(src_hw_addr); } -Tins::IEEE802_11::IEEE802_11(const std::string& iface, const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr, PDU* child) throw (std::runtime_error) : PDU(ETHERTYPE_IP, child) { +Tins::IEEE802_11::IEEE802_11(const std::string& iface, const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr, PDU* child) throw (std::runtime_error) : PDU(ETHERTYPE_IP, child), _options_size(0) { memset(&this->_header, 0, sizeof(ieee80211_header)); if(dst_hw_addr) this->dst_addr(dst_hw_addr); @@ -53,7 +53,7 @@ Tins::IEEE802_11::IEEE802_11(const std::string& iface, const uint8_t* dst_hw_add } -Tins::IEEE802_11::IEEE802_11(uint32_t iface_index, const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr, PDU* child) : PDU(ETHERTYPE_IP, child) { +Tins::IEEE802_11::IEEE802_11(uint32_t iface_index, const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr, PDU* child) : PDU(ETHERTYPE_IP, child), _options_size(0) { memset(&this->_header, 0, sizeof(ieee80211_header)); if(dst_hw_addr) this->dst_addr(dst_hw_addr); @@ -62,10 +62,28 @@ Tins::IEEE802_11::IEEE802_11(uint32_t iface_index, const uint8_t* dst_hw_addr, c this->iface(iface_index); } -Tins::IEEE802_11::IEEE802_11(const uint8_t *buffer, uint32_t total_sz) : PDU(ETHERTYPE_IP) { +Tins::IEEE802_11::IEEE802_11(const uint8_t *buffer, uint32_t total_sz) : PDU(ETHERTYPE_IP), _options_size(0) { } +Tins::IEEE802_11::~IEEE802_11() { + while(_options.size()) { + delete[] _options.front().value; + _options.pop_front(); + } +} + +Tins::IEEE802_11::IEEE802_11_Option::IEEE802_11_Option(uint8_t opt, uint8_t len, const uint8_t *val) { + value = new uint8_t[len]; + std::memcpy(value, val, len); +} + +void Tins::IEEE802_11::add_tagged_option(TaggedOption opt, uint8_t len, const uint8_t *val) { + uint32_t opt_size = len + (sizeof(uint8_t) << 1); + _options.push_back(IEEE802_11_Option((uint8_t)opt, len, val)); + _options_size += opt_size; +} + void Tins::IEEE802_11::protocol(uint8_t new_proto) { this->_header.control.protocol = new_proto; } @@ -145,7 +163,7 @@ void Tins::IEEE802_11::iface(const std::string& new_iface) throw (std::runtime_e } uint32_t Tins::IEEE802_11::header_size() const { - uint32_t sz = sizeof(ieee80211_header); + uint32_t sz = sizeof(ieee80211_header) + _options_size; if (this->to_ds() && this->from_ds()) sz += 6; return sz; @@ -170,8 +188,20 @@ void Tins::IEEE802_11::write_serialization(uint8_t *buffer, uint32_t total_sz, c assert(total_sz >= my_sz); memcpy(buffer, &this->_header, sizeof(ieee80211_header)); + buffer += sizeof(ieee80211_header); if (this->to_ds() && this->from_ds()) { - memcpy(buffer + sizeof(ieee80211_header), this->_opt_addr, 6); + memcpy(buffer, this->_opt_addr, 6); + buffer += 6; + total_sz -= 6; + } + + uint32_t child_len = write_fixed_parameters(buffer, total_sz - sizeof(ieee80211_header) - _options_size); + buffer += child_len; + for(std::list::const_iterator it = _options.begin(); it != _options.end(); ++it) { + *(buffer++) = it->option; + *(buffer++) = it->length; + std::memcpy(buffer, it->value, it->length); + buffer += it->length; } }