option_definition.cc 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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. if (type_ == IPV6_ADDRESS_TYPE && array_type_) {
  91. return (factoryAddrList6);
  92. } else if (type_ == IPV4_ADDRESS_TYPE && array_type_) {
  93. return (factoryAddrList4);
  94. } else if (type_ == EMPTY_TYPE) {
  95. return (factoryEmpty);
  96. } else if (code_ == D6O_IA_NA && haveIA6Format()) {
  97. return (factoryIA6);
  98. } else if (code_ == D6O_IAADDR && haveIAAddr6Format()) {
  99. return (factoryIAAddr6);
  100. } else if (type_ == UINT8_TYPE) {
  101. if (array_type_) {
  102. return (factoryGeneric);
  103. } else {
  104. return (factoryInteger<uint8_t>);
  105. }
  106. } else if (type_ == UINT16_TYPE) {
  107. if (array_type_) {
  108. return (factoryIntegerArray<uint16_t>);
  109. } else {
  110. return (factoryInteger<uint16_t>);
  111. }
  112. } else if (type_ == UINT32_TYPE) {
  113. if (array_type_) {
  114. return (factoryIntegerArray<uint32_t>);
  115. } else {
  116. return (factoryInteger<uint32_t>);
  117. }
  118. }
  119. return (factoryGeneric);
  120. }
  121. void
  122. OptionDefinition::sanityCheckUniverse(const Option::Universe expected_universe,
  123. const Option::Universe actual_universe) {
  124. if (expected_universe != actual_universe) {
  125. isc_throw(isc::BadValue, "invalid universe specified for the option");
  126. }
  127. }
  128. void
  129. OptionDefinition::validate() const {
  130. if (type_ >= UNKNOWN_TYPE) {
  131. isc_throw(isc::OutOfRange, "option type value " << type_
  132. << " is out of range");
  133. }
  134. }
  135. bool
  136. OptionDefinition::haveIA6Format() const {
  137. // Expect that IA_NA option format is defined as record.
  138. // Although it consists of 3 elements of the same (uint32)
  139. // type it can't be defined as array of uint32 elements because
  140. // arrays do not impose limitations on number of elements in
  141. // the array while this limitation is needed for IA_NA - need
  142. // exactly 3 elements.
  143. if (haveType(RECORD_TYPE)) {
  144. if (record_fields_.size() == 3) {
  145. for (RecordFieldsConstIter it = record_fields_.begin();
  146. it != record_fields_.end(); ++it) {
  147. if (*it != UINT32_TYPE) {
  148. return (false);
  149. }
  150. }
  151. return (true);
  152. }
  153. }
  154. return (false);
  155. }
  156. bool
  157. OptionDefinition::haveIAAddr6Format() const {
  158. if (haveType(RECORD_TYPE)) {
  159. if (record_fields_.size() == 3) {
  160. if (record_fields_[0] == IPV6_ADDRESS_TYPE &&
  161. record_fields_[1] == UINT32_TYPE &&
  162. record_fields_[2] == UINT32_TYPE) {
  163. return (true);
  164. }
  165. }
  166. }
  167. return (false);
  168. }
  169. OptionPtr
  170. OptionDefinition::factoryAddrList4(Option::Universe u, uint16_t type,
  171. const OptionBuffer& buf) {
  172. sanityCheckUniverse(u, Option::V4);
  173. boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, buf.begin(),
  174. buf.begin() + buf.size()));
  175. return (option);
  176. }
  177. OptionPtr
  178. OptionDefinition::factoryAddrList6(Option::Universe u, uint16_t type,
  179. const OptionBuffer& buf) {
  180. sanityCheckUniverse(u, Option::V6);
  181. boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, buf.begin(),
  182. buf.begin() + buf.size()));
  183. return (option);
  184. }
  185. OptionPtr
  186. OptionDefinition::factoryEmpty(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
  187. if (buf.size() > 0) {
  188. isc_throw(isc::BadValue, "input option buffer must be empty"
  189. " when creating empty option instance");
  190. }
  191. OptionPtr option(new Option(u, type));
  192. return (option);
  193. }
  194. OptionPtr
  195. OptionDefinition::factoryGeneric(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
  196. OptionPtr option(new Option(u, type, buf));
  197. return (option);
  198. }
  199. OptionPtr
  200. OptionDefinition::factoryIA6(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
  201. sanityCheckUniverse(u, Option::V6);
  202. if (buf.size() != Option6IA::OPTION6_IA_LEN) {
  203. isc_throw(isc::OutOfRange, "input option buffer has invalid size, expeted "
  204. << Option6IA::OPTION6_IA_LEN << " bytes");
  205. }
  206. boost::shared_ptr<Option6IA> option(new Option6IA(type, buf.begin(),
  207. buf.begin() + buf.size()));
  208. return (option);
  209. }
  210. OptionPtr
  211. OptionDefinition::factoryIAAddr6(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
  212. sanityCheckUniverse(u, Option::V6);
  213. if (buf.size() != Option6IAAddr::OPTION6_IAADDR_LEN) {
  214. isc_throw(isc::OutOfRange, "input option buffer has invalid size, expeted "
  215. << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes");
  216. }
  217. boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, buf.begin(),
  218. buf.begin() + buf.size()));
  219. return (option);
  220. }
  221. } // end of isc::dhcp namespace
  222. } // end of isc namespace