]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3860] Added vendor VALUE in dicts
authorFrancis Dupont <fdupont@isc.org>
Fri, 22 Aug 2025 18:37:21 +0000 (20:37 +0200)
committerFrancis Dupont <fdupont@isc.org>
Fri, 12 Sep 2025 21:44:54 +0000 (23:44 +0200)
src/hooks/dhcp/radius/client_dictionary.cc
src/hooks/dhcp/radius/client_dictionary.h
src/hooks/dhcp/radius/tests/dictionary_unittests.cc

index 270611146043de7eeb5ba27a7987a64affdd6912..ab288ad0fb3d1af25e9556315adfe28ad45df707 100644 (file)
@@ -154,9 +154,10 @@ AttrDefs::getName(const uint8_t type, const uint32_t vendor) const {
 }
 
 IntCstDefPtr
-AttrDefs::getByName(const uint8_t type, const string& name) const {
+AttrDefs::getByName(const uint8_t type, const string& name,
+                    const uint32_t vendor) const {
     auto const& idx = ic_container_.get<0>();
-    auto it = idx.find(boost::make_tuple(type, name));
+    auto it = idx.find(boost::make_tuple(vendor, type, name));
     if (it != idx.end()) {
         return (*it);
     }
@@ -164,9 +165,10 @@ AttrDefs::getByName(const uint8_t type, const string& name) const {
 }
 
 IntCstDefPtr
-AttrDefs::getByValue(const uint8_t type, const uint32_t value) const {
+AttrDefs::getByValue(const uint8_t type, const uint32_t value,
+                     const uint32_t vendor) const {
     auto const& idx = ic_container_.get<1>();
-    auto it = idx.find(boost::make_tuple(type, value));
+    auto it = idx.find(boost::make_tuple(vendor, type, value));
     if (it != idx.end()) {
         return (*it);
     }
@@ -179,7 +181,7 @@ AttrDefs::add(IntCstDefPtr def) {
         return;
     }
     auto& idx = ic_container_.get<0>();
-    auto it = idx.find(boost::make_tuple(def->type_, def->name_));
+    auto it = idx.find(boost::make_tuple(def->vendor_, def->type_, def->name_));
     if (it != idx.end()) {
         if (def->value_ == (*it)->value_) {
             // Duplicate: ignore.
@@ -191,9 +193,15 @@ AttrDefs::add(IntCstDefPtr def) {
                       << def->name_ << "' value " << (*it)->value_
                       << " by " << def->value_);
         }
-        isc_throw(BadValue, "Illegal integer constant redefinition of '"
-                  << def->name_ << "' for attribute '" << getName(def->type_)
-                  << "' value " << (*it)->value_ << " by " << def->value_);
+        ostringstream msg;
+        msg << "Illegal integer constant redefinition of '"
+            << def->name_ << "' for attribute '"
+            << getName(def->type_, def->vendor_) << "'";
+        if (def->vendor_ != 0) {
+            msg << " in vendor " << def->vendor_;
+        }
+        msg << " value " << (*it)->value_ << " by " << def->value_;
+        isc_throw(BadValue, msg.str());
     }
     static_cast<void>(ic_container_.insert(def));
 }
@@ -254,21 +262,27 @@ AttrDefs::parseLine(const string& line, uint32_t& vendor, unsigned int depth) {
     }
     // Integer constant definition.
     if (tokens[0] == "VALUE") {
-        if (vendor != 0) {
-            // Ignore vendor constant definitions.
-            return;
-        }
         if (tokens.size() != 4) {
             isc_throw(Unexpected, "expected 4 tokens, got " << tokens.size());
         }
         const string& attr_str = tokens[1];
-        AttrDefPtr attr = getByName(attr_str/*, vendor*/);
+        AttrDefPtr attr = getByName(attr_str, vendor);
         if (!attr) {
-            isc_throw(Unexpected, "unknown attribute '" << attr_str << "'");
+            ostringstream msg;
+            msg << "unknown attribute '" << attr_str << "'";
+            if (vendor != 0) {
+                msg << " in vendor " << vendor;
+            }
+            isc_throw(Unexpected, msg.str());
         }
         if (attr->value_type_ != PW_TYPE_INTEGER) {
-            isc_throw(Unexpected, "attribute '" << attr_str
-                      << "' is not an integer attribute");
+            ostringstream msg;
+            msg << "attribute '" << attr_str << "'";
+            if (vendor != 0) {
+                msg << " in vendor " << vendor;
+            }
+            msg << " is not an integer attribute";
+            isc_throw(Unexpected, msg.str());
         }
         const string& name = tokens[2];
         const string& value_str = tokens[3];
@@ -283,7 +297,7 @@ AttrDefs::parseLine(const string& line, uint32_t& vendor, unsigned int depth) {
         } catch (...) {
             isc_throw(Unexpected, "can't parse integer value " << value_str);
         }
-        IntCstDefPtr def(new IntCstDef(attr->type_, name, value));
+        IntCstDefPtr def(new IntCstDef(attr->type_, name, value, vendor));
         add(def);
         return;
     }
index 854fef899073df14754660d3010308193a2c21ef..cec8986a26120edde64102310d61989cfb285dec 100644 (file)
@@ -118,9 +118,10 @@ public:
     /// @param type attribute type.
     /// @param name integer constant name.
     /// @param value integer constant value.
+    /// @param vendor vendor id (default 0).
     IntCstDef(const uint8_t type, const std::string& name,
-              const uint32_t value)
-        : type_(type), name_(name), value_(value) {
+              const uint32_t value, const uint32_t vendor = 0)
+        : type_(type), name_(name), value_(value), vendor_(vendor) {
     }
 
     /// @brief attribute type.
@@ -131,6 +132,9 @@ public:
 
     /// @brief value.
     const uint32_t value_;
+
+    /// @brief vendor id (default 0).
+    const uint32_t vendor_;
 };
 
 /// @brief Shared pointers to Integer constant definition.
@@ -200,10 +204,13 @@ public:
         IntCstDefPtr,
         // Start specification of indexes here.
         boost::multi_index::indexed_by<
-            // Hash index for by type and name.
+            // Hash index for by vendor, type and name.
             boost::multi_index::hashed_unique<
                 boost::multi_index::composite_key<
                     IntCstDef,
+                    boost::multi_index::member<
+                        IntCstDef, const uint32_t, &IntCstDef::vendor_
+                    >,
                     boost::multi_index::member<
                         IntCstDef, const uint8_t, &IntCstDef::type_
                     >,
@@ -212,10 +219,13 @@ public:
                     >
                 >
             >,
-            // Hash index for by type and value.
+            // Hash index for by vendor, type and value.
             boost::multi_index::hashed_unique<
                 boost::multi_index::composite_key<
                     IntCstDef,
+                    boost::multi_index::member<
+                        IntCstDef, const uint32_t, &IntCstDef::vendor_
+                    >,
                     boost::multi_index::member<
                         IntCstDef, const uint8_t, &IntCstDef::type_
                     >,
@@ -271,15 +281,19 @@ public:
     ///
     /// @param type attribute type.
     /// @param name name to look for.
+    /// @param vendor vendor id to look for (default 0).
     /// @return pointer to the integer constant definition or null.
-    IntCstDefPtr getByName(const uint8_t type, const std::string& name) const;
+    IntCstDefPtr getByName(const uint8_t type, const std::string& name,
+                           const uint32_t vendor = 0) const;
 
     /// @brief Get integer constant definition by attribute type and value.
     ///
     /// @param type attribute type.
     /// @param value value to look for.
+    /// @param vendor vendor id to look for (default 0).
     /// @return pointer to the integer constant definition or null.
-    IntCstDefPtr getByValue(const uint8_t type, const uint32_t value) const;
+    IntCstDefPtr getByValue(const uint8_t type, const uint32_t value,
+                            const uint32_t vendor = 0) const;
 
     /// @brief Add (or replace) an integer constant definition.
     ///
index 436a02722c20221804523206db57584cc60b0bac..b2cc58ec7a2ad81a834a1175d10e72e4bcce44a6 100644 (file)
@@ -144,6 +144,9 @@ TEST_F(DictionaryTest, parseLine) {
                      "expected 4 tokens, got 3 at line 1");
     EXPECT_THROW_MSG(parseLine("VALUE My-Attribute My-Value 1"), BadValue,
                      "unknown attribute 'My-Attribute' at line 1");
+    EXPECT_THROW_MSG(parseLine("VALUE My-Attribute My-Value 1", 99),
+                     BadValue,
+                     "unknown attribute 'My-Attribute' in vendor 99 at line 1");
 
     EXPECT_THROW_MSG(parseLine("$INCLUDE"), BadValue,
                      "expected 2 tokens, got 1 at line 1");
@@ -229,6 +232,18 @@ TEST_F(DictionaryTest, integerConstant) {
     expected += " at line 2";
     EXPECT_THROW_MSG(parseLines(not_integer_attr), BadValue, expected);
 
+    // Same with a vendor attribute.
+    list<string> not_integer_attrv = {
+        "VENDOR DSL-Forum 3561",
+        "BEGIN-VENDOR DSL-Forum",
+        "ATTRIBUTE Agent-Circuit-Id 1 string",
+        "VALUE  Agent-Circuit-Id My-Value 1",
+        "END-VENDOR DSL-Forum"
+    };
+    expected = "attribute 'Agent-Circuit-Id' in vendor 3561";
+    expected += " is not an integer attribute at line 4";
+    EXPECT_THROW_MSG(parseLines(not_integer_attrv), BadValue, expected);
+
     // Value must be an integer.
     list<string> not_integer_val = {
         "ATTRIBUTE Acct-Status-Type 40 integer",
@@ -262,6 +277,10 @@ TEST_F(DictionaryTest, integerConstant) {
     expected += "'Start' for attribute 'Acct-Status-Type' value 1 by 2";
     expected += " at line 3";
     EXPECT_THROW_MSG(parseLines(new_value), BadValue, expected);
+    expected = "Illegal integer constant redefinition of ";
+    expected += "'Start' for attribute 'Acct-Status-Type' in vendor 1234 ";
+    expected += "value 1 by 2 at line 3";
+    EXPECT_THROW_MSG(parseLines(new_value, 1234, 1234), BadValue, expected);
 }
 
 // Verifies vendor id definitions.