From 23076df07ab0d4d6aedc30b8d72eb8128e264479 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Wed, 22 Aug 2012 12:01:36 -0300 Subject: [PATCH] Added unit tests for Dot11ManagementFrame. --- include/dot11.h | 76 ++++++++++++++++++++----- src/dot11.cpp | 114 ++++++++++++++++++++++++------------- tests/src/dot11/beacon.cpp | 67 ++++++++++++++++++---- 3 files changed, 196 insertions(+), 61 deletions(-) diff --git a/include/dot11.h b/include/dot11.h index a1b3ef5..ac4e7e5 100644 --- a/include/dot11.h +++ b/include/dot11.h @@ -965,7 +965,7 @@ namespace Tins { } __attribute__((__packed__)); struct ibss_dfs_params { - static const bool minimum_size = address_type::address_size + sizeof(uint8_t) + 2 * sizeof(uint8_t); + static const size_t minimum_size = address_type::address_size + sizeof(uint8_t) + 2 * sizeof(uint8_t); address_type dfs_owner; uint8_t recovery_interval; @@ -979,6 +979,36 @@ namespace Tins { channel_map(channels) {} }; + struct country_params { + typedef std::vector container_type; + // String identifier: 3 bytes + static const size_t minimum_size = 3 + sizeof(uint8_t) * 3; + + std::string country; + container_type first_channel, number_channels, max_transmit_power; + + country_params() {} + + country_params(const std::string &country, const container_type &first, + const container_type &number, const container_type &max) + : country(country), first_channel(first), number_channels(number), + max_transmit_power(max) {} + }; + + struct fh_pattern_type { + typedef std::vector container_type; + static const size_t minimum_size = sizeof(uint8_t) * 4; + + uint8_t flag, number_of_sets, modulus, offset; + container_type random_table; + + fh_pattern_type() {} + + fh_pattern_type(uint8_t flag, uint8_t sets, uint8_t modulus, + uint8_t offset, const container_type& table) : flag(flag), + number_of_sets(sets), modulus(modulus), offset(offset), + random_table(table) {} + }; /** * \brief Getter for the second address. @@ -1006,7 +1036,7 @@ namespace Tins { * * \return The sequence number as an uint16_t. */ - uint16_t seq_num() const { return this->_ext_header.seq_control.seq_number; } + uint16_t seq_num() const { return Utils::le_to_host(_ext_header.seq_control.seq_number); } /** * \brief Getter for the fourth address. @@ -1157,12 +1187,9 @@ namespace Tins { /** * \brief Helper method to set the country tagged option. * - * \param countries Reference to a vector of uint8_t arrays of 3 bytes. Containing the list of countries. - * \param first_channels Reference to a vector of uint8_t. Containing the first channels for each country. - * \param num_channels Reference to a vector of uint8_t. Containing the number of channels for each country. - * \param max_power Reference to a vector of uint8_t. Containing the max power for each country. + * \param params The data to be used for this country option. */ - void country(const std::vector& countries, const std::vector& first_channels, const std::vector& number_channels, const std::vector& max_power); + void country(const country_params ¶ms); /** * \brief Helper method to set the FH parameters. @@ -1175,13 +1202,9 @@ namespace Tins { /** * \brief Helper method to set the FH pattern table. * - * \param flag uint8_t with the value of the flag field. - * \param number_of_sets uint8_t with the value of the number of sets field. - * \param modulus uint8_t with the value of the modulus field. - * \param offset uint8_t with the value of the offset field. - * \param random_table reference to vector of uint8_t witht the elements of the table. + * \param params The data to be used for this fh_pattern_table option. */ - void fh_pattern_table(uint8_t flag, uint8_t number_of_sets, uint8_t modulus, uint8_t offset, const std::vector& random_table); + void fh_pattern_table(const fh_pattern_type ¶ms); /** * \brief Helper method to set the Power Constraint tagged option. @@ -1362,6 +1385,33 @@ namespace Tins { */ ibss_dfs_params ibss_dfs() const; + /** + * \brief Helper method to get the country option. + * + * Throws a std::runtime_error if the option has not been set. + * + * \return country_params containing the country attributes. + */ + country_params country() const; + + /** + * \brief Helper method to get the fh parameters option. + * + * Throws a std::runtime_error if the option has not been set. + * + * \return ibss_dfs_params containing the fh parameters. + */ + std::pair fh_parameters() const; + + /** + * \brief Helper method to get the fh patterns option. + * + * Throws a std::runtime_error if the option has not been set. + * + * \return ibss_dfs_params containing the fh patterns. + */ + fh_pattern_type fh_pattern_table() const; + // ************************ /** diff --git a/src/dot11.cpp b/src/dot11.cpp index b1b056b..dd94c6e 100644 --- a/src/dot11.cpp +++ b/src/dot11.cpp @@ -308,7 +308,7 @@ void Dot11ManagementFrame::frag_num(uint8_t new_frag_num) { } void Dot11ManagementFrame::seq_num(uint16_t new_seq_num) { - this->_ext_header.seq_control.seq_number = new_seq_num; + this->_ext_header.seq_control.seq_number = Utils::host_to_le(new_seq_num); } void Dot11ManagementFrame::addr4(const address_type &new_addr4) { @@ -455,35 +455,24 @@ void Dot11ManagementFrame::ibss_dfs(const ibss_dfs_params ¶ms) { } -void Dot11ManagementFrame::country(const std::vector& countries, - const std::vector& first_channels, - const std::vector& number_channels, - const std::vector& max_power) { - - /* Check that the lists have the same number of elements */ - if ((countries.size() != first_channels.size()) || - (countries.size() != number_channels.size()) || - (countries.size() != max_power.size())) - throw runtime_error("Lists should be of equal length!"); - - uint8_t sz = 6 * countries.size(); - if (sz & 1) // If size is odd, pad it +void Dot11ManagementFrame::country(const country_params ¶ms) { + if ((params.first_channel.size() != params.number_channels.size()) || + (params.number_channels.size() != params.max_transmit_power.size())) + throw runtime_error("The length of the lists are distinct"); + if(params.country.size() != 3) + throw runtime_error("Invalid country identifier length"); + size_t sz = sizeof(uint8_t) * 3 * params.first_channel.size() + params.country.size(); + // Use 1 byte padding at the end if the length is odd. + if((sz & 1) == 1) sz++; - uint8_t* buffer = new uint8_t[sz]; - uint8_t* ptr_buffer = buffer; - for (uint8_t i = 0; i < countries.size(); i++) { - memcpy(ptr_buffer, countries[i], 3); - ptr_buffer += 3; - *ptr_buffer = first_channels[i]; - ptr_buffer++; - *ptr_buffer = number_channels[i]; - ptr_buffer++; - *ptr_buffer = max_power[i]; - ptr_buffer++; + std::vector buffer(sz); + uint8_t *ptr = std::copy(params.country.begin(), params.country.end(), &buffer[0]); + for(size_t i(0); i < params.first_channel.size(); ++i) { + *(ptr++) = params.first_channel[i]; + *(ptr++) = params.number_channels[i]; + *(ptr++) = params.max_transmit_power[i]; } - add_tagged_option(COUNTRY, sz, buffer); - delete[] buffer; - + add_tagged_option(COUNTRY, sz, &buffer[0]); } void Dot11ManagementFrame::fh_parameters(uint8_t prime_radix, uint8_t number_channels) { @@ -493,13 +482,8 @@ void Dot11ManagementFrame::fh_parameters(uint8_t prime_radix, uint8_t number_cha add_tagged_option(HOPPING_PATTERN_PARAMS, 2, buffer); } -void Dot11ManagementFrame::fh_pattern_table(uint8_t flag, - uint8_t number_of_sets, - uint8_t modulus, - uint8_t offset, - const vector& random_table) { - - uint8_t sz = 4 + random_table.size(); +void Dot11ManagementFrame::fh_pattern_table(const fh_pattern_type ¶ms) { + /*uint8_t sz = 4 + random_table.size(); uint8_t* buffer = new uint8_t[sz]; buffer[0] = flag; buffer[1] = number_of_sets; @@ -509,7 +493,17 @@ void Dot11ManagementFrame::fh_pattern_table(uint8_t flag, for (vector::const_iterator it = random_table.begin(); it != random_table.end(); it++) *(ptr_buffer++) = *it; add_tagged_option(HOPPING_PATTERN_TABLE, sz, buffer); - delete[] buffer; + delete[] buffer;*/ + std::vector data(sizeof(uint8_t) * 4 + params.random_table.size()); + uint8_t *ptr = &data[0]; + *(ptr++) = params.flag; + *(ptr++) = params.number_of_sets; + *(ptr++) = params.modulus; + *(ptr++) = params.offset; + fh_pattern_type::container_type::const_iterator it(params.random_table.begin()); + for(; it != params.random_table.end(); ++it) + *(ptr++) = *it; + add_tagged_option(HOPPING_PATTERN_TABLE, data.size(), &data[0]); } void Dot11ManagementFrame::power_constraint(uint8_t local_power_constraint) { @@ -675,8 +669,9 @@ Dot11ManagementFrame::request_info_type Dot11ManagementFrame::request_informatio throw std::runtime_error("Request information not set"); request_info_type output; const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size(); - while(ptr != end) - output.push_back(*(ptr++)); + //while(ptr != end) + // output.push_back(*(ptr++)); + output.assign(ptr, end); return output; } @@ -724,6 +719,49 @@ Dot11ManagementFrame::ibss_dfs_params Dot11ManagementFrame::ibss_dfs() const { return output; } +Dot11ManagementFrame::country_params Dot11ManagementFrame::country() const { + const Dot11::Dot11Option *option = search_option(COUNTRY); + if(!option || option->data_size() < country_params::minimum_size) + throw std::runtime_error("Country option not set"); + country_params output; + const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size(); + std::copy(ptr, ptr + 3, std::back_inserter(output.country)); + ptr += output.country.size(); + while(end - ptr >= 3) { + output.first_channel.push_back(*(ptr++)); + output.number_channels.push_back(*(ptr++)); + output.max_transmit_power.push_back(*(ptr++)); + } + if(ptr != end) + throw std::runtime_error("Malformed option"); + return output; +} + +std::pair Dot11ManagementFrame::fh_parameters() const { + const Dot11::Dot11Option *option = search_option(HOPPING_PATTERN_PARAMS); + if(!option || option->data_size() != sizeof(uint8_t) * 2) + throw std::runtime_error("FH parameters option not set"); + const uint8_t *ptr = option->data_ptr(); + uint8_t first = *(ptr++); + return std::make_pair(first, *ptr); +} + +Dot11ManagementFrame::fh_pattern_type Dot11ManagementFrame::fh_pattern_table() const { + const Dot11::Dot11Option *option = search_option(HOPPING_PATTERN_TABLE); + if(!option || option->data_size() < fh_pattern_type::minimum_size) + throw std::runtime_error("FH pattern option not set"); + fh_pattern_type output; + const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size(); + + output.flag = *(ptr++); + output.number_of_sets = *(ptr++); + output.modulus = *(ptr++); + output.offset = *(ptr++); + + output.random_table.assign(ptr, end); + return output; +} + /* Dot11Beacon */ Dot11Beacon::Dot11Beacon(const NetworkInterface& iface, diff --git a/tests/src/dot11/beacon.cpp b/tests/src/dot11/beacon.cpp index 00874c2..2522b78 100644 --- a/tests/src/dot11/beacon.cpp +++ b/tests/src/dot11/beacon.cpp @@ -183,8 +183,7 @@ TEST_F(Dot11BeaconTest, SupportedRates) { rates.push_back(7.5f); dot11.supported_rates(rates); found_rates = dot11.supported_rates(); - ASSERT_EQ(rates.size(), found_rates.size()); - EXPECT_TRUE(std::equal(rates.begin(), rates.end(), found_rates.begin())); + EXPECT_EQ(rates, found_rates); } TEST_F(Dot11BeaconTest, ExtendedSupportedRates) { @@ -196,8 +195,7 @@ TEST_F(Dot11BeaconTest, ExtendedSupportedRates) { rates.push_back(7.5f); dot11.extended_supported_rates(rates); found_rates = dot11.extended_supported_rates(); - ASSERT_EQ(rates.size(), found_rates.size()); - EXPECT_TRUE(std::equal(rates.begin(), rates.end(), found_rates.begin())); + EXPECT_EQ(rates, found_rates); } TEST_F(Dot11BeaconTest, QOSCapability) { @@ -223,8 +221,7 @@ TEST_F(Dot11BeaconTest, SupportedChannels) { channels.push_back(std::make_pair(67, 159)); dot11.supported_channels(channels); output = dot11.supported_channels(); - ASSERT_EQ(output.size(), channels.size()); - EXPECT_TRUE(std::equal(channels.begin(), channels.end(), output.begin())); + EXPECT_EQ(output, channels); } TEST_F(Dot11BeaconTest, RequestInformation) { @@ -236,8 +233,7 @@ TEST_F(Dot11BeaconTest, RequestInformation) { info.push_back(42); dot11.request_information(info); found_info = dot11.request_information(); - ASSERT_EQ(info.size(), found_info.size()); - EXPECT_TRUE(std::equal(info.begin(), info.end(), found_info.begin())); + EXPECT_EQ(info, found_info); } TEST_F(Dot11BeaconTest, FHParameterSet) { @@ -275,7 +271,58 @@ TEST_F(Dot11BeaconTest, IBSS_DFS) { output = dot11.ibss_dfs(); EXPECT_EQ(params.dfs_owner, output.dfs_owner); EXPECT_EQ(params.recovery_interval, output.recovery_interval); - ASSERT_EQ(params.channel_map.size(), output.channel_map.size()); - EXPECT_TRUE(std::equal(params.channel_map.begin(), params.channel_map.end(), output.channel_map.begin())); + EXPECT_EQ(params.channel_map, output.channel_map); } +TEST_F(Dot11BeaconTest, Country) { + Dot11Beacon dot11; + Dot11Beacon::country_params params, output; + params.country = "ARO"; + params.first_channel.push_back(65); + params.first_channel.push_back(11); + params.first_channel.push_back(97); + + params.number_channels.push_back(123); + params.number_channels.push_back(56); + params.number_channels.push_back(42); + + params.max_transmit_power.push_back(4); + params.max_transmit_power.push_back(213); + params.max_transmit_power.push_back(165); + + dot11.country(params); + output = dot11.country(); + + EXPECT_EQ(params.country, output.country); + EXPECT_EQ(params.first_channel, output.first_channel); + EXPECT_EQ(params.number_channels, output.number_channels); + EXPECT_EQ(params.max_transmit_power, output.max_transmit_power); +} + +TEST_F(Dot11BeaconTest, FHParameters) { + Dot11Beacon dot11; + std::pair data(0x42, 0x1f); + dot11.fh_parameters(data.first, data.second); + EXPECT_EQ(data, dot11.fh_parameters()); +} + +TEST_F(Dot11BeaconTest, FHPattern) { + Dot11Beacon dot11; + Dot11Beacon::fh_pattern_type data, output; + data.flag = 0x67; + data.number_of_sets = 0x42; + data.modulus = 0x1f; + data.offset = 0x3a; + data.random_table.push_back(23); + data.random_table.push_back(15); + data.random_table.push_back(129); + + dot11.fh_pattern_table(data); + output = dot11.fh_pattern_table(); + + EXPECT_EQ(data.flag, data.flag); + EXPECT_EQ(data.number_of_sets, data.number_of_sets); + EXPECT_EQ(data.modulus, data.modulus); + EXPECT_EQ(data.offset, data.offset); + EXPECT_EQ(data.random_table, data.random_table); +}