#endif
/*
- * Build an unknown attr of the entire STRUCT.
+ * Build an unknown attr of the entire data.
*/
unknown = fr_dict_unknown_attr_afrom_da(ctx, parent);
if (!unknown) return NULL;
*/
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 **child_p, void *decoder_ctx,
+ void *decoder_ctx,
fr_decode_value_t decode_value, fr_decode_value_t decode_tlv)
{
unsigned int child_num;
* Record where we were in the list when this function was called
*/
fr_cursor_init(&child_cursor, &head);
- *child_p = NULL;
child_num = 1;
key_vp = NULL;
/*
* Decode child TLVs, according to the parent attribute.
- *
- * Return only PARTIALLY decoded data. Let the
- * caller decode the rest.
- *
- * @todo - pass TLVs to the "decode_value"
- * function, so it can decode them.
*/
if (child->type == FR_TYPE_TLV) {
- *child_p = child;
+ ssize_t slen;
+
+ fr_assert(!key_vp);
+
+ if (!decode_tlv) {
+ fr_strerror_printf("Decoding TLVs requires a decode_tlv() function to be passed");
+ return -(p - data);
+ }
+
+ /*
+ * Decode EVERYTHING as a TLV.
+ */
+ while (p < end) {
+ slen = decode_tlv(ctx, &child_cursor, fr_dict_by_da(child), child, p, end - p, decoder_ctx);
+ if (slen < 0) goto unknown;
+ p += slen;
+ }
- 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);
+ goto done;
}
child_length = child->flags.length;
} else {
fr_assert(child->type == FR_TYPE_STRUCT);
- slen = fr_struct_from_network(ctx, &child_cursor, child, p, end - p, child_p,
+ slen = fr_struct_from_network(ctx, &child_cursor, child, p, end - p,
decoder_ctx, decode_value, decode_tlv);
if (slen <= 0) goto unknown_child;
p += slen;
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 **child, void *decoder_ctx,
+ void *decoder_ctx,
fr_decode_value_t decode_value, fr_decode_value_t decode_tlv) CC_HINT(nonnull(2,3,4));
typedef ssize_t (*fr_encode_dbuff_t)(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth,
{
fr_arp_packet_t const *arp;
fr_cursor_t cursor;
- fr_dict_attr_t const *child;
if (packet_len < FR_ARP_PACKET_SIZE) {
fr_strerror_printf("Packet is too small (%d) to be ARP", (int) packet_len);
*/
fr_pair_list_init(list);
fr_cursor_init(&cursor, list);
- return fr_struct_from_network(ctx, &cursor, attr_arp_packet, packet, FR_ARP_PACKET_SIZE, &child,
+ return fr_struct_from_network(ctx, &cursor, attr_arp_packet, packet, FR_ARP_PACKET_SIZE,
NULL, NULL, NULL);
}
fr_dict_attr_t const *parent,
uint8_t const *data, size_t const data_len, void *decoder_ctx, bool do_raw);
+static ssize_t decode_tlv_trampoline(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const *dict,
+ fr_dict_attr_t const *parent,
+ uint8_t const *data, size_t const data_len, void *decoder_ctx)
+{
+ return decode_tlvs(ctx, cursor, dict, parent, data, data_len, decoder_ctx, true);
+}
+
+
static ssize_t decode_raw(TALLOC_CTX *ctx, fr_cursor_t *cursor, UNUSED fr_dict_t const *dict,
fr_dict_attr_t const *parent,
uint8_t const *data, size_t const data_len, void *decoder_ctx)
{
ssize_t slen;
fr_pair_t *vp;
- fr_dict_attr_t const *tlv;
uint8_t prefix_len;
FR_PROTO_HEX_DUMP(data, data_len, "decode_value");
break;
case FR_TYPE_STRUCT:
- slen = fr_struct_from_network(ctx, cursor, parent, data, data_len, &tlv,
- decoder_ctx, decode_value_trampoline, NULL);
+ slen = fr_struct_from_network(ctx, cursor, parent, data, data_len,
+ decoder_ctx, decode_value_trampoline, decode_tlv_trampoline);
if (slen < 0) return slen;
-
- if (tlv) {
- fr_strerror_printf("decode children not implemented");
- return PAIR_DECODE_FATAL_ERROR;
- }
-
return data_len;
case FR_TYPE_GROUP:
return fr_radius_decode_pair_value(ctx, cursor, dict, parent, data, data_len, data_len, decoder_ctx);
}
+/** Wrapper called by fr_struct_from_network()
+ */
+static ssize_t decode_tlv(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const *dict,
+ fr_dict_attr_t const *parent,
+ uint8_t const *data, size_t data_len, void *decoder_ctx)
+{
+ FR_PROTO_HEX_DUMP(data, data_len, "%s", __FUNCTION__ );
+
+ return fr_radius_decode_tlv(ctx, cursor, dict, parent, data, data_len, decoder_ctx);
+}
+
/** Create any kind of VP from the attribute contents
*
* attribute, OR it's already been grouped
* into a contiguous memory buffer.
*/
- ret = fr_struct_from_network(ctx, cursor, parent, p, attr_len, &child,
- decoder_ctx, decode_value, NULL);
+ ret = fr_struct_from_network(ctx, cursor, parent, p, attr_len,
+ decoder_ctx, decode_value, decode_tlv);
if (ret < 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) ret < attr_len)) {
- ssize_t tlv_len;
-
- /*
- * Try to decode the TLVs
- */
- tlv_len = fr_radius_decode_tlv(ctx, cursor, dict,
- child, p + ret, attr_len - ret,
- decoder_ctx);
- if (tlv_len < 0) {
- vp = fr_raw_from_network(ctx, child, p + ret, attr_len - ret);
- if (vp) fr_cursor_append(cursor, vp);
- }
- }
-
return attr_len;
default:
*/
ssize_t fr_tacacs_decode(TALLOC_CTX *ctx, uint8_t const *buffer, size_t buffer_len, UNUSED const uint8_t *original, char const * const secret, size_t secret_len, fr_cursor_t *cursor)
{
- fr_dict_attr_t const *tlv;
fr_tacacs_packet_t const *pkt;
fr_pair_t *vp;
uint8_t const *p, *end;
/*
* Call the struct encoder to do the actual work.
*/
- if (fr_struct_from_network(ctx, cursor, attr_tacacs_packet, buffer, buffer_len, &tlv, NULL, NULL, NULL) < 0) {
+ if (fr_struct_from_network(ctx, cursor, attr_tacacs_packet, buffer, buffer_len, NULL, NULL, NULL) < 0) {
fr_strerror_printf("Problems to decode %s using fr_struct_from_network()", attr_tacacs_packet->name);
return -1;
}