#
ATTRIBUTE IP-Port-Limit-Info 241.5 tlv
-#
-# These attributes can appear in all of the above TLVs. There is
-# currently no way to describe this using the existing dictionary
-# format.
-#
ATTRIBUTE Type .1 integer
ATTRIBUTE Limit .2 integer
ATTRIBUTE Ext-IPv4-Addr .3 ipaddr
ATTRIBUTE Range-End .10 integer
ATTRIBUTE Local-Id .11 string
-ATTRIBUTE IP-Port-Range 241.6 tlv
-ATTRIBUTE Type .1 integer
-ATTRIBUTE Limit .2 integer
-ATTRIBUTE Ext-IPv4-Addr .3 ipaddr
-ATTRIBUTE Int-IPv4-Addr .4 ipaddr
-ATTRIBUTE Int-IPv6-Addr .5 ipv6addr
-ATTRIBUTE Int-Port .6 integer
-ATTRIBUTE Ext-Port .7 integer
-ATTRIBUTE Alloc .8 integer
-
-VALUE Alloc Reserved 0
-VALUE Alloc Allocation 1
-VALUE Alloc Deallocation 2
-
+ATTRIBUTE IP-Port-Range 241.6 tlv clone=Extended-Attribute-1.IP-Port-Limit-Info
ATTRIBUTE Range-Start .9 integer
ATTRIBUTE Range-End .10 integer
ATTRIBUTE Local-Id .11 string
-ATTRIBUTE IP-Port-Forwarding-Map 241.7 tlv
-ATTRIBUTE Type .1 integer
-ATTRIBUTE Limit .2 integer
-ATTRIBUTE Ext-IPv4-Addr .3 ipaddr
-ATTRIBUTE Int-IPv4-Addr .4 ipaddr
-ATTRIBUTE Int-IPv6-Addr .5 ipv6addr
-ATTRIBUTE Int-Port .6 integer
-ATTRIBUTE Ext-Port .7 integer
-ATTRIBUTE Alloc .8 integer
-
-VALUE Alloc Reserved 0
-VALUE Alloc Allocation 1
-VALUE Alloc Deallocation 2
-
-ATTRIBUTE Range-Start .9 integer
-ATTRIBUTE Range-End .10 integer
-ATTRIBUTE Local-Id .11 string
+ATTRIBUTE IP-Port-Forwarding-Map 241.7 tlv clone=Extended-Attribute-1.IP-Port-Range
ATTRIBUTE Uplink-Classifier 28.9 string
ATTRIBUTE Downlink-Classifier 28.10 string
ATTRIBUTE Classifier 28.11 tlv
-ATTRIBUTE ClassifierID .1 integer
-ATTRIBUTE Classifer-Priority .2 integer
-ATTRIBUTE Classifer-Protocol .3 integer
-ATTRIBUTE Classifer-Direction .4 byte
+ATTRIBUTE ID .1 integer
+ATTRIBUTE Priority .2 integer
+ATTRIBUTE Protocol .3 integer
+ATTRIBUTE Direction .4 byte
-VALUE Classifer-Direction Reserved-0 0
-VALUE Classifer-Direction IN 1
-VALUE Classifer-Direction OUT 2
-VALUE Classifer-Direction Bi-Directional 3
-VALUE Classifer-Direction FF 4
+VALUE Direction Reserved-0 0
+VALUE Direction IN 1
+VALUE Direction OUT 2
+VALUE Direction Bi-Directional 3
+VALUE Direction FF 4
ATTRIBUTE Src-Spec 28.11.5 tlv
VALUE Assigned Dst-Assigned 2
VALUE Assigned Src-Dst-Assigned 3
-ATTRIBUTE Dst-Spec 28.11.6 tlv
-
-# Copied from 28.11.5
-ATTRIBUTE IP-Address .1 combo-ip
-# Really "combo-ip start, end"
-ATTRIBUTE IP-Address-Range .2 octets
-ATTRIBUTE IP-Address-Mask .3 octets
-ATTRIBUTE Port .4 short
-# Really "uint16 start, end"
-ATTRIBUTE Port-Range .5 integer
-ATTRIBUTE Inverted .6 byte
-ATTRIBUTE Assigned .7 byte
-VALUE Assigned Src-Assigned 1
-VALUE Assigned Dst-Assigned 2
-VALUE Assigned Src-Dst-Assigned 3
+ATTRIBUTE Dst-Spec 28.11.6 tlv clone=Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Classifier.Src-Spec
ATTRIBUTE IP-TOS/DSCP-Range-and-Mask 28.11.7 octets
ATTRIBUTE VLAN-ID 28.11.8 integer
#
# Classifiers
#
+# Almost the same as Packet-Flow-Descriptor.Classifier, but (of course)
+# with some small changes.
+#
ATTRIBUTE Classifier 84.9 tlv
ATTRIBUTE Id .1 byte
ATTRIBUTE Priority .2 byte
ATTRIBUTE Protocol .3 byte
ATTRIBUTE Direction .4 byte
-ATTRIBUTE Src-Spec 84.9.5 tlv
-# Copied from 28.11.5
-ATTRIBUTE IP-Address .1 combo-ip
-# Really "combo-ip start, end"
-ATTRIBUTE IP-Address-Range .2 octets
-ATTRIBUTE IP-Address-Mask .3 octets
-ATTRIBUTE Port .4 short
-# Really "uint16 start, end"
-ATTRIBUTE Port-Range .5 integer
-ATTRIBUTE Inverted .6 byte
-ATTRIBUTE Assigned .7 byte
-VALUE Assigned Src-Assigned 1
-VALUE Assigned Dst-Assigned 2
-VALUE Assigned Src-Dst-Assigned 3
-
+ATTRIBUTE Src-Spec 84.9.5 tlv clone=Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Classifier.Src-Spec
+# Add these two, also
ATTRIBUTE MAC-Address .8 ether
ATTRIBUTE MAC-Mask .9 ether
-ATTRIBUTE Dest-Spec 84.9.6 tlv
-# Copied from 28.11.5
-ATTRIBUTE IP-Address .1 combo-ip
-# Really "combo-ip start, end"
-ATTRIBUTE IP-Address-Range .2 octets
-ATTRIBUTE IP-Address-Mask .3 octets
-ATTRIBUTE Port .4 short
-# Really "uint16 start, end"
-ATTRIBUTE Port-Range .5 integer
-ATTRIBUTE Inverted .6 byte
-ATTRIBUTE Assigned .7 byte
-VALUE Assigned Src-Assigned 1
-VALUE Assigned Dst-Assigned 2
-VALUE Assigned Src-Dst-Assigned 3
-
-ATTRIBUTE MAC-Address .8 ether
-ATTRIBUTE MAC-Mask .9 ether
+ATTRIBUTE Dest-Spec 84.9.6 tlv clone=Vendor-Specific.WiMAX.Packet-Flow-Descriptor-v2.Classifier.Src-Spec
ATTRIBUTE Classifier-IP-ToS-DSCP 84.9.7 byte
dict_group_fixup_t *next; //!< Next in the linked list of fixups.
};
+typedef struct dict_clone_fixup_s dict_clone_fixup_t;
+
+/** A clone call, which we'll resolve later
+ *
+ */
+struct dict_clone_fixup_s {
+ char *filename; //!< where the "group" was defined
+ int line; //!< ditto
+ fr_dict_attr_t *parent; //!< parent where we add the clone
+ fr_dict_attr_t *da; //!< FR_TYPE_TLV to clone
+ char *ref; //!< the target attribute to clone
+ dict_clone_fixup_t *next; //!< Next in the linked list of fixups.
+};
+
/** Parser context for dict_from_file
*
* Allows vendor and TLV context to persist across $INCLUDEs
dict_enum_fixup_t *enum_fixup;
dict_group_fixup_t *group_fixup;
+ dict_clone_fixup_t *clone_fixup;
fr_dict_attr_t *ext_fixup; //!< Head of a list of attributes to apply fixups to.
} dict_tokenize_ctx_t;
return -1;
}
- if ((type != FR_TYPE_GROUP) && (type != FR_TYPE_TLV) && (type != FR_TYPE_STRUCT)) {
+ if (type != FR_TYPE_GROUP) {
fr_strerror_printf("The 'ref' flag cannot be used for type '%s'",
fr_table_str_by_value(fr_value_box_type_table, type, "<UNKNOWN>"));
return -1;
flags->extra = true;
flags->subtype = FLAG_HAS_REF;
+ } else if (strcmp(key, "clone") == 0) {
+ if (!value) {
+ fr_strerror_printf("Missing attribute name for 'clone=...'");
+ return -1;
+ }
+
+ if (type != FR_TYPE_TLV) {
+ fr_strerror_printf("The 'clone' flag cannot be used for type '%s'",
+ fr_table_str_by_value(fr_value_box_type_table, type, "<UNKNOWN>"));
+ return -1;
+ }
+
+ *ref = talloc_strdup(ctx->dict->pool, value);
+
} else if (ctx->dict->subtype_table) {
int subtype;
return -1;
}
+#ifndef NDEBUG
+ if (!dict_attr_by_name(NULL, parent, argv[0])) {
+ fr_strerror_printf("Failed to find attribute '%s' we just added.", argv[0]);
+ return -1;
+ }
+#endif
+
if (set_relative_attr) ctx->relative_attr = da;
/*
- * Update 'ref'. GROUPs always have refs. For TLVs and
- * STRUCTs, we add the ref after the attribute has been
- * created.
+ * Groups can refer to other dictionaries, or other attributes.
*/
- if (ref || (type == FR_TYPE_GROUP)) {
+ if (type == FR_TYPE_GROUP) {
fr_dict_attr_t *self;
fr_dict_t *dict;
char *p;
* No qualifiers, just point it to the root of the current dictionary.
*/
if (!ref) {
- fr_assert(type == FR_TYPE_GROUP);
dict = ctx->dict;
da = ctx->dict->root;
goto check;
*/
fixup->next = ctx->group_fixup;
ctx->group_fixup = fixup;
+ return 0;
} else if (ref[slen] == '\0') {
da = dict->root;
}
check:
- if ((self->type == FR_TYPE_STRUCT) && (da->type != FR_TYPE_STRUCT)) {
- fr_strerror_printf("References MUST be to attributes of type 'struct'");
- talloc_free(ref);
- return -1;
-
- } else if (da->type != FR_TYPE_TLV) {
- fr_strerror_printf("References MUST be to attributes of type 'tlv'");
- talloc_free(ref);
- return -1;
- }
-
if (fr_dict_attr_ref(da)) {
fr_strerror_printf("References MUST NOT refer to an ATTRIBUTE which also has 'ref=...'");
talloc_free(ref);
}
}
+ /*
+ * It's a "clone" thing.
+ */
+ if (ref) {
+ dict_clone_fixup_t *fixup;
+ fr_dict_attr_t *self;
+
+ memcpy(&self, &da, sizeof(self)); /* const issues */
+
+ fixup = talloc_zero(ctx->fixup_pool, dict_clone_fixup_t);
+ if (!fixup) goto oom;
+
+ fixup->filename = talloc_strdup(fixup, ctx->stack[ctx->stack_depth].filename);
+ if (!fixup->filename) goto oom;
+ fixup->line = ctx->stack[ctx->stack_depth].line;
+
+ memcpy(&fixup->parent, &parent, sizeof(parent)); /* const issues */
+ fixup->da = self;
+ fixup->ref = ref;
+
+ /*
+ * Insert to the head of the list.
+ */
+ fixup->next = ctx->clone_fixup;
+ ctx->clone_fixup = fixup;
+ return 0;
+ }
+
/*
* Adding an attribute of type 'struct' is an implicit
* BEGIN-STRUCT.
}
}
+ if (ctx->clone_fixup) {
+ dict_clone_fixup_t *mine, *this, *next;
+
+ mine = ctx->clone_fixup;
+ ctx->clone_fixup = NULL;
+
+ /*
+ * Loop over references, cloning the da.
+ */
+ for (this = mine; this != NULL; this = next) {
+ fr_dict_t *dict;
+ fr_dict_attr_t const *da;
+ fr_dict_attr_t *cloned;
+ char *p;
+ ssize_t slen;
+
+ da = fr_dict_attr_by_oid(NULL, fr_dict_root(ctx->dict), this->ref);
+ if (da) {
+ dict = ctx->dict;
+ goto clone_check;
+ }
+
+ /*
+ * The attribute doesn't exist, and the reference
+ * isn't in a "PROTO.ATTR" format, die.
+ */
+ p = strchr(this->ref, '.');
+
+ /*
+ * Get / skip protocol name.
+ */
+ slen = dict_by_protocol_substr(NULL,
+ &dict, &FR_SBUFF_IN(this->ref, strlen(this->ref)),
+ ctx->dict);
+ if (slen <= 0) {
+ fr_dict_t *other;
+
+ if (p) *p = '\0';
+
+ if (fr_dict_protocol_afrom_file(&other, this->ref, NULL) < 0) {
+ return -1;
+ }
+
+ if (p) *p = '.';
+
+ /*
+ * Grab the protocol name again
+ */
+ dict = other;
+ if (!p) {
+ dict = other;
+ da = other->root;
+ goto clone_check;
+ }
+
+ slen = p - this->ref;
+ }
+
+ if (slen < 0) {
+ clone_invalid_reference:
+ fr_strerror_printf("Invalid reference '%s' at %s[%d]",
+ this->ref,
+ fr_cwd_strip(this->filename), this->line);
+ clone_error:
+ /*
+ * Just so we don't lose track of things.
+ */
+ // @todo - don't leak clone_fixup stuff? things?
+ return -1;
+ }
+
+ /*
+ * No known dictionary, so we're asked to just
+ * use the whole string. Which we did above. So
+ * either it's a bad ref, OR it's a ref to a
+ * dictionary which doesn't exist.
+ */
+ if (slen == 0) goto clone_invalid_reference;
+
+ /*
+ * Look up the attribute.
+ */
+ da = fr_dict_attr_by_oid(NULL, fr_dict_root(dict), this->ref + slen + 1);
+ if (!da) {
+ fr_strerror_printf("No such attribute '%s' in reference at %s[%d]",
+ this->ref + slen + 1, fr_cwd_strip(this->filename), this->line);
+ goto clone_error;
+ }
+
+ clone_check:
+ if (da->type != FR_TYPE_TLV) {
+ fr_strerror_printf("Clone references MUST be to attributes of type 'tlv' at %s[%d]",
+ fr_cwd_strip(this->filename), this->line);
+ goto clone_error;
+ }
+
+ if (fr_dict_attr_ref(da)) {
+ fr_strerror_printf("Clone references MUST NOT refer to an ATTRIBUTE which has 'ref=...' at %s[%d]",
+ fr_cwd_strip(this->filename), this->line);
+ goto clone_error;
+ }
+
+ /*
+ * Copy the source attribute, but with a
+ * new name and a new attribute number.
+ */
+ cloned = dict_attr_acopy(dict->pool, da, this->da->name);
+ if (!cloned) {
+ fr_strerror_printf("Failed cloning attribute '%s' to %s", da->name, this->ref);
+ goto clone_error;
+ }
+
+ cloned->attr = this->da->attr;
+ cloned->parent = this->parent;
+
+ /*
+ * Copy any pre-existing children over.
+ */
+ if (dict_attr_children(this->da)) {
+ if (dict_attr_acopy_children(dict, cloned, this->da) < 0) {
+ fr_strerror_printf("Failed cloned attribute '%s' from children of %s", da->name, this->ref);
+ goto clone_error;
+ }
+ }
+
+ if (dict_attr_acopy_children(dict, cloned, da) < 0) {
+ fr_strerror_printf("Failed cloned attribute '%s' from children of %s", da->name, this->ref);
+ goto clone_error;
+ }
+
+ if (dict_attr_child_add(this->parent, cloned) < 0) {
+ fr_strerror_printf("Failed adding cloned attribute %s", da->name);
+ talloc_free(cloned);
+ goto clone_error;
+ }
+
+ if (dict_attr_add_to_namespace(dict, this->parent, cloned) < 0) goto clone_error;
+
+ talloc_free(this->ref);
+ next = this->next;
+ }
+ }
+
TALLOC_FREE(ctx->fixup_pool);
/*
--- /dev/null
+proto radius
+proto-dictionary radius
+
+#
+# RADIUS does not (yet) support nested TLVs.
+#
+#encode-pair IP-Port-Limit-Info = { IP-Port-Type = 1, IP-Port-Limit = 2 }
+#match fo
+
+encode-pair Extended-Attribute-1.IP-Port-Limit-Info.Type = 1
+match f1 09 05 01 06 00 00 00 01
+
+encode-pair Extended-Attribute-1.IP-Port-Limit-Info.Limit = 2
+match f1 09 05 02 06 00 00 00 02
+
+encode-pair Extended-Attribute-1.IP-Port-Limit-Info.Type = 1, Extended-Attribute-1.IP-Port-Limit-Info.Limit = 2
+match f1 0f 05 01 06 00 00 00 01 02 06 00 00 00 02
+
+decode-pair -
+match Extended-Attribute-1.IP-Port-Limit-Info.Type = 1, Extended-Attribute-1.IP-Port-Limit-Info.Limit = 2
+
+#
+# And for the other attributes
+#
+encode-pair Extended-Attribute-1.IP-Port-Range.Type = 1, Extended-Attribute-1.IP-Port-Range.Limit = 2
+match f1 0f 06 01 06 00 00 00 01 02 06 00 00 00 02
+
+decode-pair -
+match Extended-Attribute-1.IP-Port-Range.Type = 1, Extended-Attribute-1.IP-Port-Range.Limit = 2
+
+count
+match 14
encode-pair -
match 1a 11 00 00 60 b5 01 0b 00 01 05 31 2e 30 02 03 01
+#
+# Testing cloned TLVs
+#
+encode-pair Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Classifier.Src-Spec.IP-Address = 127.0.0.1, Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Classifier.Src-Spec.Port = 2112
+match 1a 17 00 00 60 b5 1c 11 00 0b 0e 05 0c 01 06 7f 00 00 01 04 04 08 40
+
+encode-pair Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Classifier.Src-Spec.Port = 2112
+match 1a 11 00 00 60 b5 1c 0b 00 0b 08 05 06 04 04 08 40
+
+#
+# Dst-Spec is copied from Src-Spec
+#
+encode-pair Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Classifier.Dst-Spec.Port = 2112
+match 1a 11 00 00 60 b5 1c 0b 00 0b 08 06 06 04 04 08 40
+
+#
+# Src-Spec is copied from the other Src-Spec, but with more attributes added
+#
+encode-pair Vendor-Specific.WiMAX.Packet-Flow-Descriptor-v2.Classifier.Src-Spec.MAC-Address = 00:01:02:03:04:05
+match 1a 15 00 00 60 b5 54 0f 00 09 0c 05 0a 08 08 00 01 02 03 04 05
+
+#
+# Dest-Spec is copied from the most recent Src-Spec
+#
+encode-pair Vendor-Specific.WiMAX.Packet-Flow-Descriptor-v2.Classifier.Dest-Spec.MAC-Address = 00:01:02:03:04:05
+match 1a 15 00 00 60 b5 54 0f 00 09 0c 06 0a 08 08 00 01 02 03 04 05
+
+#
+# We copied enums, too
+#
+encode-pair Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Classifier.Src-Spec.Assigned = Src-Assigned
+match 1a 10 00 00 60 b5 1c 0a 00 0b 07 05 05 07 03 01
+
+#
+# Enum is copied!
+#
+encode-pair Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Classifier.Dst-Spec.Assigned = Src-Assigned
+match 1a 10 00 00 60 b5 1c 0a 00 0b 07 06 05 07 03 01
+
+
+#
+# More complex tests
+#
encode-pair Vendor-Specific.WiMAX.Packet-Flow-Descriptor-v2.Classifier.Direction = 1
match 1a 0e 00 00 60 b5 54 08 00 09 05 04 03 01
# data Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Release = "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Idle-Mode-Notification-Cap = Supported
count
-match 94
+match 108