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: 2268c0bdb4a8b4acdb0868fb01feb2ebad6234bb $")
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_t *dict = da->dict;
44 fr_dict_attr_t const *parent = da->parent;
45 char const *name = da->name;
46 int attr = da->attr;
47 fr_type_t type = da->type;
48 fr_dict_attr_flags_t *flags = &da->flags;
49
50 /*
51 * Convert the 1-bit fields into bits numbers, so that we
52 * can check them in parallel.
53 */
54 all_flags = 0;
55 bit = -1;
56
57#define SET_FLAG(_flag) do { shift_ ## _flag = 1 << ++bit; if (flags->_flag) all_flags |= (1 << bit); } while (0)
58 SET_FLAG(is_root);
59 SET_FLAG(internal);
60 SET_FLAG(array);
61 SET_FLAG(has_value);
62 SET_FLAG(extra);
63 SET_FLAG(counter);
64 SET_FLAG(subtype);
65
66#define FORBID_OTHER_FLAGS(_flag, _allowed) \
67 do { \
68 if (all_flags & ~shift_ ## _flag & ~(_allowed)) { \
69 fr_strerror_printf("The '" STRINGIFY(_flag) "' flag cannot be used with any other flag (%u) %s[%d]", all_flags, da->filename, da->line); \
70 return false; \
71 } \
72 } while (0)
73
74#define ALLOW_FLAG(_flag) do { all_flags &= ~shift_ ## _flag; } while (0)
75
76 // is_root
77 // is_unknown
78 // internal
79 // array
80 // has_value
81 // extra
82 // encrypt
83 // length
84 // type_size
85
86 if (flags->is_root) {
87 FORBID_OTHER_FLAGS(is_root, 0);
88 }
89
90 if (flags->is_unknown) {
91 fr_strerror_const("The 'unknown' flag cannot be set for attributes in the dictionary.");
92 return false;
93 }
94
95 if (flags->local != parent->flags.local) {
96 fr_strerror_const("Cannot mix local variables with non-local attributes");
97 return false;
98 }
99
100 if (flags->local && (flags->is_unknown || flags->is_raw)) {
101 fr_strerror_const("Local variables cannot be 'raw' or unknown");
102 return false;
103 }
104
105 /*
106 * Only some data types can be in arrays, because we need
107 * to be able to decode the various array members.
108 */
109 if (flags->array) {
110 if (!flags->is_known_width) switch (type) {
111 default:
112 fr_strerror_printf("The 'array' flag cannot be used with attributes of type '%s'",
114 return false;
115
120 case FR_TYPE_UINT8:
121 case FR_TYPE_UINT16:
122 case FR_TYPE_UINT32:
123 case FR_TYPE_DATE:
125 break;
126
127 case FR_TYPE_ATTR:
128 flags->is_known_width = 1;
129 break;
130
131 case FR_TYPE_STRING:
132 case FR_TYPE_OCTETS:
133 if (!flags->length) {
134 fr_strerror_const("Variable length attributes cannot be marked as 'array'");
135 return false;
136 }
137
138 flags->is_known_width = 1;
139 break;
140
141 case FR_TYPE_STRUCT:
142 /*
143 * If we have arrays of structs, then the structure MUST be known width.
144 */
145 flags->is_known_width = 1;
146 break;
147 }
148
149 /*
150 * DHCPv6 has arrays of string / octets, prefixed
151 * with a uint16 field of "length". Also, arrays of dns_labels.
152 */
153 ALLOW_FLAG(extra);
154 ALLOW_FLAG(subtype);
155
156 FORBID_OTHER_FLAGS(array, 0);
157 }
158
159 /*
160 * 'has_value' should only be set internally. If the
161 * caller sets it, we still sanity check it.
162 */
163 if (flags->has_value) {
164 if (type != FR_TYPE_UINT32) {
165 fr_strerror_printf("The 'has_value' flag can only be used with attributes "
166 "of type 'integer'");
167 return false;
168 }
169
170 FORBID_OTHER_FLAGS(has_value, shift_internal);
171 }
172
173 /*
174 * Sanity check aliases.
175 */
176 if (flags->is_alias) {
178
180 if (!ext) {
181 fr_strerror_const("ALIAS is missing extension");
182 return false;
183 }
184
185 if (!ext->ref) {
186 fr_strerror_const("ALIAS is missing ref");
187 return false;
188 }
189
190 if (da->parent->type == FR_TYPE_STRUCT) {
191 fr_strerror_const("ALIAS cannot be added to a data type 'struct'");
192 return false;
193 }
194
195 fr_assert(!da->flags.is_unknown);
196 fr_assert(!da->flags.is_raw);
197 fr_assert(!da->flags.array);
198 fr_assert(!da->flags.is_known_width);
199 fr_assert(!da->flags.has_value);
200 fr_assert(!da->flags.counter);
201 fr_assert(!da->flags.secret);
202 fr_assert(!da->flags.unsafe);
203 fr_assert(!da->flags.is_ref_target);
204 fr_assert(!da->flags.local);
205 fr_assert(!da->flags.has_fixup);
206 }
207
208 /*
209 * The "extra" flag is a grab-bag of stuff, depending on
210 * the data type.
211 */
212 if (flags->extra) {
214 fr_strerror_const("The 'key' and 'length' flags cannot be used with any other flags.");
215 return false;
216 }
217
218 switch (type) {
219 case FR_TYPE_BOOL:
220 case FR_TYPE_UINT8:
221 case FR_TYPE_UINT16:
222 case FR_TYPE_UINT32:
223 case FR_TYPE_UINT64:
224 if ((flags->subtype != FLAG_KEY_FIELD) && (flags->subtype != FLAG_BIT_FIELD)) {
225 fr_strerror_const("Invalid type (not 'key' field or 'bit' field) for extra flag.");
226 return false;
227 }
228
229 if (parent->type != FR_TYPE_STRUCT) {
230 fr_strerror_const("The 'key' flag can only be used inside of a 'struct'.");
231 return false;
232 }
233
234 ALLOW_FLAG(extra);
235 ALLOW_FLAG(subtype);
236 break;
237
238 case FR_TYPE_OCTETS:
239 case FR_TYPE_STRING:
240 if (flags->length != 0) {
241 fr_strerror_const("Cannot use [..] and length=uint...");
242 return false;
243 }
244
245 /*
246 * We can do arrays of variable-length types, so long as they have a "length="
247 * modifier.
248 *
249 * But any other modifier is foridden, including the use of "length=" outside of
250 * the context of arrays.
251 */
252 if (flags->array) {
253 ALLOW_FLAG(array);
254
255 if (!da_is_length_field(da)) {
256 fr_assert(0);
257 goto invalid_extra;
258 }
259
260 } else if (flags->subtype) {
261 invalid_extra:
262 fr_strerror_const("Invalid type (not 'length=...') for extra flag.");
263 return false;
264 }
265
266 ALLOW_FLAG(extra);
267 ALLOW_FLAG(subtype);
268 break;
269
270 case FR_TYPE_STRUCT:
271 if (!da_is_length_field(da)) {
272 fr_strerror_const("Invalid type (not 'length=...') for extra flag.");
273 return false;
274 }
275
276 ALLOW_FLAG(extra);
277 ALLOW_FLAG(subtype);
278 ALLOW_FLAG(array);
279 break;
280
281 case FR_TYPE_TLV:
282 ALLOW_FLAG(extra);
283 /* @todo - allow arrays of struct? */
284 ALLOW_FLAG(subtype);
285 break;
286
287 default:
288 fr_strerror_printf("Type %s cannot hold extra flags",
290 return false;
291 }
292
293 if (da_is_length_field(da) &&
294 ((type != FR_TYPE_STRING) && (type != FR_TYPE_OCTETS) && (type != FR_TYPE_STRUCT))) {
295 fr_strerror_printf("The 'length' flag cannot be used used with type %s",
297 return false;
298 }
299
300 FORBID_OTHER_FLAGS(extra, 0);
301 }
302
303 /*
304 * Force "length" for fixed-size data types which aren't
305 * bit fields. Check / set "length" and "type_size" for
306 * other types.
307 */
308 if (!flags->extra || (flags->subtype != FLAG_BIT_FIELD)) switch (type) {
309 case FR_TYPE_INT8:
310 case FR_TYPE_UINT8:
311 case FR_TYPE_BOOL:
312 flags->length = 1;
313 break;
314
315 case FR_TYPE_INT16:
316 case FR_TYPE_UINT16:
317 flags->length = 2;
318 break;
319
320 case FR_TYPE_DATE:
322 if (!flags->length) flags->length = 4;
323
324 if ((flags->length != 2) && (flags->length != 4) && (flags->length != 8)) {
325 fr_strerror_printf("Invalid length %u for attribute of type '%s'",
326 flags->length, fr_type_to_str(type));
327 return false;
328 }
329 break;
330
332 case FR_TYPE_INT32:
333 case FR_TYPE_UINT32:
334 case FR_TYPE_FLOAT32:
335 flags->length = 4;
336 break;
337
338 case FR_TYPE_INT64:
339 case FR_TYPE_UINT64:
340 case FR_TYPE_FLOAT64:
341 flags->length = 8;
342 break;
343
344 case FR_TYPE_SIZE:
345 flags->length = sizeof(size_t);
346 break;
347
348 case FR_TYPE_ETHERNET:
349 flags->length = 6;
350 break;
351
352 case FR_TYPE_IFID:
353 flags->length = 8;
354 break;
355
358 flags->length = 16;
359 break;
360
363 flags->length = 17;
364 break;
365
366 case FR_TYPE_STRUCT:
367 ALLOW_FLAG(internal);
368 ALLOW_FLAG(array);
369 if (all_flags) {
370 fr_strerror_const("Invalid flag for attribute of type 'struct'");
371 return false;
372 }
373 break;
374
375 case FR_TYPE_VENDOR:
376 if (dict->string_based) break;
377
378 if (parent->type != FR_TYPE_VSA) {
379 fr_strerror_printf("Attributes of type 'vendor' MUST have a parent of type 'vsa' "
380 "instead of '%s'",
381 fr_type_to_str(parent->type));
382 return false;
383 }
384
385 if ((flags->length != 1) &&
386 (flags->length != 2) &&
387 (flags->length != 4)) {
388 fr_strerror_const("The 'length' flag can only be used for attributes of type 'vendor' with lengths of 1,2 or 4");
389 return false;
390 }
391 break;
392
393 case FR_TYPE_TLV:
394 if ((flags->length != 1) &&
395 (flags->length != 2) &&
396 (flags->length != 4)) {
397 fr_strerror_const("The 'length' flag can only be used for attributes of type 'tlv' with lengths of 1,2 or 4");
398 return false;
399 }
400 break;
401
402 /*
403 * 'octets[n]' can only be used in a few limited situations.
404 */
405 case FR_TYPE_OCTETS:
406 if (flags->length) {
407 /*
408 * Internal attributes can use octets[n]
409 * MS-MPPE-Keys use octets[18],encrypt=User-Password
410 * EAP-SIM-RAND uses array
411 */
412 ALLOW_FLAG(internal);
413 ALLOW_FLAG(subtype);
414 ALLOW_FLAG(array);
415
416 if (all_flags) {
417 fr_strerror_const("The 'octets[...]' syntax cannot be used any other flag");
418 return false;
419 }
420
421 if (flags->length > 253) {
422 fr_strerror_printf("Invalid length %d", flags->length);
423 return false;
424 }
425 }
426 break;
427
428 case FR_TYPE_UNION:
429 if (parent->type != FR_TYPE_STRUCT) {
430 fr_strerror_printf("Attributes of type 'union' must have a parent of type 'struct', not of type '%s'",
431 fr_type_to_str(parent->type));
432 return false;
433 }
434
435 /*
436 * If the UNION is missing a key extension, then the children of the UNION cannot find
437 * the key field in the parent STRUCT.
438 */
440 fr_strerror_const("Attribute of type 'union' is missing 'key=...'");
441 return false;
442 }
443 break;
444
445 case FR_TYPE_NULL:
446 case FR_TYPE_INTERNAL:
447 fr_strerror_printf("Attributes of type '%s' cannot be used in dictionaries",
449 return false;
450
451 /*
452 * These types are encoded differently in each protocol.
453 */
455 case FR_TYPE_ATTR:
456 case FR_TYPE_STRING:
457 case FR_TYPE_VSA:
458 case FR_TYPE_GROUP:
459 break;
460 }
461
462 /*
463 * type_size is used to limit the maximum attribute number, so it's checked first.
464 */
465 if (flags->type_size) {
466 if ((type == FR_TYPE_DATE) || (type == FR_TYPE_TIME_DELTA)) {
467 /*
468 * Allow all time res here
469 */
470 } else if (!flags->extra) {
471 if ((type != FR_TYPE_TLV) && (type != FR_TYPE_VENDOR)) {
472 fr_strerror_printf("The 'format=' flag can only be used with attributes of type 'tlv', and not type '%s'", fr_type_to_str(type));
473 return false;
474 }
475
476 if ((flags->type_size != 1) &&
477 (flags->type_size != 2) &&
478 (flags->type_size != 4)) {
479 fr_strerror_printf("The 'format=' flag can only be used with attributes of type size 1,2 or 4, not %i", flags->type_size);
480 return false;
481 }
482 }
483 }
484
485 /*
486 * Counters can be time deltas, or unsigned integers.
487 * For other data types, we don't know how to
488 * automatically add two counters.
489 */
490 if (flags->counter) {
492 ALLOW_FLAG(counter);
493 } else {
494 fr_strerror_printf("The 'counter' flag cannot be used with '%s'", fr_type_to_str(type));
495 return false;
496 }
497 }
498
499 /*
500 * Check flags against the parent attribute.
501 */
502 switch (parent->type) {
503 case FR_TYPE_STRUCT:
504 ALLOW_FLAG(extra);
505 ALLOW_FLAG(subtype);
506
507 /*
508 * If our parent is known width, then the children have to be known width, UNLESS
509 * either this child or its parent has a "length" prefix.
510 */
511 if (parent->flags.is_known_width && !flags->is_known_width && !flags->length &&
513 fr_strerror_const("Variable-sized fields cannot be used within a 'struct' which is 'array'");
514 return false;
515 }
516
517 if (flags->array) {
518 switch (type) {
520 ALLOW_FLAG(array);
521 break;
522
523 default:
524 if (flags->is_known_width) ALLOW_FLAG(array);
525 break;
526 }
527 }
528
529 if (all_flags) {
530 fr_strerror_const("Invalid flag for attribute inside of a 'struct'");
531 return false;
532 }
533
534 if (!attr) break;
535
536 /*
537 * If we have keyed structs, then the first
538 * member can be variable length.
539 *
540 * For subsequent children, have each one check
541 * the previous child.
542 */
543 if (attr != 1) {
544 int i;
545 fr_dict_attr_t const *sibling;
546
547 sibling = fr_dict_attr_child_by_num(parent, (attr) - 1);
548
549 /*
550 * sibling might not exist, if it's a deferred 'tlv clone=...'
551 */
552
553 /*
554 * Variable sized elements cannot have anything after them in a struct.
555 */
556 if (sibling && !sibling->flags.length && !sibling->flags.is_known_width) {
557 fr_strerror_const("No other field can follow a struct MEMBER which is variable sized");
558 return false;
559 }
560
561 /*
562 * The same goes for arrays.
563 */
564 if (sibling && sibling->flags.array) {
565 fr_strerror_const("No other field can follow a struct MEMBER which is 'array'");
566 return false;
567 }
568
569 /*
570 * Check for bad key fields, or multiple
571 * key fields. Yes, this is O(N^2), but
572 * the structs are small.
573 */
575 for (i = 1; i < attr; i++) {
576 sibling = fr_dict_attr_child_by_num(parent, i);
577 if (!sibling) {
578 fr_strerror_printf("Child %d of 'struct' type attribute %s does not exist.",
579 i, parent->name);
580 return false;
581 }
582
583 if (!fr_dict_attr_is_key_field(sibling)) continue;
584
585 fr_strerror_printf("Duplicate key attributes '%s' and '%s' in 'struct' type attribute %s are forbidden",
586 name, sibling->name, parent->name);
587 return false;
588 }
589 }
590 }
591 break;
592
593 case FR_TYPE_VSA:
594 if ((type != FR_TYPE_VENDOR) && !flags->internal) {
595 fr_strerror_printf("Attributes of type '%s' cannot be children of the 'vsa' type",
597 return false;
598 }
599 break;
600
601 case FR_TYPE_TLV:
602 case FR_TYPE_VENDOR:
603 break;
604
605 case FR_TYPE_UNION:
606 if (!((da->type == FR_TYPE_STRUCT) || (da->type == FR_TYPE_TLV) || fr_type_is_leaf(da->type))) {
607 fr_strerror_printf("Attributes of type '%s' cannot be children of the 'union' type",
609 return false;
610 }
611 break;
612
613 default:
614 fr_strerror_printf("Attributes of type '%s' cannot have child attributes",
615 fr_type_to_str(parent->type));
616 return false;
617 }
618
619 return true;
620}
621
622
623/** Validate a new attribute definition
624 *
625 * @todo we need to check length of none vendor attributes.
626 *
627 * @param[in] da to validate.
628 * @return
629 * - true if attribute definition is valid.
630 * - false if attribute definition is not valid.
631 */
633{
634 if (!fr_cond_assert(da->parent)) return false;
635
636 if (fr_dict_valid_name(da->name, -1) <= 0) return false;
637
638 /*
639 * Run protocol-specific validation functions, BEFORE we
640 * do the rest of the checks.
641 */
642 if (da->dict->proto->attr.valid && !da->dict->proto->attr.valid(da)) return false;
643
644 /*
645 * Check the flags, data types, and parent data types and flags.
646 */
647 if (!dict_attr_flags_valid(da)) return false;
648
649 return true;
650}
#define RCSID(id)
Definition build.h:485
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:131
unsigned int has_value
Has a value.
Definition dict.h:96
unsigned int is_root
Is root of a dictionary.
Definition dict.h:77
unsigned int array
Pack multiples into 1 attr.
Definition dict.h:92
unsigned int extra
really "subtype is used by dict, not by protocol"
Definition dict.h:120
unsigned int internal
Internal attribute, should not be received in protocol packets, should not be encoded.
Definition dict.h:90
unsigned int is_raw
This dictionary attribute was constructed from a known attribute to allow the user to assign octets v...
Definition dict.h:82
#define da_is_bit_field(_da)
Definition dict.h:171
@ FLAG_KEY_FIELD
this is a key field for a subsequent struct
Definition dict.h:164
@ FLAG_BIT_FIELD
bit field inside of a struct
Definition dict.h:165
#define da_is_length_field(_da)
Definition dict.h:172
uint8_t type_size
Type size for TLVs.
Definition dict.h:144
uint16_t length
length of the attribute
Definition dict.h:153
unsigned int local
is a local variable
Definition dict.h:122
@ FR_DICT_ATTR_EXT_REF
Attribute references another attribute and/or dictionary.
Definition dict.h:184
@ FR_DICT_ATTR_EXT_KEY
UNION attribute references a key.
Definition dict.h:186
unsigned int is_known_width
is treated as if it has a known width for structs
Definition dict.h:94
ssize_t fr_dict_valid_name(char const *name, ssize_t len)
Definition dict_util.c:4967
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:3632
#define fr_dict_attr_is_key_field(_da)
Definition dict.h:170
uint8_t subtype
needs a fixup during dictionary parsing
Definition dict.h:131
unsigned int is_alias
This isn't a real attribute, it's a reference to to one.
Definition dict.h:87
unsigned int counter
integer attribute is actually an impulse / counter
Definition dict.h:100
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.
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:134
Attribute extension - Holds a reference to an attribute in another dictionary.
Definition dict_ext.h:77
#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:857
#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
#define fr_type_is_leaf(_x)
Definition types.h:394
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