24#include <boost/lexical_cast.hpp>
25#include <boost/shared_array.hpp>
26#include <boost/shared_ptr.hpp>
44 { STANDARD_V4_OPTION_DEFINITIONS, STANDARD_V4_OPTION_DEFINITIONS_SIZE,
DHCP4_OPTION_SPACE },
45 { STANDARD_V6_OPTION_DEFINITIONS, STANDARD_V6_OPTION_DEFINITIONS_SIZE,
DHCP6_OPTION_SPACE },
64std::map<unsigned short, Option::Factory*> LibDHCP::v4factories_;
67std::map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
92bool LibDHCP::initialized_ = LibDHCP::initOptionDefs();
95LibDHCP::getOptionDefs(
const std::string& space) {
96 auto const& container = option_defs_.find(space);
97 if (container != option_defs_.end()) {
98 return (container->second);
113 }
else if (ENTERPRISE_ID_ISC == vendor_id) {
126 if (range.first != range.second) {
127 return (*range.first);
138 if (range.first != range.second) {
139 return (*range.first);
147 const std::string& name) {
156 if (range.first != range.second) {
157 return (*range.first);
165 const uint16_t code) {
177 if (range.first != range.second) {
178 return (*range.first);
189 if (range.first != range.second) {
190 return (*range.first);
201 if (range.first != range.second) {
202 return (*range.first);
210 return (runtime_option_defs_.getValue().getItems(space));
217 for (
auto const& name : option_space_names) {
219 for (
auto const& def : *container) {
224 runtime_option_defs_ = defs_copy;
229 runtime_option_defs_.reset();
234 runtime_option_defs_.revert();
239 runtime_option_defs_.commit();
247 if (range.first != range.second) {
248 return (*range.first);
259 if (range.first != range.second) {
260 return (*range.first);
279 ((code >= 224) && (code <= 254))));
286 FactoryMap::iterator it;
288 it = v4factories_.find(type);
289 if (it == v4factories_.end()) {
291 "for DHCP v4 option type " << type);
294 it = v6factories_.find(type);
295 if (it == v6factories_.end()) {
297 "for DHCPv6 option type " << type);
301 "Option::V4 or Option::V6");
303 return (it->second(u, type, buf));
309 const std::string& option_space,
311 size_t* relay_msg_offset ,
312 size_t* relay_msg_len ) {
314 size_t length = buf.size();
315 size_t last_offset = 0;
334 while (offset < length) {
336 last_offset = offset;
339 if (offset + 4 > length) {
341 return (last_offset);
351 if (offset + opt_len > length) {
360 return (last_offset);
363 if (opt_type ==
D6O_RELAY_MSG && relay_msg_offset && relay_msg_len) {
365 *relay_msg_offset = offset;
366 *relay_msg_len = opt_len;
374 if (offset + 4 > length) {
378 return (last_offset);
383 buf.begin() + offset + opt_len));
384 options.insert(std::make_pair(opt_type, vendor_opt));
401 range = idx.equal_range(opt_type);
402 num_defs = std::distance(range.first, range.second);
408 range = runtime_idx.equal_range(opt_type);
409 num_defs = std::distance(range.first, range.second);
416 " definitions for option type " << opt_type <<
417 " returned. Currently it is not supported to initialize"
418 " multiple option definitions for the same option code."
419 " This will be supported once support for option spaces"
421 }
else if (num_defs == 0) {
428 buf.begin() + offset,
429 buf.begin() + offset + opt_len));
436 opt = def->optionFactory(
Option::V6, opt_type,
437 buf.begin() + offset,
438 buf.begin() + offset + opt_len);
446 options.insert(std::make_pair(opt_type, opt));
452 last_offset = offset;
453 return (last_offset);
458 const std::string& option_space,
460 std::list<uint16_t>& deferred,
463 size_t last_offset = 0;
480 bool flex_pad = (check && (runtime_idx.count(
DHO_PAD) == 0));
481 bool flex_end = (check && (runtime_idx.count(
DHO_END) == 0));
485 while (offset < buf.size()) {
487 last_offset = offset;
490 uint8_t opt_type = buf[offset++];
495 if ((opt_type ==
DHO_END) && (space_is_dhcp4 || flex_end)) {
499 return (last_offset);
506 if ((opt_type ==
DHO_PAD) && (space_is_dhcp4 || flex_pad)) {
510 if (offset + 1 > buf.size()) {
518 return (last_offset);
521 uint8_t opt_len = buf[offset++];
522 if (offset + opt_len > buf.size()) {
527 return (last_offset);
535 if (space_is_dhcp4 && opt_len == 0 && opt_type ==
DHO_HOST_NAME) {
551 range = idx.equal_range(opt_type);
552 num_defs = std::distance(range.first, range.second);
558 range = runtime_idx.equal_range(opt_type);
559 num_defs = std::distance(range.first, range.second);
567 for (
auto const& existing : deferred) {
568 if (existing == opt_type) {
574 deferred.push_back(opt_type);
582 " definitions for option type " <<
583 static_cast<int>(opt_type) <<
584 " returned. Currently it is not supported to initialize"
585 " multiple option definitions for the same option code."
586 " This will be supported once support for option spaces"
588 }
else if (num_defs == 0) {
590 buf.begin() + offset,
591 buf.begin() + offset + opt_len));
599 opt = def->optionFactory(
Option::V4, opt_type,
600 buf.begin() + offset,
601 buf.begin() + offset + opt_len);
609 options.insert(std::make_pair(opt_type, opt));
614 last_offset = offset;
615 return (last_offset);
624 bool found_suboptions =
false;
626 for (
auto const& option : options) {
630 if (sub_options.size()) {
635 if (found_suboptions) {
644 for (
auto const& old_option :
copy) {
645 if (old_option.first == option.first) {
647 data.insert(data.end(), old_option.second->getData().begin(),
648 old_option.second->getData().end());
649 suboptions.insert(old_option.second->getOptions().begin(),
650 old_option.second->getOptions().end());
660 copy.erase(option.first);
663 candidate->getType(), data));
665 new_option->getMutableOptions() = suboptions;
667 copy.insert(make_pair(candidate->getType(), new_option));
677 if ((found <= 1) && !found_suboptions) {
689 size_t length = buf.size();
700 idx = &(option_defs->get<1>());
705 while (offset < length) {
706 if (offset + 4 > length) {
708 "Vendor option parse failed: truncated header");
717 if (offset + opt_len > length) {
719 "Vendor option parse failed. Tried to parse "
720 << offset + opt_len <<
" bytes from " << length
721 <<
"-byte long buffer.");
735 idx->equal_range(opt_type);
738 size_t num_defs = std::distance(range.first, range.second);
744 " definitions for option type " << opt_type <<
745 " returned. Currently it is not supported to"
746 " initialize multiple option definitions for the"
747 " same option code. This will be supported once"
748 " support for option spaces is implemented");
749 }
else if (num_defs == 1) {
754 opt = def->optionFactory(
Option::V6, opt_type,
755 buf.begin() + offset,
756 buf.begin() + offset + opt_len);
767 buf.begin() + offset,
768 buf.begin() + offset + opt_len));
773 options.insert(std::make_pair(opt_type, opt));
793 idx = &(option_defs->get<1>());
798 while (offset < buf.size()) {
802 uint8_t data_len = buf[offset++];
804 if (offset + data_len > buf.size()) {
807 "Attempt to parse truncated vendor option");
810 uint8_t offset_end = offset + data_len;
813 while (offset < offset_end) {
814 uint8_t opt_type = buf[offset++];
818 if (offset + 1 > offset_end) {
823 "Attempt to parse truncated vendor option "
824 <<
static_cast<int>(opt_type));
827 uint8_t opt_len = buf[offset++];
828 if (offset + opt_len > offset_end) {
830 "Option parse failed. Tried to parse "
831 << offset + opt_len <<
" bytes from " << buf.size()
832 <<
"-byte long buffer.");
845 idx->equal_range(opt_type);
848 size_t num_defs = std::distance(range.first, range.second);
854 " option definitions for option type "
855 << opt_type <<
" returned. Currently it is"
856 " not supported to initialize multiple option"
857 " definitions for the same option code."
858 " This will be supported once support for"
859 " option spaces is implemented");
860 }
else if (num_defs == 1) {
865 opt = def->optionFactory(
Option::V4, opt_type,
866 buf.begin() + offset,
867 buf.begin() + offset + opt_len);
873 buf.begin() + offset,
874 buf.begin() + offset + opt_len));
877 options.insert(std::make_pair(opt_type, opt));
890 bool top,
bool check) {
900 if (x != options.end()) {
901 x->second->pack(buf, check);
905 for (
auto const& option : options) {
907 switch (option.first) {
917 option.second->pack(buf, check);
923 for (
auto const& option : agent) {
924 option.second->pack(buf, check);
929 end->pack(buf, check);
945 for (
auto const& option : options) {
950 bool updated =
false;
951 bool found_suboptions =
false;
952 if (sub_options.size()) {
955 used + candidate->getHeaderLen());
958 if (found_suboptions || candidate->len() > 255) {
960 scoped_options.push_back(candidate_scoped_options);
963 copy.erase(option.first);
973 for (
auto sub_option : candidate->getMutableOptions()) {
975 candidate->getType(),
977 data_sub_option->addOption(sub_option.second);
978 distinct_options.insert(make_pair(candidate->getType(), data_sub_option));
986 candidate->getType(),
988 candidate->getData().end())));
990 data_option->pack(buf,
false);
991 uint32_t header_len = candidate->getHeaderLen();
993 if (used >= 255 - header_len) {
995 << candidate->getType() <<
" after parent already used "
1000 uint8_t len = 255 - header_len - used;
1005 uint32_t size = buf.
getLength() - header_len;
1014 copy.erase(option.first);
1017 uint32_t offset = 0;
1020 for (; offset != size;) {
1024 if (size - offset < len) {
1025 len = size - offset;
1029 const uint8_t* data =
static_cast<const uint8_t*
>(buf.
getData());
1032 candidate->getType(),
1034 data + offset + len)));
1039 copy.insert(make_pair(candidate->getType(), new_option));
1041 }
else if (candidate->len() > 255 && size) {
1045 copy.insert(make_pair(candidate->getType(), data_option));
1050 copy.insert(distinct_options.begin(), distinct_options.end());
1071 for (
auto const& option : options) {
1072 option.second->pack(buf);
1083 if (v6factories_.find(opt_type) != v6factories_.end()) {
1085 <<
"for option type " << opt_type);
1087 v6factories_[opt_type] = factory;
1094 if (opt_type == 0) {
1100 if (opt_type > 254) {
1103 if (v4factories_.find(opt_type) != v4factories_.end()) {
1105 <<
"for option type " << opt_type);
1107 v4factories_[opt_type] = factory;
1118LibDHCP::initOptionDefs() {
1119 for (uint32_t i = 0; OPTION_DEF_PARAMS[i].optionDefParams; ++i) {
1120 std::string space = OPTION_DEF_PARAMS[i].space;
1123 OPTION_DEF_PARAMS[i].optionDefParams,
1124 OPTION_DEF_PARAMS[i].size);
1133 if ((option_space.size() < 8) || (option_space.substr(0,7) !=
"vendor-")) {
1140 std::string x = option_space.substr(7);
1142 check = boost::lexical_cast<int64_t>(x);
1143 }
catch (
const boost::bad_lexical_cast &) {
1147 if ((check < 0) || (check > std::numeric_limits<uint32_t>::max())) {
1152 return (
static_cast<uint32_t
>(check));
1158 size_t params_size) {
1168 for (
size_t i = 0; i < params_size; ++i) {
1169 std::string encapsulates(params[i].encapsulates);
1170 if (!encapsulates.empty() && params[i].
array) {
1172 <<
"option with code '" << params[i].code
1173 <<
"' may not encapsulate option space '"
1174 << encapsulates <<
"' because the definition"
1175 <<
" indicates that this option comprises an array"
1183 if (encapsulates.empty()) {
1196 params[i].encapsulates));
1200 for (
size_t rec = 0; rec < params[i].
records_size; ++rec) {
1201 definition->addRecordField(params[i].records[rec]);
1205 definition->validate();
1217 static_cast<void>(defs->push_back(definition));
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
A generic exception that is thrown when an unexpected error condition occurs.
static size_t unpackOptions4(const OptionBuffer &buf, const std::string &option_space, isc::dhcp::OptionCollection &options, std::list< uint16_t > &deferred, bool flexible_pad_end=false)
Parses provided buffer as DHCPv4 options and creates Option objects.
static void OptionFactoryRegister(Option::Universe u, uint16_t type, Option::Factory *factory)
Registers factory method that produces options of specific option types.
static size_t unpackVendorOptions6(const uint32_t vendor_id, const OptionBuffer &buf, isc::dhcp::OptionCollection &options)
Parses provided buffer as DHCPv6 vendor options and creates Option objects.
static const OptionDefContainerPtr getOptionDefs(const std::string &space)
Returns collection of option definitions.
static bool shouldDeferOptionUnpack(const std::string &space, const uint16_t code)
Checks if an option unpacking has to be deferred.
static isc::dhcp::OptionPtr optionFactory(isc::dhcp::Option::Universe u, uint16_t type, const OptionBuffer &buf)
Factory function to create instance of option.
static void setRuntimeOptionDefs(const OptionDefSpaceContainer &defs)
Copies option definitions created at runtime.
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
static OptionDefinitionPtr getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id, const uint16_t code)
Returns vendor option definition for a given vendor-id and code.
static OptionDefContainerPtr getLastResortOptionDefs(const std::string &space)
Returns last resort option definitions for specified option space name.
static OptionDefContainerPtr getRuntimeOptionDefs(const std::string &space)
Returns runtime (non-standard) option definitions for specified option space name.
static void commitRuntimeOptionDefs()
Commits runtime option definitions.
static void clearRuntimeOptionDefs()
Removes runtime option definitions.
static void packOptions4(isc::util::OutputBuffer &buf, const isc::dhcp::OptionCollection &options, bool top=false, bool check=true)
Stores DHCPv4 options in a buffer.
static bool splitOptions4(isc::dhcp::OptionCollection &options, ScopedOptionsCopyContainer &scopedOptions, uint32_t used=0)
Split long options in multiple options with the same option code (RFC3396).
static void revertRuntimeOptionDefs()
Reverts uncommitted changes to runtime option definitions.
static const OptionDefContainerPtr getVendorOptionDefs(Option::Universe u, const uint32_t vendor_id)
Returns option definitions for given universe and vendor.
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
static OptionDefinitionPtr getRuntimeOptionDef(const std::string &space, const uint16_t code)
Returns runtime (non-standard) option definition by space and option code.
static size_t unpackOptions6(const OptionBuffer &buf, const std::string &option_space, isc::dhcp::OptionCollection &options, size_t *relay_msg_offset=0, size_t *relay_msg_len=0)
Parses provided buffer as DHCPv6 options and creates Option objects.
static void packOptions6(isc::util::OutputBuffer &buf, const isc::dhcp::OptionCollection &options)
Stores DHCPv6 options in a buffer.
static OptionDefinitionPtr getLastResortOptionDef(const std::string &space, const uint16_t code)
Returns last resort option definition by space and option code.
static bool fuseOptions4(isc::dhcp::OptionCollection &options)
Fuse multiple options with the same option code in long options (RFC3396).
static size_t unpackVendorOptions4(const uint32_t vendor_id, const OptionBuffer &buf, isc::dhcp::OptionCollection &options)
Parses provided buffer as DHCPv4 vendor options and creates Option objects.
Class of option definition space container.
void addItem(const OptionDefinitionPtr &def)
Adds a new option definition to the container.
Base class representing a DHCP option definition.
std::list< Selector > getOptionSpaceNames() const
Get a list of existing option spaces.
ItemsContainerPtr getItems(const Selector &option_space) const
Get all items for the particular option space.
This class represents vendor-specific information option.
Universe
defines option universe DHCPv4 or DHCPv6
OptionPtr Factory(Option::Universe u, uint16_t type, const OptionBuffer &buf)
a factory function prototype
RAII object enabling duplication of the stored options and restoring the original options on destruct...
Exception thrown during option unpacking This exception is thrown when an error has occurred,...
Exception thrown during option unpacking This exception is thrown when an error has occurred unpackin...
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
size_t getLength() const
Return the length of data written in the buffer.
const void * getData() const
Return a pointer to the head of the data stored in the buffer.
This class implements set/commit mechanism for a single object.
#define DOCSIS3_V6_OPTION_SPACE
#define VENDOR_ID_CABLE_LABS
#define DOCSIS3_V4_OPTION_SPACE
global docsis3 option spaces
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
void initOptionSpace(OptionDefContainerPtr &defs, const OptionDefParams *params, size_t params_size)
const OptionDefContainerPtr null_option_def_container_(new OptionDefContainer())
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
@ DHO_VENDOR_ENCAPSULATED_OPTIONS
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
const OptionDefParams DOCSIS3_V4_OPTION_DEFINITIONS[]
Definitions of standard DHCPv4 options.
const char * DOCSIS3_CLASS_EROUTER
The class as specified in vendor-class option by the devices.
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
const int DOCSIS3_V6_OPTION_DEFINITIONS_SIZE
Number of option definitions defined.
std::pair< OptionDefContainerNameIndex::const_iterator, OptionDefContainerNameIndex::const_iterator > OptionDefContainerNameRange
Pair of iterators to represent the range of options definitions having the same option name.
const char * DOCSIS3_CLASS_MODEM
DOCSIS3.0 compatible cable modem.
std::map< std::string, OptionDefContainerPtr > OptionDefContainers
Container that holds option definitions for various option spaces.
std::shared_ptr< ScopedSubOptionsCopy > ScopedOptionsCopyPtr
A pointer to a ScopedSubOptionsCopy object.
OptionDefContainer::nth_index< 2 >::type OptionDefContainerNameIndex
Type of the index #2 - option name.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
std::pair< OptionDefContainerTypeIndex::const_iterator, OptionDefContainerTypeIndex::const_iterator > OptionDefContainerTypeRange
Pair of iterators to represent the range of options definitions having the same option type value.
boost::multi_index_container< OptionDefinitionPtr, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::hashed_non_unique< boost::multi_index::const_mem_fun< OptionDefinition, uint16_t, &OptionDefinition::getCode > >, boost::multi_index::hashed_non_unique< boost::multi_index::const_mem_fun< OptionDefinition, std::string, &OptionDefinition::getName > >, boost::multi_index::ordered_non_unique< boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime, &data::StampedElement::getModificationTime > >, boost::multi_index::hashed_non_unique< boost::multi_index::tag< OptionIdIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, uint64_t, &data::BaseStampedElement::getId > > > > OptionDefContainer
Multi index container for DHCP option definitions.
const int DOCSIS3_V4_OPTION_DEFINITIONS_SIZE
Number of option definitions defined.
OptionDefContainer::nth_index< 1 >::type OptionDefContainerTypeIndex
Type of the index #1 - option type.
boost::shared_ptr< Option > OptionPtr
std::vector< ScopedOptionsCopyPtr > ScopedOptionsCopyContainer
A container of ScopedOptionsCopyPtr objects.
const OptionDefParams DOCSIS3_V6_OPTION_DEFINITIONS[]
Definitions of standard DHCPv6 options.
boost::shared_ptr< OptionDefContainer > OptionDefContainerPtr
Pointer to an option definition container.
uint16_t readUint16(const void *buffer, size_t length)
Read Unsigned 16-Bit Integer from Buffer.
Defines the logger used by the top-level component of kea-lfc.
#define V4V6_BIND_OPTION_SPACE
#define LAST_RESORT_V4_OPTION_SPACE
#define DHCP4_OPTION_SPACE
global std option spaces
#define ISC_V6_OPTION_SPACE
#define V4V6_RULE_OPTION_SPACE
#define MAPE_V6_OPTION_SPACE
#define LW_V6_OPTION_SPACE
#define DHCP6_OPTION_SPACE
#define MAPT_V6_OPTION_SPACE
Encapsulation of option definition parameters and the structure size.
Parameters being used to make up an option definition.