24RCSID(
"$Id: 8e378022b38a14a2845edc79000282b8ca66cfc8 $")
26#include <freeradius-devel/util/struct.h>
27#include <freeradius-devel/io/pair.h>
37 unsigned int child_num;
43 unsigned int offset = 0;
44 TALLOC_CTX *child_ctx;
66 child_list = &struct_vp->vp_group;
67 child_ctx = struct_vp;
79 size_t claimed_len, field_len, calc_len;
91 if ((
size_t) (end - p) < field_len) {
99 TALLOC_FREE(struct_vp);
102 if (slen < 0)
return slen;
114 FR_PROTO_TRACE(
"Length header (%zu) is smaller than minimum value (%u)",
115 claimed_len,
parent->flags.type_size);
124 if (calc_len > (
size_t) (end - p)) {
125 FR_PROTO_TRACE(
"Length header (%zu) is larger than remaining data (%zu)",
126 claimed_len + field_len, (
size_t) (end - p));
147 FR_PROTO_HEX_DUMP(p, (end - p),
"fr_struct_from_network - remaining %zu", (
size_t) (end - p));
154 unsigned int num_bits;
157 num_bits = offset + child->flags.length;
163 memset(array, 0,
sizeof(array));
166 if (offset > 0) array[0] &= (1 << (8 - offset)) - 1;
170 value >>= (8 - offset);
171 value >>= (56 - child->flags.length);
175 FR_PROTO_TRACE(
"fr_struct_from_network - failed allocating child VP");
181 switch (child->type) {
207 vp->vp_tainted =
true;
210 p += (num_bits >> 3);
211 offset = num_bits & 0x07;
222 if (!child->flags.length || child->flags.array) {
223 child_length = end - p;
226 child_length = child->flags.length;
232 if (child_length > (
size_t) (end - p)) {
233 FR_PROTO_TRACE(
"fr_struct_from_network - child length %zu overflows buffer", child_length);
242 switch (child->type) {
262 fr_strerror_const(
"Decoding TLVs requires a decode_tlv() function to be passed");
273 slen = decode_tlv(child_ctx, child_list, child, p, end - p, decode_ctx);
292 child_length = end - p;
303 substruct_da = child;
305 child_list = &
vp->vp_group;
317 if (child->flags.array) {
320 slen =
decode_value(child_ctx, child_list, child, p, child_length, decode_ctx);
348 substruct_da = key_vp->
da;
360 FR_PROTO_TRACE(
"Expected substruct, but there is none. We're done decoding this structure");
380 FR_PROTO_TRACE(
"failed allocating unknown child for key VP %s - %s",
387 FR_PROTO_TRACE(
"Failed creating raw VP from malformed or unknown substruct for child %s", child->name);
434 if (start_bit < 0 || start_bit > 7)
return -1;
435 if (num_bits < 1 || num_bits > 56)
return -1;
438 used_bits = *p & (-256 >> start_bit);
441 data &= (((uint64_t) 1) << num_bits) - 1;
444 data <<= (64 - (start_bit + num_bits));
445 data |= used_bits << 56;
449 start_bit += num_bits;
453 return start_bit % 8;
466 if (ret != 0)
return ret;
479 if (c->
da->dict !=
parent->dict || c->
da->flags.internal)
continue;
497 fr_strerror_printf(
"Asked to encode child attribute %s, but we were not passed an encoding function",
503 if (!
vp || (
vp->
da != tlv))
return 0;
509 FR_PROTO_TRACE(
"fr_struct_to_network trailing TLVs of %s", tlv->name);
514 if (slen < 0)
return slen;
533 fr_strerror_printf(
"Asked to encode child attribute %s, but we were not passed an encoding function",
548 FR_PROTO_TRACE(
"fr_struct_to_network union %s has no children", key_da->name);
608 FR_PROTO_TRACE(
"fr_struct_to_network union %s encoding key %s for child %s",
609 parent->da->name, key_da->name, child->
da->name);
623 if (slen < 0)
return slen;
667 unsigned int child_num;
668 bool do_length =
false;
674 size_t prefix_length = 0;
708 cursor = &child_cursor;
711 cursor = parent_cursor;
726 fr_strerror_printf(
"%s: Asked to encode %s, but its parent %s is not the expected parent %s",
804 if (!
vp || (
vp->
da != child)) {
811 offset =
put_bits_dbuff(&work_dbuff, &bit_buffer, offset, child->flags.length, 0);
824 if (child->type ==
FR_TYPE_TLV)
goto encode_length;
846 switch (child->type) {
904 if (slen < 0)
return slen;
916 slen =
encode_union(&work_dbuff, child, key_da, key_vp, &key_m, da_stack,
depth, cursor,
918 if (slen < 0)
return slen;
930 if (child->flags.array) {
935 if (slen < 0)
return slen;
943 if (offset != 0)
goto leftover_bits;
956 if (slen < 0)
return slen;
974 length -= prefix_length;
982 length -= prefix_length;
#define CMP_PREFER_SMALLER(_a, _b)
Evaluates to +1 for a > b, and -1 for a < b.
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
#define FR_DBUFF_ADVANCE_RETURN(_dbuff_or_marker, _len)
Advance the 'current' position in dbuff or marker by _len bytes returning if _len is out of range.
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
#define FR_DBUFF_INIT(_out, _start, _len_or_end)
#define FR_DBUFF_MEMSET_RETURN(_dbuff_or_marker, _c, _inlen)
Set _inlen bytes of a dbuff or marker to _c returning if there is insufficient space.
static uint8_t * fr_dbuff_marker(fr_dbuff_marker_t *m, fr_dbuff_t *dbuff)
Initialises a new marker pointing to the 'current' position of the dbuff.
#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space.
#define fr_dbuff_in(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff or marker.
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#define FR_DBUFF_MAX(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
static void * fr_dcursor_set_current(fr_dcursor_t *cursor, void *item)
Set the cursor to a specified item.
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
fr_dlist_head_t * dlist
Head of the doubly linked list being iterated over.
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
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, void *decode_ctx)
Decode a value from the network into an output fr_pair_list_t.
#define da_is_length_field16(_da)
#define da_length_offset(_da)
fr_dict_enum_value_t const * fr_dict_enum_iter_init(fr_dict_attr_t const *da, fr_dict_enum_iter_t *iter)
Iterate over all enumeration values for an attribute.
#define da_is_length_field8(_da)
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
#define da_is_bit_field(_da)
fr_value_box_t const * value
Enum value (what name maps to).
fr_dict_enum_value_t const * fr_dict_enum_iter_next(fr_dict_attr_t const *da, fr_dict_enum_iter_t *iter)
void fr_dict_attr_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
fr_dict_enum_value_t const * fr_dict_enum_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
Lookup the structure representing an enum value in a fr_dict_attr_t.
#define da_is_length_field(_da)
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
fr_dict_attr_t const * key_child_ref[]
for key fields
#define fr_dict_attr_is_key_field(_da)
Value of an enumerated attribute.
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
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)
Typedefs for simplifying the use and declaration of protocol encoders.
Stores the state of the current iteration operation.
#define PAIR_DECODE_OOM
Fatal error - Out of memory.
#define PAIR_ENCODE_FATAL_ERROR
Fatal encoding error.
static ssize_t encode_value(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, int depth, fr_dcursor_t *cursor, void *encode_ctx)
Encodes the data portion of an attribute.
ssize_t fr_pair_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, UNUSED void *decode_ctx)
Generic decode value.
ssize_t fr_pair_raw_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *da, uint8_t const *data, size_t data_len)
Create a "raw" pair from malformed network data.
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)
Decode an array of values from the network.
ssize_t fr_pair_array_to_network(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, int depth, fr_dcursor_t *cursor, void *encode_ctx, fr_encode_dbuff_t encode_value)
Encode an array of values from the network.
ssize_t fr_pair_encode_value(fr_dbuff_t *dbuff, UNUSED fr_da_stack_t *da_stack, UNUSED unsigned int depth, fr_dcursor_t *cursor, UNUSED void *encode_ctx)
Generic encode value.
ssize_t fr_pair_cursor_to_network(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx, fr_encode_dbuff_t encode_pair)
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
static uint8_t depth(fr_minmax_heap_index_t i)
static unsigned int fr_bytes_from_bits(unsigned int bits)
Convert bits (as in prefix length) to bytes, rounding up.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
void fr_proto_da_stack_build(fr_da_stack_t *stack, fr_dict_attr_t const *da)
Build a complete DA stack from the da back to the root.
static fr_internal_encode_ctx_t encode_ctx
static ssize_t encode_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, UNUSED void *encode_ctx)
static rc_request_t * current
static ssize_t encode_keyed_struct(fr_dbuff_t *dbuff, fr_pair_t const *vp, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx, fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
static ssize_t encode_tlv(fr_dbuff_t *dbuff, fr_dict_attr_t const *tlv, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx, UNUSED fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *parent_cursor, void *encode_ctx, fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
static void * struct_next_encodable(fr_dcursor_t *cursor, void *current, void *uctx)
static ssize_t encode_union(fr_dbuff_t *dbuff, fr_dict_attr_t const *wrapper, fr_dict_attr_t const *key_da, fr_pair_t const *key_vp, fr_dbuff_marker_t *key_m, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx, UNUSED fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
static int8_t pair_sort_increasing(void const *a, void const *b)
static int put_bits_dbuff(fr_dbuff_t *dbuff, uint8_t *p, int start_bit, uint8_t num_bits, uint64_t data)
Put bits into an output dbuff.
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, void *decode_ctx, fr_pair_decode_value_t decode_value, fr_pair_decode_value_t decode_tlv)
Convert a STRUCT to one or more VPs.
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
static ssize_t encode_data(char *p, uint8_t *output, size_t outlen)
#define fr_pair_dcursor_iter_init(_cursor, _list, _iter, _uctx)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
void fr_pair_list_sort(fr_pair_list_t *list, fr_cmp_t cmp)
Sort a doubly linked list of fr_pair_ts using merge sort.
fr_pair_t * fr_pair_list_tail(fr_pair_list_t const *list)
Get the tail of a valuepair list.
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
#define FR_PROTO_TRACE(_fmt,...)
#define FR_PROTO_STACK_PRINT(_stack, _depth)
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Structure for holding the stack of dictionary attributes being encoded.
char const * fr_strerror(void)
Get the last library error.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
@ FR_TYPE_UNION
A union of limited children.
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value)
Encode a single value box, serializing its contents in generic network format.
static size_t char ** out