From ca6b6034787fb51a7c3c7f7258b144285fff56c4 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Tue, 17 Dec 2013 19:00:00 -0300 Subject: [PATCH] Finished porting ICMPv6. --- include/icmpv6.h | 49 ++++++++++++++++++++++++++------- src/icmpv6.cpp | 65 ++++++++++++++++++++++++-------------------- tests/src/icmpv6.cpp | 10 +++++-- 3 files changed, 83 insertions(+), 41 deletions(-) diff --git a/include/icmpv6.h b/include/icmpv6.h index bc48c04..fa4d86c 100644 --- a/include/icmpv6.h +++ b/include/icmpv6.h @@ -481,7 +481,39 @@ public: static timestamp_type from_option(const option &opt); }; - + + /** + * The type used to store the shortcut limit option. + */ + struct shortcut_limit_type { + uint8_t limit, reserved1; + uint32_t reserved2; + + shortcut_limit_type(uint8_t limit = 0) + : limit(limit), reserved1(), reserved2() + { + + } + + static shortcut_limit_type from_option(const option &opt); + }; + + /** + * The type used to store new advertisement interval option. + */ + struct new_advert_interval_type { + uint16_t reserved; + uint32_t interval; + + new_advert_interval_type(uint32_t interval = 0) + : reserved(), interval(interval) + { + + } + + static new_advert_interval_type from_option(const option &opt); + }; + /** * \brief Constructs an ICMPv6 object. * @@ -883,12 +915,9 @@ public: /** * \brief Setter for the redirect header option. * - * This method appends the 6 reserved bytes and inserts the - * necessary padding at the end. - * * \param data The redirect header option data. */ - void redirect_header(PDU::serialization_type data); + void redirect_header(const byte_array &data); /** * \brief Setter for the MTU option. @@ -902,14 +931,14 @@ public: * * \param value The shortcut limit option data. */ - void shortcut_limit(uint8_t value); + void shortcut_limit(const shortcut_limit_type& value); /** * \brief Setter for the new advertisement interval option. * * \param value The new advertisement interval option data. */ - void new_advert_interval(uint32_t value); + void new_advert_interval(const new_advert_interval_type &value); /** * \brief Setter for the new home agent information option. @@ -1064,7 +1093,7 @@ public: * This method will throw an option_not_found exception if the * option is not found. */ - PDU::serialization_type redirect_header() const; + byte_array redirect_header() const; /** * \brief Getter for the MTU option. @@ -1080,7 +1109,7 @@ public: * This method will throw an option_not_found exception if the * option is not found. */ - uint8_t shortcut_limit() const; + shortcut_limit_type shortcut_limit() const; /** * \brief Getter for the new advertisement interval option. @@ -1088,7 +1117,7 @@ public: * This method will throw an option_not_found exception if the * option is not found. */ - uint32_t new_advert_interval() const; + new_advert_interval_type new_advert_interval() const; /** * \brief Getter for the new home agent information option. diff --git a/src/icmpv6.cpp b/src/icmpv6.cpp index 10cab09..35612af 100644 --- a/src/icmpv6.cpp +++ b/src/icmpv6.cpp @@ -294,33 +294,29 @@ void ICMPv6::prefix_info(prefix_info_type info) { ); } -void ICMPv6::redirect_header(PDU::serialization_type data) { - // Reserved fields - data.insert(data.begin(), 6, 0); - // Padding(if necessary) - uint8_t padding = 8 - (data.size() + sizeof(uint8_t) * 2) % 8; - if(padding == 8) - padding = 0; - data.insert(data.end(), padding, 0); +void ICMPv6::redirect_header(const byte_array& data) { add_option(option(REDIRECT_HEADER, data.begin(), data.end())); } void ICMPv6::mtu(const mtu_type& value) { uint8_t buffer[sizeof(uint16_t) + sizeof(uint32_t)] = {0}; - *(uint32_t*)buffer = Endian::host_to_be(value.first); + *(uint16_t*)buffer = Endian::host_to_be(value.first); *(uint32_t*)(buffer + sizeof(uint16_t)) = Endian::host_to_be(value.second); add_option(option(MTU, sizeof(buffer), buffer)); } -void ICMPv6::shortcut_limit(uint8_t value) { +void ICMPv6::shortcut_limit(const shortcut_limit_type &value) { uint8_t buffer[sizeof(uint16_t) + sizeof(uint32_t)] = {0}; - buffer[0] = value; + buffer[0] = value.limit; + buffer[1] = value.reserved1; + *(uint32_t*)&buffer[2] = Endian::host_to_be(value.reserved2); add_option(option(NBMA_SHORT_LIMIT, sizeof(buffer), buffer)); } -void ICMPv6::new_advert_interval(uint32_t value) { +void ICMPv6::new_advert_interval(const new_advert_interval_type &value) { uint8_t buffer[sizeof(uint16_t) + sizeof(uint32_t)] = {0}; - *((uint32_t*)(buffer + sizeof(uint16_t))) = Endian::host_to_be(value); + *(uint16_t*)buffer = Endian::host_to_be(value.reserved); + *((uint32_t*)(buffer + sizeof(uint16_t))) = Endian::host_to_be(value.interval); add_option(option(ADVERT_INTERVAL, sizeof(buffer), buffer)); } @@ -554,30 +550,20 @@ ICMPv6::prefix_info_type ICMPv6::prefix_info() const { return search_and_convert(PREFIX_INFO); } -PDU::serialization_type ICMPv6::redirect_header() const { - const option *opt = search_option(REDIRECT_HEADER); - if(!opt || opt->data_size() < 6) - throw option_not_found(); - const uint8_t *ptr = opt->data_ptr() + 6; - return serialization_type(ptr, ptr + opt->data_size() - 6); +byte_array ICMPv6::redirect_header() const { + return search_and_convert(REDIRECT_HEADER); } ICMPv6::mtu_type ICMPv6::mtu() const { return search_and_convert(MTU); } -uint8_t ICMPv6::shortcut_limit() const { - const option *opt = search_option(NBMA_SHORT_LIMIT); - if(!opt || opt->data_size() != sizeof(uint16_t) + sizeof(uint32_t)) - throw option_not_found(); - return *opt->data_ptr(); +ICMPv6::shortcut_limit_type ICMPv6::shortcut_limit() const { + return search_and_convert(NBMA_SHORT_LIMIT); } -uint32_t ICMPv6::new_advert_interval() const { - const option *opt = search_option(ADVERT_INTERVAL); - if(!opt || opt->data_size() != sizeof(uint16_t) + sizeof(uint32_t)) - throw option_not_found(); - return Endian::be_to_host(*(const uint32_t*)(opt->data_ptr() + sizeof(uint16_t))); +ICMPv6::new_advert_interval_type ICMPv6::new_advert_interval() const { + return search_and_convert(ADVERT_INTERVAL); } ICMPv6::new_ha_info_type ICMPv6::new_home_agent_info() const { @@ -867,5 +853,26 @@ ICMPv6::timestamp_type ICMPv6::timestamp_type::from_option(const option &opt) std::copy(opt.data_ptr(), opt.data_ptr() + 6, output.reserved); return output; } + +ICMPv6::shortcut_limit_type ICMPv6::shortcut_limit_type::from_option(const option &opt) +{ + if(opt.data_size() != 6) + throw malformed_option(); + const uint8_t *ptr = opt.data_ptr(); + shortcut_limit_type output(*ptr++); + output.reserved1 = *ptr++; + output.reserved2 = Endian::be_to_host(*(uint32_t*)ptr); + return output; +} + +ICMPv6::new_advert_interval_type ICMPv6::new_advert_interval_type::from_option(const option &opt) +{ + if(opt.data_size() != 6) + throw malformed_option(); + new_advert_interval_type output; + output.reserved = Endian::be_to_host(*(uint16_t*)opt.data_ptr()); + output.interval = Endian::be_to_host(*(uint32_t*)(opt.data_ptr() + sizeof(uint16_t))); + return output; +} } diff --git a/tests/src/icmpv6.cpp b/tests/src/icmpv6.cpp index 0c16d8b..21466cb 100644 --- a/tests/src/icmpv6.cpp +++ b/tests/src/icmpv6.cpp @@ -209,6 +209,7 @@ TEST_F(ICMPv6Test, RedirectHeader) { ICMPv6 icmp; IP ip = IP("127.0.0.1") / TCP(22); PDU::serialization_type buffer = ip.serialize(); + buffer.insert(buffer.begin(), 6, 0); icmp.redirect_header(buffer); EXPECT_EQ(buffer, icmp.redirect_header()); } @@ -223,13 +224,18 @@ TEST_F(ICMPv6Test, MTU) { TEST_F(ICMPv6Test, ShortcutLimit) { ICMPv6 icmp; icmp.shortcut_limit(123); - EXPECT_EQ(icmp.shortcut_limit(), 123); + ICMPv6::shortcut_limit_type sl = icmp.shortcut_limit(); + EXPECT_EQ(123, sl.limit); + EXPECT_EQ(0, sl.reserved1); + EXPECT_EQ(0, sl.reserved2); } TEST_F(ICMPv6Test, NewAdvertisementInterval) { ICMPv6 icmp; icmp.new_advert_interval(0x9a8df7); - EXPECT_EQ(icmp.new_advert_interval(), 0x9a8df7U); + ICMPv6::new_advert_interval_type data = icmp.new_advert_interval(); + EXPECT_EQ(0x9a8df7U, data.interval); + EXPECT_EQ(0, data.reserved); } TEST_F(ICMPv6Test, NewHomeAgentInformation) {