diff --git a/include/dot11.h b/include/dot11.h index 755d94a..a1b3ef5 100644 --- a/include/dot11.h +++ b/include/dot11.h @@ -938,6 +938,47 @@ namespace Tins { void immediate_block_ack(bool new_value) { this->_immediate_block_ack = new_value; } } __attribute__((__packed__)); + + struct fh_params_set { + uint16_t dwell_time; + uint8_t hop_set, hop_pattern, hop_index; + + fh_params_set() {} + + fh_params_set(uint16_t dwell_time, uint8_t hop_set, + uint8_t hop_pattern, uint8_t hop_index) + : dwell_time(dwell_time), hop_set(hop_set), + hop_pattern(hop_pattern), hop_index(hop_index) {} + } __attribute__((__packed__)); + + struct cf_params_set { + uint8_t cfp_count, cfp_period; + uint16_t cfp_max_duration, cfp_dur_remaining; + + cf_params_set() {} + + cf_params_set(uint8_t cfp_count, uint8_t cfp_period, + uint16_t cfp_max_duration, uint16_t cfp_dur_remaining) + : cfp_count(cfp_count), cfp_period(cfp_period), + cfp_max_duration(cfp_max_duration), + cfp_dur_remaining(cfp_dur_remaining) {} + } __attribute__((__packed__)); + + struct ibss_dfs_params { + static const bool minimum_size = address_type::address_size + sizeof(uint8_t) + 2 * sizeof(uint8_t); + + address_type dfs_owner; + uint8_t recovery_interval; + channels_type channel_map; + + ibss_dfs_params() {} + + ibss_dfs_params(const address_type &addr, + uint8_t recovery_interval, const channels_type &channels) + : dfs_owner(addr), recovery_interval(recovery_interval), + channel_map(channels) {} + }; + /** * \brief Getter for the second address. @@ -1081,12 +1122,9 @@ namespace Tins { /** * \brief Helper method to set the FH parameter. * - * \param dwell_time uint16_t with the dwell_time value. - * \param hop_set uint8_t with the value of the set_hop. - * \param hop_pattern uint8_t with the value of the hop_pattern field. - * \param hop_index uint8_t with the value of the hop_index field. + * \param fh_params the fh parameter set. */ - void fh_parameter_set(uint16_t dwell_time, uint8_t hop_set, uint8_t hop_pattern, uint8_t hop_index); + void fh_parameter_set(fh_params_set fh_params); /** * \brief Helper method to set the DS parameter. @@ -1098,12 +1136,9 @@ namespace Tins { /** * \brief Helper method to set the CF parameter. * - * \param cfp_count uint8_t with the value of the cfp count field. - * \param cfp_period uint8_t with the value of the cfp period field. - * \param cfp_max_duration uint16_t with the value of the cfp max duration field. - * \param cfp_dur_remaining uint16_t with the value of the DurRemaining field. + * \param params the CF parammeters to be set. */ - void cf_parameter_set(uint8_t cfp_count, uint8_t cfp_period, uint16_t cfp_max_duration, uint16_t cfp_dur_remaining); + void cf_parameter_set(cf_params_set params); /** * \brief Helper method to set the IBSS parameter. @@ -1115,11 +1150,9 @@ namespace Tins { /** * \brief Helper method to set the IBSS DFS tagged option. * - * \param dfs_owner uint8_t array of 6 bytes with the dfs owner. - * \param recovery_interval uint8_t with the value of the recovery interval field. - * \param channel_map Reference to a constant vector of pair of uint8_t with the map of channels. + * \param params The IBSS DFS data to be set. */ - void ibss_dfs(const uint8_t* dfs_owner, uint8_t recovery_interval, const std::vector >& channel_map); + void ibss_dfs(const ibss_dfs_params ¶ms); /** * \brief Helper method to set the country tagged option. @@ -1293,6 +1326,42 @@ namespace Tins { */ request_info_type request_information() const; + /** + * \brief Helper method to get the fh parameter set. + * + * Throws a std::runtime_error if the option has not been set. + * + * \return fh_params_set containing the fh parameter set. + */ + fh_params_set fh_parameter_set() const; + + /** + * \brief Helper method to get the ds parameter set. + * + * Throws a std::runtime_error if the option has not been set. + * + * \return uint8_t containing the ds parameter set. + */ + uint8_t ds_parameter_set() const; + + /** + * \brief Helper method to get the ibss parameter set. + * + * Throws a std::runtime_error if the option has not been set. + * + * \return uint16_t containing the ibss parameter set. + */ + uint16_t ibss_parameter_set() const; + + /** + * \brief Helper method to get the ibss dfs. + * + * Throws a std::runtime_error if the option has not been set. + * + * \return ibss_dfs_params containing the ibss dfs. + */ + ibss_dfs_params ibss_dfs() const; + // ************************ /** diff --git a/src/dot11.cpp b/src/dot11.cpp index 5eca823..b1b056b 100644 --- a/src/dot11.cpp +++ b/src/dot11.cpp @@ -411,14 +411,12 @@ void Dot11ManagementFrame::request_information(const request_info_type elements) delete[] buffer; } -void Dot11ManagementFrame::fh_parameter_set(uint16_t dwell_time, uint8_t hop_set, uint8_t hop_pattern, uint8_t hop_index) { - uint8_t buffer[5]; - uint16_t* ptr_buffer = (uint16_t*)buffer; - ptr_buffer[0] = dwell_time; - buffer[2] = hop_set; - buffer[3] = hop_pattern; - buffer[4] = hop_index; - add_tagged_option(FH_SET, 5, buffer); +void Dot11ManagementFrame::fh_parameter_set(fh_params_set fh_params) { + fh_params.dwell_time = Utils::host_to_le(fh_params.dwell_time); + fh_params.hop_set = Utils::host_to_le(fh_params.hop_set); + fh_params.hop_pattern = Utils::host_to_le(fh_params.hop_pattern); + fh_params.hop_index = Utils::host_to_le(fh_params.hop_index); + add_tagged_option(FH_SET, sizeof(fh_params_set), (uint8_t*)&fh_params); } @@ -426,24 +424,37 @@ void Dot11ManagementFrame::ds_parameter_set(uint8_t current_channel) { add_tagged_option(DS_SET, 1, ¤t_channel); } -void Dot11ManagementFrame::cf_parameter_set(uint8_t cfp_count, - uint8_t cfp_period, - uint16_t cfp_max_duration, - uint16_t cfp_dur_remaining) { - uint8_t buffer[6]; - uint16_t* ptr_buffer = (uint16_t*)buffer; - buffer[0] = cfp_count; - buffer[1] = cfp_period; - ptr_buffer[1] = cfp_max_duration; - ptr_buffer[2] = cfp_dur_remaining; - add_tagged_option(CF_SET, 6, buffer); - +void Dot11ManagementFrame::cf_parameter_set(cf_params_set params) { + params.cfp_count = Utils::host_to_le(params.cfp_count); + params.cfp_period = Utils::host_to_le(params.cfp_period); + params.cfp_max_duration = Utils::host_to_le(params.cfp_max_duration); + params.cfp_dur_remaining = Utils::host_to_le(params.cfp_dur_remaining); + add_tagged_option(CF_SET, sizeof(params), (uint8_t*)¶ms); } void Dot11ManagementFrame::ibss_parameter_set(uint16_t atim_window) { + atim_window = Utils::host_to_le(atim_window); add_tagged_option(IBSS_SET, 2, (uint8_t*)&atim_window); } +void Dot11ManagementFrame::ibss_dfs(const ibss_dfs_params ¶ms) { + uint8_t sz = address_type::address_size + sizeof(uint8_t) + sizeof(uint8_t) * 2 * params.channel_map.size(); + uint8_t* buffer = new uint8_t[sz]; + uint8_t* ptr_buffer = buffer; + + ptr_buffer = params.dfs_owner.copy(ptr_buffer); + *(ptr_buffer++) = params.recovery_interval; + for (channels_type::const_iterator it = params.channel_map.begin(); it != params.channel_map.end(); ++it) { + *(ptr_buffer++) = it->first; + *(ptr_buffer++) = it->second; + } + + add_tagged_option(IBSS_DFS, sz, buffer); + + delete[] buffer; + +} + void Dot11ManagementFrame::country(const std::vector& countries, const std::vector& first_channels, const std::vector& number_channels, @@ -526,25 +537,6 @@ void Dot11ManagementFrame::quiet(uint8_t quiet_count, uint8_t quiet_period, uint } -void Dot11ManagementFrame::ibss_dfs(const uint8_t* dfs_owner, uint8_t recovery_interval, const vector >& channel_map) { - uint8_t sz = 7 + 2 * channel_map.size(); - uint8_t* buffer = new uint8_t[sz]; - uint8_t* ptr_buffer = buffer; - - memcpy(ptr_buffer, dfs_owner, 6); - ptr_buffer += 6; - *(ptr_buffer++) = recovery_interval; - for (vector >::const_iterator it = channel_map.begin(); it != channel_map.end(); it++) { - *(ptr_buffer++) = it->first; - *(ptr_buffer++) = it->second; - } - - add_tagged_option(IBSS_DFS, sz, buffer); - - delete[] buffer; - -} - void Dot11ManagementFrame::tpc_report(uint8_t transmit_power, uint8_t link_margin) { uint8_t buffer[2]; buffer[0] = transmit_power; @@ -680,7 +672,7 @@ Dot11ManagementFrame::channels_type Dot11ManagementFrame::supported_channels() c Dot11ManagementFrame::request_info_type Dot11ManagementFrame::request_information() const { const Dot11::Dot11Option *option = search_option(REQUEST_INFORMATION); if(!option) - throw std::runtime_error("Supported channels not set"); + 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) @@ -688,6 +680,50 @@ Dot11ManagementFrame::request_info_type Dot11ManagementFrame::request_informatio return output; } +Dot11ManagementFrame::fh_params_set Dot11ManagementFrame::fh_parameter_set() const { + const Dot11::Dot11Option *option = search_option(FH_SET); + if(!option || option->data_size() != sizeof(fh_params_set)) + throw std::runtime_error("FH parameters set not set"); + fh_params_set output = *reinterpret_cast(option->data_ptr()); + output.dwell_time = Utils::le_to_host(output.dwell_time); + output.hop_set = Utils::le_to_host(output.hop_set); + output.hop_pattern = Utils::le_to_host(output.hop_pattern); + output.hop_index = Utils::le_to_host(output.hop_index); + return output; +} + +uint8_t Dot11ManagementFrame::ds_parameter_set() const { + const Dot11::Dot11Option *option = search_option(DS_SET); + if(!option || option->data_size() != sizeof(uint8_t)) + throw std::runtime_error("DS parameters set not set"); + return *option->data_ptr(); +} + +uint16_t Dot11ManagementFrame::ibss_parameter_set() const { + const Dot11::Dot11Option *option = search_option(IBSS_SET); + if(!option || option->data_size() != sizeof(uint16_t)) + throw std::runtime_error("IBSS parameters set not set"); + return Utils::le_to_host(*reinterpret_cast(option->data_ptr())); +} + +Dot11ManagementFrame::ibss_dfs_params Dot11ManagementFrame::ibss_dfs() const { + const Dot11::Dot11Option *option = search_option(IBSS_DFS); + if(!option || option->data_size() < ibss_dfs_params::minimum_size) + throw std::runtime_error("IBSS DFS set not set"); + ibss_dfs_params output; + const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size(); + output.dfs_owner = ptr; + ptr += output.dfs_owner.size(); + output.recovery_interval = *(ptr++); + while(ptr != end) { + uint8_t first = *(ptr++); + if(ptr == end) + throw std::runtime_error("Malformed channel data"); + output.channel_map.push_back(std::make_pair(first, *(ptr++))); + } + return output; +} + /* Dot11Beacon */ Dot11Beacon::Dot11Beacon(const NetworkInterface& iface, diff --git a/tests/src/dot11/beacon.cpp b/tests/src/dot11/beacon.cpp index b73021c..00874c2 100644 --- a/tests/src/dot11/beacon.cpp +++ b/tests/src/dot11/beacon.cpp @@ -239,3 +239,43 @@ TEST_F(Dot11BeaconTest, RequestInformation) { ASSERT_EQ(info.size(), found_info.size()); EXPECT_TRUE(std::equal(info.begin(), info.end(), found_info.begin())); } + +TEST_F(Dot11BeaconTest, FHParameterSet) { + Dot11Beacon dot11; + Dot11Beacon::fh_params_set params(0x482f, 67, 42, 0xa1), output; + dot11.fh_parameter_set(params); + output = dot11.fh_parameter_set(); + EXPECT_EQ(output.hop_index, params.hop_index); + EXPECT_EQ(output.hop_pattern, params.hop_pattern); + EXPECT_EQ(output.hop_set, params.hop_set); + EXPECT_EQ(output.dwell_time, params.dwell_time); +} + +TEST_F(Dot11BeaconTest, DSParameterSet) { + Dot11Beacon dot11; + dot11.ds_parameter_set(0x1e); + EXPECT_EQ(dot11.ds_parameter_set(), 0x1e); +} + +TEST_F(Dot11BeaconTest, IBSSParameterSet) { + Dot11Beacon dot11; + dot11.ibss_parameter_set(0x1ef3); + EXPECT_EQ(dot11.ibss_parameter_set(), 0x1ef3); +} + +TEST_F(Dot11BeaconTest, IBSS_DFS) { + Dot11Beacon dot11; + Dot11Beacon::ibss_dfs_params params, output; + params.dfs_owner = "00:01:02:03:04:05"; + params.recovery_interval = 0x7f; + params.channel_map.push_back(std::make_pair(0x8e, 0x92)); + params.channel_map.push_back(std::make_pair(0x02, 0xf2)); + params.channel_map.push_back(std::make_pair(0x3a, 0x53)); + dot11.ibss_dfs(params); + 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())); +} +