summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcp/option_vendor_class.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:15:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:15:43 +0000
commitf5f56e1a1c4d9e9496fcb9d81131066a964ccd23 (patch)
tree49e44c6f87febed37efb953ab5485aa49f6481a7 /src/lib/dhcp/option_vendor_class.cc
parentInitial commit. (diff)
downloadisc-kea-f5f56e1a1c4d9e9496fcb9d81131066a964ccd23.tar.xz
isc-kea-f5f56e1a1c4d9e9496fcb9d81131066a964ccd23.zip
Adding upstream version 2.4.1.upstream/2.4.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib/dhcp/option_vendor_class.cc')
-rw-r--r--src/lib/dhcp/option_vendor_class.cc202
1 files changed, 202 insertions, 0 deletions
diff --git a/src/lib/dhcp/option_vendor_class.cc b/src/lib/dhcp/option_vendor_class.cc
new file mode 100644
index 0000000..df4cf1c
--- /dev/null
+++ b/src/lib/dhcp/option_vendor_class.cc
@@ -0,0 +1,202 @@
+// Copyright (C) 2014-2023 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+#include <dhcp/opaque_data_tuple.h>
+#include <dhcp/option_vendor_class.h>
+#include <sstream>
+
+namespace isc {
+namespace dhcp {
+
+OptionVendorClass::OptionVendorClass(Option::Universe u,
+ const uint32_t vendor_id)
+ : Option(u, getOptionCode(u)), vendor_id_(vendor_id) {
+ if (u == Option::V4) {
+ addTuple(OpaqueDataTuple(OpaqueDataTuple::LENGTH_1_BYTE));
+ }
+}
+
+OptionVendorClass::OptionVendorClass(Option::Universe u,
+ OptionBufferConstIter begin,
+ OptionBufferConstIter end)
+ : Option(u, getOptionCode(u)) {
+ unpack(begin, end);
+}
+
+OptionPtr
+OptionVendorClass::clone() const {
+ return (cloneInternal<OptionVendorClass>());
+}
+
+void
+OptionVendorClass::pack(isc::util::OutputBuffer& buf, bool check) const {
+ packHeader(buf, check);
+
+ buf.writeUint32(getVendorId());
+
+ for (TuplesCollection::const_iterator it = tuples_.begin();
+ it != tuples_.end(); ++it) {
+ // For DHCPv4 V-I Vendor Class option, there is enterprise id before
+ // every tuple.
+ if ((getUniverse() == V4) && (it != tuples_.begin())) {
+ buf.writeUint32(getVendorId());
+ }
+ it->pack(buf);
+
+ }
+ // That's it. We don't pack any sub-options here, because this option
+ // must not contain sub-options.
+}
+
+void
+OptionVendorClass::unpack(OptionBufferConstIter begin,
+ OptionBufferConstIter end) {
+ if (std::distance(begin, end) < getMinimalLength() - getHeaderLen()) {
+ isc_throw(OutOfRange, "parsed Vendor Class option data truncated to"
+ " size " << std::distance(begin, end));
+ }
+ // Option must contain at least one enterprise id. It is ok to read 4-byte
+ // value here because we have checked that the buffer he minimal length.
+ vendor_id_ = isc::util::readUint32(&(*begin), distance(begin, end));
+ begin += sizeof(vendor_id_);
+
+ // Start reading opaque data.
+ size_t offset = 0;
+ while (offset < std::distance(begin, end)) {
+ // Parse a tuple.
+ OpaqueDataTuple tuple(OptionDataTypeUtil::getTupleLenFieldType(getUniverse()),
+ begin + offset, end);
+ addTuple(tuple);
+ // The tuple has been parsed correctly which implies that it is safe to
+ // advance the offset by its total length.
+ offset += tuple.getTotalLength();
+ // For DHCPv4 option, there is enterprise id before every opaque data
+ // tuple. Let's read it, unless we have already reached the end of
+ // buffer.
+ if ((getUniverse() == V4) && (begin + offset != end)) {
+ // Get the other enterprise id.
+ uint32_t other_id = isc::util::readUint32(&(*(begin + offset)),
+ distance(begin + offset,
+ end));
+ // Throw if there are two different enterprise ids.
+ if (other_id != vendor_id_) {
+ isc_throw(isc::BadValue, "V-I Vendor Class option with two "
+ "different enterprise ids: " << vendor_id_
+ << " and " << other_id);
+ }
+ // Advance the offset by the size of enterprise id.
+ offset += sizeof(vendor_id_);
+ // If the offset already ran over the buffer length or there is
+ // no space left for the empty tuple (thus we add 1), we have
+ // to signal the option truncation.
+ if (offset + 1 >= std::distance(begin, end)) {
+ isc_throw(isc::OutOfRange, "truncated DHCPv4 V-I Vendor Class"
+ " option - it should contain enterprise id followed"
+ " by opaque data field tuple");
+ }
+ }
+ }
+}
+
+void
+OptionVendorClass::addTuple(const OpaqueDataTuple& tuple) {
+ if (tuple.getLengthFieldType() != OptionDataTypeUtil::getTupleLenFieldType(getUniverse())) {
+ isc_throw(isc::BadValue, "attempted to add opaque data tuple having"
+ " invalid size of the length field "
+ << tuple.getDataFieldSize() << " to Vendor Class option");
+ }
+
+ tuples_.push_back(tuple);
+}
+
+
+void
+OptionVendorClass::setTuple(const size_t at, const OpaqueDataTuple& tuple) {
+ if (at >= getTuplesNum()) {
+ isc_throw(isc::OutOfRange, "attempted to set an opaque data for the"
+ " vendor option at position " << at << " which is out of"
+ " range");
+
+ } else if (tuple.getLengthFieldType() != OptionDataTypeUtil::getTupleLenFieldType(getUniverse())) {
+ isc_throw(isc::BadValue, "attempted to set opaque data tuple having"
+ " invalid size of the length field "
+ << tuple.getDataFieldSize() << " to Vendor Class option");
+ }
+
+ tuples_[at] = tuple;
+}
+
+OpaqueDataTuple
+OptionVendorClass::getTuple(const size_t at) const {
+ if (at >= getTuplesNum()) {
+ isc_throw(isc::OutOfRange, "attempted to get an opaque data for the"
+ " vendor option at position " << at << " which is out of"
+ " range. There are only " << getTuplesNum() << " tuples");
+ }
+ return (tuples_[at]);
+}
+
+bool
+OptionVendorClass::hasTuple(const std::string& tuple_str) const {
+ // Iterate over existing tuples (there shouldn't be many of them),
+ // and try to match the searched one.
+ for (TuplesCollection::const_iterator it = tuples_.begin();
+ it != tuples_.end(); ++it) {
+ if (*it == tuple_str) {
+ return (true);
+ }
+ }
+ return (false);
+}
+
+
+uint16_t
+OptionVendorClass::len() const {
+ // The option starts with the header and enterprise id.
+ uint16_t length = getHeaderLen() + sizeof(uint32_t);
+ // Now iterate over existing tuples and add their size.
+ for (TuplesCollection::const_iterator it = tuples_.begin();
+ it != tuples_.end(); ++it) {
+ // For DHCPv4 V-I Vendor Class option, there is enterprise id before
+ // every tuple.
+ if ((getUniverse() == V4) && (it != tuples_.begin())) {
+ length += sizeof(uint32_t);
+ }
+ length += it->getTotalLength();
+
+ }
+
+ return (length);
+}
+
+std::string
+OptionVendorClass::toText(int indent) const {
+ std::ostringstream s;
+
+ // Apply indentation
+ s << std::string(indent, ' ');
+ // Print type, length and first occurrence of enterprise id.
+ s << "type=" << getType() << ", len=" << len() - getHeaderLen() << ", "
+ " enterprise id=0x" << std::hex << getVendorId() << std::dec;
+ // Iterate over all tuples and print their size and contents.
+ for (unsigned i = 0; i < getTuplesNum(); ++i) {
+ // The DHCPv4 V-I Vendor Class has enterprise id before every tuple.
+ if ((getUniverse() == V4) && (i > 0)) {
+ s << ", enterprise id=0x" << std::hex << getVendorId() << std::dec;
+ }
+ // Print the tuple.
+ s << ", data-len" << i << "=" << getTuple(i).getLength();
+ s << ", vendor-class-data" << i << "='" << getTuple(i) << "'";
+ }
+
+ return (s.str());
+}
+
+} // namespace isc::dhcp
+} // namespace isc