libdhcp++.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. // Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <dhcp/dhcp4.h>
  16. #include <dhcp/dhcp6.h>
  17. #include <dhcp/libdhcp++.h>
  18. #include <dhcp/option.h>
  19. #include <dhcp/option_vendor.h>
  20. #include <dhcp/option6_ia.h>
  21. #include <dhcp/option6_iaaddr.h>
  22. #include <dhcp/option_definition.h>
  23. #include <dhcp/option_int_array.h>
  24. #include <dhcp/std_option_defs.h>
  25. #include <dhcp/docsis3_option_defs.h>
  26. #include <exceptions/exceptions.h>
  27. #include <util/buffer.h>
  28. #include <dhcp/option_definition.h>
  29. #include <boost/shared_array.hpp>
  30. #include <boost/shared_ptr.hpp>
  31. using namespace std;
  32. using namespace isc::dhcp;
  33. using namespace isc::util;
  34. // static array with factories for options
  35. std::map<unsigned short, Option::Factory*> LibDHCP::v4factories_;
  36. // static array with factories for options
  37. std::map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
  38. // Static container with DHCPv4 option definitions.
  39. OptionDefContainer LibDHCP::v4option_defs_;
  40. // Static container with DHCPv6 option definitions.
  41. OptionDefContainer LibDHCP::v6option_defs_;
  42. VendorOptionDefContainers LibDHCP::vendor4_defs_;
  43. VendorOptionDefContainers LibDHCP::vendor6_defs_;
  44. // Let's keep it in .cc file. Moving it to .h would require including optionDefParams
  45. // definitions there
  46. void initOptionSpace(OptionDefContainer& defs,
  47. const OptionDefParams* params,
  48. size_t params_size);
  49. const OptionDefContainer&
  50. LibDHCP::getOptionDefs(const Option::Universe u) {
  51. switch (u) {
  52. case Option::V4:
  53. if (v4option_defs_.empty()) {
  54. initStdOptionDefs4();
  55. initVendorOptsDocsis4();
  56. }
  57. return (v4option_defs_);
  58. case Option::V6:
  59. if (v6option_defs_.empty()) {
  60. initStdOptionDefs6();
  61. initVendorOptsDocsis6();
  62. }
  63. return (v6option_defs_);
  64. default:
  65. isc_throw(isc::BadValue, "invalid universe " << u << " specified");
  66. }
  67. }
  68. const OptionDefContainer*
  69. LibDHCP::getVendorOption4Defs(const uint32_t vendor_id) {
  70. if (vendor_id == VENDOR_ID_CABLE_LABS &&
  71. vendor4_defs_.find(VENDOR_ID_CABLE_LABS) == vendor4_defs_.end()) {
  72. initVendorOptsDocsis4();
  73. }
  74. VendorOptionDefContainers::const_iterator def = vendor4_defs_.find(vendor_id);
  75. if (def == vendor4_defs_.end()) {
  76. // No such vendor-id space
  77. return (NULL);
  78. }
  79. return (&(def->second));
  80. }
  81. const OptionDefContainer*
  82. LibDHCP::getVendorOption6Defs(const uint32_t vendor_id) {
  83. if (vendor_id == VENDOR_ID_CABLE_LABS &&
  84. vendor6_defs_.find(VENDOR_ID_CABLE_LABS) == vendor6_defs_.end()) {
  85. initVendorOptsDocsis6();
  86. }
  87. VendorOptionDefContainers::const_iterator def = vendor6_defs_.find(vendor_id);
  88. if (def == vendor6_defs_.end()) {
  89. // No such vendor-id space
  90. return (NULL);
  91. }
  92. return (&(def->second));
  93. }
  94. OptionDefinitionPtr
  95. LibDHCP::getOptionDef(const Option::Universe u, const uint16_t code) {
  96. const OptionDefContainer& defs = getOptionDefs(u);
  97. const OptionDefContainerTypeIndex& idx = defs.get<1>();
  98. const OptionDefContainerTypeRange& range = idx.equal_range(code);
  99. if (range.first != range.second) {
  100. return (*range.first);
  101. }
  102. return (OptionDefinitionPtr());
  103. }
  104. OptionDefinitionPtr
  105. LibDHCP::getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id,
  106. const uint16_t code) {
  107. const OptionDefContainer* defs = NULL;
  108. if (u == Option::V4) {
  109. defs = getVendorOption4Defs(vendor_id);
  110. } else if (u == Option::V6) {
  111. defs = getVendorOption6Defs(vendor_id);
  112. }
  113. if (!defs) {
  114. // Weird universe or unknown vendor_id. We don't care. No definitions
  115. // one way or another
  116. // What is it anyway?
  117. return (OptionDefinitionPtr());
  118. }
  119. const OptionDefContainerTypeIndex& idx = defs->get<1>();
  120. const OptionDefContainerTypeRange& range = idx.equal_range(code);
  121. if (range.first != range.second) {
  122. return (*range.first);
  123. }
  124. return (OptionDefinitionPtr());
  125. }
  126. bool
  127. LibDHCP::isStandardOption(const Option::Universe u, const uint16_t code) {
  128. if (u == Option::V6) {
  129. if (code < 79 &&
  130. code != 10 &&
  131. code != 35) {
  132. return (true);
  133. }
  134. } else if (u == Option::V4) {
  135. if (!(code == 84 ||
  136. code == 96 ||
  137. (code > 101 && code < 112) ||
  138. code == 115 ||
  139. code == 126 ||
  140. code == 127 ||
  141. (code > 146 && code < 150) ||
  142. (code > 177 && code < 208) ||
  143. (code > 213 && code < 220) ||
  144. (code > 221 && code < 224))) {
  145. return (true);
  146. }
  147. }
  148. return (false);
  149. }
  150. OptionPtr
  151. LibDHCP::optionFactory(Option::Universe u,
  152. uint16_t type,
  153. const OptionBuffer& buf) {
  154. FactoryMap::iterator it;
  155. if (u == Option::V4) {
  156. it = v4factories_.find(type);
  157. if (it == v4factories_.end()) {
  158. isc_throw(BadValue, "factory function not registered "
  159. "for DHCP v4 option type " << type);
  160. }
  161. } else if (u == Option::V6) {
  162. it = v6factories_.find(type);
  163. if (it == v6factories_.end()) {
  164. isc_throw(BadValue, "factory function not registered "
  165. "for DHCPv6 option type " << type);
  166. }
  167. } else {
  168. isc_throw(BadValue, "invalid universe specified (expected "
  169. "Option::V4 or Option::V6");
  170. }
  171. return (it->second(u, type, buf));
  172. }
  173. size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
  174. const std::string& option_space,
  175. isc::dhcp::OptionCollection& options,
  176. size_t* relay_msg_offset /* = 0 */,
  177. size_t* relay_msg_len /* = 0 */) {
  178. size_t offset = 0;
  179. size_t length = buf.size();
  180. // Get the list of standard option definitions.
  181. OptionDefContainer option_defs;
  182. if (option_space == "dhcp6") {
  183. option_defs = LibDHCP::getOptionDefs(Option::V6);
  184. }
  185. // @todo Once we implement other option spaces we should add else clause
  186. // here and gather option definitions for them. For now leaving option_defs
  187. // empty will imply creation of generic Option.
  188. // Get the search index #1. It allows to search for option definitions
  189. // using option code.
  190. const OptionDefContainerTypeIndex& idx = option_defs.get<1>();
  191. // The buffer being read comprises a set of options, each starting with
  192. // a two-byte type code and a two-byte length field.
  193. while (offset + 4 <= length) {
  194. uint16_t opt_type = isc::util::readUint16(&buf[offset]);
  195. offset += 2;
  196. uint16_t opt_len = isc::util::readUint16(&buf[offset]);
  197. offset += 2;
  198. if (offset + opt_len > length) {
  199. // @todo: consider throwing exception here.
  200. return (offset);
  201. }
  202. if (opt_type == D6O_RELAY_MSG && relay_msg_offset && relay_msg_len) {
  203. // remember offset of the beginning of the relay-msg option
  204. *relay_msg_offset = offset;
  205. *relay_msg_len = opt_len;
  206. // do not create that relay-msg option
  207. offset += opt_len;
  208. continue;
  209. }
  210. if (opt_type == D6O_VENDOR_OPTS) {
  211. if (offset + 4 > length) {
  212. // Truncated vendor-option. There is expected at least 4 bytes
  213. // long enterprise-id field
  214. return (offset);
  215. }
  216. // Parse this as vendor option
  217. OptionPtr vendor_opt(new OptionVendor(Option::V6, buf.begin() + offset,
  218. buf.begin() + offset + opt_len));
  219. options.insert(std::make_pair(opt_type, vendor_opt));
  220. offset += opt_len;
  221. continue;
  222. }
  223. // Get all definitions with the particular option code. Note that option
  224. // code is non-unique within this container however at this point we
  225. // expect to get one option definition with the particular code. If more
  226. // are returned we report an error.
  227. const OptionDefContainerTypeRange& range = idx.equal_range(opt_type);
  228. // Get the number of returned option definitions for the option code.
  229. size_t num_defs = distance(range.first, range.second);
  230. OptionPtr opt;
  231. if (num_defs > 1) {
  232. // Multiple options of the same code are not supported right now!
  233. isc_throw(isc::Unexpected, "Internal error: multiple option definitions"
  234. " for option type " << opt_type << " returned. Currently it is not"
  235. " supported to initialize multiple option definitions"
  236. " for the same option code. This will be supported once"
  237. " support for option spaces is implemented");
  238. } else if (num_defs == 0) {
  239. // @todo Don't crash if definition does not exist because only a few
  240. // option definitions are initialized right now. In the future
  241. // we will initialize definitions for all options and we will
  242. // remove this elseif. For now, return generic option.
  243. opt = OptionPtr(new Option(Option::V6, opt_type,
  244. buf.begin() + offset,
  245. buf.begin() + offset + opt_len));
  246. } else {
  247. // The option definition has been found. Use it to create
  248. // the option instance from the provided buffer chunk.
  249. const OptionDefinitionPtr& def = *(range.first);
  250. assert(def);
  251. opt = def->optionFactory(Option::V6, opt_type,
  252. buf.begin() + offset,
  253. buf.begin() + offset + opt_len);
  254. }
  255. // add option to options
  256. options.insert(std::make_pair(opt_type, opt));
  257. offset += opt_len;
  258. }
  259. return (offset);
  260. }
  261. size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
  262. const std::string& option_space,
  263. isc::dhcp::OptionCollection& options) {
  264. size_t offset = 0;
  265. // Get the list of stdandard option definitions.
  266. OptionDefContainer option_defs;
  267. if (option_space == "dhcp4") {
  268. option_defs = LibDHCP::getOptionDefs(Option::V4);
  269. }
  270. // @todo Once we implement other option spaces we should add else clause
  271. // here and gather option definitions for them. For now leaving option_defs
  272. // empty will imply creation of generic Option.
  273. // Get the search index #1. It allows to search for option definitions
  274. // using option code.
  275. const OptionDefContainerTypeIndex& idx = option_defs.get<1>();
  276. // The buffer being read comprises a set of options, each starting with
  277. // a one-byte type code and a one-byte length field.
  278. while (offset + 1 <= buf.size()) {
  279. uint8_t opt_type = buf[offset++];
  280. // DHO_END is a special, one octet long option
  281. if (opt_type == DHO_END)
  282. return (offset); // just return. Don't need to add DHO_END option
  283. // DHO_PAD is just a padding after DHO_END. Let's continue parsing
  284. // in case we receive a message without DHO_END.
  285. if (opt_type == DHO_PAD)
  286. continue;
  287. if (offset + 1 >= buf.size()) {
  288. // opt_type must be cast to integer so as it is not treated as
  289. // unsigned char value (a number is presented in error message).
  290. isc_throw(OutOfRange, "Attempt to parse truncated option "
  291. << static_cast<int>(opt_type));
  292. }
  293. uint8_t opt_len = buf[offset++];
  294. if (offset + opt_len > buf.size()) {
  295. isc_throw(OutOfRange, "Option parse failed. Tried to parse "
  296. << offset + opt_len << " bytes from " << buf.size()
  297. << "-byte long buffer.");
  298. }
  299. // Get all definitions with the particular option code. Note that option code
  300. // is non-unique within this container however at this point we expect
  301. // to get one option definition with the particular code. If more are
  302. // returned we report an error.
  303. const OptionDefContainerTypeRange& range = idx.equal_range(opt_type);
  304. // Get the number of returned option definitions for the option code.
  305. size_t num_defs = distance(range.first, range.second);
  306. OptionPtr opt;
  307. if (num_defs > 1) {
  308. // Multiple options of the same code are not supported right now!
  309. isc_throw(isc::Unexpected, "Internal error: multiple option definitions"
  310. " for option type " << static_cast<int>(opt_type)
  311. << " returned. Currently it is not supported to initialize"
  312. << " multiple option definitions for the same option code."
  313. << " This will be supported once support for option spaces"
  314. << " is implemented");
  315. } else if (num_defs == 0) {
  316. opt = OptionPtr(new Option(Option::V4, opt_type,
  317. buf.begin() + offset,
  318. buf.begin() + offset + opt_len));
  319. } else {
  320. // The option definition has been found. Use it to create
  321. // the option instance from the provided buffer chunk.
  322. const OptionDefinitionPtr& def = *(range.first);
  323. assert(def);
  324. opt = def->optionFactory(Option::V4, opt_type,
  325. buf.begin() + offset,
  326. buf.begin() + offset + opt_len);
  327. }
  328. options.insert(std::make_pair(opt_type, opt));
  329. offset += opt_len;
  330. }
  331. return (offset);
  332. }
  333. size_t LibDHCP::unpackVendorOptions6(const uint32_t vendor_id,
  334. const OptionBuffer& buf,
  335. isc::dhcp::OptionCollection& options) {
  336. size_t offset = 0;
  337. size_t length = buf.size();
  338. // Get the list of option definitions for this particular vendor-id
  339. const OptionDefContainer* option_defs = LibDHCP::getVendorOption6Defs(vendor_id);
  340. // Get the search index #1. It allows to search for option definitions
  341. // using option code. If there's no such vendor-id space, we're out of luck
  342. // anyway.
  343. const OptionDefContainerTypeIndex* idx = NULL;
  344. if (option_defs) {
  345. idx = &(option_defs->get<1>());
  346. }
  347. // The buffer being read comprises a set of options, each starting with
  348. // a two-byte type code and a two-byte length field.
  349. while (offset + 4 <= length) {
  350. uint16_t opt_type = isc::util::readUint16(&buf[offset]);
  351. offset += 2;
  352. uint16_t opt_len = isc::util::readUint16(&buf[offset]);
  353. offset += 2;
  354. if (offset + opt_len > length) {
  355. // @todo: consider throwing exception here.
  356. return (offset);
  357. }
  358. OptionPtr opt;
  359. opt.reset();
  360. // If there is a definition for such a vendor option...
  361. if (idx) {
  362. // Get all definitions with the particular option code. Note that option
  363. // code is non-unique within this container however at this point we
  364. // expect to get one option definition with the particular code. If more
  365. // are returned we report an error.
  366. const OptionDefContainerTypeRange& range = idx->equal_range(opt_type);
  367. // Get the number of returned option definitions for the option code.
  368. size_t num_defs = distance(range.first, range.second);
  369. if (num_defs > 1) {
  370. // Multiple options of the same code are not supported right now!
  371. isc_throw(isc::Unexpected, "Internal error: multiple option definitions"
  372. " for option type " << opt_type << " returned. Currently it is not"
  373. " supported to initialize multiple option definitions"
  374. " for the same option code. This will be supported once"
  375. " support for option spaces is implemented");
  376. } else if (num_defs == 1) {
  377. // The option definition has been found. Use it to create
  378. // the option instance from the provided buffer chunk.
  379. const OptionDefinitionPtr& def = *(range.first);
  380. assert(def);
  381. opt = def->optionFactory(Option::V6, opt_type,
  382. buf.begin() + offset,
  383. buf.begin() + offset + opt_len);
  384. }
  385. }
  386. // This can happen in one of 2 cases:
  387. // 1. we do not have definitions for that vendor-space
  388. // 2. we do have definitions, but that particular option was not defined
  389. if (!opt) {
  390. opt = OptionPtr(new Option(Option::V6, opt_type,
  391. buf.begin() + offset,
  392. buf.begin() + offset + opt_len));
  393. }
  394. // add option to options
  395. if (opt) {
  396. options.insert(std::make_pair(opt_type, opt));
  397. }
  398. offset += opt_len;
  399. }
  400. return (offset);
  401. }
  402. size_t LibDHCP::unpackVendorOptions4(const uint32_t vendor_id, const OptionBuffer& buf,
  403. isc::dhcp::OptionCollection& options) {
  404. size_t offset = 0;
  405. // Get the list of stdandard option definitions.
  406. const OptionDefContainer* option_defs = LibDHCP::getVendorOption4Defs(vendor_id);
  407. // Get the search index #1. It allows to search for option definitions
  408. // using option code.
  409. const OptionDefContainerTypeIndex* idx = NULL;
  410. if (option_defs) {
  411. idx = &(option_defs->get<1>());
  412. }
  413. // The buffer being read comprises a set of options, each starting with
  414. // a one-byte type code and a one-byte length field.
  415. while (offset + 1 <= buf.size()) {
  416. // Note that Vendor-Specific info option (RFC3925) has a different option
  417. // format than Vendor-Spec info for DHCPv6. (there's additional layer of
  418. // data-length
  419. uint8_t data_len = buf[offset++];
  420. if (offset + data_len > buf.size()) {
  421. // Truncated data-option
  422. return (offset);
  423. }
  424. uint8_t offset_end = offset + data_len;
  425. // beginning of data-chunk parser
  426. while (offset + 1 <= offset_end) {
  427. uint8_t opt_type = buf[offset++];
  428. // DHO_END is a special, one octet long option
  429. if (opt_type == DHO_END)
  430. return (offset); // just return. Don't need to add DHO_END option
  431. // DHO_PAD is just a padding after DHO_END. Let's continue parsing
  432. // in case we receive a message without DHO_END.
  433. if (opt_type == DHO_PAD)
  434. continue;
  435. if (offset + 1 >= buf.size()) {
  436. // opt_type must be cast to integer so as it is not treated as
  437. // unsigned char value (a number is presented in error message).
  438. isc_throw(OutOfRange, "Attempt to parse truncated option "
  439. << static_cast<int>(opt_type));
  440. }
  441. uint8_t opt_len = buf[offset++];
  442. if (offset + opt_len > buf.size()) {
  443. isc_throw(OutOfRange, "Option parse failed. Tried to parse "
  444. << offset + opt_len << " bytes from " << buf.size()
  445. << "-byte long buffer.");
  446. }
  447. OptionPtr opt;
  448. opt.reset();
  449. if (idx) {
  450. // Get all definitions with the particular option code. Note that option code
  451. // is non-unique within this container however at this point we expect
  452. // to get one option definition with the particular code. If more are
  453. // returned we report an error.
  454. const OptionDefContainerTypeRange& range = idx->equal_range(opt_type);
  455. // Get the number of returned option definitions for the option code.
  456. size_t num_defs = distance(range.first, range.second);
  457. if (num_defs > 1) {
  458. // Multiple options of the same code are not supported right now!
  459. isc_throw(isc::Unexpected, "Internal error: multiple option definitions"
  460. " for option type " << static_cast<int>(opt_type)
  461. << " returned. Currently it is not supported to initialize"
  462. << " multiple option definitions for the same option code."
  463. << " This will be supported once support for option spaces"
  464. << " is implemented");
  465. } else if (num_defs == 1) {
  466. // The option definition has been found. Use it to create
  467. // the option instance from the provided buffer chunk.
  468. const OptionDefinitionPtr& def = *(range.first);
  469. assert(def);
  470. opt = def->optionFactory(Option::V4, opt_type,
  471. buf.begin() + offset,
  472. buf.begin() + offset + opt_len);
  473. }
  474. }
  475. if (!opt) {
  476. opt = OptionPtr(new Option(Option::V4, opt_type,
  477. buf.begin() + offset,
  478. buf.begin() + offset + opt_len));
  479. }
  480. options.insert(std::make_pair(opt_type, opt));
  481. offset += opt_len;
  482. } // end of data-chunk
  483. }
  484. return (offset);
  485. }
  486. void
  487. LibDHCP::packOptions(isc::util::OutputBuffer& buf,
  488. const OptionCollection& options) {
  489. for (OptionCollection::const_iterator it = options.begin();
  490. it != options.end(); ++it) {
  491. it->second->pack(buf);
  492. }
  493. }
  494. void LibDHCP::OptionFactoryRegister(Option::Universe u,
  495. uint16_t opt_type,
  496. Option::Factory* factory) {
  497. switch (u) {
  498. case Option::V6: {
  499. if (v6factories_.find(opt_type) != v6factories_.end()) {
  500. isc_throw(BadValue, "There is already DHCPv6 factory registered "
  501. << "for option type " << opt_type);
  502. }
  503. v6factories_[opt_type]=factory;
  504. return;
  505. }
  506. case Option::V4:
  507. {
  508. // Option 0 is special (a one octet-long, equal 0) PAD option. It is never
  509. // instantiated as an Option object, but rather consumed during packet parsing.
  510. if (opt_type == 0) {
  511. isc_throw(BadValue, "Cannot redefine PAD option (code=0)");
  512. }
  513. // Option 255 is never instantiated as an option object. It is special
  514. // (a one-octet equal 255) option that is added at the end of all options
  515. // during packet assembly. It is also silently consumed during packet parsing.
  516. if (opt_type > 254) {
  517. isc_throw(BadValue, "Too big option type for DHCPv4, only 0-254 allowed.");
  518. }
  519. if (v4factories_.find(opt_type)!=v4factories_.end()) {
  520. isc_throw(BadValue, "There is already DHCPv4 factory registered "
  521. << "for option type " << opt_type);
  522. }
  523. v4factories_[opt_type]=factory;
  524. return;
  525. }
  526. default:
  527. isc_throw(BadValue, "Invalid universe type specified.");
  528. }
  529. return;
  530. }
  531. void
  532. LibDHCP::initStdOptionDefs4() {
  533. initOptionSpace(v4option_defs_, OPTION_DEF_PARAMS4, OPTION_DEF_PARAMS_SIZE4);
  534. }
  535. void
  536. LibDHCP::initStdOptionDefs6() {
  537. initOptionSpace(v6option_defs_, OPTION_DEF_PARAMS6, OPTION_DEF_PARAMS_SIZE6);
  538. }
  539. void
  540. LibDHCP::initVendorOptsDocsis4() {
  541. initOptionSpace(vendor4_defs_[VENDOR_ID_CABLE_LABS], DOCSIS3_V4_DEFS, DOCSIS3_V4_DEFS_SIZE);
  542. }
  543. void
  544. LibDHCP::initVendorOptsDocsis6() {
  545. vendor6_defs_[VENDOR_ID_CABLE_LABS] = OptionDefContainer();
  546. initOptionSpace(vendor6_defs_[VENDOR_ID_CABLE_LABS], DOCSIS3_V6_DEFS, DOCSIS3_V6_DEFS_SIZE);
  547. }
  548. void initOptionSpace(OptionDefContainer& defs,
  549. const OptionDefParams* params,
  550. size_t params_size) {
  551. defs.clear();
  552. for (int i = 0; i < params_size; ++i) {
  553. std::string encapsulates(params[i].encapsulates);
  554. if (!encapsulates.empty() && params[i].array) {
  555. isc_throw(isc::BadValue, "invalid standard option definition: "
  556. << "option with code '" << params[i].code
  557. << "' may not encapsulate option space '"
  558. << encapsulates << "' because the definition"
  559. << " indicates that this option comprises an array"
  560. << " of values");
  561. }
  562. // Depending whether an option encapsulates an option space or not
  563. // we pick different constructor to create an instance of the option
  564. // definition.
  565. OptionDefinitionPtr definition;
  566. if (encapsulates.empty()) {
  567. // Option does not encapsulate any option space.
  568. definition.reset(new OptionDefinition(params[i].name,
  569. params[i].code,
  570. params[i].type,
  571. params[i].array));
  572. } else {
  573. // Option does encapsulate an option space.
  574. definition.reset(new OptionDefinition(params[i].name,
  575. params[i].code,
  576. params[i].type,
  577. params[i].encapsulates));
  578. }
  579. for (int rec = 0; rec < params[i].records_size; ++rec) {
  580. definition->addRecordField(params[i].records[rec]);
  581. }
  582. try {
  583. definition->validate();
  584. } catch (const isc::Exception& ex) {
  585. // This is unlikely event that validation fails and may
  586. // be only caused by programming error. To guarantee the
  587. // data consistency we clear all option definitions that
  588. // have been added so far and pass the exception forward.
  589. defs.clear();
  590. throw;
  591. }
  592. defs.push_back(definition);
  593. }
  594. }