]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
enocders: Create a struct for da_stack which includes depth.
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 26 Mar 2020 22:24:46 +0000 (16:24 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 26 Mar 2020 22:24:46 +0000 (16:24 -0600)
Means we no longer have to memset the entire stack on each rebuild.

src/lib/eap_aka_sim/encode.c
src/lib/server/snmp.c
src/lib/util/dict_print.c
src/lib/util/pair.c
src/lib/util/proto.c
src/lib/util/proto.h
src/lib/util/struct.c
src/lib/util/struct.h
src/protocols/dhcpv4/encode.c
src/protocols/dhcpv6/encode.c
src/protocols/radius/encode.c

index a5f315d08ee1e6b6c7c101a717f22ad4d387a75f..262dddb4fe31aeaba6fcdebd3279c324ff0e214a 100644 (file)
@@ -55,7 +55,7 @@ RCSID("$Id$")
  */
 
 static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
-                             fr_dict_attr_t const **da_stack, unsigned int depth,
+                             fr_da_stack_t *da_stack, unsigned int depth,
                              fr_cursor_t *cursor, void *encoder_ctx);
 
 static inline bool is_encodable(fr_dict_attr_t const *root, VALUE_PAIR *vp)
@@ -295,18 +295,18 @@ static ssize_t encode_encrypted_value(uint8_t *out, size_t outlen,
  *     < 0, failure.
  */
 static ssize_t encode_value(uint8_t *out, size_t outlen,
-                           fr_dict_attr_t const **da_stack, int depth,
+                           fr_da_stack_t *da_stack, int depth,
                            fr_cursor_t *cursor, void *encoder_ctx)
 {
        ssize_t                 len;
        VALUE_PAIR const        *vp = fr_cursor_current(cursor);
-       fr_dict_attr_t const    *da = da_stack[depth];
+       fr_dict_attr_t const    *da = da_stack->da[depth];
        fr_aka_sim_encode_ctx_t *packet_ctx = encoder_ctx;
 
        VP_VERIFY(vp);
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
-       if (unlikely(da_stack[depth + 1] != NULL)) {
+       if (unlikely(da_stack->da[depth + 1] != NULL)) {
                fr_strerror_printf("%s: Encoding value but not at top of stack", __FUNCTION__);
                return PAIR_ENCODE_FATAL_ERROR;
        }
@@ -319,7 +319,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
        switch (da->type) {
        case FR_TYPE_STRUCTURAL:
                fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
-                                  fr_table_str_by_value(fr_value_box_type_table, da_stack[depth]->type, "?Unknown?"));
+                                  fr_table_str_by_value(fr_value_box_type_table, da_stack->da[depth]->type, "?Unknown?"));
                return PAIR_ENCODE_FATAL_ERROR;
 
        default:
@@ -607,7 +607,7 @@ done:
  *
  */
 static ssize_t encode_array(uint8_t *out, size_t outlen,
-                           fr_dict_attr_t const **da_stack, int depth,
+                           fr_da_stack_t *da_stack, int depth,
                            fr_cursor_t *cursor, void *encoder_ctx)
 {
        uint8_t                 *p = out, *end = p + outlen;
@@ -615,7 +615,7 @@ static ssize_t encode_array(uint8_t *out, size_t outlen,
        size_t                  pad_len;
        size_t                  element_len;
        uint16_t                actual_len;
-       fr_dict_attr_t const    *da = da_stack[depth];
+       fr_dict_attr_t const    *da = da_stack->da[depth];
        rad_assert(da->flags.array);
 
        p += 2;
@@ -684,7 +684,7 @@ static ssize_t encode_array(uint8_t *out, size_t outlen,
  * If it's a standard attribute, then vp->da->attr == attribute.
  * Otherwise, attribute may be something else.
  */
-static ssize_t encode_rfc_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const **da_stack, unsigned int depth,
+static ssize_t encode_rfc_hdr(uint8_t *out, size_t outlen, fr_da_stack_t *da_stack, unsigned int depth,
                              fr_cursor_t *cursor, void *encoder_ctx)
 {
        size_t                  pad_len;
@@ -694,17 +694,17 @@ static ssize_t encode_rfc_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const
 
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
-       switch (da_stack[depth]->type) {
+       switch (da_stack->da[depth]->type) {
        case FR_TYPE_STRUCTURAL:
                fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
-                                  fr_table_str_by_value(fr_value_box_type_table, da_stack[depth]->type, "?Unknown?"));
+                                  fr_table_str_by_value(fr_value_box_type_table, da_stack->da[depth]->type, "?Unknown?"));
                return PAIR_ENCODE_FATAL_ERROR;
 
        default:
-               if (((fr_dict_vendor_num_by_da(da_stack[depth]) == 0) && (da_stack[depth]->attr == 0)) ||
-                   (da_stack[depth]->attr > 255)) {
+               if (((fr_dict_vendor_num_by_da(da_stack->da[depth]) == 0) && (da_stack->da[depth]->attr == 0)) ||
+                   (da_stack->da[depth]->attr > 255)) {
                        fr_strerror_printf("%s: Called with non-standard attribute %u", __FUNCTION__,
-                                          da_stack[depth]->attr);
+                                          da_stack->da[depth]->attr);
                        return PAIR_ENCODE_FATAL_ERROR;
                }
                break;
@@ -721,7 +721,7 @@ static ssize_t encode_rfc_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const
         *      zero and fill any subfields like actual
         *      length.
         */
-       da = da_stack[depth];
+       da = da_stack->da[depth];
 
        p += 2; /* Leave space for attr + len */
        if (da->flags.array) {
@@ -752,13 +752,13 @@ static ssize_t encode_rfc_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const
 }
 
 static inline ssize_t encode_tlv_internal(uint8_t *out, size_t outlen,
-                                         fr_dict_attr_t const **da_stack, unsigned int depth,
+                                         fr_da_stack_t *da_stack, unsigned int depth,
                                          fr_cursor_t *cursor, void *encoder_ctx)
 {
        ssize_t                 slen;
        uint8_t                 *p = out, *end = p + outlen, *value;
        VALUE_PAIR const        *vp = fr_cursor_current(cursor);
-       fr_dict_attr_t const    *da = da_stack[depth];
+       fr_dict_attr_t const    *da = da_stack->da[depth];
 
        CHECK_FREESPACE(outlen, 2);
        *p++ = 0;       /* Reserved (0) */
@@ -779,7 +779,7 @@ static inline ssize_t encode_tlv_internal(uint8_t *out, size_t outlen,
                /*
                 *      Determine the nested type and call the appropriate encoder
                 */
-               if (da_stack[depth + 1]->type == FR_TYPE_TLV) {
+               if (da_stack->da[depth + 1]->type == FR_TYPE_TLV) {
                        slen = encode_tlv_hdr(p, sublen, da_stack, depth + 1, cursor, encoder_ctx);
                } else {
                        slen = encode_rfc_hdr(p, sublen, da_stack, depth + 1, cursor, encoder_ctx);
@@ -798,7 +798,7 @@ static inline ssize_t encode_tlv_internal(uint8_t *out, size_t outlen,
                 *      rebuilding the TLV Stack, the attribute
                 *      at this depth is the same.
                 */
-               if (da != da_stack[depth]) break;
+               if ((da != da_stack->da[depth]) || (da_stack->depth < da->depth)) break;
                vp = fr_cursor_current(cursor);
        }
 
@@ -819,7 +819,7 @@ static inline ssize_t encode_tlv_internal(uint8_t *out, size_t outlen,
 }
 
 static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
-                             fr_dict_attr_t const **da_stack, unsigned int depth,
+                             fr_da_stack_t *da_stack, unsigned int depth,
                              fr_cursor_t *cursor, void *encoder_ctx)
 {
        unsigned int            total_len;
@@ -830,13 +830,13 @@ static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
        VP_VERIFY(fr_cursor_current(cursor));
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
-       if (da_stack[depth]->type != FR_TYPE_TLV) {
+       if (da_stack->da[depth]->type != FR_TYPE_TLV) {
                fr_strerror_printf("%s: Expected type \"tlv\" got \"%s\"", __FUNCTION__,
-                                  fr_table_str_by_value(fr_value_box_type_table, da_stack[depth]->type, "?Unknown?"));
+                                  fr_table_str_by_value(fr_value_box_type_table, da_stack->da[depth]->type, "?Unknown?"));
                return PAIR_ENCODE_FATAL_ERROR;
        }
 
-       if (!da_stack[depth + 1]) {
+       if (!da_stack->da[depth + 1]) {
                fr_strerror_printf("%s: Can't encode empty TLV", __FUNCTION__);
                return PAIR_ENCODE_FATAL_ERROR;
        }
@@ -846,7 +846,7 @@ static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
         *      The ASCII art in the RFCs the attributes in
         *      this order.
         */
-       if (!da_stack[depth]->flags.extra && da_stack[depth]->flags.subtype) {
+       if (!da_stack->da[depth]->flags.extra && da_stack->da[depth]->flags.subtype) {
                len = encode_iv(out, outlen, encoder_ctx);
                if (len < 0) return len;
 
@@ -857,7 +857,7 @@ static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
        if (outlen < 4) return 0;
        if (outlen > SIM_MAX_ATTRIBUTE_VALUE_LEN) outlen = SIM_MAX_ATTRIBUTE_VALUE_LEN;
 
-       da = da_stack[depth];
+       da = da_stack->da[depth];
        len = encode_tlv_internal(p + 2, outlen - 2, da_stack, depth, cursor, encoder_ctx);
        if (len <= 0) return len;
 
@@ -882,7 +882,7 @@ ssize_t fr_aka_sim_encode_pair(uint8_t *out, size_t outlen, fr_cursor_t *cursor,
        ssize_t                 slen;
        size_t                  attr_len;
 
-       fr_dict_attr_t const    *da_stack[FR_DICT_MAX_TLV_STACK + 1];
+       fr_da_stack_t           da_stack;
        fr_dict_attr_t const    *da = NULL;
        fr_aka_sim_encode_ctx_t *packet_ctx = encoder_ctx;
 
@@ -916,30 +916,31 @@ ssize_t fr_aka_sim_encode_pair(uint8_t *out, size_t outlen, fr_cursor_t *cursor,
         *      Fast path for the common case.
         */
        if ((vp->da->parent == packet_ctx->root) && !vp->da->flags.concat && (vp->vp_type != FR_TYPE_TLV)) {
-               da_stack[0] = vp->da;
-               da_stack[1] = NULL;
-               FR_PROTO_STACK_PRINT(da_stack, 0);
-               return encode_rfc_hdr(out, attr_len, da_stack, 0, cursor, encoder_ctx);
+               da_stack.da[0] = vp->da;
+               da_stack.da[1] = NULL;
+               da_stack.depth = 1;
+               FR_PROTO_STACK_PRINT(&da_stack, 0);
+               return encode_rfc_hdr(out, attr_len, &da_stack, 0, cursor, encoder_ctx);
        }
 
        /*
         *      Do more work to set up the stack for the complex case.
         */
-       fr_proto_da_stack_build(da_stack, vp->da);
-       FR_PROTO_STACK_PRINT(da_stack, 0);
+       fr_proto_da_stack_build(&da_stack, vp->da);
+       FR_PROTO_STACK_PRINT(&da_stack, 0);
 
-       da = da_stack[0];
+       da = da_stack.da[0];
 
        switch (da->type) {
        /*
         *      Supported types
         */
        default:
-               slen = encode_rfc_hdr(out, attr_len, da_stack, 0, cursor, encoder_ctx);
+               slen = encode_rfc_hdr(out, attr_len, &da_stack, 0, cursor, encoder_ctx);
                break;
 
        case FR_TYPE_TLV:
-               slen = encode_tlv_hdr(out, attr_len, da_stack, 0, cursor, encoder_ctx);
+               slen = encode_tlv_hdr(out, attr_len, &da_stack, 0, cursor, encoder_ctx);
                break;
        }
 
index 3b50b966c846e29dd9f12317b58d323ab13c0c51..6feb84c2bf379c41d6977a7ea054263f6795f9e2 100644 (file)
@@ -458,7 +458,7 @@ static fr_snmp_map_t snmp_iso[] = {
 };
 
 static ssize_t snmp_process(fr_cursor_t *out, REQUEST *request,
-                           fr_dict_attr_t const *da_stack[], unsigned int depth,
+                           fr_da_stack_t *da_stack, unsigned int depth,
                            fr_cursor_t *cursor,
                            fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op);
 
@@ -509,20 +509,20 @@ static fr_snmp_map_t const *snmp_map_search(fr_snmp_map_t const map[], fr_dict_a
  * @param[in] depth at which to start rewriting.
  * @param[in] map at this level.
  */
-static void snmp_next_leaf(fr_dict_attr_t const *da_stack[], unsigned int depth, fr_snmp_map_t const *map)
+static void snmp_next_leaf(fr_da_stack_t *da_stack, unsigned int depth, fr_snmp_map_t const *map)
 {
        uint32_t i;
        fr_snmp_map_t const *map_p = map;
 
        for (i = depth; (i < FR_DICT_MAX_TLV_STACK) && map_p; i++) {
-               da_stack[i] = map_p->da;
+               da_stack->da[i] = map_p->da;
                map_p = map_p->child;
        }
-       da_stack[i] = NULL;
+       da_stack->depth = i;
 }
 
 static ssize_t snmp_process_index(fr_cursor_t *out, REQUEST *request,
-                                 fr_dict_attr_t const *da_stack[], unsigned int depth,
+                                 fr_da_stack_t *da_stack, unsigned int depth,
                                  fr_cursor_t cursor,
                                  fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op,
                                  uint32_t index_num)
@@ -613,7 +613,7 @@ static ssize_t snmp_process_index(fr_cursor_t *out, REQUEST *request,
 }
 
 static ssize_t snmp_process_index_attr(fr_cursor_t *out, REQUEST *request,
-                                      fr_dict_attr_t const *da_stack[], unsigned int depth,
+                                      fr_da_stack_t *da_stack, unsigned int depth,
                                       fr_cursor_t *cursor,
                                       fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
 {
@@ -640,10 +640,10 @@ static ssize_t snmp_process_index_attr(fr_cursor_t *out, REQUEST *request,
                goto error;
        }
 
-       if (da_stack[depth]->type != FR_TYPE_UINT32) {
+       if (da_stack->da[depth]->type != FR_TYPE_UINT32) {
                fr_strerror_printf("Bad index attribute: Index attribute \"%s\" should be a integer, "
-                                  "but is a %s", da_stack[depth]->name,
-                                  fr_table_str_by_value(fr_value_box_type_table, da_stack[depth]->type, "?Unknown?"));
+                                  "but is a %s", da_stack->da[depth]->name,
+                                  fr_table_str_by_value(fr_value_box_type_table, da_stack->da[depth]->type, "?Unknown?"));
                goto error;
        }
 
@@ -672,7 +672,7 @@ static ssize_t snmp_process_index_attr(fr_cursor_t *out, REQUEST *request,
 }
 
 static ssize_t snmp_process_tlv(fr_cursor_t *out, REQUEST *request,
-                               fr_dict_attr_t const *da_stack[], unsigned int depth,
+                               fr_da_stack_t *da_stack, unsigned int depth,
                                fr_cursor_t *cursor,
                                fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
 {
@@ -685,7 +685,7 @@ static ssize_t snmp_process_tlv(fr_cursor_t *out, REQUEST *request,
         *      Return element in map that matches the da at this
         *      level in the da_stack.
         */
-       map_p = snmp_map_search(map, da_stack[depth]);
+       map_p = snmp_map_search(map, da_stack->da[depth]);
        if (!map_p) {
        invalid:
                fr_strerror_printf("Invalid OID: Match stopped here");
@@ -715,7 +715,7 @@ static ssize_t snmp_process_tlv(fr_cursor_t *out, REQUEST *request,
                                          da_stack, depth,
                                          *cursor,
                                          map_p, snmp_ctx, snmp_op,
-                                         da_stack[depth]->attr);
+                                         da_stack->da[depth]->attr);
        }
 
        for (;;) {
@@ -734,7 +734,7 @@ static ssize_t snmp_process_tlv(fr_cursor_t *out, REQUEST *request,
 }
 
 static ssize_t snmp_process_leaf(fr_cursor_t *out, REQUEST *request,
-                                fr_dict_attr_t const *da_stack[], unsigned int depth,
+                                fr_da_stack_t *da_stack, unsigned int depth,
                                 fr_cursor_t *cursor,
                                 fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
 {
@@ -749,7 +749,7 @@ static ssize_t snmp_process_leaf(fr_cursor_t *out, REQUEST *request,
         *      Return element in map that matches the da at this
         *      level in the da_stack.
         */
-       map_p = snmp_map_search(map, da_stack[depth]);
+       map_p = snmp_map_search(map, da_stack->da[depth]);
        if (!map_p) {
                fr_strerror_printf("Invalid OID: Match stopped here");
        error:
@@ -872,7 +872,7 @@ static ssize_t snmp_process_leaf(fr_cursor_t *out, REQUEST *request,
  *     - <0 the depth at which an error occurred, as a negative integer.
  */
 static ssize_t snmp_process(fr_cursor_t *out, REQUEST *request,
-                           fr_dict_attr_t const *da_stack[], unsigned int depth,
+                           fr_da_stack_t *da_stack, unsigned int depth,
                            fr_cursor_t *cursor,
                            fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
 {
@@ -885,7 +885,7 @@ static ssize_t snmp_process(fr_cursor_t *out, REQUEST *request,
         *      we're performing a getNext operation, in which
         *      case we fake the rest of the stack.
         */
-       if (!da_stack[depth]) {
+       if (!da_stack->da[depth]) {
                if (snmp_op != FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT) {
                        fr_strerror_printf("Invalid OID: Not a leaf");
                        return -(ssize_t)(depth - 1);
@@ -897,20 +897,20 @@ static ssize_t snmp_process(fr_cursor_t *out, REQUEST *request,
         *      It's an index attribute, use the value of
         *      the index attribute to traverse the index.
         */
-       if (da_stack[depth]->attr == 0) return snmp_process_index_attr(out, request,
-                                                                       da_stack, depth,
-                                                                       cursor,
-                                                                       map, snmp_ctx, snmp_op);
+       if (da_stack->da[depth]->attr == 0) return snmp_process_index_attr(out, request,
+                                                                          da_stack, depth,
+                                                                          cursor,
+                                                                          map, snmp_ctx, snmp_op);
 
        /*
         *      It's a TLV, recurse, and locate the map
         *      matching the next deepest DA in the
         *      da_stack.
         */
-       if (da_stack[depth]->type == FR_TYPE_TLV) return snmp_process_tlv(out, request,
-                                                                          da_stack, depth,
-                                                                          cursor,
-                                                                          map, snmp_ctx, snmp_op);
+       if (da_stack->da[depth]->type == FR_TYPE_TLV) return snmp_process_tlv(out, request,
+                                                                             da_stack, depth,
+                                                                             cursor,
+                                                                             map, snmp_ctx, snmp_op);
 
        /*
         *      Must be a leaf, call the appropriate get/set function
@@ -930,7 +930,7 @@ int fr_snmp_process(REQUEST *request)
        char                    oid_str[FR_DICT_MAX_TLV_STACK * 4];     /* .<num>{1,3} */
        size_t                  oid_len, len;
 
-       fr_dict_attr_t const    *da_stack[FR_DICT_MAX_TLV_STACK + 1];
+       fr_da_stack_t           da_stack;
        unsigned int            depth;
        ssize_t                 ret;
 
@@ -986,20 +986,20 @@ int fr_snmp_process(REQUEST *request)
        for (vp = fr_cursor_iter_by_ancestor_init(&request_cursor, &request->packet->vps, attr_snmp_root);
             vp;
             vp = fr_cursor_next(&request_cursor)) {
-               fr_proto_da_stack_build(da_stack, vp->da);
+               fr_proto_da_stack_build(&da_stack, vp->da);
 
                /*
                 *      Wind to the frame in the TLV stack that matches our
                 *      SNMP root.
                 */
-               for (depth = 0; da_stack[depth]; depth++) if (attr_snmp_root == da_stack[depth]) break;
+               for (depth = 0; da_stack.da[depth]; depth++) if (attr_snmp_root == da_stack.da[depth]) break;
 
                /*
                 *      Any attribute returned by fr_cursor_next_by_ancestor
                 *      should have the SNMP root attribute as an ancestor.
                 */
-               rad_assert(da_stack[depth]);
-               rad_assert(da_stack[depth] == attr_snmp_root);
+               rad_assert(da_stack.da[depth]);
+               rad_assert(da_stack.da[depth] == attr_snmp_root);
 
                /*
                 *      Operator attribute acts as a request delimiter
@@ -1027,7 +1027,7 @@ int fr_snmp_process(REQUEST *request)
                 *      Returns depth (as negative integer) at which the error occurred
                 */
                ret = snmp_process(&out_cursor, request,
-                                  da_stack, depth,
+                                  &da_stack, depth,
                                   &request_cursor,
                                   snmp_iso, NULL, op->vp_uint32);
                if (ret < 0) {
@@ -1036,11 +1036,10 @@ int fr_snmp_process(REQUEST *request)
                        oid_str[0] = '.';
 
                        /* Get the length of the matching part */
-                       oid_len = fr_dict_print_attr_oid(NULL, oid_str + 1, sizeof(oid_str) - 1, attr_snmp_root, da_stack[-(ret)]);
+                       oid_len = fr_dict_print_attr_oid(NULL, oid_str + 1, sizeof(oid_str) - 1, attr_snmp_root, da_stack.da[-(ret)]);
 
                        /* Get the last frame in the current stack */
-                       for (depth = 0; da_stack[depth + 1]; depth++);
-                       len = fr_dict_print_attr_oid(NULL, oid_str + 1, sizeof(oid_str) - 1, attr_snmp_root, da_stack[depth]);
+                       len = fr_dict_print_attr_oid(NULL, oid_str + 1, sizeof(oid_str) - 1, attr_snmp_root, da_stack.da[da_stack.depth - 1]);
 
                        /* Use the difference in OID string length to place the marker */
                        REMARKER(oid_str, oid_len - (len - oid_len), "%s", fr_strerror());
index 67fb33878b8ff58937258f294bf6afe05e69dd44..6a7999cd7358f3096df864bd97d6d6b769586c3e 100644 (file)
@@ -120,7 +120,7 @@ size_t fr_dict_print_attr_oid(size_t *need, char *out, size_t outlen,
        char                    *p = out, *end = p + outlen;
        int                     i;
        int                     depth = 0;
-       fr_dict_attr_t const    *da_stack[FR_DICT_MAX_TLV_STACK + 1];
+       fr_da_stack_t           da_stack;
 
        RETURN_IF_NO_SPACE_INIT(need, 1, p, out, end);
 
@@ -133,10 +133,10 @@ size_t fr_dict_print_attr_oid(size_t *need, char *out, size_t outlen,
                return 0;
        }
 
-       fr_proto_da_stack_build(da_stack, da);
+       fr_proto_da_stack_build(&da_stack, da);
 
        if (ancestor) {
-               if (da_stack[ancestor->depth - 1] != ancestor) {
+               if (da_stack.da[ancestor->depth - 1] != ancestor) {
                        fr_strerror_printf("Attribute \"%s\" is not a descendent of \"%s\"", da->name, ancestor->name);
                        return -1;
                }
@@ -147,11 +147,11 @@ size_t fr_dict_print_attr_oid(size_t *need, char *out, size_t outlen,
         *      We don't print the ancestor, we print the OID
         *      between it and the da.
         */
-       len = snprintf(p, end - p, "%u", da_stack[depth]->attr);
+       len = snprintf(p, end - p, "%u", da_stack.da[depth]->attr);
        RETURN_IF_TRUNCATED(need, len, p, out, end);
 
        for (i = depth + 1; i < (int)da->depth; i++) {
-               len = snprintf(p, end - p, ".%u", da_stack[i]->attr);
+               len = snprintf(p, end - p, ".%u", da_stack.da[i]->attr);
                RETURN_IF_TRUNCATED(need, len, p, out, end);
        }
 
index d8d99c18e8867be98c447a12404a020b677757b8..83b06a72016e3668e7344a9dd8bcf9b04416eac2 100644 (file)
@@ -831,8 +831,8 @@ int8_t fr_pair_cmp_by_parent_num_tag(void const *a, void const *b)
        VALUE_PAIR const        *vp_b = b;
        fr_dict_attr_t const    *da_a = vp_a->da;
        fr_dict_attr_t const    *da_b = vp_b->da;
-       fr_dict_attr_t const    *da_stack_a[FR_DICT_MAX_TLV_STACK + 1];
-       fr_dict_attr_t const    *da_stack_b[FR_DICT_MAX_TLV_STACK + 1];
+       fr_da_stack_t           da_stack_a;
+       fr_da_stack_t           da_stack_b;
        int i;
 
        /*
@@ -841,10 +841,10 @@ int8_t fr_pair_cmp_by_parent_num_tag(void const *a, void const *b)
         */
        if ((da_a->parent->flags.is_root) && (da_b->parent->flags.is_root)) return pair_cmp_by_num_tag(vp_a, vp_b);
 
-       fr_proto_da_stack_build(da_stack_a, da_a);
-       fr_proto_da_stack_build(da_stack_b, da_b);
+       fr_proto_da_stack_build(&da_stack_a, da_a);
+       fr_proto_da_stack_build(&da_stack_b, da_b);
 
-       for (i = 0; (da_a = da_stack_a[i]) && (da_b = da_stack_b[i]); i++) {
+       for (i = 0; (da_a = da_stack_a.da[i]) && (da_b = da_stack_b.da[i]); i++) {
                if (da_a->attr > da_b->attr) return +1;
                if (da_a->attr < da_b->attr) return -1;
        }
index e7414141cf12ed2d88c38ac498ed1c31f43171bc..18e2aeb7a57247dc5ca19e23afb394cd7fea7e0f 100644 (file)
@@ -54,41 +54,73 @@ void fr_proto_print_hex_data(char const *file, int line, uint8_t const *data, si
 }
 DIAG_ON(format-nonliteral)
 
-void fr_proto_da_stack_print(char const *file, int line, char const *func, fr_dict_attr_t const **da_stack, unsigned int depth)
+void fr_proto_da_stack_print(char const *file, int line, char const *func, fr_da_stack_t *da_stack, unsigned int depth)
 {
-       int             i;
-
-       for (i = 0; (i < FR_DICT_MAX_TLV_STACK) && da_stack[i]; i++);
-       if (!i) return;
+       int             i = da_stack->depth;
 
        fr_log(&default_log, L_DBG, file, line, "stk: Currently in %s", func);
        for (i--; i >= 0; i--) {
                fr_log(&default_log, L_DBG, file, line,
                       "stk: %s [%i] %s: %s, vendor: 0x%x (%u), attr: 0x%x (%u)",
                       (i == (int)depth) ? ">" : " ", i,
-                      fr_table_str_by_value(fr_value_box_type_table, da_stack[i]->type, "?Unknown?"),
-                      da_stack[i]->name,
-                      fr_dict_vendor_num_by_da(da_stack[i]), fr_dict_vendor_num_by_da(da_stack[i]),
-                      da_stack[i]->attr, da_stack[i]->attr);
+                      fr_table_str_by_value(fr_value_box_type_table, da_stack->da[i]->type, "?Unknown?"),
+                      da_stack->da[i]->name,
+                      fr_dict_vendor_num_by_da(da_stack->da[i]), fr_dict_vendor_num_by_da(da_stack->da[i]),
+                      da_stack->da[i]->attr, da_stack->da[i]->attr);
        }
        fr_log(&default_log, L_DBG, file, line, "stk:");
 }
 
-void fr_proto_da_stack_build(fr_dict_attr_t const **da_stack, fr_dict_attr_t const *da)
+/** Build a complete TLV stack from the da back to the root
+ *
+ * @param[out] stack   to populate.
+ * @param[in] da       to build the stack for.
+ */
+void fr_proto_da_stack_build(fr_da_stack_t *stack, fr_dict_attr_t const *da)
 {
-       int i;
-       fr_dict_attr_t const *da_p;
-
-       memset(da_stack, 0, sizeof(*da_stack) * (FR_DICT_MAX_TLV_STACK + 1));
+       fr_dict_attr_t const    *da_p, **da_o;
 
        if (!da) return;
 
-       /*
-        *      We've finished encoding one nested structure
-        *      now we need to rebuild the da_stack and determine
-        *      where the common point is.
-        */
-       for (i = da->depth, da_p = da;
-            da_p->parent && (i >= 0);
-            i--, da_p = da_p->parent) da_stack[i - 1] = da_p;
+       da_p = da;
+       da_o = stack->da + (da->depth - 1);
+
+       while (da_o >= stack->da) {
+               *da_o-- = da_p;
+               da_p = da_p->parent;
+       }
+
+       stack->depth = da->depth;
+       stack->da[stack->depth] = NULL;
+}
+
+/** Complete the tlv stack for a child attribute
+ *
+ * @param[out] stack           to populate.
+ * @param[in] parent           to populate from.
+ * @param[in] da               to populate to.
+ */
+void fr_proto_da_stack_partial_build(fr_da_stack_t *stack, fr_dict_attr_t const *parent, fr_dict_attr_t const *da)
+{
+       fr_dict_attr_t const    *da_p, **da_q, **da_o;
+
+#ifndef NDEBUG
+       if (!fr_cond_assert(fr_dict_parent_common(parent, da, true) == parent)) {
+               fr_strerror_printf("Expected \"%s\" to be a descendent of \"%s\" but it isn't",
+                                  da->name, parent->name);
+               return;
+       }
+#endif
+
+       da_p = da;
+       da_q = stack->da + (parent->depth - 1);
+       da_o = stack->da + (da->depth - 1);
+
+       while (da_o >= da_q) {
+               *da_o-- = da_p;
+               da_p = da_p->parent;
+       }
+
+       stack->depth = da->depth;
+       stack->da[stack->depth] = NULL;
 }
index 47c0b91084352946bc18158f70cbd2710b92e806..e08bea8d1acc46fb938558c0c309b9acafaaf4c7 100644 (file)
@@ -46,13 +46,22 @@ do { \
 #  define FR_PROTO_STACK_PRINT(_x, _y)
 #endif
 
+/** Structure for holding the stack of dictionary attributes being encoded
+ *
+ */
+typedef struct {
+       fr_dict_attr_t const    *da[FR_DICT_MAX_TLV_STACK + 1];         //!< The stack.
+       uint8_t                 depth;                                  //!< Deepest attribute in the stack.
+} fr_da_stack_t;
 void fr_proto_print(char const *file, int line, char const *fmt, ...) CC_HINT(format (printf, 3, 4));
 
 void fr_proto_print_hex_data(char const *file, int line, uint8_t const *data, size_t data_len, char const *fmt, ...);
 
-void fr_proto_da_stack_print(char const *file, int line, char const *func, fr_dict_attr_t const **da_stack, unsigned int depth);
+void fr_proto_da_stack_print(char const *file, int line, char const *func, fr_da_stack_t *da_stack, unsigned int depth);
+
+void fr_proto_da_stack_build(fr_da_stack_t *stack, fr_dict_attr_t const *da);
 
-void fr_proto_da_stack_build(fr_dict_attr_t const **da_stack, fr_dict_attr_t const *da);
+void fr_proto_da_stack_partial_build(fr_da_stack_t *stack, fr_dict_attr_t const *parent, fr_dict_attr_t const *da);
 
 #ifdef __cplusplus
 }
index 08fe7774fc3d2d98c8b744aab6a3661a9b3e9aa0..e28fe116295d99618078eaa82ae246b1004105d0 100644 (file)
@@ -411,7 +411,7 @@ static int put_bits(uint8_t *p, uint8_t const *end, int start_bit, int num_bits,
 
 
 ssize_t fr_struct_to_network(uint8_t *out, size_t outlen,
-                            fr_dict_attr_t const **da_stack, unsigned int depth,
+                            fr_da_stack_t *da_stack, unsigned int depth,
                             fr_cursor_t *cursor, void *encoder_ctx,
                             fr_encode_value_t encode_value)
 {
@@ -429,7 +429,7 @@ ssize_t fr_struct_to_network(uint8_t *out, size_t outlen,
        }
 
        VP_VERIFY(vp);
-       parent = da_stack[depth];
+       parent = da_stack->da[depth];
 
        if (parent->type != FR_TYPE_STRUCT) {
                fr_strerror_printf("%s: Expected type \"struct\" got \"%s\"", __FUNCTION__,
index 31c815bf2060466309a3737c4635c208c64fcaf4..ea3d65e9c9da950cb577258289963127aaf8e132 100644 (file)
@@ -26,6 +26,7 @@ RCSIDH(struct_h, "$Id$")
 #include <freeradius-devel/util/value.h>
 #include <freeradius-devel/util/cursor.h>
 #include <freeradius-devel/util/pair.h>
+#include <freeradius-devel/util/proto.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -40,10 +41,10 @@ ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_cursor_t *cursor,
                               fr_dict_attr_t const **child,
                               fr_decode_value_t decode_value, void *decoder_ctx) CC_HINT(nonnull(2,3,4));
 
-typedef ssize_t (*fr_encode_value_t)(uint8_t *out, size_t outlen, fr_dict_attr_t const **da_stack, unsigned int depth,
+typedef ssize_t (*fr_encode_value_t)(uint8_t *out, size_t outlen, fr_da_stack_t *da_stack, unsigned int depth,
                                     fr_cursor_t *cursor, void *encoder_ctx);
 
-ssize_t fr_struct_to_network(uint8_t *out, size_t outlen, fr_dict_attr_t const **da_stack, unsigned int depth,
+ssize_t fr_struct_to_network(uint8_t *out, size_t outlen, fr_da_stack_t *da_stack, unsigned int depth,
                             fr_cursor_t *cursor, void *encoder_ctx,
                             fr_encode_value_t encode_value) CC_HINT(nonnull(1,3,5));
 
index 600cc7fc531e765d1c31f3885798af233ad6c18f..1d13aad7bbf3bc376493ed4e5501bac36e0dd243 100644 (file)
@@ -95,7 +95,7 @@ static inline VALUE_PAIR *first_encodable(fr_cursor_t *cursor, void *encoder_ctx
  *     - -2 if unsupported type.
  */
 static ssize_t encode_value(uint8_t *out, size_t outlen,
-                           fr_dict_attr_t const **da_stack, unsigned int depth,
+                           fr_da_stack_t *da_stack, unsigned int depth,
                            fr_cursor_t *cursor, fr_dhcpv4_ctx_t *encoder_ctx)
 {
        VALUE_PAIR      *vp = fr_cursor_current(cursor);
@@ -108,7 +108,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
 
        if (outlen < vp->vp_length) return -1;  /* Not enough output buffer space. */
 
-       switch (da_stack[depth]->type) {
+       switch (da_stack->da[depth]->type) {
        case FR_TYPE_BOOL:
        case FR_TYPE_UINT8:
        case FR_TYPE_UINT16:
@@ -250,13 +250,13 @@ static uint8_t *extend_option(uint8_t *start, uint8_t *end, uint8_t *p, int len)
  *     - < 0 on error.
  */
 static ssize_t encode_rfc_hdr(uint8_t *out, ssize_t outlen,
-                             fr_dict_attr_t const **da_stack, unsigned int depth,
+                             fr_da_stack_t *da_stack, unsigned int depth,
                              fr_cursor_t *cursor, fr_dhcpv4_ctx_t *encoder_ctx)
 {
        ssize_t                 len;
        uint8_t                 *p = out;
        uint8_t                 *start, *end;
-       fr_dict_attr_t const    *da = da_stack[depth];
+       fr_dict_attr_t const    *da = da_stack->da[depth];
        VALUE_PAIR              *vp = fr_cursor_current(cursor);
 
        if (outlen < 3) return 0;       /* No space */
@@ -346,14 +346,14 @@ static ssize_t encode_rfc_hdr(uint8_t *out, ssize_t outlen,
  *     - < 0 on error.
  */
 static ssize_t encode_tlv_hdr(uint8_t *out, ssize_t outlen,
-                             fr_dict_attr_t const **da_stack, unsigned int depth,
+                             fr_da_stack_t *da_stack, unsigned int depth,
                              fr_cursor_t *cursor, fr_dhcpv4_ctx_t *encoder_ctx)
 {
        ssize_t                 len;
        uint8_t                 *p = out;
        uint8_t                 *start, *end;
        VALUE_PAIR const        *vp = fr_cursor_current(cursor);
-       fr_dict_attr_t const    *da = da_stack[depth];
+       fr_dict_attr_t const    *da = da_stack->da[depth];
 
        if (outlen < 5) return 0;       /* No space */
 
@@ -376,7 +376,7 @@ static ssize_t encode_tlv_hdr(uint8_t *out, ssize_t outlen,
                /*
                 *      Determine the nested type and call the appropriate encoder
                 */
-               if (da_stack[depth + 1]->type == FR_TYPE_TLV) {
+               if (da_stack->da[depth + 1]->type == FR_TYPE_TLV) {
                        len = encode_tlv_hdr(p, end - p, da_stack, depth + 1, cursor, encoder_ctx);
                } else {
                        len = encode_rfc_hdr(p, end - p, da_stack, depth + 1, cursor, encoder_ctx);
@@ -452,7 +452,7 @@ static ssize_t encode_tlv_hdr(uint8_t *out, ssize_t outlen,
                 *      rebuilding the TLV Stack, the attribute
                 *      at this depth is the same.
                 */
-               if (da != da_stack[depth]) break;
+               if ((da != da_stack->da[depth]) || (da_stack->depth < da->depth)) break;
                vp = fr_cursor_current(cursor);
        }
 
@@ -475,7 +475,7 @@ ssize_t fr_dhcpv4_encode_option(uint8_t *out, size_t outlen, fr_cursor_t *cursor
 {
        VALUE_PAIR              *vp;
        unsigned int            depth = 0;
-       fr_dict_attr_t const    *da_stack[FR_DICT_MAX_TLV_STACK + 1];
+       fr_da_stack_t           da_stack;
        ssize_t                 len;
 
        vp = first_encodable(cursor, encoder_ctx);
@@ -489,20 +489,20 @@ ssize_t fr_dhcpv4_encode_option(uint8_t *out, size_t outlen, fr_cursor_t *cursor
                return 0;
        }
 
-       fr_proto_da_stack_build(da_stack, vp->da);
+       fr_proto_da_stack_build(&da_stack, vp->da);
 
-       FR_PROTO_STACK_PRINT(da_stack, depth);
+       FR_PROTO_STACK_PRINT(&da_stack, depth);
 
        /*
         *      We only have two types of options in DHCPv4
         */
-       switch (da_stack[depth]->type) {
+       switch (da_stack.da[depth]->type) {
        case FR_TYPE_TLV:
-               len = encode_tlv_hdr(out, outlen, da_stack, depth, cursor, encoder_ctx);
+               len = encode_tlv_hdr(out, outlen, &da_stack, depth, cursor, encoder_ctx);
                break;
 
        default:
-               len = encode_rfc_hdr(out, outlen, da_stack, depth, cursor, encoder_ctx);
+               len = encode_rfc_hdr(out, outlen, &da_stack, depth, cursor, encoder_ctx);
                break;
        }
 
index f3cf3e9271d4f47a88db7b3a5386463e88373e68..032943fa63c22de9e1320ab8d70e5fdfe1f9c6bb 100644 (file)
 #include "attrs.h"
 
 static ssize_t encode_value(uint8_t *out, size_t outlen,
-                           fr_dict_attr_t const **da_stack, unsigned int depth,
+                           fr_da_stack_t *da_stack, unsigned int depth,
                            fr_cursor_t *cursor, void *encoder_ctx);
 
 static ssize_t encode_rfc_hdr(uint8_t *out, size_t outlen,
-                             fr_dict_attr_t const **da_stack, unsigned int depth,
+                             fr_da_stack_t *da_stack, unsigned int depth,
                              fr_cursor_t *cursor, void *encoder_ctx);
 
 static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
-                             fr_dict_attr_t const **da_stack, unsigned int depth,
+                             fr_da_stack_t *da_stack, unsigned int depth,
                              fr_cursor_t *cursor, void *encoder_ctx);
 
 static inline bool is_encodable(fr_dict_attr_t const *root, VALUE_PAIR const *vp)
@@ -133,19 +133,19 @@ static inline ssize_t encode_option_hdr(uint8_t *out, size_t outlen, uint16_t op
 }
 
 static ssize_t encode_struct(uint8_t *out, size_t outlen,
-                            fr_dict_attr_t const **da_stack, unsigned int depth,
+                            fr_da_stack_t *da_stack, unsigned int depth,
                             fr_cursor_t *cursor, void *encoder_ctx)
 {
        VP_VERIFY(fr_cursor_current(cursor));
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
-       if (da_stack[depth]->type != FR_TYPE_STRUCT) {
+       if (da_stack->da[depth]->type != FR_TYPE_STRUCT) {
                fr_strerror_printf("%s: Expected type \"struct\" got \"%s\"", __FUNCTION__,
-                                  fr_table_str_by_value(fr_value_box_type_table, da_stack[depth]->type, "?Unknown?"));
+                                  fr_table_str_by_value(fr_value_box_type_table, da_stack->da[depth]->type, "?Unknown?"));
                return PAIR_ENCODE_FATAL_ERROR;
        }
 
-       if (!da_stack[depth + 1]) {
+       if (!da_stack->da[depth + 1]) {
                fr_strerror_printf("%s: Can't encode empty struct", __FUNCTION__);
                return PAIR_ENCODE_FATAL_ERROR;
        }
@@ -154,13 +154,13 @@ static ssize_t encode_struct(uint8_t *out, size_t outlen,
 }
 
 static ssize_t encode_value(uint8_t *out, size_t outlen,
-                           fr_dict_attr_t const **da_stack, unsigned int depth,
+                           fr_da_stack_t *da_stack, unsigned int depth,
                            fr_cursor_t *cursor, void *encoder_ctx)
 {
        ssize_t                 slen;
        uint8_t                 *p = out, *end = p + outlen;
        VALUE_PAIR const        *vp = fr_cursor_current(cursor);
-       fr_dict_attr_t const    *da = da_stack[depth];
+       fr_dict_attr_t const    *da = da_stack->da[depth];
 
        VP_VERIFY(vp);
        FR_PROTO_STACK_PRINT(da_stack, depth);
@@ -193,7 +193,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
         *      If it's not a TLV, it should be a value type RFC
         *      attribute make sure that it is.
         */
-       if (da_stack[depth + 1] != NULL) {
+       if (da_stack->da[depth + 1] != NULL) {
                fr_strerror_printf("%s: Encoding value but not at top of stack", __FUNCTION__);
                return PAIR_ENCODE_FATAL_ERROR;
        }
@@ -479,14 +479,14 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
 }
 
 static inline ssize_t encode_array(uint8_t *out, size_t outlen,
-                                  fr_dict_attr_t const **da_stack, int depth,
+                                  fr_da_stack_t *da_stack, int depth,
                                   fr_cursor_t *cursor, void *encoder_ctx)
 {
        uint8_t                 *p = out, *end = p + outlen;
        ssize_t                 slen;
        size_t                  element_len;
        VALUE_PAIR              *vp;
-       fr_dict_attr_t const    *da = da_stack[depth];
+       fr_dict_attr_t const    *da = da_stack->da[depth];
 
        if (!fr_cond_assert_msg(da->flags.array,
                                "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set",
@@ -559,7 +559,7 @@ static inline ssize_t encode_array(uint8_t *out, size_t outlen,
                 *      Populate the length field
                 */
                if (len_field) *len_field = htons((uint16_t) slen);
-               
+
                vp = fr_cursor_current(cursor);
                if (!vp || (vp->da != da)) break;               /* Stop if we have an attribute of a different type */
        }
@@ -568,13 +568,13 @@ static inline ssize_t encode_array(uint8_t *out, size_t outlen,
 }
 
 static ssize_t encode_tlv(uint8_t *out, size_t outlen,
-                         fr_dict_attr_t const **da_stack, unsigned int depth,
+                         fr_da_stack_t *da_stack, unsigned int depth,
                          fr_cursor_t *cursor, void *encoder_ctx)
 {
        ssize_t                 slen;
        uint8_t                 *p = out, *end = p + outlen;
        VALUE_PAIR const        *vp = fr_cursor_current(cursor);
-       fr_dict_attr_t const    *da = da_stack[depth];
+       fr_dict_attr_t const    *da = da_stack->da[depth];
 
        CHECK_FREESPACE(outlen, OPT_HDR_LEN);
 
@@ -584,7 +584,7 @@ static ssize_t encode_tlv(uint8_t *out, size_t outlen,
                /*
                 *      Determine the nested type and call the appropriate encoder
                 */
-               if (da_stack[depth + 1]->type == FR_TYPE_TLV) {
+               if (da_stack->da[depth + 1]->type == FR_TYPE_TLV) {
                        slen = encode_tlv_hdr(p, end - p, da_stack, depth + 1, cursor, encoder_ctx);
                } else {
                        slen = encode_rfc_hdr(p, end - p, da_stack, depth + 1, cursor, encoder_ctx);
@@ -603,7 +603,7 @@ static ssize_t encode_tlv(uint8_t *out, size_t outlen,
                 *      rebuilding the TLV Stack, the attribute
                 *      at this depth is the same.
                 */
-               if (da != da_stack[depth]) break;
+               if ((da != da_stack->da[depth]) || (da_stack->depth < da->depth)) break;
                vp = fr_cursor_current(cursor);
        }
 
@@ -621,12 +621,12 @@ static ssize_t encode_tlv(uint8_t *out, size_t outlen,
  * Otherwise, attribute may be something else.
  */
 static ssize_t encode_rfc_hdr(uint8_t *out, size_t outlen,
-                             fr_dict_attr_t const **da_stack, unsigned int depth,
+                             fr_da_stack_t *da_stack, unsigned int depth,
                              fr_cursor_t *cursor, void *encoder_ctx)
 {
        uint8_t                 *p = out, *end = p + outlen;
        ssize_t                 slen;
-       fr_dict_attr_t const    *da = da_stack[depth];
+       fr_dict_attr_t const    *da = da_stack->da[depth];
 
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
@@ -662,23 +662,23 @@ static ssize_t encode_rfc_hdr(uint8_t *out, size_t outlen,
 }
 
 static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
-                             fr_dict_attr_t const **da_stack, unsigned int depth,
+                             fr_da_stack_t *da_stack, unsigned int depth,
                              fr_cursor_t *cursor, void *encoder_ctx)
 {
        ssize_t                 slen;
        uint8_t                 *p = out, *end = p + outlen;
-       fr_dict_attr_t const    *da = da_stack[depth];
+       fr_dict_attr_t const    *da = da_stack->da[depth];
 
        VP_VERIFY(fr_cursor_current(cursor));
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
-       if (da_stack[depth]->type != FR_TYPE_TLV) {
+       if (da_stack->da[depth]->type != FR_TYPE_TLV) {
                fr_strerror_printf("%s: Expected type \"tlv\" got \"%s\"", __FUNCTION__,
-                                  fr_table_str_by_value(fr_value_box_type_table, da_stack[depth]->type, "?Unknown?"));
+                                  fr_table_str_by_value(fr_value_box_type_table, da_stack->da[depth]->type, "?Unknown?"));
                return PAIR_ENCODE_FATAL_ERROR;
        }
 
-       if (!da_stack[depth + 1]) {
+       if (!da_stack->da[depth + 1]) {
                fr_strerror_printf("%s: Can't encode empty TLV", __FUNCTION__);
                return PAIR_ENCODE_FATAL_ERROR;
        }
@@ -722,13 +722,13 @@ static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
 static ssize_t encode_vsio_hdr(uint8_t *out, size_t outlen,
-                              fr_dict_attr_t const **da_stack, unsigned int depth,
+                              fr_da_stack_t *da_stack, unsigned int depth,
                               fr_cursor_t *cursor, void *encoder_ctx)
 {
        ssize_t                 slen;
        uint32_t                pen;
        uint8_t                 *p = out, *end = p + outlen;
-       fr_dict_attr_t const    *da = da_stack[depth];
+       fr_dict_attr_t const    *da = da_stack->da[depth];
        fr_dict_attr_t const    *dv;
 
        FR_PROTO_STACK_PRINT(da_stack, depth);
@@ -751,7 +751,7 @@ static ssize_t encode_vsio_hdr(uint8_t *out, size_t outlen,
        /*
         *      Now process the vendor ID part (which is one attribute deeper)
         */
-       dv = da_stack[++depth];
+       dv = da_stack->da[++depth];
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
        if (dv->type != FR_TYPE_VENDOR) {
@@ -828,7 +828,7 @@ ssize_t fr_dhcpv6_encode_option(uint8_t *out, size_t outlen, fr_cursor_t *cursor
 {
        VALUE_PAIR              *vp;
        unsigned int            depth = 0;
-       fr_dict_attr_t const    *da_stack[FR_DICT_MAX_TLV_STACK + 1];
+       fr_da_stack_t           da_stack;
        ssize_t                 slen;
 
        vp = first_encodable(cursor, encoder_ctx);
@@ -840,9 +840,9 @@ ssize_t fr_dhcpv6_encode_option(uint8_t *out, size_t outlen, fr_cursor_t *cursor
                return PAIR_ENCODE_SKIPPED;
        }
 
-       fr_proto_da_stack_build(da_stack, vp->da);
+       fr_proto_da_stack_build(&da_stack, vp->da);
 
-       FR_PROTO_STACK_PRINT(da_stack, depth);
+       FR_PROTO_STACK_PRINT(&da_stack, depth);
 
        /*
         *      Trim output buffer size for sanity
@@ -852,17 +852,17 @@ ssize_t fr_dhcpv6_encode_option(uint8_t *out, size_t outlen, fr_cursor_t *cursor
        /*
         *      Deal with nested options
         */
-       switch (da_stack[depth]->type) {
+       switch (da_stack.da[depth]->type) {
        case FR_TYPE_TLV:
-               slen = encode_tlv_hdr(out, outlen, da_stack, depth, cursor, encoder_ctx);
+               slen = encode_tlv_hdr(out, outlen, &da_stack, depth, cursor, encoder_ctx);
                break;
 
        case FR_TYPE_VSA:
-               slen = encode_vsio_hdr(out, outlen, da_stack, depth, cursor, encoder_ctx);
+               slen = encode_vsio_hdr(out, outlen, &da_stack, depth, cursor, encoder_ctx);
                break;
 
        default:
-               slen = encode_rfc_hdr(out, outlen, da_stack, depth, cursor, encoder_ctx);
+               slen = encode_rfc_hdr(out, outlen, &da_stack, depth, cursor, encoder_ctx);
                break;
        }
 
index e7b115d8c42070a370ef5d5e5cf32155ced83360..d43d27db0393bf3bc5d4d8eb395d5e9e2412c2f3 100644 (file)
@@ -31,15 +31,15 @@ RCSID("$Id$")
 #include "attrs.h"
 
 static ssize_t encode_value(uint8_t *out, size_t outlen,
-                           fr_dict_attr_t const **da_stack, unsigned int depth,
+                           fr_da_stack_t *da_stack, unsigned int depth,
                            fr_cursor_t *cursor, void *encoder_ctx);
 
 static ssize_t encode_rfc_hdr_internal(uint8_t *out, size_t outlen,
-                                      fr_dict_attr_t const **da_stack, unsigned int depth,
+                                      fr_da_stack_t *da_stack, unsigned int depth,
                                       fr_cursor_t *cursor, void *encoder_ctx);
 
 static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
-                             fr_dict_attr_t const **da_stack, unsigned int depth,
+                             fr_da_stack_t *da_stack, unsigned int depth,
                              fr_cursor_t *cursor, void *encoder_ctx);
 
 
@@ -266,13 +266,13 @@ static void encode_tunnel_password(uint8_t *out, ssize_t *outlen,
 }
 
 static ssize_t encode_tlv_hdr_internal(uint8_t *out, size_t outlen,
-                                      fr_dict_attr_t const **da_stack, unsigned int depth,
+                                      fr_da_stack_t *da_stack, unsigned int depth,
                                       fr_cursor_t *cursor, void *encoder_ctx)
 {
        ssize_t                 len;
        uint8_t                 *p = out;
        VALUE_PAIR const        *vp = fr_cursor_current(cursor);
-       fr_dict_attr_t const    *da = da_stack[depth];
+       fr_dict_attr_t const    *da = da_stack->da[depth];
 
        while (outlen >= 5) {
                size_t sublen;
@@ -288,7 +288,7 @@ static ssize_t encode_tlv_hdr_internal(uint8_t *out, size_t outlen,
                /*
                 *      Determine the nested type and call the appropriate encoder
                 */
-               if (da_stack[depth + 1]->type == FR_TYPE_TLV) {
+               if (da_stack->da[depth + 1]->type == FR_TYPE_TLV) {
                        len = encode_tlv_hdr(p, sublen, da_stack, depth + 1, cursor, encoder_ctx);
                } else {
                        len = encode_rfc_hdr_internal(p, sublen, da_stack, depth + 1, cursor, encoder_ctx);
@@ -309,7 +309,7 @@ static ssize_t encode_tlv_hdr_internal(uint8_t *out, size_t outlen,
                 *      rebuilding the TLV Stack, the attribute
                 *      at this depth is the same.
                 */
-               if (da != da_stack[depth]) break;
+               if ((da != da_stack->da[depth]) || (da_stack->depth < da->depth)) break;
                vp = fr_cursor_current(cursor);
        }
 
@@ -317,7 +317,7 @@ static ssize_t encode_tlv_hdr_internal(uint8_t *out, size_t outlen,
 }
 
 static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
-                             fr_dict_attr_t const **da_stack, unsigned int depth,
+                             fr_da_stack_t *da_stack, unsigned int depth,
                              fr_cursor_t *cursor, void *encoder_ctx)
 {
        ssize_t                 len;
@@ -325,13 +325,13 @@ static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
        VP_VERIFY(fr_cursor_current(cursor));
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
-       if (da_stack[depth]->type != FR_TYPE_TLV) {
+       if (da_stack->da[depth]->type != FR_TYPE_TLV) {
                fr_strerror_printf("%s: Expected type \"tlv\" got \"%s\"", __FUNCTION__,
-                                  fr_table_str_by_value(fr_value_box_type_table, da_stack[depth]->type, "?Unknown?"));
+                                  fr_table_str_by_value(fr_value_box_type_table, da_stack->da[depth]->type, "?Unknown?"));
                return -1;
        }
 
-       if (!da_stack[depth + 1]) {
+       if (!da_stack->da[depth + 1]) {
                fr_strerror_printf("%s: Can't encode empty TLV", __FUNCTION__);
                return -1;
        }
@@ -341,7 +341,7 @@ static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
        /*
         *      Encode the first level of TLVs
         */
-       out[0] = da_stack[depth]->attr & 0xff;
+       out[0] = da_stack->da[depth]->attr & 0xff;
        out[1] = 2;     /* TLV header */
 
        if (outlen > 255) outlen = 255;
@@ -362,7 +362,7 @@ static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
  *     < 0, failure.
  */
 static ssize_t encode_value(uint8_t *out, size_t outlen,
-                           fr_dict_attr_t const **da_stack, unsigned int depth,
+                           fr_da_stack_t *da_stack, unsigned int depth,
                            fr_cursor_t *cursor, void *encoder_ctx)
 {
        size_t                  offset;
@@ -371,7 +371,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
        uint8_t                 *ptr = out;
        uint8_t                 buffer[64];
        VALUE_PAIR const        *vp = fr_cursor_current(cursor);
-       fr_dict_attr_t const    *da = da_stack[depth];
+       fr_dict_attr_t const    *da = da_stack->da[depth];
        fr_radius_ctx_t         *packet_ctx = encoder_ctx;
 
        VP_VERIFY(vp);
@@ -420,7 +420,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
                 *      TLV to be encoded here.  It's number is just
                 *      the field number in the struct.
                 */
-               while (vp && (da_stack[depth] == da) && (outlen > 0)) {
+               while (vp && (da_stack->da[depth] == da) && (da_stack->depth >= da->depth) && (outlen > 0)) {
                        len = encode_tlv_hdr_internal(out, outlen, da_stack, depth + 1, cursor, encoder_ctx);
                        if (len < 0) return len;
 
@@ -437,7 +437,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
         *      If it's not a TLV, it should be a value type RFC
         *      attribute make sure that it is.
         */
-       if (da_stack[depth + 1] != NULL) {
+       if (da_stack->da[depth + 1] != NULL) {
                fr_strerror_printf("%s: Encoding value but not at top of stack", __FUNCTION__);
                return -1;
        }
@@ -450,7 +450,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
        switch (da->type) {
        case FR_TYPE_STRUCTURAL:
                fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
-                                  fr_table_str_by_value(fr_value_box_type_table, da_stack[depth]->type, "?Unknown?"));
+                                  fr_table_str_by_value(fr_value_box_type_table, da_stack->da[depth]->type, "?Unknown?"));
                return -1;
 
        default:
@@ -693,7 +693,7 @@ static ssize_t attr_shift(uint8_t const *start, uint8_t const *end,
  *
  */
 static int encode_extended_hdr(uint8_t *out, size_t outlen,
-                              fr_dict_attr_t const **da_stack, unsigned int depth,
+                              fr_da_stack_t *da_stack, unsigned int depth,
                               fr_cursor_t *cursor, void *encoder_ctx)
 {
        int                     len;
@@ -709,14 +709,14 @@ static int encode_extended_hdr(uint8_t *out, size_t outlen,
        VP_VERIFY(vp);
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
-       extra = (!da_stack[0]->flags.extra && (da_stack[0]->flags.subtype == FLAG_EXTENDED_ATTR));
+       extra = (!da_stack->da[0]->flags.extra && (da_stack->da[0]->flags.subtype == FLAG_EXTENDED_ATTR));
 
        /*
         *      @fixme: check depth of stack
         */
-       attr_type = da_stack[0]->type;
+       attr_type = da_stack->da[0]->type;
 #ifndef NDEBUG
-       vsa_type = da_stack[1]->type;
+       vsa_type = da_stack->da[1]->type;
        if (fr_debug_lvl > 3) {
                jump += extra;
        }
@@ -732,9 +732,9 @@ static int encode_extended_hdr(uint8_t *out, size_t outlen,
                /*
                 *      Encode which extended attribute it is.
                 */
-               out[0] = da_stack[depth++]->attr & 0xff;
+               out[0] = da_stack->da[depth++]->attr & 0xff;
                out[1] = 3 + extra;
-               out[2] = da_stack[depth]->attr & 0xff;
+               out[2] = da_stack->da[depth]->attr & 0xff;
 
                if (extra) out[3] = 0;  /* flags start off at zero */
                break;
@@ -742,7 +742,7 @@ static int encode_extended_hdr(uint8_t *out, size_t outlen,
        default:
                fr_strerror_printf("%s : Called for non-extended attribute type %s",
                                   __FUNCTION__, fr_table_str_by_value(fr_value_box_type_table,
-                                  da_stack[depth]->type, "?Unknown?"));
+                                  da_stack->da[depth]->type, "?Unknown?"));
                return -1;
        }
 
@@ -751,7 +751,7 @@ static int encode_extended_hdr(uint8_t *out, size_t outlen,
        /*
         *      Handle VSA as "VENDOR + attr"
         */
-       if (da_stack[depth]->type == FR_TYPE_VSA) {
+       if (da_stack->da[depth]->type == FR_TYPE_VSA) {
                uint8_t *evs = out + out[1];
                uint32_t lvalue;
 
@@ -759,10 +759,10 @@ static int encode_extended_hdr(uint8_t *out, size_t outlen,
 
                depth++;
 
-               lvalue = htonl(da_stack[depth++]->attr);
+               lvalue = htonl(da_stack->da[depth++]->attr);
                memcpy(evs, &lvalue, 4);
 
-               evs[4] = da_stack[depth]->attr & 0xff;
+               evs[4] = da_stack->da[depth]->attr & 0xff;
 
                out[1] += 5;
 
@@ -778,7 +778,7 @@ static int encode_extended_hdr(uint8_t *out, size_t outlen,
         */
        if ((attr_type == FR_TYPE_EXTENDED) && !extra && (outlen > 255)) outlen = 255;
 
-       if (da_stack[depth]->type == FR_TYPE_TLV) {
+       if (da_stack->da[depth]->type == FR_TYPE_TLV) {
                len = encode_tlv_hdr_internal(out + out[1], outlen - out[1], da_stack, depth, cursor, encoder_ctx);
        } else {
                len = encode_value(out + out[1], outlen - out[1], da_stack, depth, cursor, encoder_ctx);
@@ -817,7 +817,7 @@ static int encode_extended_hdr(uint8_t *out, size_t outlen,
  * prepended to each chunk.
  */
 static ssize_t encode_concat(uint8_t *out, size_t outlen,
-                            fr_dict_attr_t const **da_stack, unsigned int depth,
+                            fr_da_stack_t *da_stack, unsigned int depth,
                             fr_cursor_t *cursor, UNUSED void *encoder_ctx)
 {
        uint8_t                 *ptr = out;
@@ -833,7 +833,7 @@ static ssize_t encode_concat(uint8_t *out, size_t outlen,
        while (len > 0) {
                if (outlen <= 2) break;
 
-               ptr[0] = da_stack[depth]->attr & 0xff;
+               ptr[0] = da_stack->da[depth]->attr & 0xff;
                ptr[1] = 2;
 
                left = len;
@@ -874,25 +874,25 @@ static ssize_t encode_concat(uint8_t *out, size_t outlen,
  * Otherwise, attribute may be something else.
  */
 static ssize_t encode_rfc_hdr_internal(uint8_t *out, size_t outlen,
-                                      fr_dict_attr_t const **da_stack, unsigned int depth,
+                                      fr_da_stack_t *da_stack, unsigned int depth,
                                       fr_cursor_t *cursor, void *encoder_ctx)
 {
        ssize_t len;
 
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
-       switch (da_stack[depth]->type) {
+       switch (da_stack->da[depth]->type) {
        default:
                fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
-                                  fr_table_str_by_value(fr_value_box_type_table, da_stack[depth]->type, "?Unknown?"));
+                                  fr_table_str_by_value(fr_value_box_type_table, da_stack->da[depth]->type, "?Unknown?"));
                return -1;
 
        case FR_TYPE_STRUCT:
        case FR_TYPE_VALUES:
-               if (((fr_dict_vendor_num_by_da(da_stack[depth]) == 0) && (da_stack[depth]->attr == 0)) ||
-                   (da_stack[depth]->attr > 255)) {
+               if (((fr_dict_vendor_num_by_da(da_stack->da[depth]) == 0) && (da_stack->da[depth]->attr == 0)) ||
+                   (da_stack->da[depth]->attr > 255)) {
                        fr_strerror_printf("%s: Called with non-standard attribute %u", __FUNCTION__,
-                                          da_stack[depth]->attr);
+                                          da_stack->da[depth]->attr);
                        return -1;
                }
                break;
@@ -900,7 +900,7 @@ static ssize_t encode_rfc_hdr_internal(uint8_t *out, size_t outlen,
 
        if (outlen <= 2) return 0;
 
-       out[0] = da_stack[depth]->attr & 0xff;
+       out[0] = da_stack->da[depth]->attr & 0xff;
        out[1] = 2;
 
        if (outlen > 255) outlen = 255;
@@ -921,7 +921,7 @@ static ssize_t encode_rfc_hdr_internal(uint8_t *out, size_t outlen,
  * If it's in the RFC format, call encode_rfc_hdr_internal.  Otherwise, encode it here.
  */
 static ssize_t encode_vendor_attr_hdr(uint8_t *out, size_t outlen,
-                                     fr_dict_attr_t const **da_stack, unsigned int depth,
+                                     fr_da_stack_t *da_stack, unsigned int depth,
                                      fr_cursor_t *cursor, void *encoder_ctx)
 {
        ssize_t                 len;
@@ -930,14 +930,14 @@ static ssize_t encode_vendor_attr_hdr(uint8_t *out, size_t outlen,
 
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
-       dv = da_stack[depth++];
+       dv = da_stack->da[depth++];
 
        if (dv->type != FR_TYPE_VENDOR) {
                fr_strerror_printf("Expected Vendor");
                return -1;
        }
 
-       da = da_stack[depth];
+       da = da_stack->da[depth];
 
        if ((da->type != FR_TYPE_TLV) && (dv->flags.type_size == 1) && (dv->flags.length == 1)) {
                return encode_rfc_hdr_internal(out, outlen, da_stack, depth, cursor, encoder_ctx);
@@ -997,7 +997,7 @@ static ssize_t encode_vendor_attr_hdr(uint8_t *out, size_t outlen,
         *      if this is a TLV, we must process it via the
         *      internal tlv function, else we get a double TLV header.
         */
-       if (da_stack[depth]->type == FR_TYPE_TLV) {
+       if (da_stack->da[depth]->type == FR_TYPE_TLV) {
                len = encode_tlv_hdr_internal(out + hdr_len, outlen - hdr_len, da_stack, depth, cursor, encoder_ctx);
        } else {
                len = encode_value(out + hdr_len, outlen - hdr_len, da_stack, depth, cursor, encoder_ctx);
@@ -1015,7 +1015,7 @@ static ssize_t encode_vendor_attr_hdr(uint8_t *out, size_t outlen,
  *
  */
 static int encode_wimax_hdr(uint8_t *out, size_t outlen,
-                           fr_dict_attr_t const **da_stack, unsigned int depth,
+                           fr_da_stack_t *da_stack, unsigned int depth,
                            fr_cursor_t *cursor, void *encoder_ctx)
 {
        int                     len;
@@ -1032,14 +1032,14 @@ static int encode_wimax_hdr(uint8_t *out, size_t outlen,
         */
        if (outlen < 9) return 0;
 
-       if (da_stack[depth++]->attr != FR_VENDOR_SPECIFIC) {
+       if (da_stack->da[depth++]->attr != FR_VENDOR_SPECIFIC) {
                fr_strerror_printf("%s: level[1] of da_stack is incorrect, must be Vendor-Specific (26)",
                                   __FUNCTION__);
                return -1;
        }
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
-       if (da_stack[depth++]->attr != VENDORPEC_WIMAX) {
+       if (da_stack->da[depth++]->attr != VENDORPEC_WIMAX) {
                fr_strerror_printf("%s: level[2] of da_stack is incorrect, must be Wimax vendor %i", __FUNCTION__,
                                   VENDORPEC_WIMAX);
                return -1;
@@ -1058,7 +1058,7 @@ static int encode_wimax_hdr(uint8_t *out, size_t outlen,
        /*
         *      Encode the first attribute
         */
-       out[6] = da_stack[depth]->attr;
+       out[6] = da_stack->da[depth]->attr;
        out[7] = 3;
        out[8] = 0;             /* continuation byte */
 
@@ -1066,7 +1066,7 @@ static int encode_wimax_hdr(uint8_t *out, size_t outlen,
         *      "outlen" can be larger than 255 because of the "continuation" byte.
         */
 
-       if (da_stack[depth]->type == FR_TYPE_TLV) {
+       if (da_stack->da[depth]->type == FR_TYPE_TLV) {
                len = encode_tlv_hdr_internal(out + out[1], outlen - out[1], da_stack, depth, cursor, encoder_ctx);
                if (len <= 0) return len;
        } else {
@@ -1096,12 +1096,12 @@ static int encode_wimax_hdr(uint8_t *out, size_t outlen,
  *
  */
 static int encode_vsa_hdr(uint8_t *out, size_t outlen,
-                         fr_dict_attr_t const **da_stack, unsigned int depth,
+                         fr_da_stack_t *da_stack, unsigned int depth,
                          fr_cursor_t *cursor, void *encoder_ctx)
 {
        ssize_t                 len;
        uint32_t                lvalue;
-       fr_dict_attr_t const    *da = da_stack[depth];
+       fr_dict_attr_t const    *da = da_stack->da[depth];
 
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
@@ -1114,7 +1114,7 @@ static int encode_vsa_hdr(uint8_t *out, size_t outlen,
        /*
         *      Double-check for WiMAX format
         */
-       if (fr_dict_vendor_num_by_da(da_stack[depth + 1]) == VENDORPEC_WIMAX) {
+       if (fr_dict_vendor_num_by_da(da_stack->da[depth + 1]) == VENDORPEC_WIMAX) {
                return encode_wimax_hdr(out, outlen, da_stack, depth, cursor, encoder_ctx);
        }
 
@@ -1132,7 +1132,7 @@ static int encode_vsa_hdr(uint8_t *out, size_t outlen,
        /*
         *      Now process the vendor ID part (which is one attribute deeper)
         */
-       da = da_stack[++depth];
+       da = da_stack->da[++depth];
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
        if (da->type != FR_TYPE_VENDOR) {
@@ -1159,7 +1159,7 @@ static int encode_vsa_hdr(uint8_t *out, size_t outlen,
 /** Encode an RFC standard attribute 1..255
  *
  */
-static int encode_rfc_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const **da_stack, unsigned int depth,
+static int encode_rfc_hdr(uint8_t *out, size_t outlen, fr_da_stack_t *da_stack, unsigned int depth,
                          fr_cursor_t *cursor, void *encoder_ctx)
 {
        VALUE_PAIR const *vp = fr_cursor_current(cursor);
@@ -1170,14 +1170,14 @@ static int encode_rfc_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const **da
        VP_VERIFY(vp);
        FR_PROTO_STACK_PRINT(da_stack, depth);
 
-       switch (da_stack[depth]->type) {
+       switch (da_stack->da[depth]->type) {
        case FR_TYPE_EXTENDED:
        case FR_TYPE_TLV:
        case FR_TYPE_VSA:
        case FR_TYPE_VENDOR:
                /* FR_TYPE_STRUCT is actually allowed... */
                fr_strerror_printf("%s: Expected leaf type got \"%s\"", __FUNCTION__,
-                                  fr_table_str_by_value(fr_value_box_type_table, da_stack[depth]->type, "?Unknown?"));
+                                  fr_table_str_by_value(fr_value_box_type_table, da_stack->da[depth]->type, "?Unknown?"));
                return -1;
 
        default:
@@ -1185,8 +1185,8 @@ static int encode_rfc_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const **da
                 *      Attribute 0 is fine as a TLV leaf, or VSA, but not
                 *      in the original standards space.
                 */
-               if (((fr_dict_vendor_num_by_da(da_stack[depth]) == 0) && (da_stack[depth]->attr == 0)) ||
-                   (da_stack[depth]->attr > 255)) {
+               if (((fr_dict_vendor_num_by_da(da_stack->da[depth]) == 0) && (da_stack->da[depth]->attr == 0)) ||
+                   (da_stack->da[depth]->attr > 255)) {
                        fr_strerror_printf("%s: Called with non-standard attribute %u", __FUNCTION__, vp->da->attr);
                        return -1;
                }
@@ -1246,12 +1246,12 @@ static int encode_rfc_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const **da
  */
 ssize_t fr_radius_encode_pair(uint8_t *out, size_t outlen, fr_cursor_t *cursor, void *encoder_ctx)
 {
-       VALUE_PAIR const *vp;
-       int ret;
-       size_t attr_len;
+       VALUE_PAIR const        *vp;
+       int                     ret;
+       size_t                  attr_len;
 
-       fr_dict_attr_t const *da_stack[FR_DICT_MAX_TLV_STACK + 1];
-       fr_dict_attr_t const *da = NULL;
+       fr_da_stack_t           da_stack;
+       fr_dict_attr_t const    *da = NULL;
 
        if (!cursor || !out || (outlen <= 2)) return -1;
 
@@ -1291,19 +1291,20 @@ ssize_t fr_radius_encode_pair(uint8_t *out, size_t outlen, fr_cursor_t *cursor,
         *      Fast path for the common case.
         */
        if (vp->da->parent->flags.is_root && !vp->da->flags.concat && (vp->vp_type != FR_TYPE_TLV)) {
-               da_stack[0] = vp->da;
-               da_stack[1] = NULL;
-               FR_PROTO_STACK_PRINT(da_stack, 0);
-               return encode_rfc_hdr(out, attr_len, da_stack, 0, cursor, encoder_ctx);
+               da_stack.da[0] = vp->da;
+               da_stack.da[1] = NULL;
+               da_stack.depth = 1;
+               FR_PROTO_STACK_PRINT(&da_stack, 0);
+               return encode_rfc_hdr(out, attr_len, &da_stack, 0, cursor, encoder_ctx);
        }
 
        /*
         *      Do more work to set up the stack for the complex case.
         */
-       fr_proto_da_stack_build(da_stack, vp->da);
-       FR_PROTO_STACK_PRINT(da_stack, 0);
+       fr_proto_da_stack_build(&da_stack, vp->da);
+       FR_PROTO_STACK_PRINT(&da_stack, 0);
 
-       da = da_stack[0];
+       da = da_stack.da[0];
        switch (da->type) {
        default:
                if (da->flags.concat) {
@@ -1313,10 +1314,10 @@ ssize_t fr_radius_encode_pair(uint8_t *out, size_t outlen, fr_cursor_t *cursor,
                         *      using a different scheme than the "long
                         *      extended" one.
                         */
-                       ret = encode_concat(out, outlen, da_stack, 0, cursor, encoder_ctx);
+                       ret = encode_concat(out, outlen, &da_stack, 0, cursor, encoder_ctx);
                        break;
                }
-               ret = encode_rfc_hdr(out, attr_len, da_stack, 0, cursor, encoder_ctx);
+               ret = encode_rfc_hdr(out, attr_len, &da_stack, 0, cursor, encoder_ctx);
                break;
 
        case FR_TYPE_VSA:
@@ -1327,18 +1328,18 @@ ssize_t fr_radius_encode_pair(uint8_t *out, size_t outlen, fr_cursor_t *cursor,
                         *      attributes by fragmenting them inside
                         *      of the WiMAX VSA space.
                         */
-                       ret = encode_wimax_hdr(out, outlen, da_stack, 0, cursor, encoder_ctx);
+                       ret = encode_wimax_hdr(out, outlen, &da_stack, 0, cursor, encoder_ctx);
                        break;
                }
-               ret = encode_vsa_hdr(out, attr_len, da_stack, 0, cursor, encoder_ctx);
+               ret = encode_vsa_hdr(out, attr_len, &da_stack, 0, cursor, encoder_ctx);
                break;
 
        case FR_TYPE_TLV:
-               ret = encode_tlv_hdr(out, attr_len, da_stack, 0, cursor, encoder_ctx);
+               ret = encode_tlv_hdr(out, attr_len, &da_stack, 0, cursor, encoder_ctx);
                break;
 
        case FR_TYPE_EXTENDED:
-               ret = encode_extended_hdr(out, attr_len, da_stack, 0, cursor, encoder_ctx);
+               ret = encode_extended_hdr(out, attr_len, &da_stack, 0, cursor, encoder_ctx);
                break;
 
        case FR_TYPE_INVALID: