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: 36d83e439cc1a191853f0a1878942be5b8a7a419 $")
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;
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
47 if (data_len == 0) {
48 fr_strerror_const("struct decoder was passed zero bytes of data");
49 return -1; /* at least one byte of data */
50 }
51
52 FR_PROTO_HEX_DUMP(data, data_len, "fr_struct_from_network");
53
54 /*
55 * Start a child list.
56 */
58
59 struct_vp = fr_pair_afrom_da(ctx, parent);
60 if (!struct_vp) {
61 fr_strerror_const("out of memory");
62 return -1;
63 }
64
65 fr_pair_list_init(&child_list_head); /* still used elsewhere */
66 child_list = &struct_vp->vp_group;
67 child_ctx = struct_vp;
68 child_num = 1;
69 key_vp = NULL;
70
71 /*
72 * Decode structs with length prefixes.
73 */
75 size_t claimed_len, field_len, calc_len;
76
77 /*
78 * Set how many bytes there are in the "length" field.
79 */
80 if (parent->flags.subtype == FLAG_LENGTH_UINT8) {
81 field_len = 1;
82 } else {
83 field_len = 2;
84 }
85
86 if ((size_t) (end - p) < field_len) {
87 FR_PROTO_TRACE("Insufficient room for length field");
88 goto unknown;
89 }
90
91 claimed_len = p[0];
92 if (field_len > 1) {
93 claimed_len <<= 8;
94 claimed_len |= p[1];
95 }
96 p += field_len;
97
98 if (claimed_len < da_length_offset(parent)) {
99 FR_PROTO_TRACE("Length header (%zu) is smaller than minimum value (%u)",
100 claimed_len, parent->flags.type_size);
101 goto unknown;
102 }
103
104 /*
105 * Get the calculated length of the actual data.
106 */
107 calc_len = claimed_len - da_length_offset(parent);
108
109 if (calc_len > (size_t) (end - p)) {
110 FR_PROTO_TRACE("Length header (%zu) is larger than remaining data (%zu)",
111 claimed_len + field_len, (size_t) (end - p));
112 goto unknown;
113 }
114
115 /*
116 * Limit the size of the decoded structure to the correct length.
117 */
118 data_len = calc_len;
119 end = p + data_len;
120 }
121
122 /*
123 * @todo - If the struct is truncated on a MEMBER boundary, we silently omit
124 * the trailing members. Maybe this should be an error?
125 */
126 while (p < end) {
127 size_t child_length;
128
129 /*
130 * Go to the next child. If it doesn't exist, we're done.
131 */
132 child = fr_dict_attr_child_by_num(parent, child_num);
133 if (!child) break;
134
135 FR_PROTO_HEX_DUMP(p, (end - p), "fr_struct_from_network - child %s (%d)", child->name, child->attr);
136
137 /*
138 * Check for bit fields.
139 */
140 if (da_is_bit_field(child)) {
141 uint8_t array[8];
142 unsigned int num_bits;
143 uint64_t value;
144
145 num_bits = offset + child->flags.length;
146 if ((size_t)(end - p) < fr_bytes_from_bits(num_bits)) {
147 FR_PROTO_TRACE("not enough data for bit decoder?");
148 goto unknown;
149 }
150
151 memset(array, 0, sizeof(array));
152 memcpy(&array[0], p, fr_bytes_from_bits(num_bits));
153
154 if (offset > 0) array[0] &= (1 << (8 - offset)) - 1; /* mask off bits we don't care about */
155
156 memcpy(&value, &array[0], sizeof(value));
157 value = htonll(value);
158 value >>= (8 - offset); /* move it to the lower bits */
159 value >>= (56 - child->flags.length);
160
161 vp = fr_pair_afrom_da(child_ctx, child);
162 if (!vp) {
163 FR_PROTO_TRACE("fr_struct_from_network - failed allocating child VP");
164 return PAIR_DECODE_OOM;
165 }
166
167 switch (child->type) {
168 case FR_TYPE_BOOL:
169 vp->vp_bool = value;
170 break;
171
172 case FR_TYPE_UINT8:
173 vp->vp_uint8 = value;
174 break;
175
176 case FR_TYPE_UINT16:
177 vp->vp_uint16 = value;
178 break;
179
180 case FR_TYPE_UINT32:
181 vp->vp_uint32 = value;
182 break;
183
184 case FR_TYPE_UINT64:
185 vp->vp_uint64 = value;
186 break;
187
188 default:
189 FR_PROTO_TRACE("Can't decode unknown type?");
190 goto unknown;
191 }
192
193 vp->vp_tainted = true;
194 fr_pair_append(child_list, vp);
195 p += (num_bits >> 3); /* go to the LAST bit, not the byte AFTER the last bit */
196 offset = num_bits & 0x07;
197 child_num++;
198 continue;
199 }
200 offset = 0; /* reset for non-bit-field attributes */
201
202 /*
203 * Decode child TLVs, according to the parent attribute.
204 */
205 if (child->type == FR_TYPE_TLV) {
206 fr_assert(!key_vp);
207
208 if (!decode_tlv) {
209 fr_strerror_const("Decoding TLVs requires a decode_tlv() function to be passed");
210 return -(p - data);
211 }
212
213 /*
214 * Decode EVERYTHING as a TLV.
215 */
216 while (p < end) {
217 slen = decode_tlv(child_ctx, child_list, child, p, end - p, decode_ctx);
218 if (slen < 0) {
219 FR_PROTO_TRACE("failed decoding TLV?");
220 goto unknown;
221 }
222 p += slen;
223 }
224
225 goto done;
226 }
227
228 child_length = child->flags.length;
229
230 /*
231 * If this field overflows the input, then *all*
232 * of the input is suspect.
233 */
234 if (child_length > (size_t) (end - p)) {
235 FR_PROTO_TRACE("fr_struct_from_network - child length %zu overflows buffer", child_length);
236 goto unknown;
237 }
238
239 /*
240 * The child is variable sized, OR it's an array.
241 * Eat up the rest of the data.
242 */
243 if (!child_length || (child->flags.array)) {
244 child_length = end - p;
245
246 } else if ((size_t) (end - p) < child_length) {
247 FR_PROTO_TRACE("fr_struct_from_network - child length %zu underflows buffer", child_length);
248 goto unknown;
249 }
250
251 /*
252 * Magic values get the callback called.
253 *
254 * @todo - if this is an array of DNS labels, we
255 * need to do decompression checks on the entire
256 * block, and then decode each field
257 * individually.
258 */
259 if (decode_value) {
260 if (child->flags.array) {
261 slen = fr_pair_array_from_network(child_ctx, child_list, child, p, child_length, decode_ctx, decode_value);
262 } else {
263 slen = decode_value(child_ctx, child_list, child, p, child_length, decode_ctx);
264 }
265 if (slen < 0) {
266 FR_PROTO_TRACE("Failed decoding value");
267 goto unknown;
268 }
269
270 p += slen; /* not always the same as child->flags.length */
271 child_num++; /* go to the next child */
272 if (fr_dict_attr_is_key_field(child)) key_vp = fr_pair_list_tail(child_list);
273 continue;
274 }
275
276 /*
277 * We only allow a limited number of data types
278 * inside of a struct.
279 */
280 switch (child->type) {
281 default:
282 FR_PROTO_TRACE("fr_struct_from_network - unknown child type");
283 goto unknown;
284
285 case FR_TYPE_LEAF:
286 break;
287 }
288
289 /*
290 * We don't handle this yet here.
291 */
292 fr_assert(!child->flags.array);
293
294 vp = fr_pair_afrom_da(child_ctx, child);
295 if (!vp) {
296 FR_PROTO_TRACE("fr_struct_from_network - failed allocating child VP");
297 goto unknown;
298 }
299
300 /*
301 * No protocol-specific data types here (yet).
302 *
303 * If we can't decode this field, then the entire
304 * structure is treated as a raw blob.
305 */
306 if (fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
307 &FR_DBUFF_TMP(p, child_length), child_length, true) < 0) {
308 FR_PROTO_TRACE("fr_struct_from_network - failed decoding child VP %s", vp->da->name);
310 unknown:
311 TALLOC_FREE(struct_vp);
312
313 slen = fr_pair_raw_from_network(ctx, out, parent, data, data_len);
314 if (slen < 0) return slen;
315 return data_len;
316 }
317
318 vp->vp_tainted = true;
319 fr_pair_append(child_list, vp);
320
321 if (fr_dict_attr_is_key_field(vp->da)) key_vp = vp;
322
323 /*
324 * Note that we're decoding fixed fields here.
325 * So we skip the input based on the *known*
326 * length, and not on the *decoded* length.
327 */
328 p += child_length;
329 child_num++; /* go to the next child */
330 }
331
332 /*
333 * Is there a substructure after this one? If so, go
334 * decode it.
335 */
336 if (key_vp) {
337 fr_dict_enum_value_t const *enumv;
338 child = NULL;
339
340 FR_PROTO_HEX_DUMP(p, (end - p), "fr_struct_from_network - substruct");
341
342 /*
343 * Nothing more to decode, don't decode it.
344 */
345 if (p >= end) {
346 FR_PROTO_TRACE("Expected substruct, but there is none. We're done decoding this structure");
347 goto done;
348 }
349
350 enumv = fr_dict_enum_by_value(key_vp->da, &key_vp->data);
351 if (enumv) child = enumv->child_struct[0];
352
353 if (!child) {
354 unknown_child:
355 /*
356 * Always encode the unknown child as
357 * attribute number 0. Since the unknown
358 * children have no "real" number, and
359 * are all unique da's, they are
360 * incomparable. And thus can all be
361 * given the same number.
362 */
363 child = fr_dict_attr_unknown_raw_afrom_num(child_ctx, key_vp->da, 0);
364 if (!child) {
365 FR_PROTO_TRACE("failed allocating unknown child for key VP %s - %s",
366 key_vp->da->name, fr_strerror());
367 goto unknown;
368 }
369
370 slen = fr_pair_raw_from_network(child_ctx, child_list, child, p, end - p);
371 if (slen < 0) {
372 FR_PROTO_TRACE("Failed creating raw VP from malformed or unknown substruct for child %s", child->name);
374 return slen;
375 }
376
377 p = end;
378 } else {
379 fr_assert(child->type == FR_TYPE_STRUCT);
380
381 slen = fr_struct_from_network(child_ctx, child_list, child, p, end - p,
382 decode_ctx, decode_value, decode_tlv);
383 if (slen <= 0) {
384 FR_PROTO_TRACE("substruct %s decoding failed", child->name);
385 goto unknown_child;
386 }
387 p += slen;
388 }
389
391 }
392
393done:
394 fr_assert(struct_vp != NULL);
395 fr_pair_append(out, struct_vp);
396
397 FR_PROTO_TRACE("used %zu bytes", data_len);
398 return p - data;
399}
400
401
402/** Put bits into an output dbuff
403 *
404 * @param dbuff where the bytes go
405 * @param p where leftover bits go
406 * @param start_bit start bit in the dbuff where the data goes, 0..7
407 * @param num_bits number of bits to write to the output, 0..55
408 * @param data data to write, all in the lower "num_bits" of the uint64_t variable
409 * @return
410 * >= 0 the next value to pass in for start_bit
411 * < 0 no space or invalid start_bit or num_bits parameter
412 */
413static int put_bits_dbuff(fr_dbuff_t *dbuff, uint8_t *p, int start_bit, uint8_t num_bits, uint64_t data)
414{
415 uint64_t used_bits;
416
417 if (start_bit < 0 || start_bit > 7) return -1;
418 if (num_bits < 1 || num_bits > 56) return -1;
419
420 /* Get bits buffered in *p */
421 used_bits = *p & (-256 >> start_bit);
422
423 /* Mask out all but the least significant num_bits bits of data */
424 data &= (((uint64_t) 1) << num_bits) - 1;
425
426 /* Move it towards the most significant end and put used_bits at the top */
427 data <<= (64 - (start_bit + num_bits));
428 data |= used_bits << 56;
429
430 data = htonll(data);
431
432 start_bit += num_bits;
433 if (start_bit > 7) FR_DBUFF_IN_MEMCPY_RETURN(dbuff, (uint8_t const *) &data, (size_t)(start_bit / 8));
434
435 *p = ((uint8_t *) &data)[start_bit / 8];
436 return start_bit % 8;
437}
438
439static int8_t pair_sort_increasing(void const *a, void const *b)
440{
441 fr_pair_t const *my_a = a;
442 fr_pair_t const *my_b = b;
443 int rcode;
444
445 /*
446 * Deeper attributes come later in the list.
447 */
448 rcode = CMP_PREFER_SMALLER(my_a->da->depth, my_b->da->depth);
449 if (rcode != 0) return rcode;
450
451 return CMP_PREFER_SMALLER(my_a->da->attr, my_b->da->attr);
452}
453
454static void *struct_next_encodable(fr_dlist_head_t *list, void *current, void *uctx)
455{
456 fr_pair_t *c = current;
457 fr_dict_attr_t *parent = talloc_get_type_abort(uctx, fr_dict_attr_t);
458
459 while ((c = fr_dlist_next(list, c))) {
460 PAIR_VERIFY(c);
461
462 if (c->da->dict != parent->dict || c->da->flags.internal) continue;
463 break;
464 }
465
466 return c;
467}
468
470 fr_da_stack_t *da_stack, unsigned int depth,
471 fr_dcursor_t *parent_cursor, void *encode_ctx,
473{
474 fr_dbuff_t work_dbuff;
476 int offset = 0;
477 unsigned int child_num = 1;
478 bool do_length = false;
479 uint8_t bit_buffer = 0;
480 fr_pair_t const *vp = fr_dcursor_current(parent_cursor);
481 fr_dict_attr_t const *key_da, *parent, *tlv = NULL;
482 fr_dcursor_t child_cursor, *cursor;
483 size_t prefix_length = 0;
484
485 if (!vp) {
486 fr_strerror_printf("%s: Can't encode empty struct", __FUNCTION__);
488 }
489
491 parent = da_stack->da[depth];
492
493 if (parent->type != FR_TYPE_STRUCT) {
494 fr_strerror_printf("%s: Expected type \"struct\" got \"%s\"", __FUNCTION__,
495 fr_type_to_str(parent->type));
497 }
498
499 /*
500 * If we get passed a struct VP, sort its children.
501 */
502 if (vp->vp_type == FR_TYPE_STRUCT) {
503 fr_pair_t *sorted = fr_dcursor_current(parent_cursor); /* NOT const */
504
505 fr_pair_list_sort(&sorted->vp_group, pair_sort_increasing);
506 fr_pair_dcursor_iter_init(&child_cursor, &sorted->vp_group, struct_next_encodable, parent);
507
508 /*
509 * Build the da_stack for the new structure.
510 */
511 vp = fr_dcursor_current(&child_cursor);
512 fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
513
514 FR_PROTO_TRACE("fr_struct_to_network encoding nested with parent %s", parent->name);
515 cursor = &child_cursor;
516 } else {
517 FR_PROTO_TRACE("fr_struct_to_network encoding flat");
518 cursor = parent_cursor;
519 }
520
521 /*
522 * @todo - if we get a child which *eventually* has the
523 * given parent, then allow encoding of that struct, too.
524 * This allows us to encode structures automatically,
525 * even if key fields are omitted.
526 *
527 * Note that this check catches TLVs which are "flat" and
528 * not nested. We could fix that by adding a special
529 * case, but it's better to just fix everything to handle
530 * nested attributes.
531 */
532 if (vp && (vp->da->parent != parent)) {
533 fr_strerror_printf("%s: Asked to encode %s, but its parent %s is not the expected parent %s",
534 __FUNCTION__, vp->da->name, vp->da->parent->name, parent->name);
536 }
537
538 key_da = NULL;
539
540 /*
541 * Some structs are prefixed by a 16-bit length.
542 */
544 work_dbuff = FR_DBUFF(dbuff);
545 } else {
546 if (parent->flags.subtype == FLAG_LENGTH_UINT8) {
547 work_dbuff = FR_DBUFF_MAX(dbuff, 256);
548 fr_dbuff_marker(&hdr, &work_dbuff);
549
550 FR_DBUFF_ADVANCE_RETURN(&work_dbuff, 1);
551 prefix_length = 1;
552 } else {
553 work_dbuff = FR_DBUFF_MAX(dbuff, 65536);
554 fr_dbuff_marker(&hdr, &work_dbuff);
555
556 FR_DBUFF_ADVANCE_RETURN(&work_dbuff, 2);
557 prefix_length = 2;
558 }
559 do_length = true;
560 }
561
562 for (;;) {
563 fr_dict_attr_t const *child;
564
565 /*
566 * The child attributes should be in order. If
567 * they're not, we fill the struct with zeroes.
568 *
569 * The caller will encode TLVs.
570 */
571 child = fr_dict_attr_child_by_num(parent, child_num);
572 if (!child) break;
573
574 FR_PROTO_TRACE("fr_struct_to_network child %s", child->name);
575
576 /*
577 * Encode child TLVs at the end of a struct.
578 *
579 * In order to encode the child TLVs, we need to
580 * know the length of "T" and "L", and we don't.
581 * So just let the caller do the work.
582 */
583 if (child->type == FR_TYPE_TLV) {
584 if (offset != 0) goto leftover_bits;
585
586 fr_assert(!key_da);
587
588 tlv = child;
589 goto done;
590 }
591
592 /*
593 * The MEMBER may be raw, in which case it is encoded as octets.
594 *
595 * This can happen for the last MEMBER of a struct, such as when the last member is a TLV
596 * or GROUP, and the contents are malformed.
597 *
598 * It can also happen if a middle MEMBER has the right length, but the wrong contents.
599 * e.g. when the contents have to be a well-formed IP prefix, but the prefix values are
600 * out of the permitted range.
601 */
602 if (vp && (vp->da != child) && (vp->da->parent == parent) && (vp->da->attr == child_num)) {
603 fr_assert(vp->vp_raw);
604 fr_assert(vp->vp_type == FR_TYPE_OCTETS);
605 fr_assert(!da_is_bit_field(child));
606
607 goto raw;
608 }
609
610 /*
611 * Skipped a VP, or left one off at the end, fill the struct with zeros.
612 */
613 if (!vp || (vp->da != child)) {
614 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), " no child %s", child->name);
615
616 /*
617 * Zero out the bit field.
618 */
619 if (da_is_bit_field(child)) {
620 offset = put_bits_dbuff(&work_dbuff, &bit_buffer, offset, child->flags.length, 0);
621 if (offset < 0) {
622 fr_strerror_printf("Failed encoding bit field %s", child->name);
623 return offset;
624 }
625 child_num++;
626 continue;
627 }
628
629 if (fr_dict_attr_is_key_field(child)) {
630 key_da = child;
631 }
632
633 /*
634 * Zero out the unused field.
635 */
636 FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, child->flags.length);
637 child_num++;
638 continue;
639 }
640
641 /*
642 * The 'struct' encoder handles bit fields.
643 * They're just integers, so there's no need to
644 * call the protocol encoder.
645 *
646 * This limitation means that we can't have
647 * encrypted bit fields, but that's fine.
648 */
649 if (da_is_bit_field(child)) {
650 uint64_t value;
651
652 switch (child->type) {
653 case FR_TYPE_BOOL:
654 value = vp->vp_bool;
655 break;
656
657 case FR_TYPE_UINT8:
658 value = vp->vp_uint8;
659 break;
660
661 case FR_TYPE_UINT16:
662 value = vp->vp_uint16;
663 break;
664
665 case FR_TYPE_UINT32:
666 value = vp->vp_uint32;
667 break;
668
669 case FR_TYPE_UINT64:
670 value = vp->vp_uint64;
671 break;
672
673 default:
674 fr_strerror_const("Invalid bit field");
676 }
677
678 offset = put_bits_dbuff(&work_dbuff, &bit_buffer, offset, child->flags.length, value);
679 if (offset < 0) {
680 fr_strerror_printf("Failed encoding bit field %s", child->name);
681 return offset;
682 }
683
684 vp = fr_dcursor_next(cursor);
685 /* We need to continue, there may be more fields to encode */
686
687 goto next;
688 }
689
690 /* Not a bit field; insist that no buffered bits remain. */
691 if (offset != 0) {
692 leftover_bits:
693 fr_strerror_const("leftover bits");
695 }
696
697 /*
698 * Remember key_da before we do any encoding.
699 */
700 if (fr_dict_attr_is_key_field(child)) {
701 key_da = child;
702 }
703
704 if (encode_value) {
705 ssize_t len;
706 /*
707 * Call the protocol encoder for non-bit fields.
708 */
709 fr_proto_da_stack_build(da_stack, child);
710
711 if (child->flags.array) {
712 len = fr_pair_array_to_network(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx, encode_value);
713 } else {
714 len = encode_value(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx);
715 }
716 if (len < 0) return len;
717 vp = fr_dcursor_current(cursor);
718
719 } else {
720 redo:
721 /*
722 * Hack until we find all places that don't set data.enumv
723 */
724 if (vp->da->flags.length && (vp->data.enumv != vp->da)) {
725 fr_dict_attr_t const * const *c = &vp->data.enumv;
726 fr_dict_attr_t **u;
727
728 memcpy(&u, &c, sizeof(c)); /* const issues */
729 memcpy(u, &vp->da, sizeof(vp->da));
730 }
731
732 /*
733 * Determine the nested type and call the appropriate encoder
734 */
735 raw:
736 if (fr_value_box_to_network(&work_dbuff, &vp->data) <= 0) return PAIR_ENCODE_FATAL_ERROR;
737
738 vp = fr_dcursor_next(cursor);
739 if (!vp) break;
740
741 if (child->flags.array && (vp->da == child)) goto redo;
742 }
743
744 next:
745 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "fr_struct_to_network after child %s", child->name);
746 child_num++;
747 }
748
749 /* Check for leftover bits */
750 if (offset != 0) goto leftover_bits;
751
752 /*
753 * Check for keyed data to encode.
754 */
755 if (vp && key_da) {
756 FR_PROTO_TRACE("fr_struct_to_network encoding key %s", key_da->name);
757
758 /*
759 * If our parent is a struct, AND its parent is
760 * the key_da, then we have a keyed struct for
761 * the child. Go encode it.
762 *
763 * This check is really for "nested" VPs.
764 */
765 if ((vp->da->parent == key_da) &&
766 (vp->vp_type == FR_TYPE_STRUCT)) {
767 ssize_t len;
768 fr_proto_da_stack_build(da_stack, vp->da);
769
770 len = fr_struct_to_network(&work_dbuff, da_stack, depth + 2, /* note + 2 !!! */
772 if (len < 0) return len;
773 goto done;
774 }
775
776 /*
777 * If our parent is a struct, AND its parent is
778 * the key_da, then we have a keyed struct for
779 * the child. Go encode it.
780 *
781 * This check is really for "flat" VPs.
782 */
783 if ((vp->da->parent->parent == key_da) &&
784 (vp->da->parent->type == FR_TYPE_STRUCT)) {
785 ssize_t len;
786 fr_proto_da_stack_build(da_stack, vp->da->parent);
787
788 len = fr_struct_to_network(&work_dbuff, da_stack, depth + 2, /* note + 2 !!! */
790 if (len < 0) return len;
791 goto done;
792 }
793
794 /*
795 * The next VP is likely octets and unknown.
796 */
797 if ((vp->da->parent == key_da) &&
798 (vp->vp_type != FR_TYPE_TLV)) {
799 if (fr_value_box_to_network(&work_dbuff, &vp->data) <= 0) return PAIR_ENCODE_FATAL_ERROR;
800 (void) fr_dcursor_next(cursor);
801 goto done;
802 }
803
804 /*
805 * We have no idea what to do. Ignore it.
806 */
807 }
808
809done:
810 vp = fr_dcursor_current(cursor);
811 if (tlv && vp && (vp->da == tlv) && encode_pair) {
812 ssize_t slen;
813 fr_dcursor_t tlv_cursor;
814
815 if (!encode_pair) {
816 fr_strerror_printf("Asked to encode child attribute %s, but we were not passed an encoding function",
817 tlv->name);
819 }
820
822
823 vp = fr_pair_dcursor_init(&tlv_cursor, &vp->vp_group);
824 if (vp) {
825 FR_PROTO_TRACE("fr_struct_to_network trailing TLVs of %s", tlv->name);
826 fr_proto_da_stack_build(da_stack, vp->da);
827 FR_PROTO_STACK_PRINT(da_stack, depth);
828
829 slen = fr_pair_cursor_to_network(&work_dbuff, da_stack, depth + 1, &tlv_cursor, encode_ctx, encode_pair);
830 if (slen < 0) return slen;
831 }
832 }
833
834 if (do_length) {
835 size_t length = fr_dbuff_used(&work_dbuff);
836
837#ifdef __COVERITY__
838 /*
839 * Coverity somehow can't infer that length
840 * is at least as long as the prefix, instead
841 * thinkings it's zero so that it underflows.
842 * We therefore add a Coverity-only check to
843 * reassure it.
844 */
845 if (length < prefix_length) return PAIR_ENCODE_FATAL_ERROR;
846#endif
847 if (parent->flags.subtype == FLAG_LENGTH_UINT8) {
848 length -= prefix_length;
849
850 length += da_length_offset(parent);
851
852 if (length > UINT8_MAX) return PAIR_ENCODE_FATAL_ERROR;
853
854 (void) fr_dbuff_in(&hdr, (uint8_t) length);
855 } else {
856 length -= prefix_length;
857
858 length += da_length_offset(parent);
859
860 if (length > UINT16_MAX) return PAIR_ENCODE_FATAL_ERROR;
861
862 (void) fr_dbuff_in(&hdr, (uint16_t) length);
863 }
864 }
865
866 /*
867 * We've encoded the children, so tell the parent cursor
868 * that we've encoded the parent.
869 */
870 if (cursor != parent_cursor) (void) fr_dcursor_next(parent_cursor);
871
872 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done fr_struct_to_network");
873
874 return fr_dbuff_set(dbuff, &work_dbuff);
875}
#define RCSID(id)
Definition build.h:485
#define CMP_PREFER_SMALLER(_a, _b)
Evaluates to +1 for a > b, and -1 for a < b.
Definition build.h:104
#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:767
#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:1088
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
Definition dbuff.h:81
#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:1004
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:898
#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:1508
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:1192
#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:1382
#define fr_dbuff_in(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff or marker.
Definition dbuff.h:1567
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:222
#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:301
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:514
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:288
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:337
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
fr_dict_enum_value_t * 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:3351
#define da_length_offset(_da)
Definition dict.h:160
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:585
#define da_is_bit_field(_da)
Definition dict.h:158
void fr_dict_attr_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
#define da_is_length_field(_da)
Definition dict.h:159
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:3330
#define fr_dict_attr_is_key_field(_da)
Definition dict.h:157
fr_dict_attr_t const * child_struct[]
for key fields
Definition dict.h:239
@ FLAG_LENGTH_UINT8
string / octets type is prefixed by uint8 of length
Definition dict.h:153
Value of an enumerated attribute.
Definition dict.h:231
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
Head of a doubly linked list.
Definition dlist.h:51
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
#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:272
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_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_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_UINT64
64 Bit unsigned integer.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_OCTETS
Raw octets.
long int ssize_t
unsigned char uint8_t
#define UINT8_MAX
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
static unsigned int fr_bytes_from_bits(unsigned int bits)
Convert bits (as in prefix length) to bytes, rounding up.
Definition nbo.h:237
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:1347
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:285
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:410
#define fr_assert(_expr)
Definition rad_assert.h:38
static rc_request_t * current
static bool done
Definition radclient.c:81
fr_pair_t * vp
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:469
static void * struct_next_encodable(fr_dlist_head_t *list, void *current, void *uctx)
Definition struct.c:454
static int8_t pair_sort_increasing(void const *a, void const *b)
Definition struct.c:439
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:413
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
#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:569
#define PAIR_VERIFY(_x)
Definition pair.h:191
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:591
static fr_slen_t parent
Definition pair.h:845
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition proto.h:41
#define FR_PROTO_TRACE(_fmt,...)
Definition proto.h:40
#define FR_PROTO_STACK_PRINT(_stack, _depth)
Definition proto.h:43
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Definition proto.h:56
Structure for holding the stack of dictionary attributes being encoded.
Definition proto.h:54
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
#define fr_type_is_structural(_x)
Definition types.h:371
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:433
#define FR_TYPE_LEAF
Definition types.h:297
ssize_t fr_value_box_from_network(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, fr_dbuff_t *dbuff, size_t len, bool tainted)
Decode a fr_value_box_t from serialized binary data.
Definition value.c:1800
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:1450
static fr_slen_t data
Definition value.h:1274
static size_t char ** out
Definition value.h:1012