24RCSID(
"$Id: 771ee0b75dc2e4484a6eed9ea2dbf1beacf933f2 $")
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;
67 child_list = &struct_vp->vp_group;
68 child_ctx = struct_vp;
80 size_t claimed_len, field_len, calc_len;
92 if ((
size_t) (end - p) < field_len) {
100 TALLOC_FREE(struct_vp);
103 if (slen < 0)
return slen;
115 FR_PROTO_TRACE(
"Length header (%zu) is smaller than minimum value (%u)",
116 claimed_len,
parent->flags.type_size);
125 if (calc_len > (
size_t) (end - p)) {
126 FR_PROTO_TRACE(
"Length header (%zu) is larger than remaining data (%zu)",
127 claimed_len + field_len, (
size_t) (end - p));
146 FR_PROTO_HEX_DUMP(p, (end - p),
"fr_struct_from_network - remaining %zu", (
size_t) (end - p));
153 unsigned int num_bits;
156 num_bits = offset + child->flags.length;
162 memset(array, 0,
sizeof(array));
165 if (offset > 0) array[0] &= (1 << (8 - offset)) - 1;
169 value >>= (8 - offset);
170 value >>= (56 - child->flags.length);
174 FR_PROTO_TRACE(
"fr_struct_from_network - failed allocating child VP");
180 switch (child->type) {
206 vp->vp_tainted =
true;
209 p += (num_bits >> 3);
210 offset = num_bits & 0x07;
221 if (!child->flags.length || child->flags.array) {
222 child_length = end - p;
225 child_length = child->flags.length;
231 if (child_length > (
size_t) (end - p)) {
232 child_length = (
size_t) (end - p);
240 switch (child->type) {
260 fr_strerror_const(
"Decoding TLVs requires a decode_tlv() function to be passed");
271 slen = decode_tlv(child_ctx, child_list, child, p, end - p, decode_ctx);
294 substruct_da = child;
296 child_list = &
vp->vp_group;
301 child_length = (
size_t) (end - p);
316 if (child->flags.array) {
319 slen =
decode_value(child_ctx, child_list, child, p, child_length, decode_ctx);
347 substruct_da = key_vp->
da;
359 FR_PROTO_TRACE(
"Expected substruct, but there is none. We're done decoding this structure");
387 FR_PROTO_TRACE(
"failed allocating unknown child for key VP %s - %s",
394 FR_PROTO_TRACE(
"Failed creating raw VP from malformed or unknown substruct for child %s", child->name);
402 switch (child->type) {
411 FR_PROTO_TRACE(
"Failed to pass decode_tlv() for child tlv %s", child->name);
417 slen = decode_tlv(child_ctx, child_list, child, p, end - p, decode_ctx);
434 if (!child->flags.length || child->flags.array) {
435 child_length = end - p;
438 child_length = child->flags.length;
444 if (child_length > (
size_t) (end - p)) {
445 FR_PROTO_TRACE(
"fr_struct_from_network - child length %zu overflows buffer", child_length);
450 if (child->flags.array) {
453 slen =
decode_value(child_ctx, child_list, child, p, child_length, decode_ctx);
496 if (start_bit < 0 || start_bit > 7)
return -1;
497 if (num_bits < 1 || num_bits > 56)
return -1;
500 used_bits = *p & (-256 >> start_bit);
503 data &= (((uint64_t) 1) << num_bits) - 1;
506 data <<= (64 - (start_bit + num_bits));
507 data |= used_bits << 56;
511 start_bit += num_bits;
515 return start_bit % 8;
528 if (ret != 0)
return ret;
541 if (c->
da->dict !=
parent->dict || c->
da->flags.internal)
continue;
559 fr_strerror_printf(
"Asked to encode child attribute %s, but we were not passed an encoding function",
565 if (!
vp || (
vp->
da != tlv))
return 0;
571 FR_PROTO_TRACE(
"fr_struct_to_network trailing TLVs of %s", tlv->name);
576 if (slen < 0)
return slen;
605 FR_PROTO_TRACE(
"fr_struct_to_network union %s has no children", key_da->name);
632 if (!found && child->
da->flags.is_unknown) {
657 if (!child_ref)
continue;
659 if (child_ref == child->
da)
break;
679 FR_PROTO_TRACE(
"fr_struct_to_network union %s encoding key %s for child %s",
680 parent->da->name, key_da->name, child->
da->name);
693 switch (child->
da->type) {
712 if (slen < 0)
return slen;
756 unsigned int child_num;
757 bool do_length =
false;
764 size_t prefix_length = 0;
798 cursor = &child_cursor;
801 cursor = parent_cursor;
816 fr_strerror_printf(
"%s: Asked to encode %s, but its parent %s is not the expected parent %s",
865 while (last &&
vp && (last->
da->parent ==
vp->
da->parent) && (last->
da->attr ==
vp->
da->attr)) {
903 if (!
vp || (
vp->
da != child)) {
910 offset =
put_bits_dbuff(&work_dbuff, &bit_buffer, offset, child->flags.length, 0);
924 if (child->type ==
FR_TYPE_TLV)
goto encode_length;
951 switch (child->type) {
1013 if (slen < 0)
return slen;
1025 slen =
encode_union(&work_dbuff, child, key_da, key_vp, &key_m, da_stack,
depth, cursor,
1027 if (slen < 0)
return slen;
1039 if (child->flags.array) {
1044 if (slen < 0)
return slen;
1052 if (offset != 0)
goto leftover_bits;
1062 if (slen < 0)
return slen;
1080 length -= prefix_length;
1088 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.
#define fr_dict_attr_is_key_field(_da)
Value of an enumerated attribute.
static fr_dict_attr_t const * fr_dict_enum_attr_ref(fr_dict_enum_value_t const *enumv)
Return the attribute reference associated with an enum.
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 int encode(bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t id)
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.
#define fr_type_is_integer(_x)
uint64_t fr_value_box_as_uint64(fr_value_box_t const *vb)
Return a uint64_t from a fr_value_box_t.
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