*
*/
ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_cursor_t *cursor,
- fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len)
+ fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len,
+ fr_dict_attr_t const **child_p)
{
unsigned int child_num;
uint8_t const *p = data, *end = data + data_len;
* Record where we were in the list when this function was called
*/
fr_cursor_init(&child_cursor, &head);
+ *child_p = NULL;
/*
* Data is too small for the structure, ignore it.
child = fr_dict_attr_child_by_num(parent, child_num);
if (!child) break;
+ /*
+ * Decode child TLVs, according to the parent attribute.
+ *
+ * Return only PARTIALLY decoded data. Let the
+ * caller decode the rest.
+ */
+ if (child->type == FR_TYPE_TLV) {
+ *child_p = child;
+
+ fr_cursor_head(&child_cursor);
+ fr_cursor_tail(cursor);
+ fr_cursor_merge(cursor, &child_cursor); /* Wind to the end of the new pairs */
+ return (p - data);
+ }
+
child_length = child->flags.length;
if (!child_length) child_length = (end - p);
#endif
ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_cursor_t *cursor,
- fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len) CC_HINT(nonnull);
+ fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len,
+ fr_dict_attr_t const **child) CC_HINT(nonnull(2,3,4));
ssize_t fr_struct_to_network(uint8_t *out, size_t outlen,
fr_dict_attr_t const *parent, fr_cursor_t *cursor) CC_HINT(nonnull);
* attribute, OR it's already been grouped
* into a contiguous memory buffer.
*/
- rcode = fr_struct_from_network(ctx, cursor, parent, p, attr_len);
+ rcode = fr_struct_from_network(ctx, cursor, parent, p, attr_len, &child);
if (rcode < 0) goto raw;
+
+ /*
+ * The above function only decodes fixed fields
+ * and strings. If there are TLVs at the end of
+ * the struct, we have to decode them manually
+ * here.
+ */
+ if (child && ((size_t) rcode < attr_len)) {
+ size_t tlv_len;
+
+ /*
+ * Try to decode the TLVs
+ */
+ tlv_len = fr_radius_decode_tlv(ctx, cursor, child, p + rcode, attr_len - rcode,
+ decoder_ctx);
+ if (tlv_len < 0) {
+ vp = fr_unknown_from_network(ctx, child, p + rcode, attr_len - rcode);
+ if (vp) fr_cursor_append(cursor, vp);
+ }
+ }
+
return attr_len;
case FR_TYPE_VSA: