24 RCSID(
"$Id: a87a9510bfb7653ae32547900fd3e44143a12ac2 $")
26 #include <freeradius-devel/util/struct.h>
27 #include <freeradius-devel/util/encode.h>
28 #include <freeradius-devel/io/pair.h>
38 unsigned int child_num;
44 unsigned int offset = 0;
45 TALLOC_CTX *child_ctx;
67 child_list = &struct_vp->vp_group;
68 child_ctx = struct_vp;
76 size_t claimed_len, field_len, calc_len;
87 if ((
size_t) (end - p) < field_len) {
100 FR_PROTO_TRACE(
"Length header (%zu) is smaller than minimum value (%u)",
101 claimed_len,
parent->flags.type_size);
110 if (calc_len > (
size_t) (end - p)) {
111 FR_PROTO_TRACE(
"Length header (%zu) is larger than remaining data (%zu)",
112 claimed_len + field_len, (end - p));
136 FR_PROTO_HEX_DUMP(p, (end - p),
"fr_struct_from_network - child %s (%d)", child->name, child->attr);
143 unsigned int num_bits;
146 num_bits = offset + child->flags.length;
155 if (offset > 0)
array[0] &= (1 << (8 - offset)) - 1;
159 value >>= (8 - offset);
160 value >>= (56 - child->flags.length);
164 FR_PROTO_TRACE(
"fr_struct_from_network - failed allocating child VP");
168 switch (child->type) {
194 vp->vp_tainted =
true;
196 p += (num_bits >> 3);
197 offset = num_bits & 0x07;
210 fr_strerror_const(
"Decoding TLVs requires a decode_tlv() function to be passed");
218 slen = decode_tlv(child_ctx, child_list, child, p, end - p, decode_ctx);
229 child_length = child->flags.length;
235 if (child_length > (
size_t) (end - p)) {
236 FR_PROTO_TRACE(
"fr_struct_from_network - child length %zd overflows buffer", child_length);
244 if (!child_length || (child->flags.array)) {
245 child_length = end - p;
247 }
else if ((
size_t) (end - p) < child_length) {
248 FR_PROTO_TRACE(
"fr_struct_from_network - child length %zd underflows buffer", child_length);
261 if (child->flags.array) {
264 slen =
decode_value(child_ctx, child_list, child, p, child_length, decode_ctx);
281 switch (child->type) {
297 FR_PROTO_TRACE(
"fr_struct_from_network - failed allocating child VP");
308 &
FR_DBUFF_TMP(p, child_length), child_length,
true) < 0) {
312 TALLOC_FREE(struct_vp);
315 if (slen < 0)
return slen;
319 vp->vp_tainted =
true;
347 FR_PROTO_TRACE(
"Expected substruct, but there is none. We're done decoding this structure");
366 FR_PROTO_TRACE(
"failed allocating unknown child for key VP %s - %s",
373 FR_PROTO_TRACE(
"Failed creating raw VP from malformed or unknown substruct for child %s", child->name);
418 if (start_bit < 0 || start_bit > 7)
return -1;
419 if (num_bits < 1 || num_bits > 56)
return -1;
422 used_bits = *p & (-256 >> start_bit);
425 data &= (((uint64_t) 1) << num_bits) - 1;
428 data <<= (64 - (start_bit + num_bits));
429 data |= used_bits << 56;
433 start_bit += num_bits;
437 return start_bit % 8;
450 if (rcode != 0)
return rcode;
463 if (c->
da->dict !=
parent->dict || c->
da->flags.internal)
continue;
478 unsigned int child_num = 1;
479 bool do_length =
false;
484 size_t prefix_length = 0;
516 cursor = &child_cursor;
519 cursor = parent_cursor;
534 fr_strerror_printf(
"%s: Asked to encode %s, but its parent %s is not the expected parent %s",
585 if (offset != 0)
goto leftover_bits;
614 if (!
vp || (
vp->
da != child)) {
621 offset =
put_bits_dbuff(&work_dbuff, &bit_buffer, offset, child->flags.length, 0);
653 switch (child->type) {
712 if (child->flags.array) {
717 if (len < 0)
return len;
725 if (
vp->
da->flags.length && (
vp->data.enumv !=
vp->
da)) {
729 memcpy(&u, &c,
sizeof(c));
742 if (child->flags.array && (
vp->
da == child))
goto redo;
751 if (offset != 0)
goto leftover_bits;
757 FR_PROTO_TRACE(
"fr_struct_to_network encoding key %s", key_da->name);
766 if ((
vp->
da->parent == key_da) &&
773 if (len < 0)
return len;
784 if ((
vp->
da->parent->parent == key_da) &&
791 if (len < 0)
return len;
798 if ((
vp->
da->parent == key_da) &&
817 fr_strerror_printf(
"Asked to encode child attribute %s, but we were not passed an encoding function",
826 FR_PROTO_TRACE(
"fr_struct_to_network trailing TLVs of %s", tlv->name);
831 if (slen < 0)
return slen;
849 length -= prefix_length;
857 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_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
#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.
#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 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_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
fr_dcursor_eval_t void const * uctx
fr_dcursor_iter_t void * current
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
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.
@ FLAG_LENGTH_UINT8
string / octets type is prefixed by uint8 of length
#define da_length_offset(_da)
fr_dict_enum_value_t * 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_bit_field(_da)
void fr_dict_attr_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
#define da_is_length_field(_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)
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)
fr_dict_attr_t const * child_struct[]
for key fields
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.
Head of a doubly linked 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.
#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_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_raw_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len)
Create a "raw" pair from the network data.
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_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_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_UINT64
64 Bit unsigned integer.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_OCTETS
Raw octets.
static size_t array[MY_ARRAY_SIZE]
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_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
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 void * struct_next_encodable(fr_dlist_head_t *list, void *current, void *uctx)
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 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.
#define fr_pair_dcursor_iter_init(_cursor, _list, _iter, _uctx)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
fr_pair_t * fr_pair_list_tail(fr_pair_list_t const *list)
Get the tail of a valuepair list.
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.
#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)
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
#define fr_type_is_structural(_x)
ssize_t fr_value_box_from_network(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, fr_dbuff_t *dbuff, size_t len, bool tainted)
Decode a fr_value_box_t from serialized binary data.
return fr_dbuff_set(dbuff, &our_dbuff)
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