option_definition.cc 9.1 KB

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