]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Rename BEGIN-TLV and END-TLV to BEGIN and END, and make them work for TLVs too
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 28 Nov 2024 23:17:16 +0000 (17:17 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 28 Nov 2024 23:17:16 +0000 (17:17 -0600)
17 files changed:
doc/antora/modules/reference/nav.adoc
doc/antora/modules/reference/pages/dictionary/begin-protocol.adoc
doc/antora/modules/reference/pages/dictionary/begin.adoc [moved from doc/antora/modules/reference/pages/dictionary/begin-tlv.adoc with 52% similarity]
doc/antora/modules/reference/pages/dictionary/end-tlv.adoc [deleted file]
doc/antora/modules/reference/pages/dictionary/end.adoc [new file with mode: 0644]
doc/antora/modules/reference/pages/dictionary/index.adoc
man/man5/dictionary.5
share/dictionary/eap/aka-sim/dictionary.rfc4187
share/dictionary/freeradius/dictionary.freeradius.internal
share/dictionary/freeradius/dictionary.freeradius.internal.ippool
share/dictionary/freeradius/dictionary.freeradius.internal.password
share/dictionary/ldap/dictionary.freeradius.internal
share/dictionary/snmp/dictionary.freeradius
src/lib/util/dict.h
src/lib/util/dict_fixup.c
src/lib/util/dict_fixup_priv.h
src/lib/util/dict_tokenize.c

index 865bc07afe0367193f4277fdfce1a1bdaa58aeb5..0c64019fd70cb8ea3e78c5fced31d77a4966f1cd 100644 (file)
 *** xref:dictionary/vendor.adoc[VENDOR]
 *** xref:dictionary/begin-protocol.adoc[BEGIN-PROTOCOL]
 *** xref:dictionary/end-protocol.adoc[END-PROTOCOL]
-*** xref:dictionary/begin-tlv.adoc[BEGIN-TLV]
-*** xref:dictionary/end-tlv.adoc[END-TLV]
+*** xref:dictionary/begin.adoc[BEGIN]
+*** xref:dictionary/end.adoc[END]
 *** xref:dictionary/begin-vendor.adoc[BEGIN-VENDOR]
 *** xref:dictionary/end-vendor.adoc[END-VENDOR]
 
index f7f063ee9e5c34a7837ded7b71140bfc5e27618a..8593e4e89e9115718ab9c05a5597308dfaae08bd 100644 (file)
@@ -25,7 +25,7 @@ END-PROTOCOL RADIUS
 ----
 
 Note that unlike xref:dictionary/begin-vendor.adoc[END-VENDOR] and
-xref:dictionary/begin-tlv.adoc[END-TLV], it is not possible to omit
+xref:dictionary/begin.adoc[END], it is not possible to omit
 the `BEGIN-PROTOCOL` keyword.
 
 // Copyright (C) 2023 Network RADIUS SAS.  Licenced under CC-by-NC 4.0.
similarity index 52%
rename from doc/antora/modules/reference/pages/dictionary/begin-tlv.adoc
rename to doc/antora/modules/reference/pages/dictionary/begin.adoc
index 87937bbd012704fb15eac06800689f29f08aa0fa..e2e250f01d23d9da4e20b4f23f3c156f154d66cd 100644 (file)
@@ -1,40 +1,40 @@
-= The BEGIN-TLV keyword
+= The BEGIN keyword
 
 .Syntax
 ----
-BEGIN-TLV <name>
+BEGIN <name>
 ----
 
 .Description
 
-The `BEGIN-TLV` keyword starts a "nested" set of
-xref:dictionary/attribute.adoc[ATTRIBUTE] definitions wwhich are all
-for a particular parent attribute of type `tlv`.
+The `BEGIN` keyword starts a "nested" set of
+xref:dictionary/attribute.adoc[ATTRIBUTE] definitions which are all
+for a particular parent attribute of type `tlv` or `struct`.
 
 <name>:: The name of the parent attribute.
 +
-The tlv must have previously been created in anref:dictionary/attribute.adoc[ATTRIBUTE] definition.
+The tlv or struct must have previously been created in anref:dictionary/attribute.adoc[ATTRIBUTE] definition.
 
-The `BEGIN-TLV` keyword must always be paired with a matching xref:dictionary/end-tlv.adoc[END-TLV] keyword.
+The `BEGIN` keyword must always be paired with a matching xref:dictionary/end.adoc[END] keyword.
 
-Within the context of a ``BEGIN-TLV` block, the numbers for each
+Within the context of a ``BEGIN` block, the numbers for each
 xref:dictionary/attribute.adoc[ATTRIBUTE] definition are relative to
-the parent TLV.
+the parent tlv or struct.
 
 .Example
 ----
 ATTRIBUTE Foo 2 tlv
-BEGIN-TLV Foo
+BEGIN Foo
 ATTRIBUTE Bar 1 string
-END-TLV Foo
+END Foo
 ----
 
 This example defines an attribute `Foo.Bar`, with OID `2.1`.
 
 == Purpose
 
-The `BEGIN-TLV` keyword exists for efficiency.  It is not strictly
-needed, but without a `BEGIN-TLV` keyword, every
+The `BEGIN` keyword exists for efficiency.  It is not strictly
+needed, but without a `BEGIN` keyword, every
 xref:dictionary/attribute.adoc[ATTRIBUTE] name would need to contain
 the parent attribute name, as in the following
 example.
@@ -46,19 +46,19 @@ ATTRIBUTE Foo.bar 2.1 string
 
 == Nesting
 
-It is possible to nest multiple `BEGIN-TLV` keywords, so long as each
-one is paired with a matching xref:dictionary/end-tlv.adoc[END-TLV] keyword.
+It is possible to nest multiple `BEGIN` keywords, so long as each
+one is paired with a matching xref:dictionary/end.adoc[END] keyword.
 
-.Example of nested BEGIN-TLV
+.Example of nested BEGIN
 ----
 ATTRIBUTE Foo 2 tlv
-BEGIN-TLV Foo
+BEGIN Foo
 ATTRIBUTE Bar 1 string
 ATTRIBUTE Baz 2 tlv
-BEGIN-TLV Baz
+BEGIN Baz
 ATTRIBUTE Such 4 ipaddr
-END-TLV Baz
-END-TLV Foo
+END Baz
+END Foo
 ----
 
 The above example is equivalent to the example below.
@@ -73,7 +73,7 @@ ATTRIBUTE Such .2.4 ipaddr
 
 For short entries, it can be simpler to use the full name an OID.
 However, for complex dictionaries, it is almost always clearer to use
-`BEGIN-TLV` and xref:dictionary/end-tlv.adoc[END-TLV].
+`BEGIN` and xref:dictionary/end.adoc[END].
 
 // Copyright (C) 2023 Network RADIUS SAS.  Licenced under CC-by-NC 4.0.
 // This documentation was developed by Network RADIUS SAS.
diff --git a/doc/antora/modules/reference/pages/dictionary/end-tlv.adoc b/doc/antora/modules/reference/pages/dictionary/end-tlv.adoc
deleted file mode 100644 (file)
index da6eac5..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-= The END-TLV keyword
-
-.Syntax
-----
-END-TLV <name>
-----
-
-.Description
-
-The `END-TLV` keyword finished a "nested" set of
-xref:dictionary/attribute.adoc[ATTRIBUTE] definitions which are all
-for a particular `tlv` parent attribute.
-
-<name>:: The name of the xref:dictionary/attribute.adoc[ATTRIBUTE]
-+
-The dictionary must have previously contained a matching
-xref:dictionary/begin-tlv.adoc[BEGIN-TLV].
-
-// Copyright (C) 2023 Network RADIUS SAS.  Licenced under CC-by-NC 4.0.
-// This documentation was developed by Network RADIUS SAS.
diff --git a/doc/antora/modules/reference/pages/dictionary/end.adoc b/doc/antora/modules/reference/pages/dictionary/end.adoc
new file mode 100644 (file)
index 0000000..bd8af2f
--- /dev/null
@@ -0,0 +1,21 @@
+= The END keyword
+
+.Syntax
+----
+END [<name>]
+----
+
+.Description
+
+The `END` keyword finished a "nested" set of
+xref:dictionary/attribute.adoc[ATTRIBUTE] definitions which are all
+for a particular `tlv` or `struct` parent attribute.
+
+[<name>]:: The name of the xref:dictionary/attribute.adoc[ATTRIBUTE].  This is useful
+for validation purposes, but may be omitted.
++
+The dictionary must have previously contained a matching
+xref:dictionary/begin.adoc[BEGIN].
+
+// Copyright (C) 2023 Network RADIUS SAS.  Licenced under CC-by-NC 4.0.
+// This documentation was developed by Network RADIUS SAS.
index 54725696ce2e0f4b6da56687cfb1ba3b010e06c7..d08c74892b4547726afbc4f110d90403717e7e92 100644 (file)
@@ -155,8 +155,8 @@ The following keywords still XXX
 |=====
 | xref:dictionary/begin-protocol.adoc[BEGIN-PROTOCOL]  | Begin defining a protocol dictionary
 | xref:dictionary/end-protocol.adoc[END-PROTOCOL]      | End a protocol dictionary
-| xref:dictionary/begin-tlv.adoc[BEGIN-TLV]            | Begin defining children of a `tlv` data type
-| xref:dictionary/end-tlv.adoc[END-TLV]                | End defining children of a `tlv` data type
+| xref:dictionary/begin.adoc[BEGIN]            | Begin defining children of a `tlv` data type
+| xref:dictionary/end.adoc[END]                | End defining children of a `tlv` data type
 | xref:dictionary/begin-vendor.adoc[BEGIN-VENDOR]      | Begin defining vendor-specific attributes
 | xref:dictionary/end-vendor.adoc[END-VENDOR]          | End defining vendor-specific attributes
 |=====
index da353579c94e400cc30963ce20e63e4756918eaf..9eb28ccad64085030d56136e034625f14b43a014 100644 (file)
@@ -260,12 +260,12 @@ Include dictionary entries from the file \fIfilename\fP.  The
 \fIfilename\fP is taken as relative to the location of the file which
 is asking for the inclusion.
 .TP 0.5i
-.B BEGIN-TLV name
+.B BEGIN name
 This feature is supported for backwards compatibility with older
 dictionaries.  It should not be used.  The new "oid" form for defining
 the attribute number should be used instead.
 .TP 0.5i
-.B END-TLV name
+.B END name
 This feature is supported for backwards compatibility with older
 dictionaries.  It should not be used.  The new "oid" form for defining
 the attribute number should be used instead.
index 85164f0a4491f3fbec3fc2415732317b14737b49..56eed1cd49b74cec13869a6f6fe063f2ce2cc4db 100644 (file)
@@ -51,14 +51,14 @@ ATTRIBUTE   Encr-Data                               130     tlv encrypt=aes-cbc
 #
 #  These attributes are reversibly encrypted
 #
-BEGIN-TLV      Encr-Data
+BEGIN  Encr-Data
 ATTRIBUTE      Padding                                 6       octets          # 4, 8, 12 bytes
 ATTRIBUTE      Counter                                 19      short
 ATTRIBUTE      Counter-Too-Small                       20      bool
 ATTRIBUTE      Nonce-S                                 21      octets[16]
 ATTRIBUTE      Next-Pseudonym                          132     string
 ATTRIBUTE      Next-Reauth-ID                          133     string
-END-TLV                Encr-Data
+END            Encr-Data
 
 ATTRIBUTE      Checkcode                               134     octets          # 0, 20 or 32 bytes
 ATTRIBUTE      Result-Ind                              135     bool
@@ -66,4 +66,3 @@ ATTRIBUTE     Bidding                                 136     short
 
 VALUE  Bidding                         Prefer-AKA              0
 VALUE  Bidding                         Prefer-AKA-Prime        32768   # D Bit
-
index ddbe441b2f104a7f8f387e2c76017bc39089f11a..153817e9909ee1f6d9b5b986aaf568edb6fe2697 100644 (file)
@@ -421,7 +421,7 @@ ATTRIBUTE   Log-Type                                1896    integer
 ATTRIBUTE      WiMAX-MN-NAI                            1900    string
 
 ATTRIBUTE      TLS-Certificate                         1901    tlv
-BEGIN-TLV      TLS-Certificate
+BEGIN          TLS-Certificate
 ATTRIBUTE      Serial                                  1       octets
 ATTRIBUTE      Signature                               2       octets
 ATTRIBUTE      Signature-Algorithm                     3       string
@@ -439,7 +439,7 @@ ATTRIBUTE   X509v3-Extended-Key-Usage               14      string
 ATTRIBUTE      X509v3-Subject-Key-Identifier           15      string
 ATTRIBUTE      X509v3-Authority-Key-Identifier         16      string
 ATTRIBUTE      X509v3-Basic-Constraints                17      string
-END-TLV                TLS-Certificate
+END            TLS-Certificate
 
 ATTRIBUTE      TLS-PSK-Identity                        1933    string
 ATTRIBUTE      TLS-Session-Certificate-File            1934    string
index 2996375f9df04d6ee2792f064a0b75587d2e1a6e..979621b020f3f64532dd8e987e8e7fd271aef05c 100644 (file)
@@ -15,12 +15,11 @@ FLAGS       internal
 
 ATTRIBUTE      IP-Pool                                 5100    tlv
 
-BEGIN-TLV      IP-Pool
+BEGIN  IP-Pool
 ATTRIBUTE      Name                                    1       string  # Generic identifier for the IP pool to allocate from
 ATTRIBUTE      Name-NA                                 2       string  # DHCPv6 - Non-Temporary association pool
 ATTRIBUTE      Name-PD                                 3       string  # DHCPv6 - Prefix-deligation pool
 ATTRIBUTE      Name-TA                                 4       string  # DHCPv6 - Temporary association pool
 
 ATTRIBUTE      Range                                   6       string
-END-TLV                IP-Pool
-
+END            IP-Pool
index 2d184710aea5bfa5ee14a3847e496d181c2e8c05..8b14b116f6675a3b86c3bca60c5332a41102e4e4 100644 (file)
@@ -17,7 +17,7 @@
 FLAGS  internal
 
 ATTRIBUTE      Password                                2004    tlv
-BEGIN-TLV      Password
+BEGIN  Password
 ATTRIBUTE      With-Header                             1       string
 
 ATTRIBUTE      Cleartext                               2       string  secret
@@ -64,14 +64,13 @@ ATTRIBUTE   SSHA3-256                               28      octets
 ATTRIBUTE      SSHA3-384                               29      octets
 ATTRIBUTE      SSHA3-512                               30      octets
 
-END-TLV                Password
+END            Password
 
 #  TOTP passwords and secrets
 ATTRIBUTE      TOTP                                    2005    tlv
 
-BEGIN-TLV      TOTP
+BEGIN  TOTP
 ATTRIBUTE      Secret                                  1       string  secret
 ATTRIBUTE      Key                                     2       octets  secret
 ATTRIBUTE      From-User                               3       string
-END-TLV                TOTP
-
+END            TOTP
index 056823029d9d85832e57d9c6513721bb61e32a09..13816f583cc9f67b8fff0d25774c6da1b17b570c 100644 (file)
@@ -30,7 +30,7 @@ VALUE Packet-Type                     Do-Not-Respond          255
 ATTRIBUTE      Sync-Packet-ID                          1001    integer
 
 ATTRIBUTE      LDAP-Sync                               1193    tlv
-BEGIN-TLV      LDAP-Sync
+BEGIN  LDAP-Sync
 ATTRIBUTE      Cookie                                  1       octets
 ATTRIBUTE      DN                                      2       string
 ATTRIBUTE      Filter                                  3       string
@@ -45,4 +45,4 @@ ATTRIBUTE     Entry-DN                                5       string
 ATTRIBUTE      Entry-UUID                              6       octets
 ATTRIBUTE      Original-DN                             7       string
 ATTRIBUTE      Directory-Root-DN                       8       string
-END-TLV                LDAP-Sync
+END            LDAP-Sync
index 0a8775f8902855d660dbb818c3091929dc20e853..3579ef7b1b26189133c72244851274a16dac71cf 100644 (file)
@@ -48,14 +48,14 @@ ATTRIBUTE   FreeRADIUS-Mib-2                        .3.6.1.2.1      tlv
 #
 #  Everything below is defined in the context of MIB-2
 #
-BEGIN-TLV      1.3.6.1.2.FreeRADIUS-Mib-2
+BEGIN          1.3.6.1.2.FreeRADIUS-Mib-2
 ATTRIBUTE      Radius-Mib                              67      tlv
 ATTRIBUTE      Radius-Authentication                   .1      tlv
 ATTRIBUTE      Radius-Auth-Serv-Mib                    .1.1    tlv
 ATTRIBUTE      Radius-Auth-Serv-Mib-Objects            .1.1.1  tlv
 ATTRIBUTE      Radius-Auth-Serv                        .1.1.1.1        tlv
 
-BEGIN-TLV      67.1.1.1.Radius-Auth-Serv
+BEGIN          67.1.1.1.Radius-Auth-Serv
 ATTRIBUTE      Radius-Auth-Serv-Ident                  1       string
 ATTRIBUTE      Radius-Auth-Serv-Up-Time                2       integer
 ATTRIBUTE      Radius-Auth-Serv-Reset-Time             3       integer
@@ -82,7 +82,7 @@ ATTRIBUTE     Radius-Auth-Client-Table-Index          .0      integer
 ATTRIBUTE      Radius-Auth-Client-Entry                .1      tlv
 
 # Client statistics
-BEGIN-TLV      15.Radius-Auth-Client-Entry
+BEGIN  15.Radius-Auth-Client-Entry
 ATTRIBUTE      Radius-Auth-Client-Index                1       integer
 ATTRIBUTE      Radius-Auth-Client-Address              2       ipaddr
 ATTRIBUTE      Radius-Auth-Client-ID                   3       string
@@ -95,13 +95,13 @@ ATTRIBUTE   Radius-Auth-Serv-Malformed-Access-Requests 9    integer
 ATTRIBUTE      Radius-Auth-Serv-Bad-Authenticators     10      integer
 ATTRIBUTE      Radius-Auth-Serv-Packets-Dropped        11      integer
 ATTRIBUTE      Radius-Auth-Serv-Unknown-Types          12      integer
-END-TLV                15.Radius-Auth-Client-Entry
+END            15.Radius-Auth-Client-Entry
 
 ATTRIBUTE      Radius-Auth-Client-Ext-Table            16      tlv
 ATTRIBUTE      Radius-Auth-Client-Ext-Table-Index      .0      integer
 ATTRIBUTE      Radius-Auth-Client-Ext-Entry            .1      tlv
 
-BEGIN-TLV      16.Radius-Auth-Client-Ext-Entry
+BEGIN  16.Radius-Auth-Client-Ext-Entry
 ATTRIBUTE      Radius-Auth-Client-Ext-Index            1       integer
 ATTRIBUTE      Radius-Auth-Client-Inet-Address-Type    2       integer
 ATTRIBUTE      Radius-Auth-Client-Inet-Address         3       ipaddr
@@ -116,7 +116,7 @@ ATTRIBUTE   Radius-Auth-Serv-Ext-Bad-Authenticators 11      integer
 ATTRIBUTE      Radius-Auth-Serv-Ext-Packet-Dropped     12      integer
 ATTRIBUTE      Radius-Auth-Serv-Ext-Unknown-Types      13      integer
 ATTRIBUTE      Radius-Auth-Serv-Counter-Discontinuity  14      integer
-END-TLV                16.Radius-Auth-Client-Ext-Entry
+END            16.Radius-Auth-Client-Ext-Entry
 
-END-TLV                67.1.1.1.Radius-Auth-Serv
-END-TLV                1.3.6.1.2.FreeRADIUS-Mib-2
+END            67.1.1.1.Radius-Auth-Serv
+END            1.3.6.1.2.FreeRADIUS-Mib-2
index 4a6c6989443e9b12c2ff42c9c0a9c1bbf3dd6b38..8d66cf258071b575e6d668245b5bb0723cc61cde 100644 (file)
@@ -66,6 +66,7 @@ typedef struct value_box_s fr_value_box_t;
 #  define DA_VERIFY(_x)                fr_cond_assert(_x)
 #endif
 
+typedef struct dict_tokenize_ctx_s dict_tokenize_ctx_t;
 typedef struct fr_dict_autoload_talloc_s fr_dict_autoload_talloc_t;
 
 /** Values of the encryption flags
@@ -913,6 +914,8 @@ fr_dict_t const             *fr_dict_internal(void);
  *
  * @{
  */
+void                   dict_dctx_debug(dict_tokenize_ctx_t *dctx);
+
 int                    fr_dict_parse_str(fr_dict_t *dict, char *buf,
                                          fr_dict_attr_t const *parent);
 
index 9c28f3d6eabc6e414d9dd4edcfadd16b31be64f2..1625470d6991fddb1d82145fd95012512a2dd471 100644 (file)
@@ -127,10 +127,19 @@ static inline CC_HINT(always_inline) int dict_fixup_common(fr_dlist_head_t *fixu
 }
 
 /** Resolve a ref= or copy= value to a dictionary */
-fr_dict_attr_t const *dict_protocol_reference(fr_dict_attr_t const *root, char const *ref)
+
+/** Resolve a reference string to a dictionary attribute
+ *
+ * @param[in] rel              Relative attribute to resolve from.
+ * @param[in] ref              Reference string.
+ * @param[in] absolute_root    If true, and there is no '.' prefix, searching will begin from
+ *                             the root of the dictionary, else we pretend there was a '.' and
+ *                             search from rel.
+ */
+fr_dict_attr_t const *dict_protocol_reference(fr_dict_attr_t const *rel, char const *ref, bool absolute_root)
 {
-       fr_dict_t                       *dict = fr_dict_unconst(root->dict);
-       fr_dict_attr_t const            *da = root, *found;
+       fr_dict_t                       *dict = fr_dict_unconst(rel->dict);
+       fr_dict_attr_t const            *da = rel, *found;
        ssize_t                         slen;
        fr_sbuff_t                      sbuff = FR_SBUFF_IN(ref, strlen(ref));
 
@@ -171,11 +180,11 @@ fr_dict_attr_t const *dict_protocol_reference(fr_dict_attr_t const *root, char c
                        /*
                         *      Load the new dictionary, and mark it as loaded from our dictionary.
                         */
-                       if (fr_dict_protocol_afrom_file(&dict, proto_name, NULL, (root->dict)->root->name) < 0) {
+                       if (fr_dict_protocol_afrom_file(&dict, proto_name, NULL, (rel->dict)->root->name) < 0) {
                                return NULL;
                        }
 
-                       if (!fr_hash_table_insert((root->dict)->autoref, dict)) {
+                       if (!fr_hash_table_insert((rel->dict)->autoref, dict)) {
                                fr_strerror_const("Failed inserting into internal autoref table");
                                return NULL;
                        }
@@ -192,18 +201,20 @@ fr_dict_attr_t const *dict_protocol_reference(fr_dict_attr_t const *root, char c
        }
 
        /*
-        *      If we don't have a '.' to make it relative, we're starting from the dictionary root
+        *      First '.' makes it reletive, subsequent ones traverse up the tree.
+        *
+        *      No '.' means use the root.
         */
        if (fr_sbuff_next_if_char(&sbuff, '.')) {
-               do {
+               while (fr_sbuff_next_if_char(&sbuff, '.')) {
                        if (!da->parent) {
                                fr_strerror_const("Reference attempted to navigate above dictionary root");
                                return NULL;
                        }
                        da = da->parent;
-               } while (fr_sbuff_next_if_char(&sbuff, '.'));
+               };
        } else {
-               da = dict->root;
+               da = absolute_root ? dict->root : rel;
        }
 
        /*
@@ -345,7 +356,7 @@ static inline CC_HINT(always_inline) int dict_fixup_group_apply(UNUSED dict_fixu
 {
        fr_dict_attr_t const *da;
 
-       da = dict_protocol_reference(fixup->da, fixup->ref);
+       da = dict_protocol_reference(fixup->da->parent, fixup->ref, true);
        if (!da) {
                fr_strerror_printf_push("Failed resolving reference for attribute at %s[%u]",
                                        fr_cwd_strip(fixup->da->filename), fixup->da->line);
@@ -567,7 +578,7 @@ static inline CC_HINT(always_inline) int dict_fixup_clone_apply(UNUSED dict_fixu
 {
        fr_dict_attr_t const    *src;
 
-       src = dict_protocol_reference(fixup->da, fixup->ref);
+       src = dict_protocol_reference(fixup->da->parent, fixup->ref, true);
        if (!src) {
                fr_strerror_printf_push("Failed resolving reference for attribute at %s[%u]",
                                        fr_cwd_strip(fixup->da->filename), fixup->da->line);
@@ -625,7 +636,7 @@ static inline CC_HINT(always_inline) int dict_fixup_clone_enum_apply(UNUSED dict
        fr_dict_attr_t const    *src;
        int                     copied;
 
-       src = dict_protocol_reference(fixup->da, fixup->ref);
+       src = dict_protocol_reference(fixup->da->parent, fixup->ref, true);
        if (!src) {
                fr_strerror_printf_push("Failed resolving reference for attribute at %s[%u]",
                                        fr_cwd_strip(fixup->da->filename), fixup->da->line);
index 7fa9ab1e0715d56ae523a64a7c61d9e4c7ef8a1e..94e0688b5c2e5a71db35abe4f5fe8a62679fd722 100644 (file)
@@ -40,7 +40,7 @@ typedef struct {
        fr_dlist_head_t         alias;          //!< Aliases that can't be resolved immediately.
 } dict_fixup_ctx_t;
 
-fr_dict_attr_t const *dict_protocol_reference(fr_dict_attr_t const *root, char const *ref);
+fr_dict_attr_t const *dict_protocol_reference(fr_dict_attr_t const *root, char const *ref, bool absolute_root);
 
 int    dict_fixup_enumv_enqueue(dict_fixup_ctx_t *fctx, char const *filename, int line,
                                 char const *attr, size_t attr_len,
index 5e118f7997dccf553a0941f6e0bf0a4228cd6cc1..3c269ffc587bf9b0cb43794021e6960419064b55 100644 (file)
@@ -64,6 +64,15 @@ typedef enum CC_HINT(flag_enum) {
 } dict_nest_t;
 DIAG_ON(attributes)
 
+fr_table_num_sorted_t const dict_nest_table[] = {
+       { L("ATTRIBUTE"),       NEST_ATTRIBUTE },
+       { L("NONE"),            NEST_NONE },
+       { L("PROTOCOL"),        NEST_PROTOCOL },
+       { L("ROOT"),            NEST_ROOT },
+       { L("VENDOR"),          NEST_VENDOR }
+};
+size_t const dict_nest_table_len = NUM_ELEMENTS(dict_nest_table);
+
 /** Parser context for dict_from_file
  *
  * Allows vendor and TLV context to persist across $INCLUDEs
@@ -79,7 +88,7 @@ typedef struct {
        ssize_t                 struct_size;            //!< size of the struct.
 } dict_tokenize_frame_t;
 
-typedef struct {
+struct dict_tokenize_ctx_s {
        fr_dict_t               *dict;                  //!< Protocol dictionary we're inserting attributes into.
 
        dict_tokenize_frame_t   stack[DICT_MAX_STACK];  //!< stack of attributes to track
@@ -88,7 +97,7 @@ typedef struct {
        fr_dict_attr_t          *value_attr;            //!< Cache of last attribute to speed up value processing.
        fr_dict_attr_t const    *relative_attr;         //!< for ".82" instead of "1.2.3.82". only for parents of type "tlv"
        dict_fixup_ctx_t        fixup;
-} dict_tokenize_ctx_t;
+};
 
 static int _dict_from_file(dict_tokenize_ctx_t *dctx,
                           char  const *dir_name, char const *filename,
@@ -98,6 +107,100 @@ static int _dict_from_file(dict_tokenize_ctx_t *dctx,
 #define CURRENT_FILENAME(_dctx)        (CURRENT_FRAME(_dctx)->filename)
 #define CURRENT_LINE(_dctx)    (CURRENT_FRAME(_dctx)->line)
 
+void dict_dctx_debug(dict_tokenize_ctx_t *dctx)
+{
+       int i;
+
+       for (i = 0; i <= dctx->stack_depth; i++) {
+               FR_FAULT_LOG("[%d]: %s %s (%s): %s[%u]",
+                            i,
+                            fr_table_str_by_value(dict_nest_table, dctx->stack[i].nest, "<INVALID>"),
+                            dctx->stack[i].da->name,
+                            fr_type_to_str(dctx->stack[i].da->type),
+                            dctx->stack[i].filename, dctx->stack[i].line);
+       }
+}
+
+static dict_tokenize_frame_t const *dict_dctx_find_frame(dict_tokenize_ctx_t *dctx, dict_nest_t nest)
+{
+       int i;
+
+       for (i = dctx->stack_depth; i >= 0; i--) {
+               if (dctx->stack[i].nest & nest) return &dctx->stack[i];
+       }
+
+       return NULL;
+}
+
+static int dict_dctx_push(dict_tokenize_ctx_t *dctx, fr_dict_attr_t const *da, dict_nest_t nest)
+{
+       if ((dctx->stack_depth + 1) >= DICT_MAX_STACK) {
+               fr_strerror_const_push("Attribute definitions are nested too deep.");
+               return -1;
+       }
+
+       fr_assert(da != NULL);
+
+       dctx->stack[++dctx->stack_depth] = (dict_tokenize_frame_t){
+               .dict = dctx->stack[dctx->stack_depth - 1].dict,
+               .da = da,
+               .filename = dctx->stack[dctx->stack_depth - 1].filename,
+               .line = dctx->stack[dctx->stack_depth - 1].line,
+               .nest = nest
+       };
+
+       return 0;
+}
+
+/** Pop the current stack frame
+ *
+ * @param[in] dctx             Stack to pop from.
+ * @preturn
+ *     - Pointer to the current stack frame.
+ *     - NULL, if we're already at the root.
+ */
+static dict_tokenize_frame_t const *dict_dctx_pop(dict_tokenize_ctx_t *dctx)
+{
+       if (dctx->stack_depth == 0) return NULL;
+
+       return &dctx->stack[dctx->stack_depth--];
+}
+
+/** Unwind the entire stack, returning the root frame
+ *
+ * @param[in] dctx             Stack to unwind.
+ * @return Pointer to the root frame.
+ */
+static dict_tokenize_frame_t const *dict_dctx_unwind(dict_tokenize_ctx_t *dctx)
+{
+       while ((dctx->stack_depth > 0) &&
+              (dctx->stack[dctx->stack_depth].nest == NEST_NONE)) {
+               dctx->stack_depth--;
+       }
+
+       return &dctx->stack[dctx->stack_depth];
+}
+
+/** Unwind the stack until it points to a particular type of stack frame
+ *
+ * @param[in] dctx             Stack to unwind.
+ * @param[in] nest             Frame type to unwind to.
+ * @return
+ *     - Pointer to the frame matching nest
+ *     - NULL, if we unwound the complete stack and didn't find the frame.
+ */
+static dict_tokenize_frame_t const *dict_dctx_unwind_until(dict_tokenize_ctx_t *dctx, dict_nest_t nest)
+{
+       while ((dctx->stack_depth > 0) &&
+              !(dctx->stack[dctx->stack_depth].nest & nest)) {
+               dctx->stack_depth--;
+       }
+
+       if (!(dctx->stack[dctx->stack_depth].nest & nest)) return NULL;
+
+       return &dctx->stack[dctx->stack_depth];
+}
+
 /*
  *     String split routine.  Splits an input string IN PLACE
  *     into pieces, based on spaces.
@@ -653,47 +756,6 @@ static int CC_HINT(nonnull) dict_process_flag_field(dict_tokenize_ctx_t *dctx, c
        return 0;
 }
 
-static dict_tokenize_frame_t const *dict_dctx_find_frame(dict_tokenize_ctx_t *dctx, dict_nest_t nest)
-{
-       int i;
-
-       for (i = dctx->stack_depth; i > 0; i--) {
-               if (dctx->stack[i].nest == nest) return &dctx->stack[i];
-       }
-
-       return NULL;
-}
-
-static int dict_dctx_push(dict_tokenize_ctx_t *dctx, fr_dict_attr_t const *da, dict_nest_t nest)
-{
-       if ((dctx->stack_depth + 1) >= DICT_MAX_STACK) {
-               fr_strerror_const_push("Attribute definitions are nested too deep.");
-               return -1;
-       }
-
-       fr_assert(da != NULL);
-
-       dctx->stack[++dctx->stack_depth] = (dict_tokenize_frame_t){
-               .dict = dctx->stack[dctx->stack_depth - 1].dict,
-               .da = da,
-               .filename = dctx->stack[dctx->stack_depth - 1].filename,
-               .line = dctx->stack[dctx->stack_depth - 1].line,
-               .nest = nest
-       };
-
-       return 0;
-}
-
-static fr_dict_attr_t const *dict_gctx_unwind(dict_tokenize_ctx_t *ctx)
-{
-       while ((ctx->stack_depth > 0) &&
-              (ctx->stack[ctx->stack_depth].nest == NEST_NONE)) {
-               ctx->stack_depth--;
-       }
-
-       return ctx->stack[ctx->stack_depth].da;
-}
-
 static int dict_finalise(dict_tokenize_ctx_t *dctx)
 {
        if (dict_fixup_apply(&dctx->fixup) < 0) return -1;
@@ -758,7 +820,7 @@ static int dict_attr_add_or_fixup(dict_fixup_ctx_t *fixup, fr_dict_attr_t **da_p
                        /*
                         *      See if we can immediately apply the clone
                         */
-                       fr_dict_attr_t const *src = dict_protocol_reference(da, ref->unresolved);
+                       fr_dict_attr_t const *src = dict_protocol_reference(da->parent, ref->unresolved, true);
                        if (src) {
                                if (dict_fixup_clone(da_p, src) < 0) return -1;
                                break;
@@ -1127,7 +1189,7 @@ static int dict_read_process_attribute(dict_tokenize_ctx_t *dctx, char **argv, i
         *      unwind the stack to match.
         */
        if (argv[1][0] != '.') {
-               parent = dict_gctx_unwind(dctx);
+               parent = dict_dctx_unwind(dctx)->da;
 
                /*
                 *      Allow '0xff00' as attribute numbers, but only
@@ -1268,6 +1330,59 @@ static int dict_read_process_attribute(dict_tokenize_ctx_t *dctx, char **argv, i
        return 0;
 }
 
+static int dict_read_process_begin(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flags)
+{
+       dict_tokenize_frame_t const     *frame;
+       fr_dict_attr_t const            *da;
+       fr_dict_attr_t const            *common;
+
+       dctx->value_attr = NULL;
+       dctx->relative_attr = NULL;
+
+       if (argc != 1) {
+               fr_strerror_const_push("Invalid BEGIN entry");
+       error:
+               return -1;
+       }
+
+       frame = dict_dctx_find_frame(dctx, NEST_ROOT | NEST_PROTOCOL | NEST_ATTRIBUTE);
+       if (!fr_cond_assert_msg(frame, "Context stack doesn't have an attribute or dictionary "
+                               "root to begin searching from %s[%u]", CURRENT_FILENAME(dctx), CURRENT_LINE(dctx)) ||
+           !fr_cond_assert_msg(fr_type_is_structural(frame->da->type), "Context attribute is not structural %s[%u]",
+                               CURRENT_FILENAME(dctx), CURRENT_LINE(dctx))) {
+               return -1;
+       }
+
+       /*
+        *      Not really a reference as we don't support any of the
+        *      fancy syntaxes like refs do.  A straight OID string
+        *      resolved from the current level of nesting is all we support.
+        */
+       da = fr_dict_attr_by_oid(NULL, frame->da, argv[0]);
+       if (!da) {
+               fr_strerror_printf_push("BEGIN '%s' not resolvable in context '%s'", argv[0], frame->da->name);
+               goto error;
+       }
+
+       if (!fr_type_is_tlv(da->type) && !fr_type_is_struct(da->type)) {
+               fr_strerror_printf_push("BEGIN %s should be a 'tlv' or 'struct', but is a '%s'",
+                                       argv[0],
+                                       fr_type_to_str(da->type));
+               goto error;
+       }
+
+       common = fr_dict_attr_common_parent(frame->da, da, true);
+       if (!common) {
+               fr_strerror_printf_push("BEGIN %s should be a child of '%s'",
+                                       argv[0], dctx->stack[dctx->stack_depth].da->name);
+               goto error;
+       }
+
+       if (dict_dctx_push(dctx, da, NEST_ATTRIBUTE) < 0) goto error;
+
+       return 0;
+}
+
 static int dict_read_process_begin_protocol(dict_tokenize_ctx_t *dctx, char **argv, int argc,
                                            UNUSED fr_dict_attr_flags_t *base_flags)
 {
@@ -1326,47 +1441,6 @@ static int dict_read_process_begin_protocol(dict_tokenize_ctx_t *dctx, char **ar
        return 0;
 }
 
-static int dict_read_process_begin_tlv(dict_tokenize_ctx_t *dctx, char **argv, int argc,
-                                      UNUSED fr_dict_attr_flags_t *base_flags)
-{
-       fr_dict_attr_t const *da;
-       fr_dict_attr_t const *common;
-
-       dctx->value_attr = NULL;
-       dctx->relative_attr = NULL;
-
-       if (argc != 1) {
-               fr_strerror_const_push("Invalid BEGIN-TLV entry");
-       error:
-               return -1;
-       }
-
-       da = fr_dict_attr_by_oid(NULL, dctx->stack[dctx->stack_depth].da, argv[0]);
-       if (!da) {
-               fr_strerror_const_push("Failed resolving attribute in BEGIN-TLV entry");
-               goto error;
-       }
-
-       if (da->type != FR_TYPE_TLV) {
-               fr_strerror_printf_push("Attribute '%s' should be a 'tlv', but is a '%s'",
-                                       argv[0],
-                                       fr_type_to_str(da->type));
-               goto error;
-       }
-
-       common = fr_dict_attr_common_parent(dctx->stack[dctx->stack_depth].da, da, true);
-       if (!common ||
-               (common->type == FR_TYPE_VSA)) {
-               fr_strerror_printf_push("Attribute '%s' should be a child of '%s'",
-                                       argv[0], dctx->stack[dctx->stack_depth].da->name);
-               goto error;
-       }
-
-       if (dict_dctx_push(dctx, da, NEST_TLV) < 0) goto error;
-
-       return 0;
-}
-
 static int dict_read_process_begin_vendor(dict_tokenize_ctx_t *dctx, char **argv, int argc,
                                          UNUSED fr_dict_attr_flags_t *base_flags)
 {
@@ -1512,8 +1586,9 @@ static int dict_read_process_begin_vendor(dict_tokenize_ctx_t *dctx, char **argv
 static int dict_read_process_define(dict_tokenize_ctx_t *dctx, char **argv, int argc,
                                    fr_dict_attr_flags_t *base_flags)
 {
-       fr_dict_attr_t const    *parent;
-       fr_dict_attr_t          *da;
+       fr_dict_attr_t const            *parent;
+       fr_dict_attr_t                  *da;
+       dict_tokenize_frame_t const     *frame;
 
        if ((argc < 2) || (argc > 3)) {
                fr_strerror_const("Invalid DEFINE syntax");
@@ -1545,9 +1620,10 @@ static int dict_read_process_define(dict_tokenize_ctx_t *dctx, char **argv, int
                goto error;
        }
 
-       parent = dict_gctx_unwind(dctx);
+       frame = dict_dctx_unwind(dctx);
+       if (!fr_cond_assert(frame && frame->da)) goto error;    /* Should have provided us with a parent */
 
-       if (!fr_cond_assert(parent)) goto error;        /* Should have provided us with a parent */
+       parent = frame->da;
 
        /*
         *      Members of a 'struct' MUST use MEMBER, not ATTRIBUTE.
@@ -1622,6 +1698,62 @@ static int dict_read_process_define(dict_tokenize_ctx_t *dctx, char **argv, int
        return 0;
 }
 
+static int dict_read_process_end(dict_tokenize_ctx_t *dctx, char **argv, int argc,
+                                UNUSED fr_dict_attr_flags_t *base_flags)
+{
+       fr_dict_attr_t const *current;
+       fr_dict_attr_t const *da;
+       dict_tokenize_frame_t const *frame;
+
+       dctx->value_attr = NULL;
+       dctx->relative_attr = NULL;
+
+       if (argc > 2) {
+               fr_strerror_const("Invalid END syntax, expected END <ref>");
+               goto error;
+       }
+
+       /*
+        *      Unwind until we hit an attribute nesting section
+        */
+       if (!dict_dctx_unwind_until(dctx, NEST_ATTRIBUTE)) {
+               fr_strerror_const("Unbalanced BEGIN and END keywords");
+       error:
+               return -1;
+       }
+
+       /*
+        *      Pop the stack to get the attribute we're ending.
+        */
+       current = dict_dctx_pop(dctx)->da;;
+
+       /*
+        *      No checks on the attribute, we're just popping _A_ frame,
+        *      we don't care what attribute it represents.
+        */
+       if (argc == 1) return 0;
+
+       /*
+        *      This is where we'll have begun the previous search to
+        *      evaluate the BEGIN keyword.
+        */
+       frame = dict_dctx_find_frame(dctx, NEST_ROOT | NEST_PROTOCOL | NEST_ATTRIBUTE);
+       if (!fr_cond_assert(frame)) goto error;
+
+       da = fr_dict_attr_by_oid(NULL, frame->da, argv[0]);
+       if (!da) {
+               fr_strerror_const_push("Failed resolving attribute in BEGIN entry");
+               goto error;
+       }
+
+       if (da != current) {
+               fr_strerror_printf_push("END %s does not match previous BEGIN %s", argv[0], current->name);
+               goto error;
+       }
+
+       return 0;
+}
+
 static int dict_read_process_end_protocol(dict_tokenize_ctx_t *dctx, char **argv, int argc,
                                          UNUSED fr_dict_attr_flags_t *base_flags)
 {
@@ -1688,55 +1820,6 @@ static int dict_read_process_end_protocol(dict_tokenize_ctx_t *dctx, char **argv
        return 0;
 }
 
-static int dict_read_process_end_tlv(dict_tokenize_ctx_t *dctx, char **argv, int argc,
-                                    UNUSED fr_dict_attr_flags_t *base_flags)
-{
-       fr_dict_attr_t const *da;
-
-       dctx->value_attr = NULL;
-       dctx->relative_attr = NULL;
-
-       if (argc != 1) {
-               fr_strerror_const_push("Invalid END-TLV entry");
-       error:
-               return -1;
-       }
-
-       da = fr_dict_attr_by_oid(NULL, dctx->stack[dctx->stack_depth - 1].da, argv[0]);
-       if (!da) {
-               fr_strerror_const_push("Failed resolving attribute in END-TLV entry");
-               goto error;
-       }
-
-       /*
-               *       Pop the stack until we get to a TLV nesting.
-               */
-       while ((dctx->stack_depth > 0) && (dctx->stack[dctx->stack_depth].nest != NEST_TLV)) {
-               if (dctx->stack[dctx->stack_depth].nest != NEST_NONE) {
-                       fr_strerror_printf_push("END-TLV %s with mismatched BEGIN-??? %s", argv[0],
-                               dctx->stack[dctx->stack_depth].da->name);
-                       goto error;
-               }
-
-               dctx->stack_depth--;
-       }
-
-       if (dctx->stack_depth == 0) {
-               fr_strerror_printf_push("END-TLV %s with no previous BEGIN-TLV", argv[0]);
-               goto error;
-       }
-
-       if (da != dctx->stack[dctx->stack_depth].da) {
-               fr_strerror_printf_push("END-TLV %s does not match previous BEGIN-TLV %s", argv[0],
-                                       dctx->stack[dctx->stack_depth].da->name);
-               goto error;
-       }
-
-       dctx->stack_depth--;
-
-       return 0;
-}
-
 static int dict_read_process_end_vendor(dict_tokenize_ctx_t *dctx, char **argv, int argc,
                                        UNUSED fr_dict_attr_flags_t *base_flags)
 {
@@ -2703,12 +2786,12 @@ static int _dict_from_file(dict_tokenize_ctx_t *dctx,
        static fr_dict_keyword_t const keywords[] = {
                { L("ALIAS"),                   { dict_read_process_alias } },
                { L("ATTRIBUTE"),               { dict_read_process_attribute } },
+               { L("BEGIN"),                   { dict_read_process_begin } },
                { L("BEGIN-PROTOCOL"),          { dict_read_process_begin_protocol } },
-               { L("BEGIN-TLV"),               { dict_read_process_begin_tlv } },
                { L("BEGIN-VENDOR"),            { dict_read_process_begin_vendor } },
                { L("DEFINE"),                  { dict_read_process_define } },
+               { L("END"),                     { dict_read_process_end } },
                { L("END-PROTOCOL"),            { dict_read_process_end_protocol } },
-               { L("END-TLV"),                 { dict_read_process_end_tlv } },
                { L("END-VENDOR"),              { dict_read_process_end_vendor } },
                { L("ENUM"),                    { dict_read_process_enum } },
                { L("FLAGS"),                   { dict_read_process_flags } },