The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
encode.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: a99b1b9d8b86b4f27b6f371f0cfee7cd52eaea91 $
19 *
20 * @file src/lib/util/encode.c
21 * @brief Generic functions for decoding protocols.
22 *
23 * @copyright 2022 Network RADIUS SAS (legal@networkradius.com)
24 */
25#include <freeradius-devel/io/test_point.h>
26#include <freeradius-devel/util/proto.h>
27#include <freeradius-devel/util/encode.h>
28
29/** Encode an array of values from the network
30 *
31 * @param[out] dbuff buffer to write the TLV to.
32 * @param[in] da_stack Describing nesting of options.
33 * @param[in] depth in the da_stack.
34 * @param[in,out] cursor Current attribute we're encoding.
35 * @param[in] encode_ctx Containing DHCPv4 dictionary.
36 * @param[in] encode_value Function to perform encoding of a single value.
37 * @return
38 * - >0 length of data encoded.
39 * - <= 0 on error.
40 */
43{
44 ssize_t slen;
45 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
47 fr_dict_attr_t const *da = da_stack->da[depth];
48
49 FR_PROTO_STACK_PRINT(da_stack, depth);
50
51 if (!fr_cond_assert_msg(da->flags.array,
52 "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set",
53 __FUNCTION__, da->name)) return PAIR_ENCODE_FATAL_ERROR;
54
55 while (fr_dbuff_extend(&work_dbuff)) {
56 fr_dbuff_t element_dbuff = FR_DBUFF(&work_dbuff);
57
58 /*
59 * Encoding "no data" in an array doesn't make sense.
60 */
61 slen = encode_value(&element_dbuff, da_stack, depth, cursor, encode_ctx);
62 if (slen <= 0) return slen;
63
64 fr_dbuff_set(&work_dbuff, &element_dbuff);
65
66 vp = fr_dcursor_current(cursor);
67 if (!vp || (vp->da != da)) break; /* Stop if we have an attribute of a different type */
68 }
69
70 return fr_dbuff_set(dbuff, &work_dbuff);
71}
72
74 fr_da_stack_t *da_stack, unsigned int depth,
76{
77 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
78 fr_pair_t const *vp;
79 ssize_t len;
80
81 while (true) {
82 FR_PROTO_STACK_PRINT(da_stack, depth);
83
84 vp = fr_dcursor_current(cursor);
85 fr_assert(!vp->da->flags.internal);
86
87 len = encode_pair(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx);
88 if (len < 0) return len;
89
90 /*
91 * If nothing updated the attribute, stop
92 */
93 if (!fr_dcursor_current(cursor) || (vp == fr_dcursor_current(cursor))) break;
94
95 vp = fr_dcursor_current(cursor);
96 if (!vp) break;
97
98 fr_proto_da_stack_build(da_stack, vp->da);
99 }
100
101 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done cursor");
102
103 return fr_dbuff_set(dbuff, &work_dbuff);
104}
105
106/** Encode a foreign reference to the network
107 *
108 * @param[out] dbuff buffer to write the TLV to.
109 * @param[in] da_stack Describing nesting of options.
110 * @param[in] depth in the da_stack.
111 * @param[in,out] cursor Current attribute we're encoding.
112 * @return
113 * - >0 length of data encoded.
114 * - 0 if we ran out of space.
115 * - < 0 on error.
116 */
118 fr_dcursor_t *cursor)
119{
120 ssize_t slen;
121 fr_dict_attr_t const *da;
122 fr_pair_t const *vp = fr_dcursor_current(cursor);
123 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
124
125 fr_dict_attr_t const *ref;
126 fr_dict_protocol_t const *proto;
127
128 FR_PROTO_STACK_PRINT(da_stack, depth);
129
130 da = da_stack->da[depth];
131 fr_assert(da->type == FR_TYPE_GROUP);
132
133 ref = fr_dict_attr_ref(da);
134 if (!ref) {
135 fr_strerror_printf("Invalid attribute reference for %s", da->name);
136 return 0;
137 }
138
139 proto = fr_dict_protocol(ref->dict);
140 fr_assert(proto != NULL);
141
142 if (!proto->encode) {
143 fr_strerror_printf("Attribute %s -> %s does not have an encoder", da->name, ref->name);
144 return 0;
145 }
146
147 /*
148 * The foreign functions don't take a cursor, so we have to update the cursor ourselves.
149 */
150 slen = proto->encode(&work_dbuff, &vp->vp_group);
151 if (slen < 0) return slen;
152
153 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "group ref");
154
155 vp = fr_dcursor_next(cursor);
156 fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
157
158 return fr_dbuff_set(dbuff, &work_dbuff);
159}
160
161/** Generic encode value.
162 *
163 */
165 fr_dcursor_t *cursor, UNUSED void *encode_ctx)
166{
167 fr_pair_t const *vp = fr_dcursor_current(cursor);
168 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
169
170 if (!fr_type_is_leaf(vp->vp_type)) {
171 FR_PROTO_TRACE("Cannot use generic encoder for data type %s", fr_type_to_str(vp->vp_type));
172 fr_strerror_printf("Cannot encode data type %s", fr_type_to_str(vp->vp_type));
174 }
175
176 if (fr_value_box_to_network(&work_dbuff, &vp->data) <= 0) return PAIR_ENCODE_FATAL_ERROR;
177
178 (void) fr_dcursor_next(cursor);
179
180 return fr_dbuff_set(dbuff, &work_dbuff);
181}
#define UNUSED
Definition build.h:317
#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...
Definition dbuff.h:777
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
Definition dbuff.h:1014
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:908
#define fr_dbuff_extend(_dbuff)
Extend if no space remains.
Definition dbuff.h:715
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:232
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:290
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:339
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:148
fr_dict_protocol_t const * fr_dict_protocol(fr_dict_t const *dict)
Return the protocol descriptor for the dictionary.
Definition dict_util.c:5259
fr_dict_attr_encode_func_t encode
for encoding attributes.
Definition dict.h:491
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:457
static fr_dict_attr_t const * fr_dict_attr_ref(fr_dict_attr_t const *da)
Return the reference associated with a group type attribute.
Definition dict_ext.h:148
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.
Definition encode.h:37
#define PAIR_ENCODE_FATAL_ERROR
Fatal encoding error.
Definition pair.h:36
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.
Definition encode.c:277
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.
Definition encode.c:41
ssize_t fr_pair_ref_to_network(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor)
Encode a foreign reference to the network.
Definition encode.c:117
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.
Definition encode.c:164
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)
Definition encode.c:73
@ FR_TYPE_GROUP
A grouping of other attributes.
long int ssize_t
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
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.
Definition proto.c:118
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)
Definition base.c:39
#define fr_assert(_expr)
Definition rad_assert.h:38
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition proto.h:42
#define FR_PROTO_TRACE(_fmt,...)
Definition proto.h:41
#define FR_PROTO_STACK_PRINT(_stack, _depth)
Definition proto.h:44
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Definition proto.h:57
Structure for holding the stack of dictionary attributes being encoded.
Definition proto.h:55
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_type_is_leaf(_x)
Definition types.h:394
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:455
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.
Definition value.c:1525