"enum" is for copying values.
"clone" is for copying TLV and STRUCT types
<reference>:: An OID by name `Vendor.Cisco.AVPair`, or by number `26.9.1`.
+
The full name or number must be given.
-.Examples
+
+.Example
----
ALIAS Cisco-AVPair 26.9.1
----
== Purpose of the ALIAS keyword
The purpose of the `ALIAS` keyword is to allow for easier transition
-from ealier versions of FreeRADIUS to version 4. We recognize that
+from earlier versions of FreeRADIUS to version 4. We recognize that
the old attribute names are used in many places such as databases. It
can be difficult to change many thousands of existing entries in a
"live" system.
== v3 Compatible names
All of the attributes have been renamed from v3. This change was
-necessary in order to support new funtionality in v4. The
-unfortunate side effect of this change is that all of the names in
-SQL, LDAP, and the "files" module are incompatible with v4.
+necessary in order to support new funtionality in v4. The unfortunate
+side effect of this change is that all of the names which are
+currently in SQL, LDAP, and the "files" module for use with v3, are
+incompatible with v4.
We recognize that is is difficult to change every entry in a
database, especially when there's no clear mapping between the
the "new" names need to be grouped and arranged in ways that the
old ones were not.
-The "old" names were all in flat lists, so that` User-Name` appeared
+The "old" names were all in flat lists, so that `User-Name` appeared
next to `Cisco-AVPAir`. This organization was simple enough to work
-for 20 years, but its time has come. The new names are
-hierarchical, so that the organization is nested by definition.
+for 20 years, but its time has come. The new names are hierarchical,
+and are contained in "parent" attributes. This arrangment does not
+ysyakky change the length of most attribute names.
For v4, the `Cisco-AVPair` attribute is called `AVPair`, and it lives
inside of the `Cisco` namespace, which in turn lives inside of the
|=====
| Name | Description
| `array` | For fixed-size types, declare that the contents of the packet can have an array of this value.
-| `clone=...` | For `tlv` types, clone (or copy) child definitions from another `tlv` type
+| `enum=...` | For "leaf" types, copy xref:dictionary/value.adoc[VALUE]s from an `xref:dictionary/enum.adoc[ENUM].
+| `clone=...` | For `tlv` or 'struct' types, clone (or copy) child definitions from another attribute of the same type
| `internal` | This attribute is internal to the server, and will never be sent "on the wire"
-| `ref=...` | For `group` types, specify which attributes are allowed to be in this `group`
+| `ref=...` | For `group` types, reference another attribute by name as being allowed in the `group`.
|=====
-
.Examples
----
ATTRIBUTE Foo 1 string[3]
ATTRIBUTE baz 3 ipv4addr
----
+
+== Clone
+
+In some cases, structured attributes have different parents, but
+identical children. The `clone=...` flag allows an attribute to copy
+or "clone" the children of another attribute.
+
+The `clone` flag can only be used for the data type `tlv`.
+
+.Clone Examples
+----
+ATTRIBUTE Foo 1 tlv
+ATTRIBUTE Bar 1.1 ipaddr
+ATTRIBUTE Baz 2 tlv clone=Foo
+----
+
+== References
+
+In some cases, attributes can "group" other attributes without adding
+a new hierarchy. The `ref=...` flag allows an attribute to reference
+another attribute.
+
+If `ref` is not given for an attribute of type `group` then the
+reference is assumed to be to the "root" of the current protocol
+dictionary.
+
+The `ref` flag can only be used for the data type `group`.
+
== Fixed Size Data types
The following data types can be marked up as having fixed size, by
--- /dev/null
+= The ENUM keyword
+
+.Syntax
+----
+ENUM <name> <type>
+----
+
+.Description
+The `ENUM` keyword defines name for set of xref:dictionary/value.adoc[VALUE]s.
+
+<name>:: The name of the enum.
++
+These names are in the same namespace as
+xref:dictionary/attribute.adoc[ATTRIBUTE]s, and must follow the same
+rules
+
+<type>:: A xref:type/index.adoc[data type]
++
+The list of allowed data types are the same as for xref:dictionary/value.adoc[VALUE].
+
+Once an `ENUM` is defined, it can have
+xref:dictionary/value.adoc[VALUE]s associated with it, just like with
+xref:dictionary/attribute.adoc[ATTRIBUTE]s.
+
+The main purpose of `ENUM` is to define commonly used values in one
+place, and then refer to those values from multiple places. This
+reuse simplifies the dictionaries, and helps to avoid errors.
+
+In the following example, `Ethernet-Type` is defined as an `ENUM` and
+given xref:dictionary/value.adoc[VALUE]s. We then define two
+xref:dictionary/attribute.adoc[ATTRIBUTE]s, and copy those
+xref:dictionary/value.adoc[VALUE]s from the `ENUM` to the
+xref:dictionary/attribute.adoc[ATTRIBUTE].
+
+After these definitions, when the server will allow `Some-Protocol` to
+be assigned the value `IPv4`, which will get encoded into a packet as
+the 16-bit field `0x0800.
+
+.Example
+----
+ENUM Ethernet-Type uint16
+VALUE Ethernet-Type IPv4 0x0800
+VALUE Ethernet-Type IPv6 0x86DD
+
+ATTRIBUTE Some-Protocol 2112 uint16 enum=Ethernet-Type
+ATTRIBUTE Other-Thing 6809 uint16 enum=Ethernet-Type
+----
+
+// Copyright (C) 2023 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
# Version $Id$
FLAGS internal
-ATTRIBUTE Packet-Type 1000 uint32 clone=packet.opcode
+ATTRIBUTE Packet-Type 1000 uint32 enum=packet.opcode
VALUE Packet-Type query.response 16
VALUE Packet-Type iquery.response 17
int copied;
/*
- * Structural types cannot be the source or destination of clones.
+ * Only TLV and STRUCT types can be the source or destination of clones.
*
* Leaf types can be cloned, even if they're
* different types. But only if they don't have
return -1;
}
+ if ((type != FR_TYPE_TLV) && (type != FR_TYPE_STRUCT)) {
+ fr_strerror_const("'clone=...' references can only be used for 'tlv' and 'struct' types");
+ return -1;
+ }
+
/*
* Allow cloning of any types, so long as
* the types are the same. We do the checks later.
return -1;
}
- switch (type) {
- case FR_TYPE_LEAF:
- break;
-
- default:
- fr_strerror_const("ENUM references be used for structural types");
+ if (!fr_type_is_leaf(type)) {
+ fr_strerror_const("'enum=...' references cannot be used for structural types");
return -1;
}
fr_strerror_const("Invalid reference in 'enum=...', target has no VALUEs");
return -1;
}
+
+ if (fr_dict_attr_is_key_field(da)) {
+ fr_strerror_const("Invalid reference in 'enum=...', target is a 'key' field");
+ return -1;
+ }
}
} else if (ctx->dict->subtype_table) {
}
flags = *base_flags;
+ flags.name_only = true; /* values for ENUM are irrelevant */
+ flags.internal = true; /* ENUMs will never get encoded into a protocol */
+#if 0
+ flags.is_enum = true; /* it's an enum, and can't be assigned to a #fr_pair_t */
+#endif
if (dict_process_type_field(ctx, argv[1], &type, &flags) < 0) return -1;
if (!dict_attr_fields_valid(ctx->dict, parent, argv[0], &attr, type, &flags)) return -1;
/*
- * Add in an attribute
+ * Add the ENUM as if it was an ATTRIBUTE.
*/
if (fr_dict_attr_add(ctx->dict, parent, argv[0], attr, type, &flags) < 0) return -1;