option_definition.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. // Copyright (C) 2012-2014 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 <dhcp/dhcp4.h>
  15. #include <dhcp/dhcp6.h>
  16. #include <dhcp/option4_addrlst.h>
  17. #include <dhcp/option4_client_fqdn.h>
  18. #include <dhcp/option6_addrlst.h>
  19. #include <dhcp/option6_ia.h>
  20. #include <dhcp/option6_iaaddr.h>
  21. #include <dhcp/option6_iaprefix.h>
  22. #include <dhcp/option6_client_fqdn.h>
  23. #include <dhcp/option_custom.h>
  24. #include <dhcp/option_definition.h>
  25. #include <dhcp/option_int.h>
  26. #include <dhcp/option_int_array.h>
  27. #include <dhcp/option_space.h>
  28. #include <dhcp/option_string.h>
  29. #include <dhcp/option_vendor.h>
  30. #include <dhcp/option_vendor_class.h>
  31. #include <util/encode/hex.h>
  32. #include <util/strutil.h>
  33. #include <boost/algorithm/string/classification.hpp>
  34. #include <boost/algorithm/string/predicate.hpp>
  35. using namespace std;
  36. using namespace isc::util;
  37. namespace isc {
  38. namespace dhcp {
  39. OptionDefinition::OptionDefinition(const std::string& name,
  40. const uint16_t code,
  41. const std::string& type,
  42. const bool array_type /* = false */)
  43. : name_(name),
  44. code_(code),
  45. type_(OPT_UNKNOWN_TYPE),
  46. array_type_(array_type),
  47. encapsulated_space_("") {
  48. // Data type is held as enum value by this class.
  49. // Use the provided option type string to get the
  50. // corresponding enum value.
  51. type_ = OptionDataTypeUtil::getDataType(type);
  52. }
  53. OptionDefinition::OptionDefinition(const std::string& name,
  54. const uint16_t code,
  55. const OptionDataType type,
  56. const bool array_type /* = false */)
  57. : name_(name),
  58. code_(code),
  59. type_(type),
  60. array_type_(array_type),
  61. encapsulated_space_("") {
  62. }
  63. OptionDefinition::OptionDefinition(const std::string& name,
  64. const uint16_t code,
  65. const std::string& type,
  66. const char* encapsulated_space)
  67. : name_(name),
  68. code_(code),
  69. // Data type is held as enum value by this class.
  70. // Use the provided option type string to get the
  71. // corresponding enum value.
  72. type_(OptionDataTypeUtil::getDataType(type)),
  73. array_type_(false),
  74. encapsulated_space_(encapsulated_space) {
  75. }
  76. OptionDefinition::OptionDefinition(const std::string& name,
  77. const uint16_t code,
  78. const OptionDataType type,
  79. const char* encapsulated_space)
  80. : name_(name),
  81. code_(code),
  82. type_(type),
  83. array_type_(false),
  84. encapsulated_space_(encapsulated_space) {
  85. }
  86. void
  87. OptionDefinition::addRecordField(const std::string& data_type_name) {
  88. OptionDataType data_type = OptionDataTypeUtil::getDataType(data_type_name);
  89. addRecordField(data_type);
  90. }
  91. void
  92. OptionDefinition::addRecordField(const OptionDataType data_type) {
  93. if (type_ != OPT_RECORD_TYPE) {
  94. isc_throw(isc::InvalidOperation, "'record' option type must be used"
  95. " to add data fields to the record");
  96. }
  97. if (data_type >= OPT_RECORD_TYPE ||
  98. data_type == OPT_ANY_ADDRESS_TYPE ||
  99. data_type == OPT_EMPTY_TYPE) {
  100. isc_throw(isc::BadValue,
  101. "attempted to add invalid data type to the record.");
  102. }
  103. record_fields_.push_back(data_type);
  104. }
  105. OptionPtr
  106. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  107. OptionBufferConstIter begin,
  108. OptionBufferConstIter end,
  109. UnpackOptionsCallback callback) const {
  110. try {
  111. // Some of the options are represented by the specialized classes derived
  112. // from Option class (e.g. IA_NA, IAADDR). Although, they can be also
  113. // represented by the generic classes, we want the object of the specialized
  114. // type to be returned. Therefore, we first check that if we are dealing
  115. // with such an option. If the instance is returned we just exit at this
  116. // point. If not, we will search for a generic option type to return.
  117. OptionPtr option = factorySpecialFormatOption(u, begin, end, callback);
  118. if (option) {
  119. return (option);
  120. }
  121. switch(type_) {
  122. case OPT_EMPTY_TYPE:
  123. if (getEncapsulatedSpace().empty()) {
  124. return (factoryEmpty(u, type));
  125. } else {
  126. return (OptionPtr(new OptionCustom(*this, u, begin, end)));
  127. }
  128. case OPT_BINARY_TYPE:
  129. return (factoryGeneric(u, type, begin, end));
  130. case OPT_UINT8_TYPE:
  131. return (array_type_ ?
  132. factoryIntegerArray<uint8_t>(u, type, begin, end) :
  133. factoryInteger<uint8_t>(u, type, getEncapsulatedSpace(),
  134. begin, end, callback));
  135. case OPT_INT8_TYPE:
  136. return (array_type_ ?
  137. factoryIntegerArray<int8_t>(u, type, begin, end) :
  138. factoryInteger<int8_t>(u, type, getEncapsulatedSpace(),
  139. begin, end, callback));
  140. case OPT_UINT16_TYPE:
  141. return (array_type_ ?
  142. factoryIntegerArray<uint16_t>(u, type, begin, end) :
  143. factoryInteger<uint16_t>(u, type, getEncapsulatedSpace(),
  144. begin, end, callback));
  145. case OPT_INT16_TYPE:
  146. return (array_type_ ?
  147. factoryIntegerArray<uint16_t>(u, type, begin, end) :
  148. factoryInteger<int16_t>(u, type, getEncapsulatedSpace(),
  149. begin, end, callback));
  150. case OPT_UINT32_TYPE:
  151. return (array_type_ ?
  152. factoryIntegerArray<uint32_t>(u, type, begin, end) :
  153. factoryInteger<uint32_t>(u, type, getEncapsulatedSpace(),
  154. begin, end, callback));
  155. case OPT_INT32_TYPE:
  156. return (array_type_ ?
  157. factoryIntegerArray<uint32_t>(u, type, begin, end) :
  158. factoryInteger<int32_t>(u, type, getEncapsulatedSpace(),
  159. begin, end, callback));
  160. case OPT_IPV4_ADDRESS_TYPE:
  161. // If definition specifies that an option is an array
  162. // of IPv4 addresses we return an instance of specialized
  163. // class (OptionAddrLst4). For non-array types there is no
  164. // specialized class yet implemented so we drop through
  165. // to return an instance of OptionCustom.
  166. if (array_type_) {
  167. return (factoryAddrList4(type, begin, end));
  168. }
  169. break;
  170. case OPT_IPV6_ADDRESS_TYPE:
  171. // Handle array type only here (see comments for
  172. // OPT_IPV4_ADDRESS_TYPE case).
  173. if (array_type_) {
  174. return (factoryAddrList6(type, begin, end));
  175. }
  176. break;
  177. case OPT_STRING_TYPE:
  178. return (OptionPtr(new OptionString(u, type, begin, end)));
  179. default:
  180. // Do nothing. We will return generic option a few lines down.
  181. ;
  182. }
  183. return (OptionPtr(new OptionCustom(*this, u, begin, end)));
  184. } catch (const Exception& ex) {
  185. isc_throw(InvalidOptionValue, ex.what());
  186. }
  187. }
  188. OptionPtr
  189. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  190. const OptionBuffer& buf,
  191. UnpackOptionsCallback callback) const {
  192. return (optionFactory(u, type, buf.begin(), buf.end(), callback));
  193. }
  194. OptionPtr
  195. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  196. const std::vector<std::string>& values) const {
  197. OptionBuffer buf;
  198. if (!array_type_ && type_ != OPT_RECORD_TYPE) {
  199. if (values.empty()) {
  200. isc_throw(InvalidOptionValue, "no option value specified");
  201. }
  202. writeToBuffer(util::str::trim(values[0]), type_, buf);
  203. } else if (array_type_ && type_ != OPT_RECORD_TYPE) {
  204. for (size_t i = 0; i < values.size(); ++i) {
  205. writeToBuffer(util::str::trim(values[i]), type_, buf);
  206. }
  207. } else if (type_ == OPT_RECORD_TYPE) {
  208. const RecordFieldsCollection& records = getRecordFields();
  209. if (records.size() > values.size()) {
  210. isc_throw(InvalidOptionValue, "number of data fields for the option"
  211. << " type '" << getCode() << "' is greater than number"
  212. << " of values provided.");
  213. }
  214. for (size_t i = 0; i < records.size(); ++i) {
  215. writeToBuffer(util::str::trim(values[i]),
  216. records[i], buf);
  217. }
  218. }
  219. return (optionFactory(u, type, buf.begin(), buf.end()));
  220. }
  221. void
  222. OptionDefinition::validate() const {
  223. using namespace boost::algorithm;
  224. std::ostringstream err_str;
  225. // Allowed characters in the option name are: lower or
  226. // upper case letters, digits, underscores and hyphens.
  227. // Empty option spaces are not allowed.
  228. if (!all(name_, boost::is_from_range('a', 'z') ||
  229. boost::is_from_range('A', 'Z') ||
  230. boost::is_digit() ||
  231. boost::is_any_of(std::string("-_"))) ||
  232. name_.empty() ||
  233. // Hyphens and underscores are not allowed at the beginning
  234. // and at the end of the option name.
  235. all(find_head(name_, 1), boost::is_any_of(std::string("-_"))) ||
  236. all(find_tail(name_, 1), boost::is_any_of(std::string("-_")))) {
  237. err_str << "invalid option name '" << name_ << "'";
  238. } else if (!encapsulated_space_.empty() &&
  239. !OptionSpace::validateName(encapsulated_space_)) {
  240. err_str << "invalid encapsulated option space name: '"
  241. << encapsulated_space_ << "'";
  242. } else if (type_ >= OPT_UNKNOWN_TYPE) {
  243. // Option definition must be of a known type.
  244. err_str << "option type value " << type_ << " is out of range.";
  245. } else if (array_type_) {
  246. if (type_ == OPT_STRING_TYPE) {
  247. // Array of strings is not allowed because there is no way
  248. // to determine the size of a particular string and thus there
  249. // it no way to tell when other data fields begin.
  250. err_str << "array of strings is not a valid option definition.";
  251. } else if (type_ == OPT_BINARY_TYPE) {
  252. err_str << "array of binary values is not"
  253. << " a valid option definition.";
  254. } else if (type_ == OPT_EMPTY_TYPE) {
  255. err_str << "array of empty value is not"
  256. << " a valid option definition.";
  257. }
  258. } else if (type_ == OPT_RECORD_TYPE) {
  259. // At least two data fields should be added to the record. Otherwise
  260. // non-record option definition could be used.
  261. if (getRecordFields().size() < 2) {
  262. err_str << "invalid number of data fields: "
  263. << getRecordFields().size()
  264. << " specified for the option of type 'record'. Expected at"
  265. << " least 2 fields.";
  266. } else {
  267. // If the number of fields is valid we have to check if their order
  268. // is valid too. We check that string or binary data fields are not
  269. // laid before other fields. But we allow that they are laid at the
  270. // end of an option.
  271. const RecordFieldsCollection& fields = getRecordFields();
  272. for (RecordFieldsConstIter it = fields.begin();
  273. it != fields.end(); ++it) {
  274. if (*it == OPT_STRING_TYPE &&
  275. it < fields.end() - 1) {
  276. err_str << "string data field can't be laid before data"
  277. << " fields of other types.";
  278. break;
  279. }
  280. if (*it == OPT_BINARY_TYPE &&
  281. it < fields.end() - 1) {
  282. err_str << "binary data field can't be laid before data"
  283. << " fields of other types.";
  284. }
  285. /// Empty type is not allowed within a record.
  286. if (*it == OPT_EMPTY_TYPE) {
  287. err_str << "empty data type can't be stored as a field in"
  288. << " an option record.";
  289. break;
  290. }
  291. }
  292. }
  293. }
  294. // Non-empty error string means that we have hit the error. We throw
  295. // exception and include error string.
  296. if (!err_str.str().empty()) {
  297. isc_throw(MalformedOptionDefinition, err_str.str());
  298. }
  299. }
  300. bool
  301. OptionDefinition::haveIAx6Format(OptionDataType first_type) const {
  302. return (haveType(OPT_RECORD_TYPE) &&
  303. record_fields_.size() == 3 &&
  304. record_fields_[0] == first_type &&
  305. record_fields_[1] == OPT_UINT32_TYPE &&
  306. record_fields_[2] == OPT_UINT32_TYPE);
  307. }
  308. bool
  309. OptionDefinition::haveIA6Format() const {
  310. // Expect that IA_NA option format is defined as record.
  311. // Although it consists of 3 elements of the same (uint32)
  312. // type it can't be defined as array of uint32 elements because
  313. // arrays do not impose limitations on number of elements in
  314. // the array while this limitation is needed for IA_NA - need
  315. // exactly 3 elements.
  316. return (haveIAx6Format(OPT_UINT32_TYPE));
  317. }
  318. bool
  319. OptionDefinition::haveIAAddr6Format() const {
  320. return (haveIAx6Format(OPT_IPV6_ADDRESS_TYPE));
  321. }
  322. bool
  323. OptionDefinition::haveIAPrefix6Format() const {
  324. return (haveType(OPT_RECORD_TYPE) &&
  325. record_fields_.size() == 4 &&
  326. record_fields_[0] == OPT_UINT32_TYPE &&
  327. record_fields_[1] == OPT_UINT32_TYPE &&
  328. record_fields_[2] == OPT_UINT8_TYPE &&
  329. record_fields_[3] == OPT_IPV6_ADDRESS_TYPE);
  330. }
  331. bool
  332. OptionDefinition::haveFqdn4Format() const {
  333. return (haveType(OPT_RECORD_TYPE) &&
  334. record_fields_.size() == 4 &&
  335. record_fields_[0] == OPT_UINT8_TYPE &&
  336. record_fields_[1] == OPT_UINT8_TYPE &&
  337. record_fields_[2] == OPT_UINT8_TYPE &&
  338. record_fields_[3] == OPT_FQDN_TYPE);
  339. }
  340. bool
  341. OptionDefinition::haveClientFqdnFormat() const {
  342. return (haveType(OPT_RECORD_TYPE) &&
  343. (record_fields_.size() == 2) &&
  344. (record_fields_[0] == OPT_UINT8_TYPE) &&
  345. (record_fields_[1] == OPT_FQDN_TYPE));
  346. }
  347. bool
  348. OptionDefinition::haveVendor4Format() const {
  349. return (true);
  350. }
  351. bool
  352. OptionDefinition::haveVendor6Format() const {
  353. return (getType() == OPT_UINT32_TYPE && !getEncapsulatedSpace().empty());
  354. }
  355. bool
  356. OptionDefinition::haveVendorClass4Format() const {
  357. return (haveType(OPT_RECORD_TYPE) &&
  358. (record_fields_.size() == 2) &&
  359. (record_fields_[0] == OPT_UINT32_TYPE) &&
  360. (record_fields_[1] == OPT_BINARY_TYPE));
  361. }
  362. bool
  363. OptionDefinition::haveVendorClass6Format() const {
  364. return (haveType(OPT_RECORD_TYPE) &&
  365. (record_fields_.size() == 2) &&
  366. (record_fields_[0] == OPT_UINT32_TYPE) &&
  367. (record_fields_[1] == OPT_BINARY_TYPE));
  368. }
  369. bool
  370. OptionDefinition::convertToBool(const std::string& value_str) const {
  371. // Case insensitve check that the input is one of: "true" or "false".
  372. if (boost::iequals(value_str, "true")) {
  373. return (true);
  374. } else if (boost::iequals(value_str, "false")) {
  375. return (false);
  376. }
  377. // The input string is neither "true" nor "false", so let's check
  378. // if it is not an integer wrapped in a string.
  379. int result;
  380. try {
  381. result = boost::lexical_cast<int>(value_str);
  382. } catch (const boost::bad_lexical_cast&) {
  383. isc_throw(BadDataTypeCast, "unable to covert the value '"
  384. << value_str << "' to boolean data type");
  385. }
  386. // The boolean value is encoded in DHCP option as 0 or 1. Therefore,
  387. // we only allow a user to specify those values for options which
  388. // have boolean fields.
  389. if (result != 1 && result != 0) {
  390. isc_throw(BadDataTypeCast, "unable to convert '" << value_str
  391. << "' to boolean data type");
  392. }
  393. return (static_cast<bool>(result));
  394. }
  395. template<typename T>
  396. T
  397. OptionDefinition::lexicalCastWithRangeCheck(const std::string& value_str)
  398. const {
  399. // The lexical cast should be attempted when converting to an integer
  400. // value only.
  401. if (!OptionDataTypeTraits<T>::integer_type) {
  402. isc_throw(BadDataTypeCast,
  403. "must not convert '" << value_str
  404. << "' to non-integer data type");
  405. }
  406. // We use the 64-bit value here because it has wider range than
  407. // any other type we use here and it allows to detect out of
  408. // bounds conditions e.g. negative value specified for uintX_t
  409. // data type. Obviously if the value exceeds the limits of int64
  410. // this function will not handle that properly.
  411. int64_t result = 0;
  412. try {
  413. result = boost::lexical_cast<int64_t>(value_str);
  414. } catch (const boost::bad_lexical_cast&) {
  415. isc_throw(BadDataTypeCast, "unable to convert the value '"
  416. << value_str << "' to integer data type");
  417. }
  418. // Perform range checks.
  419. if (OptionDataTypeTraits<T>::integer_type) {
  420. if (result > numeric_limits<T>::max() ||
  421. result < numeric_limits<T>::min()) {
  422. isc_throw(BadDataTypeCast, "unable to convert '"
  423. << value_str << "' to numeric type. This value is "
  424. " expected to be in the range of "
  425. << numeric_limits<T>::min()
  426. << ".." << numeric_limits<T>::max());
  427. }
  428. }
  429. return (static_cast<T>(result));
  430. }
  431. void
  432. OptionDefinition::writeToBuffer(const std::string& value,
  433. const OptionDataType type,
  434. OptionBuffer& buf) const {
  435. // We are going to write value given by value argument to the buffer.
  436. // The actual type of the value is given by second argument. Check
  437. // this argument to determine how to write this value to the buffer.
  438. switch (type) {
  439. case OPT_BINARY_TYPE:
  440. OptionDataTypeUtil::writeBinary(value, buf);
  441. return;
  442. case OPT_BOOLEAN_TYPE:
  443. // We encode the true value as 1 and false as 0 on 8 bits.
  444. // That way we actually waste 7 bits but it seems to be the
  445. // simpler way to encode boolean.
  446. // @todo Consider if any other encode methods can be used.
  447. OptionDataTypeUtil::writeBool(convertToBool(value), buf);
  448. return;
  449. case OPT_INT8_TYPE:
  450. OptionDataTypeUtil::writeInt<uint8_t>
  451. (lexicalCastWithRangeCheck<int8_t>(value),
  452. buf);
  453. return;
  454. case OPT_INT16_TYPE:
  455. OptionDataTypeUtil::writeInt<uint16_t>
  456. (lexicalCastWithRangeCheck<int16_t>(value),
  457. buf);
  458. return;
  459. case OPT_INT32_TYPE:
  460. OptionDataTypeUtil::writeInt<uint32_t>
  461. (lexicalCastWithRangeCheck<int32_t>(value),
  462. buf);
  463. return;
  464. case OPT_UINT8_TYPE:
  465. OptionDataTypeUtil::writeInt<uint8_t>
  466. (lexicalCastWithRangeCheck<uint8_t>(value),
  467. buf);
  468. return;
  469. case OPT_UINT16_TYPE:
  470. OptionDataTypeUtil::writeInt<uint16_t>
  471. (lexicalCastWithRangeCheck<uint16_t>(value),
  472. buf);
  473. return;
  474. case OPT_UINT32_TYPE:
  475. OptionDataTypeUtil::writeInt<uint32_t>
  476. (lexicalCastWithRangeCheck<uint32_t>(value),
  477. buf);
  478. return;
  479. case OPT_IPV4_ADDRESS_TYPE:
  480. case OPT_IPV6_ADDRESS_TYPE:
  481. {
  482. asiolink::IOAddress address(value);
  483. if (!address.isV4() && !address.isV6()) {
  484. isc_throw(BadDataTypeCast, "provided address "
  485. << address
  486. << " is not a valid IPv4 or IPv6 address.");
  487. }
  488. OptionDataTypeUtil::writeAddress(address, buf);
  489. return;
  490. }
  491. case OPT_STRING_TYPE:
  492. OptionDataTypeUtil::writeString(value, buf);
  493. return;
  494. case OPT_FQDN_TYPE:
  495. OptionDataTypeUtil::writeFqdn(value, buf);
  496. return;
  497. default:
  498. // We hit this point because invalid option data type has been specified
  499. // This may be the case because 'empty' or 'record' data type has been
  500. // specified. We don't throw exception here because it will be thrown
  501. // at the exit point from this function.
  502. ;
  503. }
  504. isc_throw(isc::BadValue, "attempt to write invalid option data field type"
  505. " into the option buffer: " << type);
  506. }
  507. OptionPtr
  508. OptionDefinition::factoryAddrList4(uint16_t type,
  509. OptionBufferConstIter begin,
  510. OptionBufferConstIter end) {
  511. boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, begin,
  512. end));
  513. return (option);
  514. }
  515. OptionPtr
  516. OptionDefinition::factoryAddrList6(uint16_t type,
  517. OptionBufferConstIter begin,
  518. OptionBufferConstIter end) {
  519. boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, begin,
  520. end));
  521. return (option);
  522. }
  523. OptionPtr
  524. OptionDefinition::factoryEmpty(Option::Universe u, uint16_t type) {
  525. OptionPtr option(new Option(u, type));
  526. return (option);
  527. }
  528. OptionPtr
  529. OptionDefinition::factoryGeneric(Option::Universe u, uint16_t type,
  530. OptionBufferConstIter begin,
  531. OptionBufferConstIter end) {
  532. OptionPtr option(new Option(u, type, begin, end));
  533. return (option);
  534. }
  535. OptionPtr
  536. OptionDefinition::factoryIA6(uint16_t type,
  537. OptionBufferConstIter begin,
  538. OptionBufferConstIter end) {
  539. if (std::distance(begin, end) < Option6IA::OPTION6_IA_LEN) {
  540. isc_throw(isc::OutOfRange, "input option buffer has invalid size,"
  541. << " expected at least " << Option6IA::OPTION6_IA_LEN
  542. << " bytes");
  543. }
  544. boost::shared_ptr<Option6IA> option(new Option6IA(type, begin, end));
  545. return (option);
  546. }
  547. OptionPtr
  548. OptionDefinition::factoryIAAddr6(uint16_t type,
  549. OptionBufferConstIter begin,
  550. OptionBufferConstIter end) {
  551. if (std::distance(begin, end) < Option6IAAddr::OPTION6_IAADDR_LEN) {
  552. isc_throw(isc::OutOfRange,
  553. "input option buffer has invalid size, expected at least "
  554. << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes");
  555. }
  556. boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, begin,
  557. end));
  558. return (option);
  559. }
  560. OptionPtr
  561. OptionDefinition::factoryIAPrefix6(uint16_t type,
  562. OptionBufferConstIter begin,
  563. OptionBufferConstIter end) {
  564. if (std::distance(begin, end) < Option6IAPrefix::OPTION6_IAPREFIX_LEN) {
  565. isc_throw(isc::OutOfRange,
  566. "input option buffer has invalid size, expected at least "
  567. << Option6IAPrefix::OPTION6_IAPREFIX_LEN << " bytes");
  568. }
  569. boost::shared_ptr<Option6IAPrefix> option(new Option6IAPrefix(type, begin,
  570. end));
  571. return (option);
  572. }
  573. OptionPtr
  574. OptionDefinition::factorySpecialFormatOption(Option::Universe u,
  575. OptionBufferConstIter begin,
  576. OptionBufferConstIter end,
  577. UnpackOptionsCallback) const {
  578. if (u == Option::V6) {
  579. if ((getCode() == D6O_IA_NA || getCode() == D6O_IA_PD) &&
  580. haveIA6Format()) {
  581. // Return Option6IA instance for IA_PD and IA_NA option
  582. // types only. We don't want to return Option6IA for other
  583. // options that comprise 3 UINT32 data fields because
  584. // Option6IA accessors' and modifiers' names are derived
  585. // from the IA_NA and IA_PD options' field names: IAID,
  586. // T1, T2. Using functions such as getIAID, getT1 etc. for
  587. // options other than IA_NA and IA_PD would be bad practice
  588. // and cause confusion.
  589. return (factoryIA6(getCode(), begin, end));
  590. } else if (getCode() == D6O_IAADDR && haveIAAddr6Format()) {
  591. // Rerurn Option6IAAddr option instance for the IAADDR
  592. // option only for the same reasons as described in
  593. // for IA_NA and IA_PD above.
  594. return (factoryIAAddr6(getCode(), begin, end));
  595. } else if (getCode() == D6O_IAPREFIX && haveIAPrefix6Format()) {
  596. return (factoryIAPrefix6(getCode(), begin, end));
  597. } else if (getCode() == D6O_CLIENT_FQDN && haveClientFqdnFormat()) {
  598. // FQDN option requires special processing. Thus, there is
  599. // a specialized class to handle it.
  600. return (OptionPtr(new Option6ClientFqdn(begin, end)));
  601. } else if (getCode() == D6O_VENDOR_OPTS && haveVendor6Format()) {
  602. // Vendor-Specific Information (option code 17)
  603. return (OptionPtr(new OptionVendor(Option::V6, begin, end)));
  604. } else if (getCode() == D6O_VENDOR_CLASS && haveVendorClass6Format()) {
  605. // Vendor Class (option code 16).
  606. return (OptionPtr(new OptionVendorClass(Option::V6, begin, end)));
  607. }
  608. } else {
  609. if ((getCode() == DHO_FQDN) && haveFqdn4Format()) {
  610. return (OptionPtr(new Option4ClientFqdn(begin, end)));
  611. } else if ((getCode() == DHO_VIVCO_SUBOPTIONS) &&
  612. haveVendorClass4Format()) {
  613. // V-I Vendor Class (option code 124).
  614. return (OptionPtr(new OptionVendorClass(Option::V4, begin, end)));
  615. } else if (getCode() == DHO_VIVSO_SUBOPTIONS && haveVendor4Format()) {
  616. // Vendor-Specific Information (option code 125).
  617. return (OptionPtr(new OptionVendor(Option::V4, begin, end)));
  618. }
  619. }
  620. return (OptionPtr());
  621. }
  622. } // end of isc::dhcp namespace
  623. } // end of isc namespace