option_vendor_unittest.cc 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <dhcp/dhcp4.h>
  8. #include <dhcp/dhcp6.h>
  9. #include <dhcp/docsis3_option_defs.h>
  10. #include <dhcp/libdhcp++.h>
  11. #include <dhcp/option_vendor.h>
  12. #include <dhcp/option_int.h>
  13. #include <dhcp/option_int_array.h>
  14. #include <exceptions/exceptions.h>
  15. #include <util/buffer.h>
  16. #include <util/encode/hex.h>
  17. #include <boost/scoped_ptr.hpp>
  18. #include <gtest/gtest.h>
  19. #include <iostream>
  20. #include <sstream>
  21. using namespace std;
  22. using namespace isc;
  23. using namespace isc::dhcp;
  24. using namespace isc::util;
  25. using boost::scoped_ptr;
  26. namespace {
  27. class OptionVendorTest : public ::testing::Test {
  28. public:
  29. OptionVendorTest() {
  30. }
  31. OptionBuffer createV4VendorOptions() {
  32. // Copied from wireshark, file docsis-*-CG3000DCR-Registration-Filtered.cap
  33. // packet #1
  34. /* V-I Vendor-specific Information (125)
  35. Length: 127
  36. Enterprise ID: Cable Television Laboratories, Inc. (4491)
  37. Suboption 1: Option Request
  38. Suboption 5: Modem capabilities */
  39. string from_wireshark = "7d7f0000118b7a01010205750101010201030301010401"
  40. "0105010106010107010f0801100901030a01010b01180c01010d0200400e020010"
  41. "0f010110040000000211010014010015013f1601011701011801041901041a0104"
  42. "1b01201c01021d01081e01201f0110200110210102220101230100240100250101"
  43. "260200ff270101";
  44. OptionBuffer bin;
  45. // Decode the hex string and store it in bin (which happens
  46. // to be OptionBuffer format)
  47. isc::util::encode::decodeHex(from_wireshark, bin);
  48. return (bin);
  49. }
  50. OptionBuffer createV6VendorOption() {
  51. // Copied from wireshark, docsis-CG3000DCR-Registration-v6CMM-Filtered.cap
  52. // packet #1 (v6 vendor option with lots of cable modem specific data)
  53. string from_wireshark = "001100ff0000118b0001000a0020002100220025002600"
  54. "02000345434d0003000b45434d3a45524f555445520004000d3242523232395534"
  55. "303034344300050004312e30340006000856312e33332e303300070007322e332e"
  56. "3052320008000630303039354200090009434733303030444352000a00074e6574"
  57. "6765617200230077057501010102010303010104010105010106010107010f0801"
  58. "100901030a01010b01180c01010d0200400e0200100f0101100400000002110100"
  59. "14010015013f1601011701011801041901041a01041b01201c01021d01081e0120"
  60. "1f0110200110210102220101230100240100250101260200ff2701010024000620"
  61. "e52ab81514";
  62. /* Vendor-specific Information
  63. Option: Vendor-specific Information (17)
  64. Length: 255
  65. Value: 0000118b0001000a00200021002200250026000200034543...
  66. Enterprise ID: Cable Television Laboratories, Inc. (4491)
  67. Suboption 1: Option Request = 32 33 34 37 38
  68. Suboption 2: Device Type = "ECM"
  69. Suboption 3: Embedded Components = "ECM:EROUTER"
  70. Suboption 4: Serial Number = "2BR229U40044C"
  71. Suboption 5: Hardware Version = "1.04"
  72. Suboption 6: Software Version = "V1.33.03"
  73. Suboption 7: Boot ROM Version = "2.3.0R2"
  74. Suboption 8: Organization Unique Identifier = "00095B"
  75. Suboption 9: Model Number = "CG3000DCR"
  76. Suboption 10: Vendor Name = "Netgear"
  77. Suboption 35: TLV5 = 057501010102010303010104010105010106010107010f08...
  78. Suboption 36: Device Identifier = 20e52ab81514 */
  79. OptionBuffer bin;
  80. // Decode the hex string and store it in bin (which happens
  81. // to be OptionBuffer format)
  82. isc::util::encode::decodeHex(from_wireshark, bin);
  83. return (bin);
  84. }
  85. };
  86. // Basic test for v4 vendor option functionality
  87. TEST_F(OptionVendorTest, v4Basic) {
  88. uint32_t vendor_id = 1234;
  89. scoped_ptr<Option> opt;
  90. EXPECT_NO_THROW(opt.reset(new OptionVendor(Option::V4, vendor_id)));
  91. EXPECT_EQ(Option::V4, opt->getUniverse());
  92. EXPECT_EQ(DHO_VIVSO_SUBOPTIONS, opt->getType());
  93. // Minimal length is 7: 1(type) + 1(length) + 4(vendor-id) + datalen(1)
  94. EXPECT_EQ(7, opt->len());
  95. // Check destructor
  96. EXPECT_NO_THROW(opt.reset());
  97. }
  98. // Basic test for v6 vendor option functionality
  99. TEST_F(OptionVendorTest, v6Basic) {
  100. uint32_t vendor_id = 1234;
  101. scoped_ptr<Option> opt;
  102. EXPECT_NO_THROW(opt.reset(new OptionVendor(Option::V6, vendor_id)));
  103. EXPECT_EQ(Option::V6, opt->getUniverse());
  104. EXPECT_EQ(D6O_VENDOR_OPTS, opt->getType());
  105. // Minimal length is 8: 2(type) + 2(length) + 4(vendor-id)
  106. EXPECT_EQ(8, opt->len());
  107. // Check destructor
  108. EXPECT_NO_THROW(opt.reset());
  109. }
  110. // Tests whether we can parse v4 vendor options properly
  111. TEST_F(OptionVendorTest, v4Parse) {
  112. OptionBuffer binary = createV4VendorOptions();
  113. // Let's create vendor option based on incoming buffer
  114. OptionVendorPtr vendor;
  115. ASSERT_NO_THROW(vendor.reset(new OptionVendor(Option::V4, binary.begin() + 2,
  116. binary.end())));
  117. // We know that there are supposed to be 2 options inside
  118. EXPECT_TRUE(vendor->getOption(DOCSIS3_V4_ORO));
  119. EXPECT_TRUE(vendor->getOption(5));
  120. }
  121. // Tests whether we can parse and then pack a v4 option.
  122. TEST_F(OptionVendorTest, packUnpack4) {
  123. OptionBuffer binary = createV4VendorOptions();
  124. OptionVendorPtr vendor;
  125. // Create vendor option (ignore the first 2 bytes, these are option code
  126. // and option length
  127. ASSERT_NO_THROW(vendor.reset(new OptionVendor(Option::V4, binary.begin() + 2,
  128. binary.end())));
  129. OutputBuffer output(0);
  130. EXPECT_NO_THROW(vendor->pack(output));
  131. ASSERT_EQ(binary.size(), output.getLength());
  132. // We're lucky, because the packet capture we have happens to have options
  133. // with monotonically increasing values (1 and 5), so our pack() method
  134. // will pack them in exactly the same order as in the original.
  135. EXPECT_FALSE(memcmp(&binary[0], output.getData(), output.getLength()));
  136. }
  137. // Tests whether we can parse v6 vendor options properly
  138. TEST_F(OptionVendorTest, v6Parse) {
  139. OptionBuffer binary = createV6VendorOption();
  140. OptionVendorPtr vendor;
  141. // Create vendor option (ignore the first 4 bytes. These are option code
  142. // (2 bytes) and option length (2 bytes).
  143. ASSERT_NO_THROW(vendor.reset(new OptionVendor(Option::V6, binary.begin() + 4,
  144. binary.end())));
  145. OptionPtr opt;
  146. opt = vendor->getOption(DOCSIS3_V6_ORO);
  147. ASSERT_TRUE(opt);
  148. OptionUint16ArrayPtr oro =
  149. boost::dynamic_pointer_cast<OptionUint16Array>(opt);
  150. // Check that all remaining expected options are there
  151. EXPECT_TRUE(vendor->getOption(2));
  152. EXPECT_TRUE(vendor->getOption(3));
  153. EXPECT_TRUE(vendor->getOption(4));
  154. EXPECT_TRUE(vendor->getOption(5));
  155. EXPECT_TRUE(vendor->getOption(6));
  156. EXPECT_TRUE(vendor->getOption(7));
  157. EXPECT_TRUE(vendor->getOption(8));
  158. EXPECT_TRUE(vendor->getOption(9));
  159. EXPECT_TRUE(vendor->getOption(10));
  160. EXPECT_TRUE(vendor->getOption(35));
  161. EXPECT_TRUE(vendor->getOption(36));
  162. // Check that there are no other options there
  163. for (uint16_t i = 11; i < 35; ++i) {
  164. EXPECT_FALSE(vendor->getOption(i));
  165. }
  166. for (uint16_t i = 37; i < 65535; ++i) {
  167. EXPECT_FALSE(vendor->getOption(i));
  168. }
  169. }
  170. // Tests whether we can parse and then pack a v6 option.
  171. TEST_F(OptionVendorTest, packUnpack6) {
  172. OptionBuffer binary = createV6VendorOption();
  173. OptionVendorPtr vendor;
  174. // Create vendor option (ignore the first 4 bytes. These are option code
  175. // (2 bytes) and option length (2 bytes).
  176. ASSERT_NO_THROW(vendor.reset(new OptionVendor(Option::V6, binary.begin() + 4,
  177. binary.end())));
  178. OutputBuffer output(0);
  179. EXPECT_NO_THROW(vendor->pack(output));
  180. ASSERT_EQ(binary.size(), output.getLength());
  181. EXPECT_FALSE(memcmp(&binary[0], output.getData(), output.getLength()));
  182. }
  183. // Tests that the vendor option is correctly returned in the textual
  184. // format for DHCPv4 case.
  185. TEST_F(OptionVendorTest, toText4) {
  186. OptionVendor option(Option::V4, 1024);
  187. option.addOption(OptionPtr(new OptionUint32(Option::V4, 1, 100)));
  188. EXPECT_EQ("type=125, len=011: 1024 (uint32) 6 (uint8),\n"
  189. "options:\n"
  190. " type=001, len=004: 100 (uint32)",
  191. option.toText());
  192. }
  193. // Tests that the vendor option is correctly returned in the textual
  194. // format for DHCPv6 case.
  195. TEST_F(OptionVendorTest, toText6) {
  196. OptionVendor option(Option::V6, 2048);
  197. option.addOption(OptionPtr(new OptionUint16(Option::V6, 1, 100)));
  198. EXPECT_EQ("type=00017, len=00010: 2048 (uint32),\n"
  199. "options:\n"
  200. " type=00001, len=00002: 100 (uint16)",
  201. option.toText());
  202. }
  203. }