From ecfed8db4495634a4c0d8ab429914203ff11c20d Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Sat, 3 Jun 2017 09:17:29 -0700 Subject: [PATCH] Add support for XChannel field on RadioTap --- include/tins/radiotap.h | 26 ++++++++++++++++++++++---- src/radiotap.cpp | 37 ++++++++++++++++--------------------- tests/src/radiotap_test.cpp | 20 ++++++++++++++++++-- 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/include/tins/radiotap.h b/include/tins/radiotap.h index 520456b..17dac80 100644 --- a/include/tins/radiotap.h +++ b/include/tins/radiotap.h @@ -84,7 +84,7 @@ public: */ enum PresentFlags { TSFT = 1 << 0, - TSTF = 1 << 0, // Deprecated (typo in the name...) + TSTF = 1 << 0, ///< Deprecated (typo), use TSFT FLAGS = 1 << 1, RATE = 1 << 2, CHANNEL = 1 << 3, @@ -101,6 +101,7 @@ public: RX_FLAGS = 1 << 14, TX_FLAGS = 1 << 15, DATA_RETRIES = 1 << 17, + XCHANNEL = 1 << 18, CHANNEL_PLUS = 1 << 18, MCS = 1 << 19 }; @@ -128,6 +129,17 @@ public: uint8_t flags; uint8_t mcs; } TINS_END_PACK; + + /** + * \brief The type used to represent the XChannel field + */ + TINS_BEGIN_PACK + struct xchannel_type { + uint32_t flags; + uint16_t frequency; + uint8_t channel; + uint8_t max_power; + } TINS_END_PACK; /** * The type used to store RadioTap options @@ -250,6 +262,12 @@ public: */ void tx_flags(uint16_t new_tx_flag); + /** + * \brief Setter for the xchannel field. + * \param new_xchannel The xchannel field + */ + void xchannel(xchannel_type new_xchannel); + /** * \brief Setter for the data retries field. * \param new_rx_flag The data retries. @@ -343,10 +361,10 @@ public: uint8_t db_signal() const; /** - * \brief Getter for the channel+ field. - * \return The channel+ field. + * \brief Getter for the XChannel field. + * \return The XChannel field. */ - uint32_t channel_plus() const; + xchannel_type xchannel() const; /** * \brief Getter for the data retries field diff --git a/src/radiotap.cpp b/src/radiotap.cpp index 8d60266..777e99f 100644 --- a/src/radiotap.cpp +++ b/src/radiotap.cpp @@ -180,6 +180,14 @@ void RadioTap::tx_flags(uint16_t new_tx_flags) { add_integral_option(*this, TX_FLAGS, new_tx_flags); } +void RadioTap::xchannel(xchannel_type new_xchannel) { + uint8_t buffer[sizeof(new_xchannel)]; + new_xchannel.flags = Endian::host_to_le(new_xchannel.flags); + new_xchannel.frequency = Endian::host_to_le(new_xchannel.frequency); + memcpy(buffer, &new_xchannel, sizeof(new_xchannel)); + add_option(RadioTap::option(XCHANNEL, sizeof(buffer), buffer)); +} + void RadioTap::mcs(const mcs_type& new_mcs) { uint8_t buffer[sizeof(new_mcs)]; memcpy(buffer, &new_mcs, sizeof(new_mcs)); @@ -279,7 +287,7 @@ uint8_t RadioTap::antenna() const { RadioTap::mcs_type RadioTap::mcs() const { const option opt = do_find_option(MCS); mcs_type output; - memcpy(&output, opt.data_ptr(), sizeof(mcs_type)); + memcpy(&output, opt.data_ptr(), sizeof(output)); return output; } @@ -287,13 +295,13 @@ uint8_t RadioTap::db_signal() const { return do_find_option(DB_SIGNAL).to(); } -uint32_t RadioTap::channel_plus() const { - /*if (!header_.flags.channel_plus) { - throw field_not_present(); - } - return Endian::le_to_host(channel_type_);*/ - // TODO: wat - return 0xdadedade; +RadioTap::xchannel_type RadioTap::xchannel() const { + const option opt = do_find_option(XCHANNEL); + xchannel_type output; + memcpy(&output, opt.data_ptr(), sizeof(output)); + output.flags = Endian::le_to_host(output.flags); + output.frequency = Endian::le_to_host(output.frequency); + return output; } uint16_t RadioTap::rx_flags() const { @@ -355,19 +363,6 @@ void RadioTap::write_serialization(uint8_t* buffer, uint32_t total_sz) { header_.it_len = Endian::host_to_le(header_size()); stream.write(header_); stream.write(options_payload_.begin(), options_payload_.end()); - /*if (header_.flags.channel_plus) { - const uint32_t padding = ((stream.pointer() - buffer_start) % 4); - if (padding != 0) { - stream.fill(4 - padding, 0); - } - uint32_t dummy = channel_type_; - // nasty Big Endian fix - dummy = Endian::le_to_host(Endian::host_to_le(dummy)); - stream.write(dummy); - stream.write(channel_freq_); - stream.write(channel_); - stream.write(max_power_); - }*/ // If we have a trailer size, then we have the FCS flag on if (trailer_size() > 0 && inner_pdu()) { diff --git a/tests/src/radiotap_test.cpp b/tests/src/radiotap_test.cpp index c5c0893..f4dbc8f 100644 --- a/tests/src/radiotap_test.cpp +++ b/tests/src/radiotap_test.cpp @@ -346,7 +346,7 @@ TEST_F(RadioTapTest, ConstructorFromBuffer) { EXPECT_TRUE((radio.present() & RadioTap::RATE) != 0); EXPECT_TRUE((radio.present() & RadioTap::DBM_SIGNAL) != 0); EXPECT_TRUE((radio.present() & RadioTap::ANTENNA) != 0); - EXPECT_TRUE((radio.present() & RadioTap::CHANNEL_PLUS) != 0); + EXPECT_TRUE((radio.present() & RadioTap::XCHANNEL) != 0); EXPECT_TRUE((radio.flags() & RadioTap::FCS) != 0); EXPECT_THROW(radio.channel_type(), field_not_present); @@ -507,6 +507,22 @@ TEST_F(RadioTapTest, TSFT) { EXPECT_EQ(radio.tsft(), 0x7afb9a8dU); } +TEST_F(RadioTapTest, XChannel) { + RadioTap radio; + RadioTap::xchannel_type xchannel; + xchannel.flags = 0xabcd1234; + xchannel.frequency = 0xda21; + xchannel.max_power = 0x19; + xchannel.channel = 0x99; + radio.xchannel(xchannel); + + RadioTap::xchannel_type found_xchannel = radio.xchannel(); + EXPECT_EQ(xchannel.flags, found_xchannel.flags); + EXPECT_EQ(xchannel.frequency, found_xchannel.frequency); + EXPECT_EQ(xchannel.max_power, found_xchannel.max_power); + EXPECT_EQ(xchannel.channel, found_xchannel.channel); +} + TEST_F(RadioTapTest, SerializationWorksFine) { const uint8_t expected[] = { 0, 0, 26, 0, 43, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 108, @@ -555,7 +571,7 @@ TEST_F(RadioTapTest, RadioTapParsing) { EXPECT_EQ(2, parser.current_option().to()); EXPECT_TRUE(parser.advance_field()); - EXPECT_EQ(RadioTap::CHANNEL_PLUS,parser.current_field()); + EXPECT_EQ(RadioTap::XCHANNEL,parser.current_field()); EXPECT_EQ(0x1124143c00000140ULL, parser.current_option().to()); EXPECT_FALSE(parser.advance_field());