option_definition.cc 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // Copyright (C) 2012 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/dhcp6.h>
  15. #include <dhcp/option_definition.h>
  16. #include <dhcp/option4_addrlst.h>
  17. #include <dhcp/option6_addrlst.h>
  18. #include <dhcp/option6_ia.h>
  19. #include <dhcp/option6_iaaddr.h>
  20. #include <dhcp/option6_int.h>
  21. #include <dhcp/option6_int_array.h>
  22. using namespace std;
  23. using namespace isc::util;
  24. namespace isc {
  25. namespace dhcp {
  26. OptionDefinition::DataTypeUtil::DataTypeUtil() {
  27. data_types_["empty"] = EMPTY_TYPE;
  28. data_types_["binary"] = BINARY_TYPE;
  29. data_types_["boolean"] = BOOLEAN_TYPE;
  30. data_types_["int8"] = INT8_TYPE;
  31. data_types_["int16"] = INT16_TYPE;
  32. data_types_["int32"] = INT32_TYPE;
  33. data_types_["uint8"] = UINT8_TYPE;
  34. data_types_["uint16"] = UINT16_TYPE;
  35. data_types_["uint32"] = UINT32_TYPE;
  36. data_types_["ipv4-address"] = IPV4_ADDRESS_TYPE;
  37. data_types_["ipv6-address"] = IPV6_ADDRESS_TYPE;
  38. data_types_["string"] = STRING_TYPE;
  39. data_types_["fqdn"] = FQDN_TYPE;
  40. data_types_["record"] = RECORD_TYPE;
  41. }
  42. OptionDefinition::DataType
  43. OptionDefinition::DataTypeUtil::getDataType(const std::string& data_type) {
  44. std::map<std::string, DataType>::const_iterator data_type_it =
  45. data_types_.find(data_type);
  46. if (data_type_it != data_types_.end()) {
  47. return (data_type_it->second);
  48. }
  49. return UNKNOWN_TYPE;
  50. }
  51. OptionDefinition::OptionDefinition(const std::string& name,
  52. const uint16_t code,
  53. const std::string& type,
  54. const bool array_type /* = false */)
  55. : name_(name),
  56. code_(code),
  57. type_(UNKNOWN_TYPE),
  58. array_type_(array_type) {
  59. // Data type is held as enum value by this class.
  60. // Use the provided option type string to get the
  61. // corresponding enum value.
  62. type_ = DataTypeUtil::instance().getDataType(type);
  63. }
  64. OptionDefinition::OptionDefinition(const std::string& name,
  65. const uint16_t code,
  66. const DataType type,
  67. const bool array_type /* = false */)
  68. : name_(name),
  69. code_(code),
  70. type_(type),
  71. array_type_(array_type) {
  72. }
  73. void
  74. OptionDefinition::addRecordField(const std::string& data_type_name) {
  75. DataType data_type = DataTypeUtil::instance().getDataType(data_type_name);
  76. addRecordField(data_type);
  77. }
  78. void
  79. OptionDefinition::addRecordField(const DataType data_type) {
  80. if (type_ != RECORD_TYPE) {
  81. isc_throw(isc::InvalidOperation, "'record' option type must be used"
  82. " to add data fields to the record");
  83. }
  84. if (data_type >= UNKNOWN_TYPE) {
  85. isc_throw(isc::BadValue, "attempted to add invalid data type to the record");
  86. }
  87. record_fields_.push_back(data_type);
  88. }
  89. Option::Factory*
  90. OptionDefinition::getFactory() const {
  91. validate();
  92. // @todo This function must be extended to return more factory
  93. // functions that create instances of more specialized options.
  94. // This requires us to first implement those more specialized
  95. // options that will be derived from Option class.
  96. if (type_ == BINARY_TYPE) {
  97. return (factoryGeneric);
  98. } else if (type_ == IPV6_ADDRESS_TYPE && array_type_) {
  99. return (factoryAddrList6);
  100. } else if (type_ == IPV4_ADDRESS_TYPE && array_type_) {
  101. return (factoryAddrList4);
  102. } else if (type_ == EMPTY_TYPE) {
  103. return (factoryEmpty);
  104. } else if (code_ == D6O_IA_NA && haveIA6Format()) {
  105. return (factoryIA6);
  106. } else if (code_ == D6O_IAADDR && haveIAAddr6Format()) {
  107. return (factoryIAAddr6);
  108. } else if (type_ == UINT8_TYPE) {
  109. if (array_type_) {
  110. return (factoryGeneric);
  111. } else {
  112. return (factoryInteger<uint8_t>);
  113. }
  114. } else if (type_ == UINT16_TYPE) {
  115. if (array_type_) {
  116. return (factoryIntegerArray<uint16_t>);
  117. } else {
  118. return (factoryInteger<uint16_t>);
  119. }
  120. } else if (type_ == UINT32_TYPE) {
  121. if (array_type_) {
  122. return (factoryIntegerArray<uint32_t>);
  123. } else {
  124. return (factoryInteger<uint32_t>);
  125. }
  126. }
  127. // Factory generic returns instance of Option class. However, once we
  128. // implement CustomOption class we may want to return factory function
  129. // that will create instance of CustomOption rather than Option.
  130. // CustomOption will allow to access particular data fields within the
  131. // option rather than raw data buffer.
  132. return (factoryGeneric);
  133. }
  134. void
  135. OptionDefinition::sanityCheckUniverse(const Option::Universe expected_universe,
  136. const Option::Universe actual_universe) {
  137. if (expected_universe != actual_universe) {
  138. isc_throw(isc::BadValue, "invalid universe specified for the option");
  139. }
  140. }
  141. void
  142. OptionDefinition::validate() const {
  143. // Option name must not be empty.
  144. if (name_.empty()) {
  145. isc_throw(isc::BadValue, "option name must not be empty");
  146. }
  147. // Option name must not contain spaces.
  148. if (name_.find(" ") != string::npos) {
  149. isc_throw(isc::BadValue, "option name must not contain spaces");
  150. }
  151. // Unsupported option types are not allowed.
  152. if (type_ >= UNKNOWN_TYPE) {
  153. isc_throw(isc::OutOfRange, "option type value " << type_
  154. << " is out of range");
  155. }
  156. }
  157. bool
  158. OptionDefinition::haveIAx6Format(OptionDefinition::DataType first_type) const {
  159. return (haveType(RECORD_TYPE) &&
  160. record_fields_.size() == 3 &&
  161. record_fields_[0] == first_type &&
  162. record_fields_[1] == UINT32_TYPE &&
  163. record_fields_[2] == UINT32_TYPE);
  164. }
  165. bool
  166. OptionDefinition::haveIA6Format() const {
  167. // Expect that IA_NA option format is defined as record.
  168. // Although it consists of 3 elements of the same (uint32)
  169. // type it can't be defined as array of uint32 elements because
  170. // arrays do not impose limitations on number of elements in
  171. // the array while this limitation is needed for IA_NA - need
  172. // exactly 3 elements.
  173. return (haveIAx6Format(UINT32_TYPE));
  174. }
  175. bool
  176. OptionDefinition::haveIAAddr6Format() const {
  177. return (haveIAx6Format(IPV6_ADDRESS_TYPE));
  178. }
  179. OptionPtr
  180. OptionDefinition::factoryAddrList4(Option::Universe u, uint16_t type,
  181. const OptionBuffer& buf) {
  182. sanityCheckUniverse(u, Option::V4);
  183. boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, buf.begin(),
  184. buf.begin() + buf.size()));
  185. return (option);
  186. }
  187. OptionPtr
  188. OptionDefinition::factoryAddrList6(Option::Universe u, uint16_t type,
  189. const OptionBuffer& buf) {
  190. sanityCheckUniverse(u, Option::V6);
  191. boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, buf.begin(),
  192. buf.begin() + buf.size()));
  193. return (option);
  194. }
  195. OptionPtr
  196. OptionDefinition::factoryEmpty(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
  197. if (buf.size() > 0) {
  198. isc_throw(isc::BadValue, "input option buffer must be empty"
  199. " when creating empty option instance");
  200. }
  201. OptionPtr option(new Option(u, type));
  202. return (option);
  203. }
  204. OptionPtr
  205. OptionDefinition::factoryGeneric(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
  206. OptionPtr option(new Option(u, type, buf));
  207. return (option);
  208. }
  209. OptionPtr
  210. OptionDefinition::factoryIA6(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
  211. sanityCheckUniverse(u, Option::V6);
  212. if (buf.size() != Option6IA::OPTION6_IA_LEN) {
  213. isc_throw(isc::OutOfRange, "input option buffer has invalid size, expeted "
  214. << Option6IA::OPTION6_IA_LEN << " bytes");
  215. }
  216. boost::shared_ptr<Option6IA> option(new Option6IA(type, buf.begin(),
  217. buf.begin() + buf.size()));
  218. return (option);
  219. }
  220. OptionPtr
  221. OptionDefinition::factoryIAAddr6(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
  222. sanityCheckUniverse(u, Option::V6);
  223. if (buf.size() != Option6IAAddr::OPTION6_IAADDR_LEN) {
  224. isc_throw(isc::OutOfRange, "input option buffer has invalid size, expeted "
  225. << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes");
  226. }
  227. boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, buf.begin(),
  228. buf.begin() + buf.size()));
  229. return (option);
  230. }
  231. } // end of isc::dhcp namespace
  232. } // end of isc namespace