--- /dev/null
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file src/lib/util/decode.c
+ * @brief Generic functions for decoding protocols.
+ *
+ * @copyright 2022 Network RADIUS SAS (legal@networkradius.com)
+ */
+#include <freeradius-devel/io/test_point.h>
+#include <freeradius-devel/util/proto.h>
+#include <freeradius-devel/util/decode.h>
+
+/** Decode an array of values from the network
+ *
+ * @param[in] ctx context to alloc new attributes in.
+ * @param[out] out Where to write the decoded options.
+ * @param[in] parent dictionary entry, must have parent->flags.array set
+ * @param[in] data to parse.
+ * @param[in] data_len of data to parse.
+ * @param[in] decode_ctx passed to decode_value
+ * @param[in] decode_value function to decode one value.
+ */
+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)
+{
+ uint8_t const *p = data, *end = p + data_len;
+ ssize_t slen;
+
+ FR_PROTO_HEX_DUMP(data, data_len, "fr_pair_array_from_network");
+
+ if (!fr_cond_assert_msg(parent->flags.array,
+ "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set",
+ __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR;
+
+ while (p < end) {
+ slen = decode_value(ctx, out, parent, p, (end - p), decode_ctx);
+ if (slen < 0) return slen - (p - data);
+
+ p += slen;
+ }
+
+ return data_len;
+}
*
* @file src/lib/util/decode.h
*
- * @copyright 2021 Network RADIUS SAS
+ * @copyright 2022 Network RADIUS SAS (legal@networkradius.com)
*/
RCSIDH(decode_h, "$Id$")
/** Typedefs for simplifying the use and declaration of protocol decoders.
*
*/
-typedef struct fr_proto_decode_ctx_s fr_proto_decode_ctx_t;
-
-typedef ssize_t (*fr_proto_decode_pair_t)(TALLOC_CTX *ctx, fr_pair_list_t *out,
+typedef 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, fr_proto_decode_ctx_t *decode_ctx);
+ uint8_t const *data, size_t const data_len, void *decode_ctx);
#define PROTO_DECODE_FUNC(_name) static ssize_t _name(TALLOC_CTX *ctx, fr_pair_list_t *out, \
fr_dict_attr_t const *parent, \
uint8_t const *data, size_t const data_len, fr_proto_decode_ctx_t *decode_ctx); \
+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);
+
#ifdef __cplusplus
}
#endif
cap.c \
dbuff.c \
debug.c \
+ decode.c \
dict_ext.c \
dict_fixup.c \
dict_print.c \
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,
bool nested, void *decode_ctx,
- fr_decode_value_t decode_value, fr_decode_value_t decode_tlv)
+ fr_pair_decode_value_t decode_value, fr_pair_decode_value_t decode_tlv)
{
unsigned int child_num;
uint8_t const *p = data, *end = data + data_len;
if (decode_value) {
ssize_t slen;
- slen = decode_value(child_ctx, child_list, child, p, child_length, decode_ctx);
+ if (child->flags.array) {
+ slen = fr_pair_array_from_network(child_ctx, child_list, child, p, child_length, decode_ctx, decode_value);
+ } else {
+ slen = decode_value(child_ctx, child_list, child, p, child_length, decode_ctx);
+ }
if (slen < 0) {
FR_PROTO_TRACE("Failed decoding value");
goto unknown;
#include <freeradius-devel/util/pair.h>
#include <freeradius-devel/util/value.h>
#include <freeradius-devel/util/proto.h>
+#include <freeradius-devel/util/decode.h>
#ifdef __cplusplus
extern "C" {
#endif
-typedef ssize_t (*fr_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);
-
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,
bool nested, void *decode_ctx,
- fr_decode_value_t decode_value, fr_decode_value_t decode_tlv) CC_HINT(nonnull(2,3,4));
+ fr_pair_decode_value_t decode_value, fr_pair_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_dcursor_t *cursor, void *encode_ctx);
static ssize_t decode_tlv(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);
-static ssize_t decode_array(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);
-
static ssize_t decode_value(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);
return decode_dns_labels(ctx, out, parent, data, data_len, decode_ctx);
}
- if (parent->flags.array) return decode_array(ctx, out, parent, data, data_len, decode_ctx);
-
return decode_value(ctx, out, parent, data, data_len, decode_ctx);
}
return data_len;
}
-static ssize_t decode_array(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)
-{
- uint8_t const *p = data, *end = p + data_len;
- ssize_t slen;
-
- FR_PROTO_HEX_DUMP(data, data_len, "decode_array");
-
- if (!fr_cond_assert_msg(parent->flags.array,
- "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set",
- __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR;
-
- while (p < end) {
- slen = decode_value(ctx, out, parent, p, (end - p), decode_ctx);
- if (slen < 0) return slen - (p - data);
-
- p += slen;
- }
-
- /*
- * We MUST have decoded the entire input. If
- * not, we ignore the extra bits.
- */
- return data_len;
-}
-
static ssize_t decode_dns_labels(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)
fr_pair_list_append(out, &tmp);
} else if (da->flags.array) {
- slen = decode_array(ctx, out, da, data + 2, len, decode_ctx);
+ slen = fr_pair_array_from_network(ctx, out, da, data + 2, len, decode_ctx, decode_value);
} else if (da->type == FR_TYPE_VSA) {
slen = decode_vsa(ctx, out, da, data + 2, len, decode_ctx);
slen = decode_tlv(ctx, out, da, packet_ctx->buffer, q - packet_ctx->buffer, packet_ctx);
} else if (da->flags.array) {
- slen = decode_array(ctx, out, da, packet_ctx->buffer, q - packet_ctx->buffer, packet_ctx);
+ slen = fr_pair_array_from_network(ctx, out, da, packet_ctx->buffer, q - packet_ctx->buffer, packet_ctx, decode_value);
} else {
slen = decode_value(ctx, out, da, packet_ctx->buffer, q - packet_ctx->buffer, packet_ctx);
static ssize_t decode_value(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);
-static ssize_t decode_array(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);
static ssize_t decode_dns_labels(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);
return decode_dns_labels(ctx, out, parent, data, data_len, decode_ctx);
}
- if (parent->flags.array) return decode_array(ctx, out, parent, data, data_len, decode_ctx);
-
return decode_value(ctx, out, parent, data, data_len, decode_ctx);
}
}
-static ssize_t decode_array(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)
-{
- uint8_t const *p = data, *end = p + data_len;
- ssize_t slen;
-
- FR_PROTO_HEX_DUMP(data, data_len, "decode_array");
-
- if (!fr_cond_assert_msg(parent->flags.array,
- "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set",
- __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR;
-
- while (p < end) {
- slen = decode_value(ctx, out, parent, p, (end - p), decode_ctx);
- if (slen < 0) return slen;
-
- p += slen;
- }
-
- /*
- * We MUST have decoded the entire input. If
- * not, we ignore the extra bits.
- */
- return data_len;
-}
-
static ssize_t decode_dns_labels(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)
fr_pair_list_append(out, &tmp);
} else if (da->flags.array) {
- slen = decode_array(ctx, out, da, data + 4, len, decode_ctx);
+ slen = fr_pair_array_from_network(ctx, out, da, data + 4, len, decode_ctx, decode_value);
} else if (da->type == FR_TYPE_VSA) {
slen = decode_vsa(ctx, out, da, data + 4, len, decode_ctx);
static ssize_t decode_value(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);
-static ssize_t decode_array(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);
+
static ssize_t decode_dns_labels(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);
FR_PROTO_TRACE("decode DNS labels");
return decode_dns_labels(ctx, out, parent, data, data_len, decode_ctx);
}
-
- if (parent->flags.array) return decode_array(ctx, out, parent, data, data_len, decode_ctx);
-
+
return decode_value(ctx, out, parent, data, data_len, decode_ctx);
}
}
-static ssize_t decode_array(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)
-{
- uint8_t const *p = data, *end = p + data_len;
- ssize_t slen;
- size_t element_len;
-
- FR_PROTO_HEX_DUMP(data, data_len, "decode_array");
-
- if (!fr_cond_assert_msg(parent->flags.array,
- "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set",
- __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR;
-
- /*
- * If the data is variable length i.e. strings or octets
- * there is a length field before each element.
- *
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+
- * | text-len | String |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+
- */
- while (p < end) {
- if ((end - p) < 2) {
- raw:
- slen = decode_raw(ctx, out, parent, p, end - p , decode_ctx);
- if (slen < 0) return slen;
- break;
- }
-
- element_len = fr_nbo_to_uint16(p);
- if ((p + 2 + element_len) > end) {
- goto raw;
- }
-
- p += 2;
- slen = decode_value(ctx, out, parent, p, element_len, decode_ctx);
- if (slen < 0) return slen;
- p += slen;
- }
-
- return data_len;
-}
-
static ssize_t decode_dns_labels(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)
}
} else if (da->flags.array) {
- slen = decode_array(ctx, out, da, data + 4, len, decode_ctx);
+ slen = fr_pair_array_from_network(ctx, out, da, data + 4, len, decode_ctx, decode_value);
} else {
slen = decode_value(ctx, out, da, data + 4, len, decode_ctx);