The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 9a776f1bccb6fda44ce026f2b5226ed31f045b25 $
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 if we ran out of space.
40  * - < 0 on error.
41  */
44 {
45  ssize_t slen;
46  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
47  fr_pair_t *vp;
48  fr_dict_attr_t const *da = da_stack->da[depth];
49 
50  FR_PROTO_STACK_PRINT(da_stack, depth);
51 
52  if (!fr_cond_assert_msg(da->flags.array,
53  "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set",
54  __FUNCTION__, da->name)) return PAIR_ENCODE_FATAL_ERROR;
55 
56  while (fr_dbuff_extend(&work_dbuff)) {
57  fr_dbuff_t element_dbuff = FR_DBUFF(&work_dbuff);
58 
59  slen = encode_value(&element_dbuff, da_stack, depth, cursor, encode_ctx);
60  if (slen < 0) return slen;
61 
62  fr_dbuff_set(&work_dbuff, &element_dbuff);
63 
64  vp = fr_dcursor_current(cursor);
65  if (!vp || (vp->da != da)) break; /* Stop if we have an attribute of a different type */
66  }
67 
68  return fr_dbuff_set(dbuff, &work_dbuff);
69 }
70 
72  fr_da_stack_t *da_stack, unsigned int depth,
73  fr_dcursor_t *cursor, void *encode_ctx, fr_encode_dbuff_t encode_pair)
74 {
75  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
76  fr_pair_t const *vp;
77  fr_dict_attr_t const *da = da_stack->da[depth];
78  ssize_t len;
79 
80  while (true) {
81  FR_PROTO_STACK_PRINT(da_stack, depth);
82 
83  vp = fr_dcursor_current(cursor);
84  fr_assert(!vp->da->flags.internal);
85 
86  len = encode_pair(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx);
87  if (len < 0) return len;
88 
89  /*
90  * If nothing updated the attribute, stop
91  */
92  if (!fr_dcursor_current(cursor) || (vp == fr_dcursor_current(cursor))) break;
93 
94  vp = fr_dcursor_current(cursor);
95  if (!vp) break;
96 
97  fr_proto_da_stack_build(da_stack, vp->da);
98 
99  /*
100  * We can encode multiple children, if after
101  * rebuilding the DA Stack, the attribute at this
102  * depth is the same.
103  */
104  if ((da != da_stack->da[depth]) || (da_stack->depth < da->depth)) break;
105  }
106 
107  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done cursor");
108 
109  return fr_dbuff_set(dbuff, &work_dbuff);
110 }
111 
112 /** Encode a foreign reference to the network
113  *
114  * @param[out] dbuff buffer to write the TLV to.
115  * @param[in] da_stack Describing nesting of options.
116  * @param[in] depth in the da_stack.
117  * @param[in,out] cursor Current attribute we're encoding.
118  * @return
119  * - >0 length of data encoded.
120  * - 0 if we ran out of space.
121  * - < 0 on error.
122  */
124  fr_dcursor_t *cursor)
125 {
126  ssize_t slen;
127  fr_dict_attr_t const *da;
128  fr_pair_t const *vp = fr_dcursor_current(cursor);
129  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
130 
131  fr_dict_attr_t const *ref;
132  fr_dict_protocol_t const *proto;
133 
134  FR_PROTO_STACK_PRINT(da_stack, depth);
135 
136  da = da_stack->da[depth];
137  fr_assert(da->type == FR_TYPE_GROUP);
138 
139  ref = fr_dict_attr_ref(da);
140  if (!ref) {
141  fr_strerror_printf("Invalid attribute reference for %s", da->name);
142  return 0;
143  }
144 
145  proto = fr_dict_protocol(ref->dict);
146  fr_assert(proto != NULL);
147 
148  if (!proto->encode) {
149  fr_strerror_printf("Attribute %s -> %s does not have an encoder", da->name, ref->name);
150  return 0;
151  }
152 
153  /*
154  * The foreign functions don't take a cursor, so we have to update the cursor ourselves.
155  */
156  slen = proto->encode(&work_dbuff, &vp->vp_group);
157  if (slen <= 0) return slen;
158 
159  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "group ref");
160 
161  vp = fr_dcursor_next(cursor);
162  fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
163 
164  return fr_dbuff_set(dbuff, &work_dbuff);
165 }
#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:762
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition: dbuff.h:893
#define fr_dbuff_extend(_dbuff)
Extend if no space remains.
Definition: dbuff.h:700
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition: dbuff.h:222
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition: dcursor.h:336
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:154
fr_dict_protocol_t const * fr_dict_protocol(fr_dict_t const *dict)
Return the protocol descriptor for the dictionary.
Definition: dict_util.c:4537
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition: dict.h:341
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:164
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:37
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:272
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:42
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:123
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:71
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
long int ssize_t
Definition: merged_model.c:24
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 char const * proto(int id, int porttype)
Definition: radwho.c:85
fr_assert(0)
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:41
#define FR_PROTO_STACK_PRINT(_stack, _depth)
Definition: proto.h:43
uint8_t depth
Deepest attribute in the stack.
Definition: proto.h:55
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Definition: proto.h:56
Structure for holding the stack of dictionary attributes being encoded.
Definition: proto.h:54
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
return fr_dbuff_set(dbuff, &our_dbuff)