The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
struct.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library 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 GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Functions to encode / decode structures on the wire
18 *
19 * @file src/lib/util/struct.c
20 *
21 * @copyright 2018 The FreeRADIUS server project
22 * @copyright 2018 Alan DeKok (aland@freeradius.org)
23 */
24RCSID("$Id: 2d6c4ef4935c7ff5015b89802b5aaeec8ba9e9ec $")
25
26#include <freeradius-devel/util/struct.h>
27#include <freeradius-devel/io/pair.h>
28
29/** Convert a STRUCT to one or more VPs
30 *
31 */
33 fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len,
34 void *decode_ctx,
36{
37 unsigned int child_num;
38 uint8_t const *p = data, *end = data + data_len;
39 fr_dict_attr_t const *child, *substruct_da;
40 fr_pair_list_t child_list_head;
41 fr_pair_list_t *child_list;
42 fr_pair_t *vp, *key_vp, *struct_vp = NULL;
43 unsigned int offset = 0;
44 TALLOC_CTX *child_ctx;
45 ssize_t slen;
46 size_t child_length;
47
48 if (data_len == 0) {
49 fr_strerror_const("struct decoder was passed zero bytes of data");
50 return -1; /* at least one byte of data */
51 }
52
53 FR_PROTO_TRACE("Decoding struct %s", parent->name);
54 FR_PROTO_HEX_DUMP(data, data_len, "fr_struct_from_network");
55
56 /*
57 * Start a child list.
58 */
60
61 struct_vp = fr_pair_afrom_da(ctx, parent);
62 if (!struct_vp) {
63 return PAIR_DECODE_OOM;
64 }
65 PAIR_ALLOCED(struct_vp);
66
67 fr_pair_list_init(&child_list_head); /* still used elsewhere */
68 child_list = &struct_vp->vp_group;
69 child_ctx = struct_vp;
70 key_vp = NULL;
71
72 /*
73 * Simplify the code by having a generic decode routine.
74 */
76
77 /*
78 * Decode structs with length prefixes.
79 */
81 size_t claimed_len, field_len, calc_len;
82
83 /*
84 * Set how many bytes there are in the "length" field.
85 */
87 field_len = 1;
88 } else {
90 field_len = 2;
91 }
92
93 if ((size_t) (end - p) < field_len) {
94 FR_PROTO_TRACE("Insufficient room for length field");
95
96 invalid_struct:
97 /*
98 * Some field could not be decoded. Nuke the entire struct, and just make the
99 * whole thing "raw".
100 */
101 TALLOC_FREE(struct_vp);
102
103 slen = fr_pair_raw_from_network(ctx, out, parent, data, data_len);
104 if (slen < 0) return slen;
105 return data_len;
106 }
107
108 claimed_len = p[0];
109 if (field_len > 1) {
110 claimed_len <<= 8;
111 claimed_len |= p[1];
112 }
113 p += field_len;
114
115 if (claimed_len < da_length_offset(parent)) {
116 FR_PROTO_TRACE("Length header (%zu) is smaller than minimum value (%u)",
117 claimed_len, parent->flags.type_size);
118 goto invalid_struct;
119 }
120
121 /*
122 * Get the calculated length of the actual data.
123 */
124 calc_len = claimed_len - da_length_offset(parent);
125
126 if (calc_len > (size_t) (end - p)) {
127 FR_PROTO_TRACE("Length header (%zu) is larger than remaining data (%zu)",
128 claimed_len + field_len, (size_t) (end - p));
129 goto invalid_struct;
130 }
131
132 /*
133 * Limit the size of the decoded structure to the correct length.
134 */
135 data_len = calc_len;
136 end = p + data_len;
137 }
138
139 /*
140 * @todo - If the struct is truncated on a MEMBER boundary, we silently omit
141 * the trailing members. Maybe this should be an error?
142 */
143 for (child_num = 1;
144 (p < end) && (child = fr_dict_attr_child_by_num(parent, child_num)) != NULL;
145 child_num++) {
146 FR_PROTO_TRACE("Decoding struct %s child %s (%d)", parent->name, child->name, child->attr);
147 FR_PROTO_HEX_DUMP(p, (end - p), "fr_struct_from_network - remaining %zu", (size_t) (end - p));
148
149 /*
150 * Check for bit fields.
151 */
152 if (da_is_bit_field(child)) {
153 uint8_t array[8];
154 unsigned int num_bits;
155 uint64_t value;
156
157 num_bits = offset + child->flags.length;
158 if ((size_t)(end - p) < fr_bytes_from_bits(num_bits)) {
159 FR_PROTO_TRACE("not enough data for bit decoder?");
160 goto remainder_raw;
161 }
162
163 memset(array, 0, sizeof(array));
164 memcpy(&array[0], p, fr_bytes_from_bits(num_bits));
165
166 if (offset > 0) array[0] &= (1 << (8 - offset)) - 1; /* mask off bits we don't care about */
167
168 memcpy(&value, &array[0], sizeof(value));
169 value = htonll(value);
170 value >>= (8 - offset); /* move it to the lower bits */
171 value >>= (56 - child->flags.length);
172
173 vp = fr_pair_afrom_da(child_ctx, child);
174 if (!vp) {
175 FR_PROTO_TRACE("fr_struct_from_network - failed allocating child VP");
176 oom:
177 talloc_free(struct_vp);
178 return PAIR_DECODE_OOM;
179 }
181
182 switch (child->type) {
183 case FR_TYPE_BOOL:
184 vp->vp_bool = value;
185 break;
186
187 case FR_TYPE_UINT8:
188 vp->vp_uint8 = value;
189 break;
190
191 case FR_TYPE_UINT16:
192 vp->vp_uint16 = value;
193 break;
194
195 case FR_TYPE_UINT32:
196 vp->vp_uint32 = value;
197 break;
198
199 case FR_TYPE_UINT64:
200 vp->vp_uint64 = value;
201 break;
202
203 default:
204 FR_PROTO_TRACE("Can't decode unknown type?");
205 goto remainder_raw;
206 }
207
208 vp->vp_tainted = true;
209 fr_pair_append(child_list, vp);
210
211 p += (num_bits >> 3); /* go to the LAST bit, not the byte AFTER the last bit */
212 offset = num_bits & 0x07;
213 continue;
214 }
215
216 fr_assert(offset == 0);
217 offset = 0; /* reset for non-bit-field attributes */
218
219 /*
220 * The child is either unknown width, OR known width with a length that is too large for
221 * the "length" field, OR is known width via some kind of protocol-specific length header.
222 */
223 if (!child->flags.length || child->flags.array) {
224 child_length = end - p;
225
226 } else {
227 child_length = child->flags.length;
228
229 /*
230 * If this field overflows the input, then *all*
231 * of the input is suspect.
232 */
233 if (child_length > (size_t) (end - p)) {
234 child_length = (size_t) (end - p);
235 }
236 }
237
238 /*
239 * We only allow a limited number of data types
240 * inside of a struct.
241 */
242 switch (child->type) {
243 case FR_TYPE_INTERNAL:
244 case FR_TYPE_NULL:
245 FR_PROTO_TRACE("fr_struct_from_network - unknown child type");
246 goto remainder_raw;
247
248 case FR_TYPE_STRUCT:
249 case FR_TYPE_VSA:
250 case FR_TYPE_VENDOR:
251 case FR_TYPE_GROUP:
252 case FR_TYPE_LEAF:
253 break;
254
255 /*
256 * Decode child TLVs, according to the parent attribute.
257 */
258 case FR_TYPE_TLV:
259 fr_assert(!key_vp);
260
261 if (!decode_tlv) {
262 fr_strerror_const("Decoding TLVs requires a decode_tlv() function to be passed");
263 talloc_free(struct_vp);
264 return -(p - data);
265 }
266
267 /*
268 * Decode all of the remaining data as
269 * TLVs. Any malformed TLVs are appended
270 * as raw VP.
271 */
272 while (p < end) {
273 slen = decode_tlv(child_ctx, child_list, child, p, end - p, decode_ctx);
274 if (slen < 0) {
275 FR_PROTO_TRACE("failed decoding TLV?");
276 goto remainder_raw;
277 }
278 p += slen;
279 }
280
281 goto done;
282
283 /*
284 * The child is a union, it MUST be at the end of
285 * the struct, and we must have seen a key before
286 * we reach the union. See dict_tokenize.
287 */
288 case FR_TYPE_UNION:
289 /*
290 * Create the union wrapper, and reset the child_ctx and child_list to it.
291 */
292 vp = fr_pair_afrom_da(child_ctx, child);
293 if (!vp) goto oom;
295
296 fr_pair_append(child_list, vp);
297 substruct_da = child;
298 child_ctx = vp;
299 child_list = &vp->vp_group;
300
301 fr_assert(!fr_dict_attr_child_by_num(parent, child_num + 1)); /* has to be the last one */
302 if (!key_vp) {
303 remainder_raw:
304 child_length = (size_t) (end - p);
305 goto raw;
306 }
307
308 goto substruct;
309 }
310
311 /*
312 * Magic values get the callback called.
313 *
314 * @todo - if this is an array of DNS labels, we
315 * need to do decompression checks on the entire
316 * block, and then decode each field
317 * individually.
318 */
319 if (child->flags.array) {
320 slen = fr_pair_array_from_network(child_ctx, child_list, child, p, child_length, decode_ctx, decode_value);
321 } else {
322 slen = decode_value(child_ctx, child_list, child, p, child_length, decode_ctx);
323 }
324 if (slen < 0) {
325 FR_PROTO_TRACE("Failed decoding value");
326
327 raw:
328 slen = fr_pair_raw_from_network(child_ctx, child_list, child, p, child_length);
329 if (slen < 0) {
330 talloc_free(struct_vp);
331 return slen;
332 }
333 }
334
335 p += slen; /* not always the same as child->flags.length */
336
337 if (fr_dict_attr_is_key_field(child)) {
338 fr_assert(!key_vp);
339 key_vp = fr_pair_list_tail(child_list);
340 }
341 }
342
343 /*
344 * Is there a substructure after this one? If so, go
345 * decode it.
346 */
347 if (key_vp) {
348 fr_dict_enum_value_t const *enumv;
349
350 substruct_da = key_vp->da;
351
352 substruct:
353 child = NULL;
354
355 FR_PROTO_TRACE("Key %s", key_vp->da->name);
356 FR_PROTO_HEX_DUMP(p, (end - p), "fr_struct_from_network - child structure");
357
358 /*
359 * Nothing more to decode, don't decode it.
360 */
361 if (p >= end) {
362 FR_PROTO_TRACE("Expected substruct, but there is none. We're done decoding this structure");
363 goto done;
364 }
365
366 enumv = fr_dict_enum_by_value(key_vp->da, &key_vp->data);
367 if (enumv) child = fr_dict_enum_attr_ref(enumv);
368
369 if (!child) {
370 /*
371 * Always encode the unknown child as attribute number 0. Since the unknown
372 * children have no "real" number, and are all unique da's, they are
373 * incomparable. And thus can all be given the same number.
374 */
375 uint64_t attr;
376
377 FR_PROTO_TRACE("No matching child structure found");
378
379 unknown_child:
380 attr = 0;
381
382 /*
383 * But if we have a key field, the unknown attribute number is taken from the
384 * from the key field.
385 */
386 if (fr_type_is_integer(key_vp->vp_type)) {
387 attr = fr_value_box_as_uint64(&key_vp->data);
388 }
389
390 child = fr_dict_attr_unknown_raw_afrom_num(child_ctx, substruct_da, attr);
391 if (!child) {
392 FR_PROTO_TRACE("failed allocating unknown child for key VP %s - %s",
393 key_vp->da->name, fr_strerror());
394 goto oom;
395 }
396
397 slen = fr_pair_raw_from_network(child_ctx, child_list, child, p, end - p);
398 if (slen < 0) {
399 FR_PROTO_TRACE("Failed creating raw VP from malformed or unknown substruct for child %s", child->name);
401 return slen;
402 }
403
404 p = end;
405
406 } else {
407 switch (child->type) {
408 case FR_TYPE_STRUCT:
409 FR_PROTO_TRACE("Decoding child structure %s", child->name);
410 slen = fr_struct_from_network(child_ctx, child_list, child, p, end - p,
411 decode_ctx, decode_value, decode_tlv);
412 break;
413
414 case FR_TYPE_TLV:
415 if (!decode_tlv) {
416 FR_PROTO_TRACE("Failed to pass decode_tlv() for child tlv %s", child->name);
417 goto unknown_child;
418 }
419
420 FR_PROTO_TRACE("Decoding child tlv %s", child->name);
421
422 slen = decode_tlv(child_ctx, child_list, child, p, end - p, decode_ctx);
423 break;
424
425 case FR_TYPE_LEAF:
427
428 FR_PROTO_TRACE("Decoding child %s", child->name);
429
430 /*
431 * @todo - unify this code with the code above, but for now copying is
432 * easier.
433 */
434
435 /*
436 * The child is either unknown width, OR known width with a length that is too large for
437 * the "length" field, OR is known width via some kind of protocol-specific length header.
438 */
439 if (!child->flags.length || child->flags.array) {
440 child_length = end - p;
441
442 } else {
443 child_length = child->flags.length;
444
445 /*
446 * If this field overflows the input, then *all*
447 * of the input is suspect.
448 */
449 if (child_length > (size_t) (end - p)) {
450 FR_PROTO_TRACE("fr_struct_from_network - child length %zu overflows buffer", child_length);
451 goto remainder_raw;
452 }
453 }
454
455 if (child->flags.array) {
456 slen = fr_pair_array_from_network(child_ctx, child_list, child, p, child_length, decode_ctx, decode_value);
457 } else {
458 slen = decode_value(child_ctx, child_list, child, p, child_length, decode_ctx);
459 }
460 break;
461
462 default:
463 FR_PROTO_TRACE("Unknown data type %s in child %s", fr_type_to_str(child->type), child->name);
464 goto unknown_child;
465 }
466
467 if (slen <= 0) {
468 FR_PROTO_TRACE("failed decoding child %s", child->name);
469 goto unknown_child;
470 }
471 p += slen;
472 }
473
475 }
476
477done:
478 fr_assert(struct_vp != NULL);
479 fr_pair_append(out, struct_vp);
480
481 FR_PROTO_TRACE("used %zu bytes", data_len);
482 return p - data;
483}
484
485
486/** Put bits into an output dbuff
487 *
488 * @param dbuff where the bytes go
489 * @param p where leftover bits go
490 * @param start_bit start bit in the dbuff where the data goes, 0..7
491 * @param num_bits number of bits to write to the output, 0..55
492 * @param data data to write, all in the lower "num_bits" of the uint64_t variable
493 * @return
494 * >= 0 the next value to pass in for start_bit
495 * < 0 no space or invalid start_bit or num_bits parameter
496 */
497static int put_bits_dbuff(fr_dbuff_t *dbuff, uint8_t *p, int start_bit, uint8_t num_bits, uint64_t data)
498{
499 uint64_t used_bits;
500
501 if (start_bit < 0 || start_bit > 7) return -1;
502 if (num_bits < 1 || num_bits > 56) return -1;
503
504 /* Get bits buffered in *p */
505 used_bits = *p & (-256 >> start_bit);
506
507 /* Mask out all but the least significant num_bits bits of data */
508 data &= (((uint64_t) 1) << num_bits) - 1;
509
510 /* Move it towards the most significant end and put used_bits at the top */
511 data <<= (64 - (start_bit + num_bits));
512 data |= used_bits << 56;
513
514 data = htonll(data);
515
516 start_bit += num_bits;
517 if (start_bit > 7) FR_DBUFF_IN_MEMCPY_RETURN(dbuff, (uint8_t const *) &data, (size_t)(start_bit / 8));
518
519 *p = ((uint8_t *) &data)[start_bit / 8];
520 return start_bit % 8;
521}
522
523static int8_t pair_sort_increasing(void const *a, void const *b)
524{
525 fr_pair_t const *my_a = a;
526 fr_pair_t const *my_b = b;
527 int8_t ret;
528
529 /*
530 * Deeper attributes come later in the list.
531 */
532 ret = CMP_PREFER_SMALLER(my_a->da->depth, my_b->da->depth);
533 if (ret != 0) return ret;
534
535 return CMP_PREFER_SMALLER(my_a->da->attr, my_b->da->attr);
536}
537
538static void *struct_next_encodable(fr_dcursor_t *cursor, void *current, void *uctx)
539{
540 fr_pair_t *c = current;
541 fr_dict_attr_t *parent = talloc_get_type_abort(uctx, fr_dict_attr_t);
542
543 while ((c = fr_dlist_next(cursor->dlist, c))) {
544 PAIR_VERIFY(c);
545
546 if (c->da->dict != parent->dict || c->da->flags.internal) continue;
547 break;
548 }
549
550 return c;
551}
552
553static ssize_t encode_tlv(fr_dbuff_t *dbuff, fr_dict_attr_t const *tlv,
554 fr_da_stack_t *da_stack, unsigned int depth,
555 fr_dcursor_t *cursor, void *encode_ctx,
557
558{
559 fr_pair_t *vp;
560 fr_dcursor_t child_cursor;
561 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
562
563 if (!encode_pair) {
564 fr_strerror_printf("Asked to encode child attribute %s, but we were not passed an encoding function",
565 tlv->name);
567 }
568
569 vp = fr_dcursor_current(cursor);
570 if (!vp || (vp->da != tlv)) return 0;
571
572 vp = fr_pair_dcursor_init(&child_cursor, &vp->vp_group);
573 if (vp) {
574 ssize_t slen;
575
576 FR_PROTO_TRACE("fr_struct_to_network trailing TLVs of %s", tlv->name);
577 fr_proto_da_stack_build(da_stack, vp->da);
578 FR_PROTO_STACK_PRINT(da_stack, depth);
579
580 slen = fr_pair_cursor_to_network(&work_dbuff, da_stack, depth + 1, &child_cursor, encode_ctx, encode_pair);
581 if (slen < 0) return slen;
582 }
583
584 return fr_dbuff_set(dbuff, &work_dbuff);
585}
586
587static ssize_t encode_union(fr_dbuff_t *dbuff, fr_dict_attr_t const *wrapper,
588 fr_dict_attr_t const *key_da, fr_pair_t const *key_vp, fr_dbuff_marker_t *key_m,
589 fr_da_stack_t *da_stack, unsigned int depth,
590 fr_dcursor_t *cursor, void *encode_ctx,
592
593{
594 ssize_t slen;
595 fr_pair_t *parent, *child, *found = NULL;
596 fr_dict_attr_t const *child_ref;
597 fr_dcursor_t child_cursor;
598 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
599
600 parent = fr_dcursor_current(cursor);
601 if (!parent || (parent->da != wrapper)) return 0;
602
603 fr_assert(key_vp); /* @todo */
604
605 child = fr_pair_dcursor_init(&child_cursor, &parent->vp_group);
606 if (!child) {
607 /*
608 * @todo - do we want to skip encoding the entire parent structure?
609 */
610 FR_PROTO_TRACE("fr_struct_to_network union %s has no children", key_da->name);
611 return 0;
612 }
613
614 /*
615 * There's a key VP, we find the matching child struct, and then set the cursor to encode just
616 * that child.
617 */
618 if (key_vp) {
619 fr_dict_enum_value_t const *enumv;
620
621 enumv = fr_dict_enum_by_value(key_da, &key_vp->data);
622 if (enumv && ((child_ref = fr_dict_enum_attr_ref(enumv)) != NULL)) {
623 found = fr_pair_find_by_da(&parent->vp_group, NULL, child_ref);
624 if (found) {
625 (void) fr_dcursor_set_current(&child_cursor, found);
626 }
627 }
628 }
629
630 /*
631 * @todo - encode the key field based on the attribute number?
632 *
633 * However, we are likely better off just not doing that.
634 * Which allows us to have the key and UNION contents
635 * disagree.
636 */
637 if (!found && child->da->flags.is_unknown) {
638 fr_assert(child->da->type == FR_TYPE_OCTETS);
639
640 goto encode;
641 }
642
643 /*
644 * No child matching the key vp was found. Either there's no key_vp, or the key_vp doesn't match
645 * the chld we have.
646 *
647 * We then update the key field so that it corresponds to the child that we found.
648 */
649 if (!found) {
650 fr_dict_enum_value_t const *enumv;
652 fr_dbuff_t key_dbuff;
653
654 /*
655 * Root through the enum values, looking for a child ref which matches the child we
656 * found.
657 */
658 for (enumv = fr_dict_enum_iter_init(key_da, &iter);
659 enumv != NULL;
660 enumv = fr_dict_enum_iter_next(key_da, &iter)) {
661 child_ref = fr_dict_enum_attr_ref(enumv);
662 if (!child_ref) continue;
663
664 if (child_ref == child->da) break;
665 }
666
667 /*
668 * There's a child, but no matching enum. That's a fatal error of the dictionary
669 * tokenizer.
670 */
671 if (!fr_cond_assert(enumv)) return PAIR_ENCODE_FATAL_ERROR;
672
673 /*
674 * Create a dbuff for the key, and encode the key.
675 *
676 * Note that enumv->value->vb_length is NOT set. That field is really only used for
677 * string / octet data types.
678 */
679 fr_assert(key_da->flags.length >= 1);
680 fr_assert(key_da->flags.length <= 4);
681
682 FR_DBUFF_INIT(&key_dbuff, fr_dbuff_current(key_m), (size_t) key_da->flags.length);
683
684 FR_PROTO_TRACE("fr_struct_to_network union %s encoding key %s for child %s",
685 parent->da->name, key_da->name, child->da->name);
686
687 if (fr_value_box_to_network(&key_dbuff, enumv->value) <= 0) return PAIR_ENCODE_FATAL_ERROR;
688 }
689
690 /*
691 * And finally encode the one child.
692 */
693encode:
694 FR_PROTO_TRACE("fr_struct_to_network union %s encoding child %s", parent->da->name, child->da->name);
695 fr_proto_da_stack_build(da_stack, child->da);
696 FR_PROTO_STACK_PRINT(da_stack, depth);
697
698 switch (child->da->type) {
699 case FR_TYPE_STRUCT:
700 slen = fr_struct_to_network(&work_dbuff, da_stack, depth + 2,
701 &child_cursor, encode_ctx, encode_value, encode_pair);
702 break;
703
704 case FR_TYPE_TLV:
705 slen = encode_tlv(&work_dbuff, child->da, da_stack, depth + 2, &child_cursor, encode_ctx, encode_value, encode_pair);
706 break;
707
708 case FR_TYPE_LEAF:
709 slen = encode_value(&work_dbuff, da_stack, depth + 2, &child_cursor, encode_ctx);
710 break;
711
712 default:
713 slen = 0;
714 break;
715 }
716
717 if (slen < 0) return slen;
718
719 /*
720 * @todo - if there is more than one child of the union, that's an error!
721 */
722
723 return fr_dbuff_set(dbuff, &work_dbuff);
724}
725
727 fr_da_stack_t *da_stack, unsigned int depth,
728 fr_dcursor_t *cursor, void *encode_ctx,
730{
731 FR_PROTO_TRACE("fr_struct_to_network encoding key %s", vp->da->name);
732
733 /*
734 * We usually have a keyed struct for the child.
735 */
736 if (vp->vp_type == FR_TYPE_STRUCT) {
737 fr_proto_da_stack_build(da_stack, vp->da);
738 return fr_struct_to_network(dbuff, da_stack, depth + 2, /* note + 2 !!! */
740 }
741
742 /*
743 * If it's not a real child, then it's a raw something.
744 */
745 fr_assert(vp->vp_type == FR_TYPE_OCTETS);
746 fr_assert(vp->da->flags.is_unknown);
747
748 if (fr_value_box_to_network(dbuff, &vp->data) <= 0) return PAIR_ENCODE_FATAL_ERROR;
749 (void) fr_dcursor_next(cursor);
750 return 0;
751}
752
754 fr_da_stack_t *da_stack, unsigned int depth,
755 fr_dcursor_t *parent_cursor, void *encode_ctx,
757{
758 fr_dbuff_t work_dbuff;
760 int offset = 0;
761 unsigned int child_num;
762 bool do_length = false;
763 uint8_t bit_buffer = 0;
764 fr_pair_t const *vp = fr_dcursor_current(parent_cursor);
765 fr_pair_t const *last = NULL;
766 fr_pair_t const *key_vp = NULL;
767 fr_dict_attr_t const *child, *parent, *key_da = NULL;
768 fr_dcursor_t child_cursor, *cursor;
769 size_t prefix_length = 0;
770 ssize_t slen;
771 fr_dbuff_marker_t key_m;
772
773 if (!vp) {
774 fr_strerror_printf("%s: Can't encode empty struct", __FUNCTION__);
776 }
777
779 parent = da_stack->da[depth];
780
781 if (parent->type != FR_TYPE_STRUCT) {
782 fr_strerror_printf("%s: Expected type \"struct\" got \"%s\"", __FUNCTION__,
783 fr_type_to_str(parent->type));
785 }
786
787 /*
788 * If we get passed a struct VP, sort its children.
789 */
790 if (vp->vp_type == FR_TYPE_STRUCT) {
791 fr_pair_t *sorted = fr_dcursor_current(parent_cursor); /* NOT const */
792
793 fr_pair_list_sort(&sorted->vp_group, pair_sort_increasing);
794 fr_pair_dcursor_iter_init(&child_cursor, &sorted->vp_group, struct_next_encodable, parent);
795
796 /*
797 * Build the da_stack for the new structure.
798 */
799 vp = fr_dcursor_current(&child_cursor);
800 fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
801
802 FR_PROTO_TRACE("fr_struct_to_network encoding nested with parent %s", parent->name);
803 cursor = &child_cursor;
804 } else {
805 FR_PROTO_TRACE("fr_struct_to_network encoding flat");
806 cursor = parent_cursor;
807 }
808
809 /*
810 * @todo - if we get a child which *eventually* has the
811 * given parent, then allow encoding of that struct, too.
812 * This allows us to encode structures automatically,
813 * even if key fields are omitted.
814 *
815 * Note that this check catches TLVs which are "flat" and
816 * not nested. We could fix that by adding a special
817 * case, but it's better to just fix everything to handle
818 * nested attributes.
819 */
820 if (vp && (vp->da->parent != parent)) {
821 fr_strerror_printf("%s: Asked to encode %s, but its parent %s is not the expected parent %s",
822 __FUNCTION__, vp->da->name, vp->da->parent->name, parent->name);
824 }
825
826 /*
827 * Some structs are prefixed by a 16-bit length.
828 */
830 work_dbuff = FR_DBUFF(dbuff);
831
832 } else if (da_is_length_field8(parent)) {
833 work_dbuff = FR_DBUFF_MAX(dbuff, UINT8_MAX);
834 fr_dbuff_marker(&hdr, &work_dbuff);
835
836 FR_DBUFF_ADVANCE_RETURN(&work_dbuff, 1);
837 prefix_length = 1;
838 do_length = true;
839
840 } else {
842
843 work_dbuff = FR_DBUFF_MAX(dbuff, UINT16_MAX);
844 fr_dbuff_marker(&hdr, &work_dbuff);
845
846 FR_DBUFF_ADVANCE_RETURN(&work_dbuff, 2);
847 prefix_length = 2;
848 do_length = true;
849 }
850
852
853 /*
854 * Loop over all children.
855 */
856 for (child_num = 1;
857 (child = fr_dict_attr_child_by_num(parent, child_num)) != NULL;
858 child_num++) {
859 /*
860 * The child attributes should be in order. If
861 * they're not, we fill the struct with zeroes.
862 *
863 * The caller will encode TLVs.
864 */
865 FR_PROTO_TRACE("fr_struct_to_network child %s", child->name);
866
867 /*
868 * If the caller specifies a member twice, then we only encode the first member.
869 */
870 while (last && vp && (last->da->parent == vp->da->parent) && (last->da->attr == vp->da->attr)) {
871 fr_assert(last != vp);
872 vp = fr_dcursor_next(cursor);
873 }
874 last = vp;
875
876 /*
877 * The MEMBER may be raw, in which case it is encoded as octets.
878 *
879 * This can happen for the last MEMBER of a struct, such as when the last member is a TLV
880 * or GROUP, and the contents are malformed.
881 *
882 * It can also happen if a middle MEMBER has the right length, but the wrong contents.
883 * e.g. when the contents have to be a well-formed IP prefix, but the prefix values are
884 * out of the permitted range.
885 */
886 if (vp && (vp->da != child) && (vp->da->parent == parent) && (vp->da->attr == child_num)) {
887 fr_assert(vp->vp_raw);
888 fr_assert(vp->vp_type == FR_TYPE_OCTETS);
889 fr_assert(!da_is_bit_field(child));
890
891 goto encode_data; /* we may have a raw entry in an array :( */
892 }
893
894 /*
895 * Remember the key field. Note that we ignore raw key fields.
896 */
897 if (fr_dict_attr_is_key_field(child)) {
898 fr_assert(!key_da);
899
900 key_da = child;
901 key_vp = vp;
902 fr_dbuff_marker(&key_m, &work_dbuff);
903 }
904
905 /*
906 * Skipped a VP, or left one off at the end, fill the struct with zeros.
907 */
908 if (!vp || (vp->da != child)) {
909 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), " no child %s", child->name);
910
911 /*
912 * Zero out the bit field.
913 */
914 if (da_is_bit_field(child)) {
915 offset = put_bits_dbuff(&work_dbuff, &bit_buffer, offset, child->flags.length, 0);
916 if (offset < 0) {
917 fr_strerror_printf("Failed encoding bit field %s", child->name);
918 return offset;
919 }
920 last = NULL;
921 continue;
922 }
923
924 /*
925 * A child TLV is missing, we're done, and we don't encode any data.
926 *
927 * @todo - mark up the TLVs as required?
928 */
929 if (child->type == FR_TYPE_TLV) goto encode_length;
930
931 /*
932 * Zero out the unused field.
933 */
934 FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, child->flags.length);
935
936 /*
937 * We didn't encode the current VP, so it's not the last one.
938 */
939 last = NULL;
940 continue;
941 }
942
943 /*
944 * The 'struct' encoder handles bit fields.
945 * They're just integers, so there's no need to
946 * call the protocol encoder.
947 *
948 * This limitation means that we can't have
949 * encrypted bit fields, but that's fine.
950 */
951 if (da_is_bit_field(child)) {
952 uint64_t value;
953
954 FR_PROTO_TRACE("child %s is a bit field", child->name);
955
956 switch (child->type) {
957 case FR_TYPE_BOOL:
958 value = vp->vp_bool;
959 break;
960
961 case FR_TYPE_UINT8:
962 value = vp->vp_uint8;
963 break;
964
965 case FR_TYPE_UINT16:
966 value = vp->vp_uint16;
967 break;
968
969 case FR_TYPE_UINT32:
970 value = vp->vp_uint32;
971 break;
972
973 case FR_TYPE_UINT64:
974 value = vp->vp_uint64;
975 break;
976
977 default:
978 fr_strerror_const("Invalid bit field");
980 }
981
982 offset = put_bits_dbuff(&work_dbuff, &bit_buffer, offset, child->flags.length, value);
983 if (offset < 0) {
984 fr_strerror_printf("Failed encoding bit field %s", child->name);
985 return offset;
986 }
987
988 /*
989 * We have to go to the next pair manually, as the protocol-specific
990 * encode_value() function will normally go to the next cursor entry.
991 */
992 vp = fr_dcursor_next(cursor);
993 /* We need to continue, there may be more fields to encode */
994
995 goto next;
996 }
997
998 /* Not a bit field; insist that no buffered bits remain. */
999 if (offset != 0) {
1000 leftover_bits:
1001 fr_strerror_const("leftover bits");
1003 }
1004
1005 /*
1006 * Encode child TLVs at the end of a struct.
1007 *
1008 * In order to encode the child TLVs, we need to
1009 * know the length of "T" and "L", and we don't.
1010 * So just let the caller do the work.
1011 */
1012 if (child->type == FR_TYPE_TLV) {
1013 fr_assert(!key_da);
1014
1015 FR_PROTO_TRACE("child %s is a TLV field", child->name);
1016 slen = encode_tlv(&work_dbuff, child, da_stack, depth, cursor,
1018 if (slen < 0) return slen;
1019 goto encode_length;
1020 }
1021
1022 if (child->type == FR_TYPE_UNION) {
1023 FR_PROTO_TRACE("child %s is a UNION field", child->name);
1024
1025 if (!key_da) {
1026 FR_PROTO_TRACE("structure %s is missing key_da", parent->name);
1027 goto encode_length;
1028 }
1029
1030 slen = encode_union(&work_dbuff, child, key_da, key_vp, &key_m, da_stack, depth, cursor,
1032 if (slen < 0) return slen;
1033 goto encode_length;
1034 }
1035
1036 FR_PROTO_TRACE("child %s encode_value", child->name);
1037
1038 /*
1039 * Call the protocol encoder for non-bit fields.
1040 */
1042 fr_proto_da_stack_build(da_stack, child);
1043
1044 if (child->flags.array) {
1045 slen = fr_pair_array_to_network(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx, encode_value);
1046 } else {
1047 slen = encode_value(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx);
1048 }
1049 if (slen < 0) return slen;
1050 vp = fr_dcursor_current(cursor);
1051
1052 next:
1053 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "fr_struct_to_network after child %s", child->name);
1054 }
1055
1056 /* Check for leftover bits */
1057 if (offset != 0) goto leftover_bits;
1058
1059 /*
1060 * Check for keyed data to encode.
1061 */
1062 if (vp && key_da) {
1063 fr_assert((vp->da->parent->type == FR_TYPE_UNION) || (vp->da->parent == key_da) || vp->da->flags.is_unknown || vp->da->flags.is_raw);
1064
1065 slen = encode_keyed_struct(&work_dbuff, vp, da_stack, depth,
1067 if (slen < 0) return slen;
1068 }
1069
1070encode_length:
1071 if (do_length) {
1072 size_t length = fr_dbuff_used(&work_dbuff);
1073
1074#ifdef __COVERITY__
1075 /*
1076 * Coverity somehow can't infer that length
1077 * is at least as long as the prefix, instead
1078 * thinkings it's zero so that it underflows.
1079 * We therefore add a Coverity-only check to
1080 * reassure it.
1081 */
1082 if (length < prefix_length) return PAIR_ENCODE_FATAL_ERROR;
1083#endif
1085 length -= prefix_length;
1086
1087 length += da_length_offset(parent);
1088
1089 if (length > UINT8_MAX) return PAIR_ENCODE_FATAL_ERROR;
1090
1091 (void) fr_dbuff_in(&hdr, (uint8_t) length);
1092 } else {
1093 length -= prefix_length;
1094
1095 length += da_length_offset(parent);
1096
1097 if (length > UINT16_MAX) return PAIR_ENCODE_FATAL_ERROR;
1098
1099 (void) fr_dbuff_in(&hdr, (uint16_t) length);
1100 }
1101 }
1102
1103 /*
1104 * We've encoded the children, so tell the parent cursor
1105 * that we've encoded the parent.
1106 */
1107 if (cursor != parent_cursor) (void) fr_dcursor_next(parent_cursor);
1108
1109 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done fr_struct_to_network");
1110
1111 return fr_dbuff_set(dbuff, &work_dbuff);
1112}
#define RCSID(id)
Definition build.h:487
#define CMP_PREFER_SMALLER(_a, _b)
Evaluates to +1 for a > b, and -1 for a < b.
Definition build.h:104
#define UNUSED
Definition build.h:317
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition dbuff.h:777
#define FR_DBUFF_ADVANCE_RETURN(_dbuff_or_marker, _len)
Advance the 'current' position in dbuff or marker by _len bytes returning if _len is out of range.
Definition dbuff.h:1099
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
Definition dbuff.h:83
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:921
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
Definition dbuff.h:1014
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:908
#define FR_DBUFF_INIT(_out, _start, _len_or_end)
Definition dbuff.h:387
#define FR_DBUFF_MEMSET_RETURN(_dbuff_or_marker, _c, _inlen)
Set _inlen bytes of a dbuff or marker to _c returning if there is insufficient space.
Definition dbuff.h:1519
static uint8_t * fr_dbuff_marker(fr_dbuff_marker_t *m, fr_dbuff_t *dbuff)
Initialises a new marker pointing to the 'current' position of the dbuff.
Definition dbuff.h:1203
#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space.
Definition dbuff.h:1393
#define fr_dbuff_in(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff or marker.
Definition dbuff.h:1578
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:232
#define FR_DBUFF_MAX(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
Definition dbuff.h:311
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:290
static void * fr_dcursor_set_current(fr_dcursor_t *cursor, void *item)
Set the cursor to a specified item.
Definition dcursor.h:355
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:339
fr_dlist_head_t * dlist
Head of the doubly linked list being iterated over.
Definition dcursor.h:94
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:131
ssize_t(* fr_pair_decode_value_t)(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx)
Decode a value from the network into an output fr_pair_list_t.
Definition decode.h:45
#define da_is_length_field16(_da)
Definition dict.h:176
#define da_length_offset(_da)
Definition dict.h:177
fr_dict_enum_value_t const * fr_dict_enum_iter_init(fr_dict_attr_t const *da, fr_dict_enum_iter_t *iter)
Iterate over all enumeration values for an attribute.
Definition dict_util.c:3618
#define da_is_length_field8(_da)
Definition dict.h:175
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Definition dict.h:613
#define da_is_bit_field(_da)
Definition dict.h:173
fr_value_box_t const * value
Enum value (what name maps to).
Definition dict.h:259
fr_dict_enum_value_t const * fr_dict_enum_iter_next(fr_dict_attr_t const *da, fr_dict_enum_iter_t *iter)
Definition dict_util.c:3639
void fr_dict_attr_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
fr_dict_enum_value_t const * fr_dict_enum_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
Lookup the structure representing an enum value in a fr_dict_attr_t.
Definition dict_util.c:3659
#define da_is_length_field(_da)
Definition dict.h:174
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:3597
#define fr_dict_attr_is_key_field(_da)
Definition dict.h:172
Value of an enumerated attribute.
Definition dict.h:255
static fr_dict_attr_t const * fr_dict_enum_attr_ref(fr_dict_enum_value_t const *enumv)
Return the attribute reference associated with an enum.
Definition dict_ext.h:230
Test enumeration values.
Definition dict_test.h:92
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition dlist.h:555
ssize_t(* fr_encode_dbuff_t)(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
Typedefs for simplifying the use and declaration of protocol encoders.
Definition encode.h:37
Stores the state of the current iteration operation.
Definition hash.h:41
#define PAIR_DECODE_OOM
Fatal error - Out of memory.
Definition pair.h:45
#define PAIR_ENCODE_FATAL_ERROR
Fatal encoding error.
Definition pair.h:36
static ssize_t encode_value(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, int depth, fr_dcursor_t *cursor, void *encode_ctx)
Encodes the data portion of an attribute.
Definition encode.c:277
ssize_t fr_pair_decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, UNUSED void *decode_ctx)
Generic decode value.
Definition decode.c:337
ssize_t fr_pair_raw_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *da, uint8_t const *data, size_t data_len)
Create a "raw" pair from malformed network data.
Definition decode.c:79
ssize_t fr_pair_array_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx, fr_pair_decode_value_t decode_value)
Decode an array of values from the network.
Definition decode.c:41
ssize_t fr_pair_array_to_network(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, int depth, fr_dcursor_t *cursor, void *encode_ctx, fr_encode_dbuff_t encode_value)
Encode an array of values from the network.
Definition encode.c:42
ssize_t fr_pair_encode_value(fr_dbuff_t *dbuff, UNUSED fr_da_stack_t *da_stack, UNUSED unsigned int depth, fr_dcursor_t *cursor, UNUSED void *encode_ctx)
Generic encode value.
Definition encode.c:162
ssize_t fr_pair_cursor_to_network(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx, fr_encode_dbuff_t encode_pair)
Definition encode.c:71
talloc_free(reap)
unsigned short uint16_t
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ 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_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
long int ssize_t
unsigned char uint8_t
unsigned long int size_t
#define UINT8_MAX
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
static int encode(bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t id)
Definition bio.c:1259
static unsigned int fr_bytes_from_bits(unsigned int bits)
Convert bits (as in prefix length) to bytes, rounding up.
Definition nbo.h:237
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:703
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1348
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:289
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
void fr_proto_da_stack_build(fr_da_stack_t *stack, fr_dict_attr_t const *da)
Build a complete DA stack from the da back to the root.
Definition proto.c:118
static fr_internal_encode_ctx_t encode_ctx
static ssize_t encode_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, UNUSED void *encode_ctx)
Definition base.c:39
#define decode_value
Definition decode.c:411
#define fr_assert(_expr)
Definition rad_assert.h:38
static rc_request_t * current
static bool done
Definition radclient.c:83
fr_pair_t * vp
static ssize_t encode_keyed_struct(fr_dbuff_t *dbuff, fr_pair_t const *vp, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx, fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
Definition struct.c:726
static ssize_t encode_tlv(fr_dbuff_t *dbuff, fr_dict_attr_t const *tlv, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx, UNUSED fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
Definition struct.c:553
ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *parent_cursor, void *encode_ctx, fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
Definition struct.c:753
static void * struct_next_encodable(fr_dcursor_t *cursor, void *current, void *uctx)
Definition struct.c:538
static ssize_t encode_union(fr_dbuff_t *dbuff, fr_dict_attr_t const *wrapper, fr_dict_attr_t const *key_da, fr_pair_t const *key_vp, fr_dbuff_marker_t *key_m, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx, UNUSED fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
Definition struct.c:587
static int8_t pair_sort_increasing(void const *a, void const *b)
Definition struct.c:523
static int put_bits_dbuff(fr_dbuff_t *dbuff, uint8_t *p, int start_bit, uint8_t num_bits, uint64_t data)
Put bits into an output dbuff.
Definition struct.c:497
ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx, fr_pair_decode_value_t decode_value, fr_pair_decode_value_t decode_tlv)
Convert a STRUCT to one or more VPs.
Definition struct.c:32
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
static ssize_t encode_data(char *p, uint8_t *output, size_t outlen)
#define fr_pair_dcursor_iter_init(_cursor, _list, _iter, _uctx)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition pair.h:585
#define PAIR_ALLOCED(_x)
Definition pair.h:212
#define PAIR_VERIFY(_x)
Definition pair.h:204
void fr_pair_list_sort(fr_pair_list_t *list, fr_cmp_t cmp)
Sort a doubly linked list of fr_pair_ts using merge sort.
fr_pair_t * fr_pair_list_tail(fr_pair_list_t const *list)
Get the tail of a valuepair list.
Definition pair_inline.c:55
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition pair.h:605
static fr_slen_t parent
Definition pair.h:857
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition proto.h:42
#define FR_PROTO_TRACE(_fmt,...)
Definition proto.h:41
#define FR_PROTO_STACK_PRINT(_stack, _depth)
Definition proto.h:44
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Definition proto.h:57
Structure for holding the stack of dictionary attributes being encoded.
Definition proto.h:55
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553
#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
#define FR_TYPE_INTERNAL
Definition types.h:320
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_LEAF
Definition types.h:318
uint64_t fr_value_box_as_uint64(fr_value_box_t const *vb)
Return a uint64_t from a fr_value_box_t.
Definition value.c:4182
ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value)
Encode a single value box, serializing its contents in generic network format.
Definition value.c:1517
static fr_slen_t data
Definition value.h:1326
static size_t char ** out
Definition value.h:1023