return start_bit % 8;
}
+static int8_t pair_sort_increasing(void const *a, void const *b)
+{
+ fr_pair_t const *my_a = a;
+ fr_pair_t const *my_b = b;
+
+ return (my_a->da->attr > my_b->da->attr) - (my_a->da->attr < my_b->da->attr);
+}
+
+
ssize_t fr_struct_to_network(fr_dbuff_t *dbuff,
fr_da_stack_t *da_stack, unsigned int depth,
- fr_cursor_t *cursor, void *encoder_ctx,
+ fr_cursor_t *parent_cursor, void *encoder_ctx,
fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_tlv)
{
fr_dbuff_t work_dbuff = FR_DBUFF_NO_ADVANCE(dbuff);
unsigned int child_num = 1;
bool do_length = false;
uint8_t bit_buffer = 0;
- fr_pair_t const *vp = fr_cursor_current(cursor);
+ fr_pair_t const *vp = fr_cursor_current(parent_cursor);
fr_dict_attr_t const *key_da, *parent, *tlv = NULL;
+ fr_cursor_t child_cursor, *cursor;
if (!vp) {
fr_strerror_printf("%s: Can't encode empty struct", __FUNCTION__);
return -1;
}
+ /*
+ * If we get passed a struct VP, sort it's children.
+ */
+ if (vp->da->type == FR_TYPE_STRUCT) {
+ fr_pair_t *sorted = fr_cursor_current(parent_cursor); /* NOT const */
+
+ fr_pair_list_sort(&sorted->vp_group, pair_sort_increasing);
+ fr_cursor_init(&child_cursor, &sorted->vp_group);
+
+ /*
+ * Always skip the VP containing the struct.
+ *
+ * @todo - do this only on success.
+ */
+ (void) fr_cursor_next(parent_cursor);
+
+ /*
+ * Build the da_stack for the new structure.
+ */
+ vp = fr_cursor_current(&child_cursor);
+ fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
+
+ cursor = &child_cursor;
+ } else {
+ cursor = parent_cursor;
+ }
+
/*
* @todo - if we get a child which *eventually* has the
* given parent, then allow encoding of that struct, too.
}
-static int8_t pair_sort_increasing(void const *a, void const *b)
-{
- fr_pair_t const *my_a = a;
- fr_pair_t const *my_b = b;
-
- return (my_a->da->attr > my_b->da->attr) - (my_a->da->attr < my_b->da->attr);
-}
-
static ssize_t encode_value(fr_dbuff_t *dbuff,
fr_da_stack_t *da_stack, unsigned int depth,
fr_cursor_t *cursor, void *encoder_ctx)
/*
* Pack multiple attributes into into a single option
*/
- if (vp->da->type == FR_TYPE_STRUCT) {
- fr_cursor_t child_cursor;
- fr_pair_t *sorted = fr_cursor_current(cursor); /* NOT const */
-
- fr_assert(vp->da == da);
-
- fr_pair_list_sort(&sorted->vp_group, pair_sort_increasing);
- fr_cursor_init(&child_cursor, &sorted->vp_group);
-
- /*
- * Build the da_stack for the new structure.
- */
- vp = fr_cursor_head(&child_cursor);
- fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
-
+ if ((vp->da->type == FR_TYPE_STRUCT) || (da->type == FR_TYPE_STRUCT)) {
slen = fr_struct_to_network(&work_dbuff, da_stack, depth, cursor, encoder_ctx, encode_value, encode_tlv);
if (slen <= 0) return slen;
- (void) fr_cursor_next(cursor); /* skip the VP containing the struct */
-
/*
* Rebuild the da_stack for the next option.
*/
return fr_dbuff_set(dbuff, &work_dbuff);
}
- /*
- * If there's a struct on the da_stack, then the struct
- * members MUST be in a flat list.
- */
- if (da->type == FR_TYPE_STRUCT) {
- slen = fr_struct_to_network(&work_dbuff, da_stack, depth, cursor, encoder_ctx, encode_value, encode_tlv);
- if (slen <= 0) return slen;
-
- vp = fr_cursor_current(cursor);
- fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
- return fr_dbuff_set(dbuff, &work_dbuff);
- }
-
/*
* If it's not a TLV, it should be a value type RFC
* attribute make sure that it is.
/*
* This has special requirements.
*/
- if (vp->da->type == FR_TYPE_STRUCT) {
- fr_cursor_t child_cursor;
-
- fr_assert(vp->da == da);
-
- fr_cursor_init(&child_cursor, &vp->vp_group);
-
- slen = fr_struct_to_network(&work_dbuff, da_stack, depth, &child_cursor, encoder_ctx, encode_value,
- encode_tlv_hdr_internal);
- if (slen <= 0) return slen;
-
- /*
- * Skip the attribute we just encoded, and re-build the da_stack.
- */
- vp = fr_cursor_next(cursor);
- fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
- return fr_dbuff_set(dbuff, &work_dbuff);
- }
-
- /*
- * Old-style struct fields in a flat list.
- */
- if (da->type == FR_TYPE_STRUCT) {
+ if ((vp->da->type == FR_TYPE_STRUCT) || (da->type == FR_TYPE_STRUCT)) {
slen = fr_struct_to_network(&work_dbuff, da_stack, depth, cursor, encoder_ctx, encode_value,
encode_tlv_hdr_internal);
if (slen <= 0) return slen;