123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include <dhcp/dhcp6.h>
- #include <dhcp/option_definition.h>
- #include <dhcp/option4_addrlst.h>
- #include <dhcp/option6_addrlst.h>
- #include <dhcp/option6_ia.h>
- #include <dhcp/option6_iaaddr.h>
- #include <dhcp/option6_int.h>
- #include <dhcp/option6_int_array.h>
- using namespace std;
- using namespace isc::util;
- namespace isc {
- namespace dhcp {
- OptionDefinition::DataTypeUtil::DataTypeUtil() {
- data_types_["empty"] = EMPTY_TYPE;
- data_types_["binary"] = BINARY_TYPE;
- data_types_["boolean"] = BOOLEAN_TYPE;
- data_types_["int8"] = INT8_TYPE;
- data_types_["int16"] = INT16_TYPE;
- data_types_["int32"] = INT32_TYPE;
- data_types_["uint8"] = UINT8_TYPE;
- data_types_["uint16"] = UINT16_TYPE;
- data_types_["uint32"] = UINT32_TYPE;
- data_types_["ipv4-address"] = IPV4_ADDRESS_TYPE;
- data_types_["ipv6-address"] = IPV6_ADDRESS_TYPE;
- data_types_["string"] = STRING_TYPE;
- data_types_["fqdn"] = FQDN_TYPE;
- data_types_["record"] = RECORD_TYPE;
- }
- OptionDefinition::DataType
- OptionDefinition::DataTypeUtil::getDataType(const std::string& data_type) {
- std::map<std::string, DataType>::const_iterator data_type_it =
- data_types_.find(data_type);
- if (data_type_it != data_types_.end()) {
- return (data_type_it->second);
- }
- return UNKNOWN_TYPE;
- }
- OptionDefinition::OptionDefinition(const std::string& name,
- const uint16_t code,
- const std::string& type,
- const bool array_type /* = false */)
- : name_(name),
- code_(code),
- type_(UNKNOWN_TYPE),
- array_type_(array_type) {
- // Data type is held as enum value by this class.
- // Use the provided option type string to get the
- // corresponding enum value.
- type_ = DataTypeUtil::instance().getDataType(type);
- }
- OptionDefinition::OptionDefinition(const std::string& name,
- const uint16_t code,
- const DataType type,
- const bool array_type /* = false */)
- : name_(name),
- code_(code),
- type_(type),
- array_type_(array_type) {
- }
- void
- OptionDefinition::addRecordField(const std::string& data_type_name) {
- DataType data_type = DataTypeUtil::instance().getDataType(data_type_name);
- addRecordField(data_type);
- }
- void
- OptionDefinition::addRecordField(const DataType data_type) {
- if (type_ != RECORD_TYPE) {
- isc_throw(isc::InvalidOperation, "'record' option type must be used"
- " to add data fields to the record");
- }
- if (data_type >= UNKNOWN_TYPE) {
- isc_throw(isc::BadValue, "attempted to add invalid data type to the record");
- }
- record_fields_.push_back(data_type);
- }
- Option::Factory*
- OptionDefinition::getFactory() const {
- validate();
- // @todo This function must be extended to return more factory
- // functions that create instances of more specialized options.
- // This requires us to first implement those more specialized
- // options that will be derived from Option class.
- if (type_ == BINARY_TYPE) {
- return (factoryGeneric);
- } else if (type_ == IPV6_ADDRESS_TYPE && array_type_) {
- return (factoryAddrList6);
- } else if (type_ == IPV4_ADDRESS_TYPE && array_type_) {
- return (factoryAddrList4);
- } else if (type_ == EMPTY_TYPE) {
- return (factoryEmpty);
- } else if (code_ == D6O_IA_NA && haveIA6Format()) {
- return (factoryIA6);
- } else if (code_ == D6O_IAADDR && haveIAAddr6Format()) {
- return (factoryIAAddr6);
- } else if (type_ == UINT8_TYPE) {
- if (array_type_) {
- return (factoryGeneric);
- } else {
- return (factoryInteger<uint8_t>);
- }
- } else if (type_ == UINT16_TYPE) {
- if (array_type_) {
- return (factoryIntegerArray<uint16_t>);
- } else {
- return (factoryInteger<uint16_t>);
- }
- } else if (type_ == UINT32_TYPE) {
- if (array_type_) {
- return (factoryIntegerArray<uint32_t>);
- } else {
- return (factoryInteger<uint32_t>);
- }
- }
- // Factory generic returns instance of Option class. However, once we
- // implement CustomOption class we may want to return factory function
- // that will create instance of CustomOption rather than Option.
- // CustomOption will allow to access particular data fields within the
- // option rather than raw data buffer.
- return (factoryGeneric);
- }
- void
- OptionDefinition::sanityCheckUniverse(const Option::Universe expected_universe,
- const Option::Universe actual_universe) {
- if (expected_universe != actual_universe) {
- isc_throw(isc::BadValue, "invalid universe specified for the option");
- }
- }
- void
- OptionDefinition::validate() const {
- // Option name must not be empty.
- if (name_.empty()) {
- isc_throw(isc::BadValue, "option name must not be empty");
- }
- // Option name must not contain spaces.
- if (name_.find(" ") != string::npos) {
- isc_throw(isc::BadValue, "option name must not contain spaces");
- }
- // Unsupported option types are not allowed.
- if (type_ >= UNKNOWN_TYPE) {
- isc_throw(isc::OutOfRange, "option type value " << type_
- << " is out of range");
- }
- }
- bool
- OptionDefinition::haveIAx6Format(OptionDefinition::DataType first_type) const {
- return (haveType(RECORD_TYPE) &&
- record_fields_.size() == 3 &&
- record_fields_[0] == first_type &&
- record_fields_[1] == UINT32_TYPE &&
- record_fields_[2] == UINT32_TYPE);
- }
- bool
- OptionDefinition::haveIA6Format() const {
- // Expect that IA_NA option format is defined as record.
- // Although it consists of 3 elements of the same (uint32)
- // type it can't be defined as array of uint32 elements because
- // arrays do not impose limitations on number of elements in
- // the array while this limitation is needed for IA_NA - need
- // exactly 3 elements.
- return (haveIAx6Format(UINT32_TYPE));
- }
- bool
- OptionDefinition::haveIAAddr6Format() const {
- return (haveIAx6Format(IPV6_ADDRESS_TYPE));
- }
- OptionPtr
- OptionDefinition::factoryAddrList4(Option::Universe u, uint16_t type,
- const OptionBuffer& buf) {
- sanityCheckUniverse(u, Option::V4);
- boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, buf.begin(),
- buf.begin() + buf.size()));
- return (option);
- }
- OptionPtr
- OptionDefinition::factoryAddrList6(Option::Universe u, uint16_t type,
- const OptionBuffer& buf) {
- sanityCheckUniverse(u, Option::V6);
- boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, buf.begin(),
- buf.begin() + buf.size()));
- return (option);
- }
- OptionPtr
- OptionDefinition::factoryEmpty(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
- if (buf.size() > 0) {
- isc_throw(isc::BadValue, "input option buffer must be empty"
- " when creating empty option instance");
- }
- OptionPtr option(new Option(u, type));
- return (option);
- }
- OptionPtr
- OptionDefinition::factoryGeneric(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
- OptionPtr option(new Option(u, type, buf));
- return (option);
- }
- OptionPtr
- OptionDefinition::factoryIA6(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
- sanityCheckUniverse(u, Option::V6);
- if (buf.size() != Option6IA::OPTION6_IA_LEN) {
- isc_throw(isc::OutOfRange, "input option buffer has invalid size, expeted "
- << Option6IA::OPTION6_IA_LEN << " bytes");
- }
- boost::shared_ptr<Option6IA> option(new Option6IA(type, buf.begin(),
- buf.begin() + buf.size()));
- return (option);
- }
- OptionPtr
- OptionDefinition::factoryIAAddr6(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
- sanityCheckUniverse(u, Option::V6);
- if (buf.size() != Option6IAAddr::OPTION6_IAADDR_LEN) {
- isc_throw(isc::OutOfRange, "input option buffer has invalid size, expeted "
- << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes");
- }
- boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, buf.begin(),
- buf.begin() + buf.size()));
- return (option);
- }
- } // end of isc::dhcp namespace
- } // end of isc namespace
|