The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
dict_validate.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Validation framework to allow protocols to set custom validation rules
18 *
19 * @file src/lib/util/dict_validate.c
20 *
21 * @copyright 2019 The FreeRADIUS server project
22 * @copyright 2024 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 */
24RCSID("$Id: 1017550c53496499be4070bdac5c798caa62bccd $")
25
26#include <freeradius-devel/util/dict_priv.h>
27
28/** Validate a set of flags
29 *
30 * @param[in] da to check.
31 * @return
32 * - true if attribute definition is valid.
33 * - false if attribute definition is not valid.
34 */
36{
37 int bit;
38 uint32_t all_flags;
39 uint32_t shift_is_root, shift_internal;
40 uint32_t shift_array, shift_has_value;
41 uint32_t shift_subtype, shift_extra;
42 uint32_t shift_counter;
43 fr_dict_attr_t const *v;
44 fr_dict_t *dict = da->dict;
45 fr_dict_attr_t const *parent = da->parent;
46 char const *name = da->name;
47 int attr = da->attr;
48 fr_type_t type = da->type;
49 fr_dict_attr_flags_t *flags = &da->flags;
50
51 /*
52 * Convert the 1-bit fields into bits numbers, so that we
53 * can check them in parallel.
54 */
55 all_flags = 0;
56 bit = -1;
57
58#define SET_FLAG(_flag) do { shift_ ## _flag = 1 << ++bit; if (flags->_flag) all_flags |= (1 << bit); } while (0)
59 SET_FLAG(is_root);
60 SET_FLAG(internal);
61 SET_FLAG(array);
62 SET_FLAG(has_value);
63 SET_FLAG(extra);
64 SET_FLAG(counter);
65 SET_FLAG(subtype);
66
67#define FORBID_OTHER_FLAGS(_flag, _allowed) \
68 do { \
69 if (all_flags & ~shift_ ## _flag & ~(_allowed)) { \
70 fr_strerror_printf("The '" STRINGIFY(_flag) "' flag cannot be used with any other flag (%u) %s[%d]", all_flags, da->filename, da->line); \
71 return false; \
72 } \
73 } while (0)
74
75#define ALLOW_FLAG(_flag) do { all_flags &= ~shift_ ## _flag; } while (0)
76
77 // is_root
78 // is_unknown
79 // internal
80 // array
81 // has_value
82 // extra
83 // encrypt
84 // length
85 // type_size
86
87 if (flags->is_root) {
88 FORBID_OTHER_FLAGS(is_root, 0);
89 }
90
91 if (flags->is_unknown) {
92 fr_strerror_const("The 'unknown' flag cannot be set for attributes in the dictionary.");
93 return false;
94 }
95
96 if (flags->local != parent->flags.local) {
97 fr_strerror_const("Cannot mix local variables with non-local attributes");
98 return false;
99 }
100
101 /*
102 * Only some data types can be in arrays, because we need
103 * to be able to decode the various array members.
104 */
105 if (flags->array) {
106 if (!flags->is_known_width) switch (type) {
107 default:
108 fr_strerror_printf("The 'array' flag cannot be used with attributes of type '%s'",
110 return false;
111
116 case FR_TYPE_UINT8:
117 case FR_TYPE_UINT16:
118 case FR_TYPE_UINT32:
119 case FR_TYPE_DATE:
121 break;
122
123 case FR_TYPE_ATTR:
124 flags->is_known_width = 1;
125 break;
126
127 case FR_TYPE_STRING:
128 case FR_TYPE_OCTETS:
129 if (!flags->length) {
130 fr_strerror_const("Variable length attributes cannot be marked as 'array'");
131 return false;
132 }
133
134 flags->is_known_width = 1;
135 break;
136
137 case FR_TYPE_STRUCT:
138 /*
139 * If we have arrays of structs, then the structure MUST be known width.
140 */
141 flags->is_known_width = 1;
142 break;
143 }
144
145 /*
146 * DHCPv6 has arrays of string / octets, prefixed
147 * with a uint16 field of "length". Also, arrays of dns_labels.
148 */
149 ALLOW_FLAG(extra);
150 ALLOW_FLAG(subtype);
151
152 FORBID_OTHER_FLAGS(array, 0);
153 }
154
155 /*
156 * 'has_value' should only be set internally. If the
157 * caller sets it, we still sanity check it.
158 */
159 if (flags->has_value) {
160 if (type != FR_TYPE_UINT32) {
161 fr_strerror_printf("The 'has_value' flag can only be used with attributes "
162 "of type 'integer'");
163 return false;
164 }
165
166 FORBID_OTHER_FLAGS(has_value, shift_internal);
167 }
168
169 /*
170 * The "extra" flag is a grab-bag of stuff, depending on
171 * the data type.
172 */
173 if (flags->extra) {
175 fr_strerror_const("The 'key' and 'length' flags cannot be used with any other flags.");
176 return false;
177 }
178
179 switch (type) {
180 case FR_TYPE_BOOL:
181 case FR_TYPE_UINT8:
182 case FR_TYPE_UINT16:
183 case FR_TYPE_UINT32:
184 case FR_TYPE_UINT64:
185 if ((flags->subtype != FLAG_KEY_FIELD) && (flags->subtype != FLAG_BIT_FIELD)) {
186 fr_strerror_const("Invalid type (not 'key' field or 'bit' field) for extra flag.");
187 return false;
188 }
189
190 if (parent->type != FR_TYPE_STRUCT) {
191 fr_strerror_const("The 'key' flag can only be used inside of a 'struct'.");
192 return false;
193 }
194
195 ALLOW_FLAG(extra);
196 ALLOW_FLAG(subtype);
197 break;
198
199 case FR_TYPE_OCTETS:
200 case FR_TYPE_STRING:
201 if (flags->length != 0) {
202 fr_strerror_const("Cannot use [..] and length=uint...");
203 return false;
204 }
205
206 /*
207 * We can do arrays of variable-length types, so long as they have a "length="
208 * modifier.
209 *
210 * But any other modifier is foridden, including the use of "length=" outside of
211 * the context of arrays.
212 */
213 if (flags->array) {
214 ALLOW_FLAG(array);
215
216 if (!da_is_length_field(da)) {
217 fr_assert(0);
218 goto invalid_extra;
219 }
220
221 } else if (flags->subtype) {
222 invalid_extra:
223 fr_strerror_const("Invalid type (not 'length=...') for extra flag.");
224 return false;
225 }
226
227 ALLOW_FLAG(extra);
228 ALLOW_FLAG(subtype);
229 break;
230
231 case FR_TYPE_STRUCT:
232 if (!da_is_length_field(da)) {
233 fr_strerror_const("Invalid type (not 'length=...') for extra flag.");
234 return false;
235 }
236
237 ALLOW_FLAG(extra);
238 ALLOW_FLAG(subtype);
239 ALLOW_FLAG(array);
240 break;
241
242 case FR_TYPE_TLV:
243 ALLOW_FLAG(extra);
244 /* @todo - allow arrays of struct? */
245 ALLOW_FLAG(subtype);
246 break;
247
248 default:
249 fr_strerror_printf("Type %s cannot hold extra flags",
251 return false;
252 }
253
254 if (da_is_length_field(da) &&
255 ((type != FR_TYPE_STRING) && (type != FR_TYPE_OCTETS) && (type != FR_TYPE_STRUCT))) {
256 fr_strerror_printf("The 'length' flag cannot be used used with type %s",
258 return false;
259 }
260
261 FORBID_OTHER_FLAGS(extra, 0);
262 }
263
264 /*
265 * Force "length" for fixed-size data types which aren't
266 * bit fields. Check / set "length" and "type_size" for
267 * other types.
268 */
269 if (!flags->extra || (flags->subtype != FLAG_BIT_FIELD)) switch (type) {
270 case FR_TYPE_INT8:
271 case FR_TYPE_UINT8:
272 case FR_TYPE_BOOL:
273 flags->length = 1;
274 break;
275
276 case FR_TYPE_INT16:
277 case FR_TYPE_UINT16:
278 flags->length = 2;
279 break;
280
281 case FR_TYPE_DATE:
283 if (!flags->length) flags->length = 4;
284
285 if ((flags->length != 2) && (flags->length != 4) && (flags->length != 8)) {
286 fr_strerror_printf("Invalid length %u for attribute of type '%s'",
287 flags->length, fr_type_to_str(type));
288 return false;
289 }
290 break;
291
293 case FR_TYPE_INT32:
294 case FR_TYPE_UINT32:
295 case FR_TYPE_FLOAT32:
296 flags->length = 4;
297 break;
298
299 case FR_TYPE_INT64:
300 case FR_TYPE_UINT64:
301 case FR_TYPE_FLOAT64:
302 flags->length = 8;
303 break;
304
305 case FR_TYPE_SIZE:
306 flags->length = sizeof(size_t);
307 break;
308
309 case FR_TYPE_ETHERNET:
310 flags->length = 6;
311 break;
312
313 case FR_TYPE_IFID:
314 flags->length = 8;
315 break;
316
319 flags->length = 16;
320 break;
321
324 flags->length = 17;
325 break;
326
327 case FR_TYPE_STRUCT:
328 ALLOW_FLAG(internal);
329 ALLOW_FLAG(array);
330 if (all_flags) {
331 fr_strerror_const("Invalid flag for attribute of type 'struct'");
332 return false;
333 }
334 break;
335
336 case FR_TYPE_VENDOR:
337 if (parent->type != FR_TYPE_VSA) {
338 fr_strerror_printf("Attributes of type 'vendor' MUST have a parent of type 'vsa' "
339 "instead of '%s'",
340 fr_type_to_str(parent->type));
341 return false;
342 }
343
344 if (flags->length) {
345 if ((flags->length != 1) &&
346 (flags->length != 2) &&
347 (flags->length != 4)) {
348 fr_strerror_const("The 'length' flag can only be used for attributes of type 'vendor' with lengths of 1,2 or 4");
349 return false;
350 }
351
352 break;
353 }
354
355 /*
356 * Set the length / type_size of vendor
357 * attributes from the vendor definition.
358 */
359 flags->type_size = 1;
360 flags->length = 1;
361 if (attr > 0) {
362 fr_dict_vendor_t const *dv;
363
364 dv = fr_dict_vendor_by_num(dict, attr);
365 if (dv) {
366 flags->type_size = dv->type;
367 flags->length = dv->length;
368 }
369 }
370 break;
371
372 case FR_TYPE_TLV:
373 if (flags->length) {
374 if ((flags->length != 1) &&
375 (flags->length != 2) &&
376 (flags->length != 4)) {
377 fr_strerror_const("The 'length' flag can only be used for attributes of type 'tlv' with lengths of 1,2 or 4");
378 return false;
379 }
380
381 break;
382 }
383
384 /*
385 * Find an appropriate parent to copy the
386 * TLV-specific fields from.
387 */
388 for (v = parent; v != NULL; v = v->parent) {
389 if ((v->type == FR_TYPE_TLV) || (v->type == FR_TYPE_VENDOR)) {
390 break;
391 }
392 }
393
394 /*
395 * root is always FR_TYPE_TLV, so we're OK.
396 */
397 if (!v) {
398 fr_strerror_printf("Attributes of type '%s' require a parent attribute",
400 return false;
401 }
402
403 /*
404 * Over-ride whatever was there before, so we
405 * don't have multiple formats of VSAs.
406 */
407 flags->type_size = v->flags.type_size;
408 flags->length = v->flags.length;
409 break;
410
411 /*
412 * 'octets[n]' can only be used in a few limited situations.
413 */
414 case FR_TYPE_OCTETS:
415 if (flags->length) {
416 /*
417 * Internal attributes can use octets[n]
418 * MS-MPPE-Keys use octets[18],encrypt=User-Password
419 * EAP-SIM-RAND uses array
420 */
421 ALLOW_FLAG(internal);
422 ALLOW_FLAG(subtype);
423 ALLOW_FLAG(array);
424
425 if (all_flags) {
426 fr_strerror_const("The 'octets[...]' syntax cannot be used any other flag");
427 return false;
428 }
429
430 if (flags->length > 253) {
431 fr_strerror_printf("Invalid length %d", flags->length);
432 return false;
433 }
434 }
435 break;
436
437 case FR_TYPE_UNION:
438 if (parent->type != FR_TYPE_STRUCT) {
439 fr_strerror_printf("Attributes of type 'union' must have a parent of type 'struct', not of type '%s'",
440 fr_type_to_str(parent->type));
441 return false;
442 }
443
445 fr_strerror_const("Attribute of type 'union' is missing 'key=...'");
446 return false;
447 }
448 break;
449
450 case FR_TYPE_NULL:
451 case FR_TYPE_INTERNAL:
452 fr_strerror_printf("Attributes of type '%s' cannot be used in dictionaries",
454 return false;
455
456 /*
457 * These types are encoded differently in each protocol.
458 */
460 case FR_TYPE_ATTR:
461 case FR_TYPE_STRING:
462 case FR_TYPE_VSA:
463 case FR_TYPE_GROUP:
464 break;
465 }
466
467 /*
468 * type_size is used to limit the maximum attribute number, so it's checked first.
469 */
470 if (flags->type_size) {
471 if ((type == FR_TYPE_DATE) || (type == FR_TYPE_TIME_DELTA)) {
472 /*
473 * Allow all time res here
474 */
475 } else if (!flags->extra) {
476 if ((type != FR_TYPE_TLV) && (type != FR_TYPE_VENDOR)) {
477 fr_strerror_const("The 'format=' flag can only be used with attributes of type 'tlv'");
478 return false;
479 }
480
481 if ((flags->type_size != 1) &&
482 (flags->type_size != 2) &&
483 (flags->type_size != 4)) {
484 fr_strerror_const("The 'format=' flag can only be used with attributes of type size 1,2 or 4");
485 return false;
486 }
487 }
488 }
489
490 /*
491 * Counters can be time deltas, or unsigned integers.
492 * For other data types, we don't know how to
493 * automatically add two counters.
494 */
495 if (flags->counter) {
497 ALLOW_FLAG(counter);
498 } else {
499 fr_strerror_printf("The 'counter' flag cannot be used with '%s'", fr_type_to_str(type));
500 return false;
501 }
502 }
503
504 /*
505 * Check flags against the parent attribute.
506 */
507 switch (parent->type) {
508 case FR_TYPE_STRUCT:
509 ALLOW_FLAG(extra);
510 ALLOW_FLAG(subtype);
511
512 /*
513 * If our parent is known width, then the children have to be known width, UNLESS
514 * either this child or its parent has a "length" prefix.
515 */
516 if (parent->flags.is_known_width && !flags->is_known_width && !flags->length &&
518 fr_strerror_const("Variable-sized fields cannot be used within a 'struct' which is 'array'");
519 return false;
520 }
521
522 if (flags->array) {
523 switch (type) {
525 ALLOW_FLAG(array);
526 break;
527
528 default:
529 if (flags->is_known_width) ALLOW_FLAG(array);
530 break;
531 }
532 }
533
534 if (all_flags) {
535 fr_strerror_const("Invalid flag for attribute inside of a 'struct'");
536 return false;
537 }
538
539 if (!attr) break;
540
541 /*
542 * If we have keyed structs, then the first
543 * member can be variable length.
544 *
545 * For subsequent children, have each one check
546 * the previous child.
547 */
548 if (attr != 1) {
549 int i;
550 fr_dict_attr_t const *sibling;
551
552 sibling = fr_dict_attr_child_by_num(parent, (attr) - 1);
553
554 /*
555 * sibling might not exist, if it's a deferred 'tlv clone=...'
556 */
557
558 /*
559 * Variable sized elements cannot have anything after them in a struct.
560 */
561 if (sibling && !sibling->flags.length && !sibling->flags.is_known_width) {
562 fr_strerror_const("No other field can follow a struct MEMBER which is variable sized");
563 return false;
564 }
565
566 /*
567 * The same goes for arrays.
568 */
569 if (sibling && sibling->flags.array) {
570 fr_strerror_const("No other field can follow a struct MEMBER which is 'array'");
571 return false;
572 }
573
574 /*
575 * Check for bad key fields, or multiple
576 * key fields. Yes, this is O(N^2), but
577 * the structs are small.
578 */
580 for (i = 1; i < attr; i++) {
581 sibling = fr_dict_attr_child_by_num(parent, i);
582 if (!sibling) {
583 fr_strerror_printf("Child %d of 'struct' type attribute %s does not exist.",
584 i, parent->name);
585 return false;
586 }
587
588 if (!fr_dict_attr_is_key_field(sibling)) continue;
589
590 fr_strerror_printf("Duplicate key attributes '%s' and '%s' in 'struct' type attribute %s are forbidden",
591 name, sibling->name, parent->name);
592 return false;
593 }
594 }
595 }
596 break;
597
598 case FR_TYPE_VSA:
599 if ((type != FR_TYPE_VENDOR) && !flags->internal) {
600 fr_strerror_printf("Attributes of type '%s' cannot be children of the 'vsa' type",
602 return false;
603 }
604 break;
605
606 case FR_TYPE_TLV:
607 case FR_TYPE_VENDOR:
608 break;
609
610 case FR_TYPE_UNION:
611 if (da->type != FR_TYPE_STRUCT) {
612 fr_strerror_printf("Attributes of type '%s' cannot be children of the 'union' type",
614 return false;
615 }
616 break;
617
618 /*
619 * "key" fields inside of a STRUCT can have
620 * children, even if they are integer data type.
621 */
622 case FR_TYPE_UINT8:
623 case FR_TYPE_UINT16:
624 case FR_TYPE_UINT32:
625 /*
626 * @todo - remove after migration_union_key is deleted
627 */
630
631 default:
632 fr_strerror_printf("Attributes of type '%s' cannot have child attributes",
633 fr_type_to_str(parent->type));
634 return false;
635 }
636
637 return true;
638}
639
640
641/** Validate a new attribute definition
642 *
643 * @todo we need to check length of none vendor attributes.
644 *
645 * @param[in] da to validate.
646 * @return
647 * - true if attribute definition is valid.
648 * - false if attribute definition is not valid.
649 */
651{
652 if (!fr_cond_assert(da->parent)) return false;
653
654 if (fr_dict_valid_name(da->name, -1) <= 0) return false;
655
656 /*
657 * Run protocol-specific validation functions, BEFORE we
658 * do the rest of the checks.
659 */
660 if (da->dict->proto->attr.valid && !da->dict->proto->attr.valid(da)) return false;
661
662 /*
663 * Check the flags, data types, and parent data types and flags.
664 */
665 if (!dict_attr_flags_valid(da)) return false;
666
667 return true;
668}
#define RCSID(id)
Definition build.h:485
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:131
size_t type
Length of type data.
Definition dict.h:267
unsigned int has_value
Has a value.
Definition dict.h:95
unsigned int is_root
Is root of a dictionary.
Definition dict.h:77
unsigned int array
Pack multiples into 1 attr.
Definition dict.h:91
unsigned int extra
really "subtype is used by dict, not by protocol"
Definition dict.h:117
unsigned int internal
Internal attribute, should not be received in protocol packets, should not be encoded.
Definition dict.h:89
#define da_is_bit_field(_da)
Definition dict.h:170
@ FLAG_KEY_FIELD
this is a key field for a subsequent struct
Definition dict.h:163
@ FLAG_BIT_FIELD
bit field inside of a struct
Definition dict.h:164
#define da_is_length_field(_da)
Definition dict.h:171
uint8_t type_size
Type size for TLVs.
Definition dict.h:143
size_t length
Length of length data.
Definition dict.h:268
uint16_t length
length of the attribute
Definition dict.h:152
unsigned int local
is a local variable
Definition dict.h:119
@ FR_DICT_ATTR_EXT_KEY
UNION attribute references a key.
Definition dict.h:185
unsigned int is_known_width
is treated as if it has a known width for structs
Definition dict.h:93
fr_dict_vendor_t const * fr_dict_vendor_by_num(fr_dict_t const *dict, uint32_t vendor_pen)
Look up a vendor by its PEN.
Definition dict_util.c:2776
ssize_t fr_dict_valid_name(char const *name, ssize_t len)
Definition dict_util.c:4759
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition dict_util.c:3424
#define fr_dict_attr_is_key_field(_da)
Definition dict.h:169
uint8_t subtype
protocol-specific values, OR key fields
Definition dict.h:130
unsigned int counter
integer attribute is actually an impulse / counter
Definition dict.h:99
unsigned int is_unknown
This dictionary attribute is ephemeral and not part of the main dictionary.
Definition dict.h:79
Values of the encryption flags.
Private enterprise.
Definition dict.h:264
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:141
#define FORBID_OTHER_FLAGS(_flag, _allowed)
bool dict_attr_flags_valid(fr_dict_attr_t *da)
Validate a set of flags.
bool dict_attr_valid(fr_dict_attr_t *da)
Validate a new attribute definition.
#define ALLOW_FLAG(_flag)
#define SET_FLAG(_flag)
fr_type_t
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_FLOAT32
Single precision floating point.
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
@ FR_TYPE_IFID
Interface ID.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
@ FR_TYPE_FLOAT64
Double precision floating point.
unsigned int uint32_t
unsigned long int size_t
#define fr_assert(_expr)
Definition rad_assert.h:38
static char const * name
fr_aka_sim_id_type_t type
static fr_slen_t parent
Definition pair.h:841
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
@ FR_TYPE_UNION
A union of limited children.
Definition types.h:82
@ FR_TYPE_ATTR
A contains an attribute reference.
Definition types.h:84
#define FR_TYPE_INTERNAL
Definition types.h:320
#define fr_type_is_signed(_x)
Definition types.h:384
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:455
#define fr_type_is_integer(_x)
Definition types.h:382
#define FR_TYPE_FIXED_SIZE
Definition types.h:311