enum {
FLAG_EXTRA_NONE = 0, //!< no extra meaning, should be invalid
FLAG_KEY_FIELD, //!< this is a key field for a subsequent struct
+ FLAG_LENGTH_UINT16, //!< string / octets type is prefixed by uint16 of length
};
#define da_is_key_field(_da) ((_da)->flags.extra && ((_da)->flags.subtype == FLAG_KEY_FIELD))
+#define da_is_length_field(_da) ((_da)->flags.extra && ((_da)->flags.subtype == FLAG_LENGTH_UINT16))
extern const size_t dict_attr_sizes[FR_TYPE_MAX + 1][2];
extern fr_dict_t *fr_dict_internal;
FLAG_SET(concat);
FLAG_SET(virtual);
- if (dict && flags->subtype) {
+ if (dict && !flags->extra && flags->subtype) {
p += snprintf(p, end - p, "%s", fr_table_str_by_value(dict->subtype_table, flags->subtype, "?"));
if (p >= end) return -1;
}
}
if (flags->extra) {
- switch (type) {
- case FR_TYPE_UINT8:
- case FR_TYPE_UINT16:
- case FR_TYPE_UINT32:
+ switch (flags->subtype) {
+ case FLAG_KEY_FIELD:
p += snprintf(p, end - p, "key,");
break;
+ case FLAG_LENGTH_UINT16:
+ p += snprintf(p, end - p, "length=uint16,");
+ break;
+
default:
break;
}
flags->extra = 1;
flags->subtype = FLAG_KEY_FIELD;
+ } else if (strcmp(key, "length") == 0) {
+ if (!value || (strcmp(value, "uint16") != 0)) {
+ fr_strerror_printf("The 'length' flag can only be used with value 'uint16'");
+ }
+
+ if ((type != FR_TYPE_STRING) && (type != FR_TYPE_OCTETS) && (type != FR_TYPE_UINT32)) {
+ fr_strerror_printf("The 'length' flag can only be used for attributes of type 'string' or 'octets'");
+ return -1;
+ }
+
+ flags->extra = 1;
+ flags->subtype = FLAG_LENGTH_UINT16;
+
} else if ((type == FR_TYPE_DATE) || (type == FR_TYPE_TIME_DELTA)) {
flags->length = 4;
flags->type_size = FR_TIME_RES_SEC;
break;
}
+ /*
+ * DHCPv6 has arrays of string / octets, prefixed
+ * with a uint16 field of "length". Also, arrays of dns_labels.
+ */
if (dict->root->attr == FR_PROTOCOL_DHCPV6) {
+ ALLOW_FLAG(extra);
ALLOW_FLAG(subtype);
}
* the data type.
*/
if (flags->extra) {
- if (flags->subtype != FLAG_KEY_FIELD) {
- fr_strerror_printf("The 'key' flag cannot be used with any other flags.");
+ if ((flags->subtype != FLAG_KEY_FIELD) && (flags->subtype != FLAG_LENGTH_UINT16)) {
+ fr_strerror_printf("The 'key' and 'length' flags cannot be used with any other flags.");
return false;
}
case FR_TYPE_UINT8:
case FR_TYPE_UINT16:
case FR_TYPE_UINT32:
- ALLOW_FLAG(extra);
- ALLOW_FLAG(subtype);
+ if (flags->subtype != FLAG_KEY_FIELD) {
+ fr_strerror_printf("Invalid type for extra flag.");
+ return false;
+ }
+
if (parent->type != FR_TYPE_STRUCT) {
fr_strerror_printf("The 'key' flag can only be used inside of a 'struct'.");
return false;
}
+ ALLOW_FLAG(extra);
+ ALLOW_FLAG(subtype);
+ break;
+
+ case FR_TYPE_OCTETS:
+ if (flags->length != 0) {
+ fr_strerror_printf("Cannot use [..] and length=uint16");
+ return false;
+ }
+ /* FALL-THROUGH */
+
+ case FR_TYPE_STRING:
+ if (flags->subtype != FLAG_LENGTH_UINT16) {
+ fr_strerror_printf("Invalid type for extra flag.");
+ return false;
+ }
+
+ ALLOW_FLAG(extra);
+ ALLOW_FLAG(array);
+ ALLOW_FLAG(subtype);
break;
default:
- fr_strerror_printf("The 'key' flag can only be used with unsigned integer data types");
return -1;
}