25 #include <boost/lexical_cast.hpp>
26 #include <boost/shared_array.hpp>
27 #include <boost/shared_ptr.hpp>
37 std::map<unsigned short, Option::Factory*> LibDHCP::v4factories_;
40 std::map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
81 LibDHCP::getOptionDefs(
const std::string& space) {
84 if (v4option_defs_->empty()) {
86 initVendorOptsDocsis4();
88 initVendorOptsDocsis6();
89 initLastResortOptionDefs();
93 return (v4option_defs_);
96 return (v6option_defs_);
99 OptionDefContainers::const_iterator container = option_defs_.find(space);
100 if (container != option_defs_.end()) {
101 return (container->second);
107 LibDHCP::getVendorOption4Defs(
const uint32_t vendor_id) {
111 initVendorOptsDocsis4();
114 VendorOptionDefContainers::const_iterator def = vendor4_defs_.find(vendor_id);
115 if (def == vendor4_defs_.end()) {
119 return (def->second);
123 LibDHCP::getVendorOption6Defs(
const uint32_t vendor_id) {
127 initVendorOptsDocsis6();
130 if (vendor_id == ENTERPRISE_ID_ISC &&
131 vendor6_defs_.find(ENTERPRISE_ID_ISC) == vendor6_defs_.end()) {
132 initVendorOptsIsc6();
135 VendorOptionDefContainers::const_iterator def = vendor6_defs_.find(vendor_id);
136 if (def == vendor6_defs_.end()) {
140 return (def->second);
144 LibDHCP::getOptionDef(
const std::string& space,
const uint16_t code) {
148 if (range.first != range.second) {
149 return (*range.first);
155 LibDHCP::getOptionDef(
const std::string& space,
const std::string& name) {
159 if (range.first != range.second) {
160 return (*range.first);
167 const std::string& name) {
169 getVendorOption6Defs(vendor_id));
177 if (range.first != range.second) {
178 return (*range.first);
185 const uint16_t code) {
187 getVendorOption6Defs(vendor_id));
198 if (range.first != range.second) {
199 return (*range.first);
205 LibDHCP::getRuntimeOptionDef(
const std::string& space,
const uint16_t code) {
209 if (range.first != range.second) {
210 return (*range.first);
217 LibDHCP::getRuntimeOptionDef(
const std::string& space,
const std::string& name) {
221 if (range.first != range.second) {
222 return (*range.first);
229 LibDHCP::getRuntimeOptionDefs(
const std::string& space) {
230 return (runtime_option_defs_.getValue().getItems(space));
237 for (std::list<std::string>::const_iterator name = option_space_names.begin();
238 name != option_space_names.end(); ++name) {
240 for (OptionDefContainer::const_iterator def = container->begin();
241 def != container->end(); ++def) {
243 defs_copy.
addItem(def_copy, *name);
246 runtime_option_defs_ = defs_copy;
250 LibDHCP::clearRuntimeOptionDefs() {
251 runtime_option_defs_.reset();
255 LibDHCP::revertRuntimeOptionDefs() {
256 runtime_option_defs_.revert();
260 LibDHCP::commitRuntimeOptionDefs() {
261 runtime_option_defs_.commit();
265 LibDHCP::getLastResortOptionDef(
const std::string& space,
const uint16_t code) {
269 if (range.first != range.second) {
270 return (*range.first);
277 LibDHCP::getLastResortOptionDef(
const std::string& space,
const std::string& name) {
281 if (range.first != range.second) {
282 return (*range.first);
289 LibDHCP::getLastResortOptionDefs(
const std::string& space) {
291 return (lastresort_defs_);
297 LibDHCP::shouldDeferOptionUnpack(
const std::string& space,
const uint16_t code) {
300 ((code >= 224) && (code <= 254))));
307 FactoryMap::iterator it;
308 if (u == Option::V4) {
309 it = v4factories_.find(type);
310 if (it == v4factories_.end()) {
312 "for DHCP v4 option type " << type);
314 }
else if (u == Option::V6) {
315 it = v6factories_.find(type);
316 if (it == v6factories_.end()) {
318 "for DHCPv6 option type " << type);
322 "Option::V4 or Option::V6");
324 return (it->second(u, type, buf));
329 const std::string& option_space,
331 size_t* relay_msg_offset ,
332 size_t* relay_msg_len ) {
334 size_t length = buf.size();
335 size_t last_offset = 0;
354 while (offset < length) {
356 last_offset = offset;
359 if (offset + 4 > length) {
361 return (last_offset);
371 if (offset + opt_len > length) {
380 return (last_offset);
383 if (opt_type ==
D6O_RELAY_MSG && relay_msg_offset && relay_msg_len) {
385 *relay_msg_offset = offset;
386 *relay_msg_len = opt_len;
394 if (offset + 4 > length) {
398 return (last_offset);
403 buf.begin() + offset + opt_len));
404 options.insert(std::make_pair(opt_type, vendor_opt));
421 range = idx.equal_range(opt_type);
422 num_defs = std::distance(range.first, range.second);
428 range = runtime_idx.equal_range(opt_type);
429 num_defs = std::distance(range.first, range.second);
436 " definitions for option type " << opt_type <<
437 " returned. Currently it is not supported to initialize"
438 " multiple option definitions for the same option code."
439 " This will be supported once support for option spaces"
441 }
else if (num_defs == 0) {
448 buf.begin() + offset,
449 buf.begin() + offset + opt_len));
455 opt = def->optionFactory(Option::V6, opt_type,
456 buf.begin() + offset,
457 buf.begin() + offset + opt_len);
460 options.insert(std::make_pair(opt_type, opt));
464 last_offset = offset;
465 return (last_offset);
469 const std::string& option_space,
471 std::list<uint16_t>& deferred) {
473 size_t last_offset = 0;
488 while (offset < buf.size()) {
490 last_offset = offset;
493 uint8_t opt_type = buf[offset++];
500 return (last_offset);
508 if (offset + 1 > buf.size()) {
516 return (last_offset);
519 uint8_t opt_len = buf[offset++];
520 if (offset + opt_len > buf.size()) {
525 return (last_offset);
540 range = idx.equal_range(opt_type);
541 num_defs = std::distance(range.first, range.second);
547 range = runtime_idx.equal_range(opt_type);
548 num_defs = std::distance(range.first, range.second);
552 if (shouldDeferOptionUnpack(option_space, opt_type)) {
554 deferred.push_back(opt_type);
561 " definitions for option type " <<
562 static_cast<int>(opt_type) <<
563 " returned. Currently it is not supported to initialize"
564 " multiple option definitions for the same option code."
565 " This will be supported once support for option spaces"
567 }
else if (num_defs == 0) {
569 buf.begin() + offset,
570 buf.begin() + offset + opt_len));
577 opt = def->optionFactory(Option::V4, opt_type,
578 buf.begin() + offset,
579 buf.begin() + offset + opt_len);
582 options.insert(std::make_pair(opt_type, opt));
585 last_offset = offset;
586 return (last_offset);
589 size_t LibDHCP::unpackVendorOptions6(
const uint32_t vendor_id,
593 size_t length = buf.size();
603 idx = &(option_defs->get<1>());
608 while (offset < length) {
609 if (offset + 4 > length) {
611 "Vendor option parse failed: truncated header");
620 if (offset + opt_len > length) {
622 "Vendor option parse failed. Tried to parse "
623 << offset + opt_len <<
" bytes from " << length
624 <<
"-byte long buffer.");
638 idx->equal_range(opt_type);
641 size_t num_defs = std::distance(range.first, range.second);
647 " definitions for option type " << opt_type <<
648 " returned. Currently it is not supported to"
649 " initialize multiple option definitions for the"
650 " same option code. This will be supported once"
651 " support for option spaces is implemented");
652 }
else if (num_defs == 1) {
657 opt = def->optionFactory(Option::V6, opt_type,
658 buf.begin() + offset,
659 buf.begin() + offset + opt_len);
670 buf.begin() + offset,
671 buf.begin() + offset + opt_len));
676 options.insert(std::make_pair(opt_type, opt));
684 size_t LibDHCP::unpackVendorOptions4(
const uint32_t vendor_id,
const OptionBuffer& buf,
694 idx = &(option_defs->get<1>());
699 while (offset < buf.size()) {
703 uint8_t data_len = buf[offset++];
705 if (offset + data_len > buf.size()) {
708 "Attempt to parse truncated vendor option");
711 uint8_t offset_end = offset + data_len;
714 while (offset < offset_end) {
715 uint8_t opt_type = buf[offset++];
719 if (offset + 1 > offset_end) {
724 "Attempt to parse truncated vendor option "
725 <<
static_cast<int>(opt_type));
728 uint8_t opt_len = buf[offset++];
729 if (offset + opt_len > offset_end) {
731 "Option parse failed. Tried to parse "
732 << offset + opt_len <<
" bytes from " << buf.size()
733 <<
"-byte long buffer.");
746 idx->equal_range(opt_type);
749 size_t num_defs = std::distance(range.first, range.second);
755 " option definitions for option type "
756 << opt_type <<
" returned. Currently it is"
757 " not supported to initialize multiple option"
758 " definitions for the same option code."
759 " This will be supported once support for"
760 " option spaces is implemented");
761 }
else if (num_defs == 1) {
766 opt = def->optionFactory(Option::V4, opt_type,
767 buf.begin() + offset,
768 buf.begin() + offset + opt_len);
774 buf.begin() + offset,
775 buf.begin() + offset + opt_len));
778 options.insert(std::make_pair(opt_type, opt));
793 for (OptionCollection::const_iterator it = options.begin();
794 it != options.end(); ++it) {
805 it->second->pack(buf);
824 for (OptionCollection::const_iterator it = options.begin();
825 it != options.end(); ++it) {
826 it->second->pack(buf);
832 Option::Factory* factory) {
835 if (v6factories_.find(opt_type) != v6factories_.end()) {
837 <<
"for option type " << opt_type);
839 v6factories_[opt_type]=factory;
852 if (opt_type > 254) {
855 if (v4factories_.find(opt_type)!=v4factories_.end()) {
857 <<
"for option type " << opt_type);
859 v4factories_[opt_type]=factory;
870 LibDHCP::initStdOptionDefs4() {
872 STANDARD_V4_OPTION_DEFINITIONS_SIZE);
876 LibDHCP::initStdOptionDefs6() {
878 STANDARD_V6_OPTION_DEFINITIONS_SIZE);
880 MAPE_V6_OPTION_DEFINITIONS_SIZE);
882 MAPT_V6_OPTION_DEFINITIONS_SIZE);
884 LW_V6_OPTION_DEFINITIONS_SIZE);
886 V4V6_RULE_OPTION_DEFINITIONS_SIZE);
888 V4V6_BIND_OPTION_DEFINITIONS_SIZE);
892 LibDHCP::initLastResortOptionDefs() {
894 LAST_RESORT_V4_OPTION_DEFINITIONS_SIZE);
898 LibDHCP::initVendorOptsDocsis4() {
904 LibDHCP::initVendorOptsDocsis6() {
910 LibDHCP::initVendorOptsIsc6() {
911 initOptionSpace(vendor6_defs_[ENTERPRISE_ID_ISC], ISC_V6_OPTION_DEFINITIONS,
912 ISC_V6_OPTION_DEFINITIONS_SIZE);
916 LibDHCP::optionSpaceToVendorId(
const std::string& option_space) {
918 if ((option_space.size() < 8) || (option_space.substr(0,7) !=
"vendor-")) {
925 std::string x = option_space.substr(7);
927 check = boost::lexical_cast<int64_t>(x);
929 }
catch (
const boost::bad_lexical_cast &) {
933 if ((check < 0) || (check > std::numeric_limits<uint32_t>::max())) {
938 return (
static_cast<uint32_t
>(check));
943 size_t params_size) {
954 for (
size_t i = 0; i < params_size; ++i) {
955 std::string encapsulates(params[i].encapsulates);
956 if (!encapsulates.empty() && params[i].
array) {
958 <<
"option with code '" << params[i].code
959 <<
"' may not encapsulate option space '"
960 << encapsulates <<
"' because the definition"
961 <<
" indicates that this option comprises an array"
969 if (encapsulates.empty()) {
980 params[i].encapsulates));
984 for (
size_t rec = 0; rec < params[i].
records_size; ++rec) {
985 definition->addRecordField(params[i].records[rec]);
989 definition->validate();
998 defs->push_back(definition);