Kea 3.2.0-git
libdhcp++.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2026 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <dhcp/dhcp4.h>
10#include <dhcp/dhcp6.h>
11#include <dhcp/libdhcp++.h>
12#include <dhcp/option.h>
13#include <dhcp/option_vendor.h>
14#include <dhcp/option6_ia.h>
15#include <dhcp/option6_iaaddr.h>
19#include <dhcp/option_custom.h>
24#include <util/buffer.h>
25#include <util/io.h>
26
27#include <boost/foreach.hpp>
28#include <boost/lexical_cast.hpp>
29#include <boost/shared_array.hpp>
30#include <boost/shared_ptr.hpp>
31
32#include <limits>
33#include <list>
34#include <unordered_map>
35#include <vector>
36
37using namespace std;
38using namespace isc::dhcp;
39using namespace isc::util;
40
41namespace isc {
42namespace dhcp {
43
44namespace {
45
49const OptionDefParamsEncapsulation OPTION_DEF_PARAMS[] = {
50 { STANDARD_V4_OPTION_DEFINITIONS, STANDARD_V4_OPTION_DEFINITIONS_SIZE, DHCP4_OPTION_SPACE },
51 { STANDARD_V6_OPTION_DEFINITIONS, STANDARD_V6_OPTION_DEFINITIONS_SIZE, DHCP6_OPTION_SPACE },
54 { ISC_V6_OPTION_DEFINITIONS, ISC_V6_OPTION_DEFINITIONS_SIZE, ISC_V6_OPTION_SPACE },
55 { MAPE_V6_OPTION_DEFINITIONS, MAPE_V6_OPTION_DEFINITIONS_SIZE, MAPE_V6_OPTION_SPACE },
56 { MAPT_V6_OPTION_DEFINITIONS, MAPT_V6_OPTION_DEFINITIONS_SIZE, MAPT_V6_OPTION_SPACE },
57 { LW_V6_OPTION_DEFINITIONS, LW_V6_OPTION_DEFINITIONS_SIZE, LW_V6_OPTION_SPACE },
58 { V4V6_RULE_OPTION_DEFINITIONS, V4V6_RULE_OPTION_DEFINITIONS_SIZE, V4V6_RULE_OPTION_SPACE },
59 { V4V6_BIND_OPTION_DEFINITIONS, V4V6_BIND_OPTION_DEFINITIONS_SIZE, V4V6_BIND_OPTION_SPACE },
60 { V6_NTP_SERVER_DEFINITIONS, V6_NTP_SERVER_DEFINITIONS_SIZE, V6_NTP_SERVER_SPACE },
61 { CABLELABS_CLIENT_CONF_DEFINITIONS, CABLELABS_CLIENT_CONF_DEFINITIONS_SIZE,
63 { LAST_RESORT_V4_OPTION_DEFINITIONS, LAST_RESORT_V4_OPTION_DEFINITIONS_SIZE, LAST_RESORT_V4_OPTION_SPACE },
64 { DHCP_AGENT_OPTION_DEFINITIONS, DHCP_AGENT_OPTION_DEFINITIONS_SIZE, DHCP_AGENT_OPTION_SPACE },
65 { NULL, 0, "" }
66};
67
68} // namespace
69
70} // namespace dhcp
71} // namespace isc
72
73// static array with factories for options
74map<unsigned short, Option::Factory*> LibDHCP::v4factories_;
75
76// static array with factories for options
77map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
78
79// Static container with option definitions grouped by option space.
80OptionDefContainers LibDHCP::option_defs_;
81
82// Static container with option definitions created in runtime.
83StagedValue<OptionDefSpaceContainer> LibDHCP::runtime_option_defs_;
84
85// Null container.
87
88// Those two vendor classes are used for cable modems:
89
91const char* isc::dhcp::DOCSIS3_CLASS_MODEM = "docsis3.0";
92
94const char* isc::dhcp::DOCSIS3_CLASS_EROUTER = "eRouter1.0";
95
96// Let's keep it in .cc file. Moving it to .h would require including optionDefParams
97// definitions there
99 const OptionDefParams* params,
100 size_t params_size);
101
102bool LibDHCP::initialized_ = LibDHCP::initOptionDefs();
103
105LibDHCP::getOptionDefs(const string& space) {
106 auto const& container = option_defs_.find(space);
107 if (container != option_defs_.end()) {
108 return (container->second);
109 }
110
112}
113
115LibDHCP::getVendorOptionDefs(const Option::Universe u, const uint32_t vendor_id) {
116 if (Option::V4 == u) {
117 if (VENDOR_ID_CABLE_LABS == vendor_id) {
119 }
120 } else if (Option::V6 == u) {
121 if (VENDOR_ID_CABLE_LABS == vendor_id) {
123 } else if (ENTERPRISE_ID_ISC == vendor_id) {
125 }
126 }
127
129}
130
132LibDHCP::getOptionDef(const string& space, const uint16_t code) {
133 const OptionDefContainerPtr& defs = getOptionDefs(space);
134 const OptionDefContainerTypeIndex& idx = defs->get<1>();
135 const OptionDefContainerTypeRange& range = idx.equal_range(code);
136 if (range.first != range.second) {
137 return (*range.first);
138 }
139
140 return (OptionDefinitionPtr());
141}
142
144LibDHCP::getOptionDef(const string& space, const string& name) {
145 const OptionDefContainerPtr& defs = getOptionDefs(space);
146 const OptionDefContainerNameIndex& idx = defs->get<2>();
147 const OptionDefContainerNameRange& range = idx.equal_range(name);
148 if (range.first != range.second) {
149 return (*range.first);
150 }
151
152 return (OptionDefinitionPtr());
153}
154
156LibDHCP::getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id,
157 const string& name) {
158 const OptionDefContainerPtr& defs = getVendorOptionDefs(u, vendor_id);
159
160 if (!defs) {
161 return (OptionDefinitionPtr());
162 }
163
164 const OptionDefContainerNameIndex& idx = defs->get<2>();
165 const OptionDefContainerNameRange& range = idx.equal_range(name);
166 if (range.first != range.second) {
167 return (*range.first);
168 }
169
170 return (OptionDefinitionPtr());
171}
172
174LibDHCP::getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id,
175 const uint16_t code) {
176 const OptionDefContainerPtr& defs = getVendorOptionDefs(u, vendor_id);
177
178 if (!defs) {
179 // Weird universe or unknown vendor_id. We don't care. No definitions
180 // one way or another
181 // What is it anyway?
182 return (OptionDefinitionPtr());
183 }
184
185 const OptionDefContainerTypeIndex& idx = defs->get<1>();
186 const OptionDefContainerTypeRange& range = idx.equal_range(code);
187 if (range.first != range.second) {
188 return (*range.first);
189 }
190
191 return (OptionDefinitionPtr());
192}
193
195LibDHCP::getRuntimeOptionDef(const string& space, const uint16_t code) {
196 OptionDefContainerPtr container = runtime_option_defs_.getValue().getItems(space);
197 const OptionDefContainerTypeIndex& index = container->get<1>();
198 const OptionDefContainerTypeRange& range = index.equal_range(code);
199 if (range.first != range.second) {
200 return (*range.first);
201 }
202
203 return (OptionDefinitionPtr());
204}
205
207LibDHCP::getRuntimeOptionDef(const string& space, const string& name) {
208 OptionDefContainerPtr container = runtime_option_defs_.getValue().getItems(space);
209 const OptionDefContainerNameIndex& index = container->get<2>();
210 const OptionDefContainerNameRange& range = index.equal_range(name);
211 if (range.first != range.second) {
212 return (*range.first);
213 }
214
215 return (OptionDefinitionPtr());
216}
217
219LibDHCP::getRuntimeOptionDefs(const string& space) {
220 return (runtime_option_defs_.getValue().getItems(space));
221}
222
223void
225 OptionDefSpaceContainer defs_copy;
226 list<string> option_space_names = defs.getOptionSpaceNames();
227 for (auto const& name : option_space_names) {
228 OptionDefContainerPtr container = defs.getItems(name);
229 for (auto const& def : *container) {
230 OptionDefinitionPtr def_copy(new OptionDefinition(*def));
231 defs_copy.addItem(def_copy);
232 }
233 }
234 runtime_option_defs_ = defs_copy;
235}
236
237void
239 runtime_option_defs_.reset();
240}
241
242void
244 runtime_option_defs_.revert();
245}
246
247void
249 runtime_option_defs_.commit();
250}
251
253LibDHCP::getLastResortOptionDef(const string& space, const uint16_t code) {
255 const OptionDefContainerTypeIndex& index = container->get<1>();
256 const OptionDefContainerTypeRange& range = index.equal_range(code);
257 if (range.first != range.second) {
258 return (*range.first);
259 }
260
261 return (OptionDefinitionPtr());
262}
263
265LibDHCP::getLastResortOptionDef(const string& space, const string& name) {
267 const OptionDefContainerNameIndex& index = container->get<2>();
268 const OptionDefContainerNameRange& range = index.equal_range(name);
269 if (range.first != range.second) {
270 return (*range.first);
271 }
272
273 return (OptionDefinitionPtr());
274}
275
278 if (space == DHCP4_OPTION_SPACE) {
280 }
281
283}
284
285bool
286LibDHCP::shouldDeferOptionUnpack(const string& space, const uint16_t code) {
287 return ((space == DHCP4_OPTION_SPACE) &&
289 ((code >= 224) && (code <= 254))));
290}
291
294 uint16_t type,
295 const OptionBuffer& buf) {
296 FactoryMap::iterator it;
297 if (u == Option::V4) {
298 it = v4factories_.find(type);
299 if (it == v4factories_.end()) {
300 isc_throw(BadValue, "factory function not registered "
301 "for DHCP v4 option type " << type);
302 }
303 } else if (u == Option::V6) {
304 it = v6factories_.find(type);
305 if (it == v6factories_.end()) {
306 isc_throw(BadValue, "factory function not registered "
307 "for DHCPv6 option type " << type);
308 }
309 } else {
310 isc_throw(BadValue, "invalid universe specified (expected "
311 "Option::V4 or Option::V6");
312 }
313 return (it->second(u, type, buf));
314}
315
316size_t
318
319size_t
320LibDHCP::unpackOptions6(const OptionBuffer& buf, const string& option_space,
321 OptionCollection& options,
322 size_t* relay_msg_offset /* = 0 */,
323 size_t* relay_msg_len /* = 0 */,
324 size_t rec_level /* = 0 */) {
325 ++rec_level;
326 if (rec_level >= MAX_RECURSION_LEVEL) {
327 isc_throw(isc::Unexpected, "Too deep recursion in unpacking options");
328 }
329 size_t offset = 0;
330 size_t length = buf.size();
331 size_t last_offset = 0;
332
333 // Get the list of standard option definitions.
334 const OptionDefContainerPtr& option_defs = LibDHCP::getOptionDefs(option_space);
335 // Runtime option definitions for non standard option space and if
336 // the definition doesn't exist within the standard option definitions.
337 const OptionDefContainerPtr& runtime_option_defs = LibDHCP::getRuntimeOptionDefs(option_space);
338
339 // @todo Once we implement other option spaces we should add else clause
340 // here and gather option definitions for them. For now leaving option_defs
341 // empty will imply creation of generic Option.
342
343 // Get the search indexes #1. It allows to search for option definitions
344 // using option code.
345 const OptionDefContainerTypeIndex& idx = option_defs->get<1>();
346 const OptionDefContainerTypeIndex& runtime_idx = runtime_option_defs->get<1>();
347
348 // The buffer being read comprises a set of options, each starting with
349 // a two-byte type code and a two-byte length field.
350 while (offset < length) {
351 // Save the current offset for backtracking
352 last_offset = offset;
353
354 // Check if there is room for another option
355 if (offset + 4 > length) {
356 // Still something but smaller than an option
357 return (last_offset);
358 }
359
360 // Parse the option header
361 uint16_t opt_type = readUint16(&buf[offset], 2);
362 offset += 2;
363
364 uint16_t opt_len = readUint16(&buf[offset], 2);
365 offset += 2;
366
367 if (offset + opt_len > length) {
368 // We peeked at the option header of the next option, but
369 // discovered that it would end up beyond buffer end, so
370 // the option is truncated. Hence we can't parse
371 // it. Therefore we revert back by those bytes (as if
372 // we never parsed them).
373 //
374 // @note it is the responsibility of the caller to throw
375 // an exception on partial parsing
376 return (last_offset);
377 }
378
379 if (opt_type == D6O_RELAY_MSG && relay_msg_offset && relay_msg_len) {
380 // remember offset of the beginning of the relay-msg option
381 *relay_msg_offset = offset;
382 *relay_msg_len = opt_len;
383
384 // do not create that relay-msg option
385 offset += opt_len;
386 continue;
387 }
388
389 if (opt_type == D6O_VENDOR_OPTS) {
390 if (offset + 4 > length) {
391 // Truncated vendor-option. We expect at least
392 // 4 bytes for the enterprise-id field. Let's roll back
393 // option code + option length (4 bytes) and return.
394 return (last_offset);
395 }
396
397 // Parse this as vendor option
398 OptionPtr vendor_opt(new OptionVendor(Option::V6, buf.begin() + offset,
399 buf.begin() + offset + opt_len));
400 options.insert(std::make_pair(opt_type, vendor_opt));
401
402 offset += opt_len;
403 continue;
404 }
405
406 // Get all definitions with the particular option code. Note
407 // that option code is non-unique within this container
408 // however at this point we expect to get one option
409 // definition with the particular code. If more are returned
410 // we report an error.
412 // Number of option definitions returned.
413 size_t num_defs = 0;
414
415 // We previously did the lookup only for dhcp6 option space, but with the
416 // addition of S46 options, we now do it for every space.
417 range = idx.equal_range(opt_type);
418 num_defs = std::distance(range.first, range.second);
419
420 // Standard option definitions do not include the definition for
421 // our option or we're searching for non-standard option. Try to
422 // find the definition among runtime option definitions.
423 if (num_defs == 0) {
424 range = runtime_idx.equal_range(opt_type);
425 num_defs = std::distance(range.first, range.second);
426 }
427
428 OptionPtr opt;
429 if (num_defs > 1) {
430 // Multiple options of the same code are not supported right now!
431 isc_throw(isc::Unexpected, "Internal error: multiple option"
432 " definitions for option type " << opt_type <<
433 " returned. Currently it is not supported to initialize"
434 " multiple option definitions for the same option code."
435 " This will be supported once support for option spaces"
436 " is implemented");
437 } else if (num_defs == 0) {
438 // @todo Don't crash if definition does not exist because
439 // only a few option definitions are initialized right
440 // now. In the future we will initialize definitions for
441 // all options and we will remove this elseif. For now,
442 // return generic option.
443 opt = OptionPtr(new Option(Option::V6, opt_type,
444 buf.begin() + offset,
445 buf.begin() + offset + opt_len));
446 } else {
447 try {
448 // The option definition has been found. Use it to create
449 // the option instance from the provided buffer chunk.
450 const OptionDefinitionPtr& def = *(range.first);
451 isc_throw_assert(def);
452 opt = def->optionFactory(Option::V6, opt_type,
453 buf.begin() + offset,
454 buf.begin() + offset + opt_len,
455 false, rec_level);
456 } catch (const SkipThisOptionError&) {
457 opt.reset();
458 } catch (const SkipRemainingOptionsError&) {
459 throw;
460 } catch (const std::exception& ex) {
461 isc_throw(OptionParseError, "opt_type: " << static_cast<uint16_t>(opt_type)
462 << ", opt_len " << static_cast<uint16_t>(opt_len)
463 << ", error: " << ex.what());
464 }
465 }
466
467 // add option to options
468 if (opt) {
469 options.insert(std::make_pair(opt_type, opt));
470 }
471
472 offset += opt_len;
473 }
474
475 last_offset = offset;
476 return (last_offset);
477}
478
479size_t
480LibDHCP::unpackOptions4(const OptionBuffer& buf, const string& option_space,
481 OptionCollection& options, list<uint16_t>& deferred,
482 bool check) {
483 size_t offset = 0;
484 size_t last_offset = 0;
485
486 // Special case when option_space is dhcp4.
487 bool space_is_dhcp4 = (option_space == DHCP4_OPTION_SPACE);
488
489 // Get the list of standard option definitions.
490 const OptionDefContainerPtr& option_defs = LibDHCP::getOptionDefs(option_space);
491 // Runtime option definitions for non standard option space and if
492 // the definition doesn't exist within the standard option definitions.
493 const OptionDefContainerPtr& runtime_option_defs = LibDHCP::getRuntimeOptionDefs(option_space);
494
495 // Get the search indexes #1. It allows to search for option definitions
496 // using option code.
497 const OptionDefContainerTypeIndex& idx = option_defs->get<1>();
498 const OptionDefContainerTypeIndex& runtime_idx = runtime_option_defs->get<1>();
499
500 // Flexible PAD and END parsing.
501 bool flex_pad = (check && (runtime_idx.count(DHO_PAD) == 0));
502 bool flex_end = (check && (runtime_idx.count(DHO_END) == 0));
503
504 // The buffer being read comprises a set of options, each starting with
505 // a one-byte type code and a one-byte length field.
506
507 // Track seen options in a first pass.
508 vector<uint32_t> count(256, 0);
509 while (offset < buf.size()) {
510 // Get the option type
511 uint8_t opt_type = buf[offset++];
512
513 // DHO_END is a special, one octet long option
514 // Valid in dhcp4 space or when check is true and
515 // there is a sub-option configured for this code.
516 if ((opt_type == DHO_END) && (space_is_dhcp4 || flex_end)) {
517 // Done.
518 break;
519 }
520
521 // DHO_PAD is just a padding after DHO_END. Let's continue parsing
522 // in case we receive a message without DHO_END.
523 // Valid in dhcp4 space or when check is true and
524 // there is a sub-option configured for this code.
525 if ((opt_type == DHO_PAD) && (space_is_dhcp4 || flex_pad)) {
526 continue;
527 }
528
529 if (offset + 1 > buf.size()) {
530 // Error case.
531 break;
532 }
533
534 uint8_t opt_len = buf[offset++];
535 if (offset + opt_len > buf.size()) {
536 // Error case.
537 break;
538 }
539
540 // See below for this special case.
541 if (space_is_dhcp4 && opt_len == 0 && opt_type == DHO_HOST_NAME) {
542 continue;
543 }
544
545 offset += opt_len;
546
547 // Increment count.
548 count[opt_type] += 1;
549 }
550
551 // Fusing option buffers.
552 unordered_map<uint8_t, pair<OptionBuffer, uint32_t>> fused;
553
554 // Second pass.
555 offset = 0;
556 while (offset < buf.size()) {
557 // Save the current offset for backtracking
558 last_offset = offset;
559
560 // Get the option type
561 uint8_t opt_type = buf[offset++];
562
563 // DHO_END is a special, one octet long option
564 // Valid in dhcp4 space or when check is true and
565 // there is a sub-option configured for this code.
566 if ((opt_type == DHO_END) && (space_is_dhcp4 || flex_end)) {
567 // just return. Don't need to add DHO_END option
568 // Don't return offset because it makes this condition
569 // and partial parsing impossible to recognize.
570 return (last_offset);
571 }
572
573 // DHO_PAD is just a padding after DHO_END. Let's continue parsing
574 // in case we receive a message without DHO_END.
575 // Valid in dhcp4 space or when check is true and
576 // there is a sub-option configured for this code.
577 if ((opt_type == DHO_PAD) && (space_is_dhcp4 || flex_pad)) {
578 continue;
579 }
580
581 if (offset + 1 > buf.size()) {
582 // We peeked at the option header of the next option, but
583 // discovered that it would end up beyond buffer end, so
584 // the option is truncated. Hence we can't parse
585 // it. Therefore we revert back (as if we never parsed it).
586 //
587 // @note it is the responsibility of the caller to throw
588 // an exception on partial parsing
589 return (last_offset);
590 }
591
592 uint8_t opt_len = buf[offset++];
593 if (offset + opt_len > buf.size()) {
594 // We peeked at the option header of the next option, but
595 // discovered that it would end up beyond buffer end, so
596 // the option is truncated. Hence we can't parse
597 // it. Therefore we revert back (as if we never parsed it).
598 return (last_offset);
599 }
600
601 // While an empty Host Name option is non-RFC compliant, some clients
602 // do send it. In the spirit of being liberal, we'll just drop it,
603 // rather than the dropping the whole packet. We do not have a
604 // way to log this from here but meh... a PCAP will show it arriving,
605 // and we know we drop it.
606 if (space_is_dhcp4 && opt_len == 0 && opt_type == DHO_HOST_NAME) {
607 continue;
608 }
609
610 OptionBuffer obuf(buf.begin() + offset, buf.begin() + offset + opt_len);
611 offset += opt_len;
612
613 // Concatenate multiple instance of an option.
614 uint32_t opt_count = count[opt_type];
615 if (opt_count > 1) {
616 OptionBuffer& previous = fused[opt_type].first;
617 previous.insert(previous.end(), obuf.begin(), obuf.end());
618 uint32_t& already_seen = fused[opt_type].second;
619 ++already_seen;
620 if (already_seen != opt_count) {
621 continue;
622 } else {
623 // last occurrence: build the option.
624 obuf = previous;
625 }
626 }
627
628 // Get all definitions with the particular option code. Note
629 // that option code is non-unique within this container
630 // however at this point we expect to get one option
631 // definition with the particular code. If more are returned
632 // we report an error.
634 // Number of option definitions returned.
635 size_t num_defs = 0;
636
637 // Previously we did the lookup only for "dhcp4" option space, but there
638 // may be standard options in other spaces (e.g. radius). So we now do
639 // the lookup for every space.
640 range = idx.equal_range(opt_type);
641 num_defs = std::distance(range.first, range.second);
642
643 // Standard option definitions do not include the definition for
644 // our option or we're searching for non-standard option. Try to
645 // find the definition among runtime option definitions.
646 if (num_defs == 0) {
647 range = runtime_idx.equal_range(opt_type);
648 num_defs = std::distance(range.first, range.second);
649 }
650
651 // Check if option unpacking must be deferred
652 if (shouldDeferOptionUnpack(option_space, opt_type)) {
653 num_defs = 0;
654 // Store deferred option only once.
655 bool found = false;
656 for (auto const& existing : deferred) {
657 if (existing == opt_type) {
658 found = true;
659 break;
660 }
661 }
662 if (!found) {
663 deferred.push_back(opt_type);
664 }
665 }
666
667 if (space_is_dhcp4 &&
668 (opt_type == DHO_VIVSO_SUBOPTIONS ||
669 opt_type == DHO_VIVCO_SUBOPTIONS)) {
670 num_defs = 0;
671 }
672
673 OptionPtr opt;
674 if (num_defs > 1) {
675 // Multiple options of the same code are not supported right now!
676 isc_throw(isc::Unexpected, "Internal error: multiple option"
677 " definitions for option type " <<
678 static_cast<int>(opt_type) <<
679 " returned. Currently it is not supported to initialize"
680 " multiple option definitions for the same option code."
681 " This will be supported once support for option spaces"
682 " is implemented");
683 } else if (num_defs == 0) {
684 opt = OptionPtr(new Option(Option::V4, opt_type, obuf));
685 } else {
686 try {
687 // The option definition has been found. Use it to create
688 // the option instance from the provided buffer chunk.
689 const OptionDefinitionPtr& def = *(range.first);
690 isc_throw_assert(def);
691 opt = def->optionFactory(Option::V4, opt_type, obuf);
692 } catch (const SkipThisOptionError&) {
693 opt.reset();
694 } catch (const SkipRemainingOptionsError&) {
695 throw;
696 } catch (const std::exception& ex) {
697 isc_throw(OptionParseError, "opt_type: " << static_cast<uint16_t>(opt_type)
698 << ", opt_len: " << static_cast<uint16_t>(opt_len)
699 << ", error: " << ex.what());
700 }
701 }
702
703 // If we have the option, insert it
704 if (opt) {
705 options.insert(std::make_pair(opt_type, opt));
706 }
707 }
708 last_offset = offset;
709 return (last_offset);
710}
711
712namespace { // Anonymous namespace.
713
714// VIVCO part of extendVendorOptions4.
715
716void
717extendVivco(OptionCollection& options) {
718 typedef vector<OpaqueDataTuple> TuplesCollection;
719 map<uint32_t, TuplesCollection> vendors_tuples;
720 auto const& range = options.equal_range(DHO_VIVCO_SUBOPTIONS);
721 BOOST_FOREACH(auto const& it, range) {
722 uint32_t offset = 0;
723 auto const& data = it.second->getData();
724 size_t size;
725 while ((size = data.size() - offset) != 0) {
726 if (size < sizeof(uint32_t)) {
727 options.erase(DHO_VIVCO_SUBOPTIONS);
729 "Truncated vendor-class information option"
730 << ", length=" << size);
731 }
732 uint32_t vendor_id = readUint32(&data[offset], data.size());
733 offset += 4;
734 try {
735 // From OptionVendorClass::unpack.
737 data.begin() + offset, data.end());
738 vendors_tuples[vendor_id].push_back(tuple);
739 offset += tuple.getTotalLength();
740 } catch (const OpaqueDataTupleError&) {
741 // Ignore this kind of error and continue.
742 break;
743 } catch (const isc::Exception&) {
744 options.erase(DHO_VIVCO_SUBOPTIONS);
745 throw;
746 }
747 }
748 }
749 if (vendors_tuples.empty()) {
750 return;
751 }
752 // Delete the initial option.
753 options.erase(DHO_VIVCO_SUBOPTIONS);
754 // Create a new instance of OptionVendor for each enterprise ID.
755 for (auto const& vendor : vendors_tuples) {
756 if (vendor.second.empty()) {
757 continue;
758 }
760 vendor.first));
761 for (size_t i = 0; i < vendor.second.size(); ++i) {
762 if (i == 0) {
763 vendor_opt->setTuple(0, vendor.second[0]);
764 } else {
765 vendor_opt->addTuple(vendor.second[i]);
766 }
767 }
768 // Add the new instance of VendorOption with respective sub-options for
769 // this enterprise ID.
770 options.insert(std::make_pair(DHO_VIVCO_SUBOPTIONS, vendor_opt));
771 }
772}
773
774// VIVSO part of extendVendorOptions4.
775
776void
777extendVivso(OptionCollection& options) {
778 map<uint32_t, OptionCollection> vendors_data;
779 auto const& range = options.equal_range(DHO_VIVSO_SUBOPTIONS);
780 BOOST_FOREACH(auto const& it, range) {
781 uint32_t offset = 0;
782 auto const& data = it.second->getData();
783 size_t size;
784 while ((size = data.size() - offset) != 0) {
785 if (size < sizeof(uint32_t)) {
786 options.erase(DHO_VIVSO_SUBOPTIONS);
788 "Truncated vendor-specific information option"
789 << ", length=" << size);
790 }
791 uint32_t vendor_id = readUint32(&data[offset], data.size());
792 offset += 4;
793 const OptionBuffer vendor_buffer(data.begin() + offset, data.end());
794 try {
795 offset += LibDHCP::unpackVendorOptions4(vendor_id, vendor_buffer,
796 vendors_data[vendor_id]);
797 } catch (const SkipThisOptionError&) {
798 // Ignore this kind of error and continue.
799 break;
800 } catch (const isc::Exception&) {
801 options.erase(DHO_VIVSO_SUBOPTIONS);
802 throw;
803 }
804 }
805 }
806 if (vendors_data.empty()) {
807 return;
808 }
809 // Delete the initial option.
810 options.erase(DHO_VIVSO_SUBOPTIONS);
811 // Create a new instance of OptionVendor for each enterprise ID.
812 for (auto const& vendor : vendors_data) {
813 OptionVendorPtr vendor_opt(new OptionVendor(Option::V4, vendor.first));
814 for (auto const& option : vendor.second) {
815 vendor_opt->addOption(option.second);
816 }
817 // Add the new instance of VendorOption with respective sub-options for
818 // this enterprise ID.
819 options.insert(std::make_pair(DHO_VIVSO_SUBOPTIONS, vendor_opt));
820 }
821}
822
823} // end of anonymous namespace.
824
825void
827 extendVivco(options);
828 extendVivso(options);
829}
830
831size_t
832LibDHCP::unpackVendorOptions6(const uint32_t vendor_id, const OptionBuffer& buf,
833 OptionCollection& options) {
834 size_t offset = 0;
835 size_t length = buf.size();
836
837 // Get the list of option definitions for this particular vendor-id
838 const OptionDefContainerPtr& option_defs =
840
841 // Get the search index #1. It allows to search for option definitions
842 // using option code. If there's no such vendor-id space, we're out of luck
843 // anyway.
844 const OptionDefContainerTypeIndex* idx = NULL;
845 if (option_defs) {
846 idx = &(option_defs->get<1>());
847 }
848
849 // The buffer being read comprises a set of options, each starting with
850 // a two-byte type code and a two-byte length field.
851 while (offset < length) {
852 if (offset + 4 > length) {
854 "Vendor option parse failed: truncated header");
855 }
856
857 uint16_t opt_type = readUint16(&buf[offset], 2);
858 offset += 2;
859
860 uint16_t opt_len = readUint16(&buf[offset], 2);
861 offset += 2;
862
863 if (offset + opt_len > length) {
865 "Vendor option parse failed. Tried to parse "
866 << offset + opt_len << " bytes from " << length
867 << "-byte long buffer.");
868 }
869
870 OptionPtr opt;
871 opt.reset();
872
873 // If there is a definition for such a vendor option...
874 if (idx) {
875 // Get all definitions with the particular option
876 // code. Note that option code is non-unique within this
877 // container however at this point we expect to get one
878 // option definition with the particular code. If more are
879 // returned we report an error.
880 const OptionDefContainerTypeRange& range =
881 idx->equal_range(opt_type);
882 // Get the number of returned option definitions for the
883 // option code.
884 size_t num_defs = std::distance(range.first, range.second);
885
886 if (num_defs > 1) {
887 // Multiple options of the same code are not supported
888 // right now!
889 isc_throw(isc::Unexpected, "Internal error: multiple option"
890 " definitions for option type " << opt_type <<
891 " returned. Currently it is not supported to"
892 " initialize multiple option definitions for the"
893 " same option code. This will be supported once"
894 " support for option spaces is implemented");
895 } else if (num_defs == 1) {
896 // The option definition has been found. Use it to create
897 // the option instance from the provided buffer chunk.
898 const OptionDefinitionPtr& def = *(range.first);
899 isc_throw_assert(def);
900 opt = def->optionFactory(Option::V6, opt_type,
901 buf.begin() + offset,
902 buf.begin() + offset + opt_len);
903 }
904 }
905
906 // This can happen in one of 2 cases:
907 // 1. we do not have definitions for that vendor-space
908 // 2. we do have definitions, but that particular option was
909 // not defined
910
911 if (!opt) {
912 opt = OptionPtr(new Option(Option::V6, opt_type,
913 buf.begin() + offset,
914 buf.begin() + offset + opt_len));
915 }
916
917 // add option to options
918 if (opt) {
919 options.insert(std::make_pair(opt_type, opt));
920 }
921 offset += opt_len;
922 }
923
924 return (offset);
925}
926
927size_t
928LibDHCP::unpackVendorOptions4(const uint32_t vendor_id, const OptionBuffer& buf,
929 OptionCollection& options) {
930 size_t offset = 0;
931
932 // Get the list of standard option definitions.
933 const OptionDefContainerPtr& option_defs =
935 // Get the search index #1. It allows to search for option definitions
936 // using option code.
937 const OptionDefContainerTypeIndex* idx = NULL;
938 if (option_defs) {
939 idx = &(option_defs->get<1>());
940 }
941
942 // The buffer being read comprises a set of options, each starting with
943 // a one-byte type code and a one-byte length field.
944 while (offset < buf.size()) {
945 // Note that Vendor-Specific info option (RFC3925) has a
946 // different option format than Vendor-Spec info for
947 // DHCPv6. (there's additional layer of data-length)
948 uint8_t data_len = buf[offset++];
949
950 if (offset + data_len > buf.size()) {
951 // The option is truncated.
953 "Attempt to parse truncated vendor option");
954 }
955
956 uint8_t offset_end = offset + data_len;
957
958 // beginning of data-chunk parser
959 while (offset < offset_end) {
960 uint8_t opt_type = buf[offset++];
961
962 // No DHO_END or DHO_PAD in vendor options
963
964 if (offset + 1 > offset_end) {
965 // opt_type must be cast to integer so as it is not
966 // treated as unsigned char value (a number is
967 // presented in error message).
969 "Attempt to parse truncated vendor option "
970 << static_cast<int>(opt_type));
971 }
972
973 uint8_t opt_len = buf[offset++];
974 if (offset + opt_len > offset_end) {
976 "Option parse failed. Tried to parse "
977 << offset + opt_len << " bytes from " << buf.size()
978 << "-byte long buffer.");
979 }
980
981 OptionPtr opt;
982 opt.reset();
983
984 if (idx) {
985 // Get all definitions with the particular option
986 // code. Note that option code is non-unique within
987 // this container however at this point we expect to
988 // get one option definition with the particular
989 // code. If more are returned we report an error.
990 const OptionDefContainerTypeRange& range =
991 idx->equal_range(opt_type);
992 // Get the number of returned option definitions for
993 // the option code.
994 size_t num_defs = std::distance(range.first, range.second);
995
996 if (num_defs > 1) {
997 // Multiple options of the same code are not
998 // supported right now!
999 isc_throw(isc::Unexpected, "Internal error: multiple"
1000 " option definitions for option type "
1001 << opt_type << " returned. Currently it is"
1002 " not supported to initialize multiple option"
1003 " definitions for the same option code."
1004 " This will be supported once support for"
1005 " option spaces is implemented");
1006 } else if (num_defs == 1) {
1007 // The option definition has been found. Use it to create
1008 // the option instance from the provided buffer chunk.
1009 const OptionDefinitionPtr& def = *(range.first);
1010 isc_throw_assert(def);
1011 opt = def->optionFactory(Option::V4, opt_type,
1012 buf.begin() + offset,
1013 buf.begin() + offset + opt_len);
1014 }
1015 }
1016
1017 if (!opt) {
1018 opt = OptionPtr(new Option(Option::V4, opt_type,
1019 buf.begin() + offset,
1020 buf.begin() + offset + opt_len));
1021 }
1022
1023 options.insert(std::make_pair(opt_type, opt));
1024 offset += opt_len;
1025
1026 } // end of data-chunk
1027
1028 break; // end of the vendor block.
1029 }
1030 return (offset);
1031}
1032
1033void
1035 bool top, bool check) {
1036 OptionCollection agent;
1037 OptionPtr end;
1038
1039 // We only look for type when we're the top level
1040 // call that starts packing for options for a packet.
1041 // This way we avoid doing type logic in all ensuing
1042 // recursive calls.
1043 if (top) {
1044 auto x = options.find(DHO_DHCP_MESSAGE_TYPE);
1045 if (x != options.end()) {
1046 x->second->pack(buf, check);
1047 }
1048 }
1049
1050 for (auto const& option : options) {
1051 // TYPE is already done, RAI and END options must be last.
1052 switch (option.first) {
1054 break;
1056 agent.insert(make_pair(DHO_DHCP_AGENT_OPTIONS, option.second));
1057 break;
1058 case DHO_END:
1059 end = option.second;
1060 break;
1061 default:
1062 option.second->pack(buf, check);
1063 break;
1064 }
1065 }
1066
1067 // Add the RAI option if it exists.
1068 for (auto const& option : agent) {
1069 option.second->pack(buf, check);
1070 }
1071
1072 // And at the end the END option.
1073 if (end) {
1074 end->pack(buf, check);
1075 }
1076}
1077
1078bool
1080 ScopedOptionsCopyContainer& scoped_options,
1081 uint32_t used) {
1082 bool result = false;
1083 // We need to loop until all options have been split.
1084 uint32_t tries = 0;
1085 for (;; tries++) {
1086 // Let's not do this forever if there is a bug hiding here somewhere...
1087 // 65535 times should be enough for any packet load...
1088 if (tries == std::numeric_limits<uint16_t>::max()) {
1089 isc_throw(Unexpected, "packet split failed after trying "
1090 << tries << " times.");
1091 }
1092 bool found = false;
1093 // Make a copy of the options so we can safely iterate over the
1094 // old container.
1095 OptionCollection copy = options;
1096 // Iterate over all options in the container.
1097 for (auto const& option : options) {
1098 OptionPtr candidate = option.second;
1099 OptionCollection& sub_options = candidate->getMutableOptions();
1100 // Split suboptions recursively, if any.
1101 OptionCollection distinct_options;
1102 bool updated = false;
1103 bool found_suboptions = false;
1104 // There are 3 cases when the total size is larger than (255 - used):
1105 // 1. option has no suboptions and has large data
1106 // 2. option has large suboptions and has no data
1107 // 3. option has both options and suboptions:
1108 // 3.1. suboptions are large and data is large
1109 // 3.2. suboptions are large and data is small
1110 // 3.3. suboptions are small and data is large
1111 // 3.4. suboptions are small and data is small but combined they are large
1112 // All other combinations reside in total size smaller than (255 - used):
1113 // 4. no split of any suboption or data:
1114 // 4.1 option has no suboptions and has small data
1115 // 4.2 option has small suboptions and has no data
1116 // 4.3 option has both small suboptions and small data
1117 // 4.4 option has no suboptions and has no data
1118 if (sub_options.size()) {
1119 // The 2. and 3. and 4.2 and 4.3 cases are handled here (the suboptions part).
1120 ScopedOptionsCopyPtr candidate_scoped_options(new ScopedSubOptionsCopy(candidate));
1121 found_suboptions = LibDHCP::splitOptions4(sub_options, scoped_options,
1122 used + candidate->getHeaderLen());
1123 // There are 3 cases here:
1124 // 2. option has large suboptions and has no data
1125 // 3. option has both options and suboptions:
1126 // 3.1. suboptions are large and data is large so there is suboption splitting
1127 // and found_suboptions is true
1128 // 3.2. suboptions are large and data is small so there is suboption splitting
1129 // and found_suboptions is true
1130 // 3.3. suboptions are small and data is large so there is no suboption splitting
1131 // and found_suboptions is false
1132 // 3.4. suboptions are small and data is small so there is no suboption splitting
1133 // and found_suboptions is false but combined they are large
1134 // 4. no split of any suboption or data
1135 // Also split if the overflow is caused by adding the suboptions
1136 // to the option data.
1137 if (found_suboptions || candidate->len() > (255 - used)) {
1138 // The 2. and 3. cases are handled here (the suboptions part).
1139 updated = true;
1140 scoped_options.push_back(candidate_scoped_options);
1141 // Erase the old options from the new container so that only
1142 // the new options are present.
1143 copy.erase(option.first);
1144 result = true;
1145 // If there are suboptions which have been split, one parent
1146 // option will be created for each of the chunk of the
1147 // suboptions. If the suboptions have not been split,
1148 // but they cause overflow when added to the option data,
1149 // one parent option will contain the option data and one
1150 // parent option will be created for each suboption.
1151 // This will guarantee that none of the options plus
1152 // suboptions will have more than 255 bytes.
1153 for (auto const& sub_option : candidate->getMutableOptions()) {
1154 OptionPtr data_sub_option(new Option(candidate->getUniverse(),
1155 candidate->getType(),
1156 OptionBuffer(0)));
1157 data_sub_option->addOption(sub_option.second);
1158 distinct_options.insert(make_pair(candidate->getType(), data_sub_option));
1159 }
1160 }
1161 }
1162 // The 1. and 3. and 4. cases are handled here (the data part).
1163 // Create a new option containing only data that needs to be split
1164 // and no suboptions (which are inserted in completely separate
1165 // options which are added at the end).
1166 OptionPtr data_option(new Option(candidate->getUniverse(),
1167 candidate->getType(),
1168 OptionBuffer(candidate->getData().begin(),
1169 candidate->getData().end())));
1170 OutputBuffer buf(0);
1171 data_option->pack(buf, false);
1172 uint32_t header_len = candidate->getHeaderLen();
1173 // At least 1 + header length bytes must be available.
1174 if (used >= 255 - header_len) {
1175 isc_throw(BadValue, "there is no space left to split option "
1176 << candidate->getType() << " after parent already used "
1177 << used);
1178 }
1179 // Maximum option buffer size is 255 - header size - buffer size
1180 // already used by parent options.
1181 uint8_t len = 255 - header_len - used;
1182 // Current option size after split is the sum of the data and the
1183 // header size. The suboptions are serialized in separate options.
1184 // The header is duplicated in all new options, but the rest of the
1185 // data must be split and serialized.
1186 uint32_t size = buf.getLength() - header_len;
1187 // Only split if data does not fit in the current option.
1188 // There are 3 cases here:
1189 // 1. option has no suboptions and has large data
1190 // 3. option has both options and suboptions:
1191 // 3.1. suboptions are large and data is large
1192 // 3.2. suboptions are large and data is small
1193 // 3.3. suboptions are small and data is large
1194 // 3.4. suboptions are small and data is small but combined they are large
1195 // 4. no split of any suboption or data
1196 if (size > len) {
1197 // The 1. and 3.1. and 3.3 cases are handled here (the data part).
1198 // Erase the old option from the new container so that only new
1199 // options are present.
1200 if (!updated) {
1201 updated = true;
1202 // Erase the old options from the new container so that only
1203 // the new options are present.
1204 copy.erase(option.first);
1205 result = true;
1206 }
1207 uint32_t offset = 0;
1208 // Drain the option buffer in multiple new options until all
1209 // data is serialized.
1210 for (; offset != size;) {
1211 // Adjust the data length of the new option if remaining
1212 // data is less than the 255 - header size (for the last
1213 // option).
1214 if (size - offset < len) {
1215 len = size - offset;
1216 }
1217 // Create new option with data starting from offset and
1218 // containing truncated length.
1219 const uint8_t* data = buf.getData();
1220 data += header_len;
1221 OptionPtr new_option(new Option(candidate->getUniverse(),
1222 candidate->getType(),
1223 OptionBuffer(data + offset,
1224 data + offset + len)));
1225 // Adjust the offset for remaining data to be written to the
1226 // next new option.
1227 offset += len;
1228 // Add the new option to the new container.
1229 copy.insert(make_pair(candidate->getType(), new_option));
1230 }
1231 } else if ((candidate->len() > (255 - used)) && size) {
1232 // The 3.2 and 3.4 cases are handled here (the data part).
1233 // Also split if the overflow is caused by adding the suboptions
1234 // to the option data (which should be of non zero size).
1235 // Add the new option to the new container.
1236 copy.insert(make_pair(candidate->getType(), data_option));
1237 }
1238 if (updated) {
1239 // Add the new options containing the split suboptions, if any,
1240 // to the new container.
1241 copy.insert(distinct_options.begin(), distinct_options.end());
1242 // After all new options have been split and added, update the
1243 // option container with the new container.
1244 options = copy;
1245 // Other options might need splitting, so we need to iterate
1246 // again until no option needs splitting.
1247 found = true;
1248 break;
1249 }
1250 }
1251 // No option needs splitting, so we can exit the loop.
1252 if (!found) {
1253 break;
1254 }
1255 }
1256 return (result);
1257}
1258
1259void
1261 for (auto const& option : options) {
1262 option.second->pack(buf);
1263 }
1264}
1265
1266void
1268 pair<OptionCollection::const_iterator, OptionCollection::const_iterator>
1269 range = options.equal_range(D6O_NTP_SERVER);
1270 if (range.first == range.second) {
1271 return;
1272 }
1273 auto const& ntp_servers = OptionCollection(range.first, range.second);
1274 static_cast<void>(options.erase(range.first, range.second));
1275 auto const& def = D6O_NTP_SERVER_DEF();
1276 for (auto const& opt : ntp_servers) {
1277 for (auto const& sub : opt.second->getOptions()) {
1278 auto new_option(new OptionCustom(def, Option::V6));
1279 new_option->addOption(sub.second);
1280 options.insert(make_pair(D6O_NTP_SERVER, new_option));
1281 }
1282 }
1283}
1284
1285void
1287 Option::Factory* factory) {
1288 switch (u) {
1289 case Option::V6:
1290 {
1291 if (v6factories_.find(opt_type) != v6factories_.end()) {
1292 isc_throw(BadValue, "There is already DHCPv6 factory registered "
1293 << "for option type " << opt_type);
1294 }
1295 v6factories_[opt_type] = factory;
1296 return;
1297 }
1298 case Option::V4:
1299 {
1300 // Option 0 is special (a one octet-long, equal 0) PAD option. It is never
1301 // instantiated as an Option object, but rather consumed during packet parsing.
1302 if (opt_type == 0) {
1303 isc_throw(BadValue, "Cannot redefine PAD option (code=0)");
1304 }
1305 // Option 255 is never instantiated as an option object. It is special
1306 // (a one-octet equal 255) option that is added at the end of all options
1307 // during packet assembly. It is also silently consumed during packet parsing.
1308 if (opt_type > 254) {
1309 isc_throw(BadValue, "Too big option type for DHCPv4, only 0-254 allowed.");
1310 }
1311 if (v4factories_.find(opt_type) != v4factories_.end()) {
1312 isc_throw(BadValue, "There is already DHCPv4 factory registered "
1313 << "for option type " << opt_type);
1314 }
1315 v4factories_[opt_type] = factory;
1316 return;
1317 }
1318 default:
1319 isc_throw(BadValue, "Invalid universe type specified.");
1320 }
1321
1322 return;
1323}
1324
1325bool
1326LibDHCP::initOptionDefs() {
1327 for (uint32_t i = 0; OPTION_DEF_PARAMS[i].optionDefParams; ++i) {
1328 string space = OPTION_DEF_PARAMS[i].space;
1329 option_defs_[space] = OptionDefContainerPtr(new OptionDefContainer());
1330 initOptionSpace(option_defs_[space],
1331 OPTION_DEF_PARAMS[i].optionDefParams,
1332 OPTION_DEF_PARAMS[i].size);
1333 }
1334
1335 static_cast<void>(LibDHCP::DHO_DHCP_REQUESTED_ADDRESS_DEF());
1336 static_cast<void>(LibDHCP::DHO_DHCP_SERVER_IDENTIFIER_DEF());
1337 static_cast<void>(LibDHCP::DHO_DHCP_AGENT_OPTIONS_DEF());
1338 static_cast<void>(LibDHCP::DHO_SUBNET_SELECTION_DEF());
1339 static_cast<void>(LibDHCP::DHO_DOMAIN_SEARCH_DEF());
1340 static_cast<void>(LibDHCP::DHO_STATUS_CODE_DEF());
1341 static_cast<void>(LibDHCP::D6O_CLIENT_FQDN_DEF());
1342 static_cast<void>(LibDHCP::D6O_LQ_QUERY_DEF());
1343 static_cast<void>(LibDHCP::D6O_CLIENT_DATA_DEF());
1344 static_cast<void>(LibDHCP::D6O_LQ_RELAY_DATA_DEF());
1345 static_cast<void>(LibDHCP::D6O_NTP_SERVER_DEF());
1346 static_cast<void>(LibDHCP::D6O_BOOTFILE_URL_DEF());
1347 static_cast<void>(LibDHCP::D6O_RSOO_DEF());
1348 static_cast<void>(LibDHCP::D6O_IAADDR_DEF());
1349
1350 return (true);
1351}
1352
1353uint32_t
1354LibDHCP::optionSpaceToVendorId(const string& option_space) {
1355 // 8 is a minimal length of "vendor-X" format
1356 if ((option_space.size() < 8) || (option_space.substr(0,7) != "vendor-")) {
1357 return (0);
1358 }
1359
1360 int64_t check;
1361 try {
1362 // text after "vendor-", supposedly numbers only
1363 string x = option_space.substr(7);
1364
1365 check = boost::lexical_cast<int64_t>(x);
1366 } catch (const boost::bad_lexical_cast &) {
1367 return (0);
1368 }
1369
1370 if ((check < 0) || (check > std::numeric_limits<uint32_t>::max())) {
1371 return (0);
1372 }
1373
1374 // value is small enough to fit
1375 return (static_cast<uint32_t>(check));
1376}
1377
1378void
1380 size_t params_size) {
1381 // Container holding vendor options is typically not initialized, as it
1382 // is held in map of null pointers. We need to initialize here in this
1383 // case.
1384 if (!defs) {
1385 defs.reset(new OptionDefContainer());
1386 } else {
1387 defs->clear();
1388 }
1389
1390 for (size_t i = 0; i < params_size; ++i) {
1391 string encapsulates(params[i].encapsulates);
1392 if (!encapsulates.empty() && params[i].array) {
1393 isc_throw(isc::BadValue, "invalid standard option definition: "
1394 << "option with code '" << params[i].code
1395 << "' may not encapsulate option space '"
1396 << encapsulates << "' because the definition"
1397 << " indicates that this option comprises an array"
1398 << " of values");
1399 }
1400
1401 // Depending whether an option encapsulates an option space or not
1402 // we pick different constructor to create an instance of the option
1403 // definition.
1404 OptionDefinitionPtr definition;
1405 if (encapsulates.empty()) {
1406 // Option does not encapsulate any option space.
1407 definition.reset(new OptionDefinition(params[i].name,
1408 params[i].code,
1409 params[i].space,
1410 params[i].type,
1411 params[i].array));
1412 } else {
1413 // Option does encapsulate an option space.
1414 definition.reset(new OptionDefinition(params[i].name,
1415 params[i].code,
1416 params[i].space,
1417 params[i].type,
1418 params[i].encapsulates));
1419
1420 }
1421
1422 for (size_t rec = 0; rec < params[i].records_size; ++rec) {
1423 definition->addRecordField(params[i].records[rec]);
1424 }
1425
1426 try {
1427 definition->validate();
1428 } catch (const isc::Exception&) {
1429 // This is unlikely event that validation fails and may
1430 // be only caused by programming error. To guarantee the
1431 // data consistency we clear all option definitions that
1432 // have been added so far and pass the exception forward.
1433 defs->clear();
1434 throw;
1435 }
1436
1437 // option_defs is a multi-index container with no unique indexes
1438 // so push_back can't fail).
1439 static_cast<void>(defs->push_back(definition));
1440 }
1441}
1442
1443const OptionDefinition&
1445 static OptionDefinitionPtr def =
1447 static bool check_once(true);
1448 if (check_once) {
1449 isc_throw_assert(def);
1450 isc_throw_assert(def->getName() == "dhcp-requested-address");
1452 isc_throw_assert(def->getType() == OPT_IPV4_ADDRESS_TYPE);
1453 isc_throw_assert(!def->getArrayType());
1454 isc_throw_assert(def->getEncapsulatedSpace().empty());
1455 isc_throw_assert(def->getOptionSpaceName() == DHCP4_OPTION_SPACE);
1456 check_once = false;
1457 }
1458 return (*def);
1459}
1460
1461const OptionDefinition&
1463 static OptionDefinitionPtr def =
1465 static bool check_once(true);
1466 if (check_once) {
1467 isc_throw_assert(def);
1468 isc_throw_assert(def->getName() == "dhcp-server-identifier");
1470 isc_throw_assert(def->getType() == OPT_IPV4_ADDRESS_TYPE);
1471 isc_throw_assert(!def->getArrayType());
1472 isc_throw_assert(def->getEncapsulatedSpace().empty());
1473 isc_throw_assert(def->getOptionSpaceName() == DHCP4_OPTION_SPACE);
1474 check_once = false;
1475 }
1476 return (*def);
1477}
1478
1479const OptionDefinition&
1481 static OptionDefinitionPtr def =
1483 static bool check_once(true);
1484 if (check_once) {
1485 isc_throw_assert(def);
1486 isc_throw_assert(def->getName() == "dhcp-agent-options");
1487 isc_throw_assert(def->getCode() == DHO_DHCP_AGENT_OPTIONS);
1488 isc_throw_assert(def->getType() == OPT_EMPTY_TYPE);
1489 isc_throw_assert(!def->getArrayType());
1490 isc_throw_assert(def->getEncapsulatedSpace() == DHCP_AGENT_OPTION_SPACE);
1491 isc_throw_assert(def->getOptionSpaceName() == DHCP4_OPTION_SPACE);
1492 check_once = false;
1493 }
1494 return (*def);
1495}
1496
1497const OptionDefinition&
1499 static OptionDefinitionPtr def =
1501 static bool check_once(true);
1502 if (check_once) {
1503 isc_throw_assert(def);
1504 isc_throw_assert(def->getName() == "subnet-selection");
1505 isc_throw_assert(def->getCode() == DHO_SUBNET_SELECTION);
1506 isc_throw_assert(def->getType() == OPT_IPV4_ADDRESS_TYPE);
1507 isc_throw_assert(!def->getArrayType());
1508 isc_throw_assert(def->getEncapsulatedSpace().empty());
1509 isc_throw_assert(def->getOptionSpaceName() == DHCP4_OPTION_SPACE);
1510 check_once = false;
1511 }
1512 return (*def);
1513}
1514
1515const OptionDefinition&
1517 static OptionDefinitionPtr def =
1519 static bool check_once(true);
1520 if (check_once) {
1521 isc_throw_assert(def);
1522 isc_throw_assert(def->getName() == "domain-search");
1523 isc_throw_assert(def->getCode() == DHO_DOMAIN_SEARCH);
1524 isc_throw_assert(def->getType() == OPT_FQDN_TYPE);
1525 isc_throw_assert(def->getArrayType());
1526 isc_throw_assert(def->getEncapsulatedSpace().empty());
1527 isc_throw_assert(def->getOptionSpaceName() == DHCP4_OPTION_SPACE);
1528 check_once = false;
1529 }
1530 return (*def);
1531}
1532
1533const OptionDefinition&
1535 static OptionDefinitionPtr def =
1537 static bool check_once(true);
1538 if (check_once) {
1539 isc_throw_assert(def);
1540 isc_throw_assert(def->getName() == "status-code");
1541 isc_throw_assert(def->getCode() == DHO_STATUS_CODE);
1542 isc_throw_assert(def->getType() == OPT_RECORD_TYPE);
1543 isc_throw_assert(!def->getArrayType());
1544 isc_throw_assert(def->getEncapsulatedSpace().empty());
1545 isc_throw_assert(def->getOptionSpaceName() == DHCP4_OPTION_SPACE);
1546 check_once = false;
1547 }
1548 return (*def);
1549}
1550
1551const OptionDefinition&
1553 static OptionDefinitionPtr def =
1555 static bool check_once(true);
1556 if (check_once) {
1557 isc_throw_assert(def);
1558 isc_throw_assert(def->getName() == "client-fqdn");
1559 isc_throw_assert(def->getCode() == D6O_CLIENT_FQDN);
1560 isc_throw_assert(def->getType() == OPT_RECORD_TYPE);
1561 isc_throw_assert(!def->getArrayType());
1562 isc_throw_assert(def->getEncapsulatedSpace().empty());
1563 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1564 check_once = false;
1565 }
1566 return (*def);
1567}
1568
1569const OptionDefinition&
1571 static OptionDefinitionPtr def =
1573 static bool check_once(true);
1574 if (check_once) {
1575 isc_throw_assert(def);
1576 isc_throw_assert(def->getName() == "lq-query");
1577 isc_throw_assert(def->getCode() == D6O_LQ_QUERY);
1578 isc_throw_assert(def->getType() == OPT_RECORD_TYPE);
1579 isc_throw_assert(!def->getArrayType());
1580 isc_throw_assert(def->getEncapsulatedSpace() == DHCP6_OPTION_SPACE);
1581 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1582 check_once = false;
1583 }
1584 return (*def);
1585}
1586
1587const OptionDefinition&
1589 static OptionDefinitionPtr def =
1591 static bool check_once(true);
1592 if (check_once) {
1593 isc_throw_assert(def);
1594 isc_throw_assert(def->getName() == "client-data");
1595 isc_throw_assert(def->getCode() == D6O_CLIENT_DATA);
1596 isc_throw_assert(def->getType() == OPT_EMPTY_TYPE);
1597 isc_throw_assert(!def->getArrayType());
1598 isc_throw_assert(def->getEncapsulatedSpace() == DHCP6_OPTION_SPACE);
1599 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1600 check_once = false;
1601 }
1602 return (*def);
1603}
1604
1605const OptionDefinition&
1607 static OptionDefinitionPtr def =
1609 static bool check_once(true);
1610 if (check_once) {
1611 isc_throw_assert(def);
1612 isc_throw_assert(def->getName() == "lq-relay-data");
1613 isc_throw_assert(def->getCode() == D6O_LQ_RELAY_DATA);
1614 isc_throw_assert(def->getType() == OPT_RECORD_TYPE);
1615 isc_throw_assert(!def->getArrayType());
1616 isc_throw_assert(def->getEncapsulatedSpace().empty());
1617 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1618 check_once = false;
1619 }
1620 return (*def);
1621}
1622
1623const OptionDefinition&
1625 static OptionDefinitionPtr def =
1627 static bool check_once(true);
1628 if (check_once) {
1629 isc_throw_assert(def);
1630 isc_throw_assert(def->getName() == "ntp-server");
1631 isc_throw_assert(def->getCode() == D6O_NTP_SERVER);
1632 isc_throw_assert(def->getType() == OPT_EMPTY_TYPE);
1633 isc_throw_assert(!def->getArrayType());
1634 isc_throw_assert(def->getEncapsulatedSpace() == V6_NTP_SERVER_SPACE);
1635 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1636 check_once = false;
1637 }
1638 return (*def);
1639}
1640
1641const OptionDefinition&
1643 static OptionDefinitionPtr def =
1645 static bool check_once(true);
1646 if (check_once) {
1647 isc_throw_assert(def);
1648 isc_throw_assert(def->getName() == "bootfile-url");
1649 isc_throw_assert(def->getCode() == D6O_BOOTFILE_URL);
1650 isc_throw_assert(def->getType() == OPT_STRING_TYPE);
1651 isc_throw_assert(!def->getArrayType());
1652 isc_throw_assert(def->getEncapsulatedSpace().empty());
1653 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1654 check_once = false;
1655 }
1656 return (*def);
1657}
1658
1659const OptionDefinition&
1661 static OptionDefinitionPtr def =
1663 static bool check_once(true);
1664 if (check_once) {
1665 isc_throw_assert(def);
1666 isc_throw_assert(def->getName() == "rsoo");
1667 isc_throw_assert(def->getCode() == D6O_RSOO);
1668 isc_throw_assert(def->getType() == OPT_EMPTY_TYPE);
1669 isc_throw_assert(!def->getArrayType());
1670 isc_throw_assert(def->getEncapsulatedSpace() == "rsoo-opts");
1671 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1672 check_once = false;
1673 }
1674 return (*def);
1675}
1676
1677const OptionDefinition&
1679 static OptionDefinitionPtr def =
1681 static bool check_once(true);
1682 if (check_once) {
1683 isc_throw_assert(def);
1684 isc_throw_assert(def->getName() == "iaaddr");
1685 isc_throw_assert(def->getCode() == D6O_IAADDR);
1686 isc_throw_assert(def->getType() == OPT_RECORD_TYPE);
1687 isc_throw_assert(!def->getArrayType());
1688 isc_throw_assert(def->getEncapsulatedSpace().empty());
1689 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1690 check_once = false;
1691 }
1692 return (*def);
1693}
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.
Definition libdhcp++.cc:480
static void OptionFactoryRegister(Option::Universe u, uint16_t type, Option::Factory *factory)
Registers factory method that produces options of specific option types.
static const OptionDefinition & D6O_LQ_RELAY_DATA_DEF()
Get definition of D6O_LQ_RELAY_DATA option.
static const OptionDefinition & D6O_NTP_SERVER_DEF()
Get definition of D6O_NTP_SERVER option.
static const OptionDefinition & D6O_RSOO_DEF()
Get definition of D6O_RSOO option.
static size_t MAX_RECURSION_LEVEL
Maximum level of recursion unpacking options.
Definition libdhcp++.h:480
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.
Definition libdhcp++.cc:832
static const OptionDefContainerPtr getOptionDefs(const std::string &space)
Returns collection of option definitions.
Definition libdhcp++.cc:105
static void splitNtpServerOptions6(isc::dhcp::OptionCollection &options)
Split NTP server option to one suboption per instance.
static bool shouldDeferOptionUnpack(const std::string &space, const uint16_t code)
Checks if an option unpacking has to be deferred.
Definition libdhcp++.cc:286
static isc::dhcp::OptionPtr optionFactory(isc::dhcp::Option::Universe u, uint16_t type, const OptionBuffer &buf)
Factory function to create instance of option.
Definition libdhcp++.cc:293
static void setRuntimeOptionDefs(const OptionDefSpaceContainer &defs)
Copies option definitions created at runtime.
Definition libdhcp++.cc:224
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition libdhcp++.cc:132
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.
Definition libdhcp++.cc:174
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, size_t rec_level=0)
Parses provided buffer as DHCPv6 options and creates Option objects.
Definition libdhcp++.cc:320
static OptionDefContainerPtr getLastResortOptionDefs(const std::string &space)
Returns last resort option definitions for specified option space name.
Definition libdhcp++.cc:277
static const OptionDefinition & D6O_LQ_QUERY_DEF()
Get definition of D6O_LQ_QUERY option.
static OptionDefContainerPtr getRuntimeOptionDefs(const std::string &space)
Returns runtime (non-standard) option definitions for specified option space name.
Definition libdhcp++.cc:219
static void commitRuntimeOptionDefs()
Commits runtime option definitions.
Definition libdhcp++.cc:248
static void clearRuntimeOptionDefs()
Removes runtime option definitions.
Definition libdhcp++.cc:238
static const OptionDefinition & D6O_IAADDR_DEF()
Get definition of D6O_IAADDR option.
static void extendVendorOptions4(isc::dhcp::OptionCollection &options)
Extend vendor options from fused options in multiple OptionVendor or OptionVendorClass options and ad...
Definition libdhcp++.cc:826
static const OptionDefinition & D6O_CLIENT_DATA_DEF()
Get definition of D6O_CLIENT_DATA option.
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 const OptionDefinition & DHO_DHCP_REQUESTED_ADDRESS_DEF()
Get definition of DHO_DHCP_REQUESTED_ADDRESS option.
static const OptionDefinition & D6O_BOOTFILE_URL_DEF()
Get definition of D6O_BOOTFILE_URL option.
static const OptionDefinition & DHO_DHCP_SERVER_IDENTIFIER_DEF()
Get definition of DHO_DHCP_SERVER_IDENTIFIER option.
static const OptionDefinition & DHO_SUBNET_SELECTION_DEF()
Get definition of DHO_SUBNET_SELECTION option.
static void revertRuntimeOptionDefs()
Reverts uncommitted changes to runtime option definitions.
Definition libdhcp++.cc:243
static const OptionDefinition & DHO_DOMAIN_SEARCH_DEF()
Get definition of DHO_DOMAIN_SEARCH option.
static const OptionDefContainerPtr getVendorOptionDefs(Option::Universe u, const uint32_t vendor_id)
Returns option definitions for given universe and vendor.
Definition libdhcp++.cc:115
static const OptionDefinition & D6O_CLIENT_FQDN_DEF()
Get definition of D6O_CLIENT_FQDN option.
static const OptionDefinition & DHO_DHCP_AGENT_OPTIONS_DEF()
Get definition of DHO_DHCP_AGENT_OPTIONS option.
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.
Definition libdhcp++.cc:195
static void packOptions6(isc::util::OutputBuffer &buf, const isc::dhcp::OptionCollection &options)
Stores DHCPv6 options in a buffer.
static const OptionDefinition & DHO_STATUS_CODE_DEF()
Get definition of DHO_STATUS_CODE option.
static OptionDefinitionPtr getLastResortOptionDef(const std::string &space, const uint16_t code)
Returns last resort option definition by space and option code.
Definition libdhcp++.cc:253
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.
Definition libdhcp++.cc:928
Exception to be thrown when the operation on OpaqueDataTuple object results in an error.
Represents a single instance of the opaque data preceded by length.
Option with defined data fields represented as buffers that can be accessed using data field index.
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.
Wrapper exception thrown by unpackOptionsX functions to add option type and len to the underlying err...
Definition option.h:75
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 encapsulates DHCPv6 Vendor Class and DHCPv4 V-I Vendor Class options.
This class represents vendor-specific information option.
Universe
defines option universe DHCPv4 or DHCPv6
Definition option.h:90
OptionPtr Factory(Option::Universe u, uint16_t type, const OptionBuffer &buf)
a factory function prototype
Definition option.h:103
RAII object enabling duplication of the stored options and restoring the original options on destruct...
Definition pkt.h:1013
Exception thrown during option unpacking This exception is thrown when an error has occurred,...
Definition option.h:52
Exception thrown during option unpacking This exception is thrown when an error has occurred unpackin...
Definition option.h:67
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition buffer.h:346
const uint8_t * getData() const
Return a pointer to the head of the data stored in the buffer.
Definition buffer.h:398
size_t getLength() const
Return the length of data written in the buffer.
Definition buffer.h:412
This class implements set/commit mechanism for a single object.
@ D6O_CLIENT_FQDN
Definition dhcp6.h:59
@ D6O_RSOO
Definition dhcp6.h:86
@ D6O_RELAY_MSG
Definition dhcp6.h:29
@ D6O_VENDOR_OPTS
Definition dhcp6.h:37
@ D6O_BOOTFILE_URL
Definition dhcp6.h:79
@ D6O_LQ_QUERY
Definition dhcp6.h:64
@ D6O_IAADDR
Definition dhcp6.h:25
@ D6O_CLIENT_DATA
Definition dhcp6.h:65
@ D6O_LQ_RELAY_DATA
Definition dhcp6.h:67
@ D6O_NTP_SERVER
Definition dhcp6.h:76
#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.
Definition isc_assert.h:18
void initOptionSpace(OptionDefContainerPtr &defs, const OptionDefParams *params, size_t params_size)
const OptionDefContainerPtr null_option_def_container_(new OptionDefContainer())
ElementPtr copy(ConstElementPtr from, unsigned level)
Copy the data up to a nesting level.
Definition data.cc:1522
boost::shared_ptr< OptionVendor > OptionVendorPtr
Pointer to a vendor option.
@ DHO_DHCP_MESSAGE_TYPE
Definition dhcp4.h:122
@ DHO_DHCP_SERVER_IDENTIFIER
Definition dhcp4.h:123
@ DHO_HOST_NAME
Definition dhcp4.h:81
@ DHO_VIVCO_SUBOPTIONS
Definition dhcp4.h:188
@ DHO_DHCP_REQUESTED_ADDRESS
Definition dhcp4.h:119
@ DHO_END
Definition dhcp4.h:229
@ DHO_PAD
Definition dhcp4.h:69
@ DHO_DHCP_AGENT_OPTIONS
Definition dhcp4.h:151
@ DHO_VENDOR_ENCAPSULATED_OPTIONS
Definition dhcp4.h:112
@ DHO_SUBNET_SELECTION
Definition dhcp4.h:182
@ DHO_DOMAIN_SEARCH
Definition dhcp4.h:183
@ DHO_VIVSO_SUBOPTIONS
Definition dhcp4.h:189
@ DHO_STATUS_CODE
Definition dhcp4.h:205
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
Definition option.h:40
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.
Definition libdhcp++.cc:94
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.
Definition libdhcp++.cc:91
boost::shared_ptr< OptionVendorClass > OptionVendorClassPtr
Defines a pointer to the OptionVendorClass.
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.
Definition libdhcp++.h:30
OptionDefContainer::nth_index< 2 >::type OptionDefContainerNameIndex
Type of the index #2 - option name.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition option.h:24
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
Definition option.h:37
std::vector< ScopedOptionsCopyPtr > ScopedOptionsCopyContainer
A container of ScopedOptionsCopyPtr objects.
Definition libdhcp++.h:32
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(void const *const buffer, size_t const length)
uint16_t wrapper over readUint.
Definition io.h:76
uint32_t readUint32(void const *const buffer, size_t const length)
uint32_t wrapper over readUint.
Definition io.h:82
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 V6_NTP_SERVER_SPACE
#define V4V6_RULE_OPTION_SPACE
#define MAPE_V6_OPTION_SPACE
#define DHCP_AGENT_OPTION_SPACE
encapsulated option spaces
#define LW_V6_OPTION_SPACE
#define DHCP6_OPTION_SPACE
#define MAPT_V6_OPTION_SPACE
#define CABLELABS_CLIENT_CONF_SPACE
Encapsulation of option definition parameters and the structure size.
Parameters being used to make up an option definition.