28 RCSID(
"$Id: 3640834e39910cd0f01ded26c0974c6e8055e9db $")
30 #include <freeradius-devel/util/atexit.h>
31 #include <freeradius-devel/util/debug.h>
33 #include <freeradius-devel/util/misc.h>
34 #include <freeradius-devel/util/proto.h>
35 #include <freeradius-devel/util/value.h>
37 #include <freeradius-devel/server/dependency.h>
38 #include <freeradius-devel/server/main_loop.h>
40 #include <freeradius-devel/protocol/snmp/freeradius.h>
64 #define FR_FREERADIUS_SNMP_TYPE_OBJECT 0
66 #define SNMP_MAP_TERMINATOR { .name = NULL, .da = NULL, .type = 0 }
105 static int reset_state = FR_RADIUS_AUTH_SERV_CONFIG_RESET_VALUE_RUNNING;
169 switch (
in->vb_uint32) {
170 case FR_RADIUS_AUTH_SERV_CONFIG_RESET_VALUE_RESET:
176 return -(FR_FREERADIUS_SNMP_FAILURE_VALUE_WRONG_VALUE);
200 if (!client)
return 1;
202 *snmp_ctx_out = client;
234 if (client->
ipaddr.
af != AF_INET)
return 0;
235 memcpy(&
out->vb_ip, &client->
ipaddr,
sizeof(
out->vb_ip));
267 { .
name =
"Radius-Auth-Client-Index",
268 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_INTEGER,
270 { .name =
"Radius-Auth-Client-Address",
271 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_IPADDRESS,
273 { .name =
"Radius-Auth-Client-ID",
274 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_STRING,
276 { .name =
"Radius-Auth-Serv-Access-Requests",
277 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
278 .offset = offsetof(
fr_stats_t, total_requests),
280 { .name =
"Radius-Auth-Serv-Dup-Access-Requests",
281 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
282 .offset = offsetof(
fr_stats_t, total_dup_requests),
284 { .name =
"Radius-Auth-Serv-Access-Accepts",
285 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
286 .offset = offsetof(
fr_stats_t, total_access_accepts),
288 { .name =
"Radius-Auth-Serv-Access-Rejects",
289 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
290 .offset = offsetof(
fr_stats_t, total_access_rejects),
292 { .name =
"Radius-Auth-Serv-Access-Challenges",
293 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
294 .offset = offsetof(
fr_stats_t, total_access_challenges),
296 { .name =
"Radius-Auth-Serv-Malformed-Access-Requests",
297 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
298 .offset = offsetof(
fr_stats_t, total_malformed_requests),
300 { .name =
"Radius-Auth-Serv-Bad-Authenticators",
301 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
302 .offset = offsetof(
fr_stats_t, total_bad_authenticators),
304 { .name =
"Radius-Auth-Serv-Packets-Dropped",
305 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
306 .offset = offsetof(
fr_stats_t, total_packets_dropped),
308 { .name =
"Radius-Auth-Serv-Unknown-Types",
309 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
310 .offset = offsetof(
fr_stats_t, total_unknown_types),
316 { .
name =
"Radius-Auth-Client-Entry",
324 { .
name =
"Radius-Auth-Serv-Ident",
325 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_STRING,
327 { .name =
"Radius-Auth-Serv-Up-Time",
328 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_TIMETICKS,
330 { .name =
"Radius-Auth-Serv-Reset-Time",
331 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_TIMETICKS,
333 { .name =
"Radius-Auth-Serv-Config-Reset",
334 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_INTEGER,
337 { .name =
"Radius-Auth-Serv-Total-Access-Requests",
338 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
339 .offset = offsetof(
fr_stats_t, total_requests),
341 { .name =
"Radius-Auth-Serv-Total-Invalid-Requests",
342 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
343 .offset = offsetof(
fr_stats_t, total_invalid_requests),
345 { .name =
"Radius-Auth-Serv-Total-Dup-Access-Requests",
346 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
347 .offset = offsetof(
fr_stats_t, total_dup_requests),
349 { .name =
"Radius-Auth-Serv-Total-Access-Accepts",
350 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
351 .offset = offsetof(
fr_stats_t, total_access_accepts),
353 { .name =
"Radius-Auth-Serv-Total-Access-Rejects",
354 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
355 .offset = offsetof(
fr_stats_t, total_access_rejects),
357 { .name =
"Radius-Auth-Serv-Total-Access-Challenges",
358 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
359 .offset = offsetof(
fr_stats_t, total_access_challenges),
361 { .name =
"Radius-Auth-Serv-Total-Malformed-Access-Requests",
362 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
363 .offset = offsetof(
fr_stats_t, total_malformed_requests),
365 { .name =
"Radius-Auth-Serv-Total-Bad-Authenticators",
366 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
367 .offset = offsetof(
fr_stats_t, total_bad_authenticators),
369 { .name =
"Radius-Auth-Serv-Total-Packets-Dropped",
370 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
371 .offset = offsetof(
fr_stats_t, total_packets_dropped),
373 { .name =
"Radius-Auth-Serv-Total-Unknown-Types",
374 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
375 .offset = offsetof(
fr_stats_t, total_unknown_types),
377 { .name =
"Radius-Auth-Client-table",
384 { .
name =
"Radius-Auth-Serv",
391 { .
name =
"Radius-Auth-Serv-Mib-Objects",
398 { .
name =
"Radius-Auth-Serv-Mib",
405 { .
name =
"Radius-Authentication",
412 { .
name =
"Radius-Mib",
419 { .
name =
"FreeRADIUS-Mib-2",
426 { .
name =
"FreeRADIUS-Mgmt",
433 { .
name =
"FreeRADIUS-Internet",
440 { .
name =
"FreeRADIUS-Dod",
447 { .
name =
"FreeRADIUS-Org",
454 { .
name =
"FreeRADIUS-Iso",
463 fr_snmp_map_t const *map,
void *snmp_ctx,
unsigned int snmp_op);
485 if (p->
da->attr == da->attr)
return p;
489 m = p + ((q - p) / 2);
492 if (m->da->attr < da->attr) p = m + 1;
493 else if (m->da->attr == da->attr)
break;
495 m = p + ((q - p) / 2);
497 if (p > q)
return NULL;
518 da_stack->
da[i] = map_p->
da;
519 map_p = map_p->
child;
527 fr_snmp_map_t const *map,
void *snmp_ctx,
unsigned int snmp_op,
537 void *this_snmp_ctx = NULL;
540 for (i = index_num; i < UINT32_MAX; i++) {
544 tmp_ctx = talloc_new(request);
550 ret = map->
index(tmp_ctx, &this_snmp_ctx, map, snmp_ctx, i);
558 if (snmp_op != FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT) {
570 map->
child, this_snmp_ctx, snmp_op);
571 TALLOC_FREE(tmp_ctx);
573 if (ret < 0)
return ret;
575 if (snmp_op != FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT)
goto invalid;
588 this_snmp_ctx = NULL;
618 fr_snmp_map_t const *map,
void *snmp_ctx,
unsigned int snmp_op)
626 if (map[0].last < &map[1]) {
644 fr_strerror_printf(
"Bad index attribute: Index attribute \"%s\" should be a integer, "
645 "but is a %s", da_stack->
da[
depth]->name,
654 index_num =
vp->vp_uint32;
670 &map[1], snmp_ctx, snmp_op,
677 fr_snmp_map_t const *map,
void *snmp_ctx,
unsigned int snmp_op)
717 map_p, snmp_ctx, snmp_op,
725 map_p->
child, snmp_ctx, snmp_op);
726 if (ret < 0)
return ret;
728 if (snmp_op != FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT)
goto invalid;
729 if (++map_p <= map[0].last)
continue;
739 fr_snmp_map_t const *map,
void *snmp_ctx,
unsigned int snmp_op)
763 case FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT:
764 if (map_p == map[0].last) {
767 if (map_p->
da ==
vp->
da) {
778 map_p->
child, snmp_ctx, snmp_op);
783 case FR_FREERADIUS_SNMP_OPERATION_VALUE_GET:
808 if (map_p->
get(request->reply, &
data, map_p, snmp_ctx) < 0)
goto error;
815 vp->vp_uint32 = map_p->
type;
820 case FR_FREERADIUS_SNMP_OPERATION_VALUE_SET:
826 vp->vp_uint32 = FR_FREERADIUS_SNMP_FAILURE_VALUE_NOT_WRITABLE;
832 ret = map_p->
set(map_p, snmp_ctx, &
vp->data);
833 if (ret < 0)
switch (-(ret)) {
834 case FR_FREERADIUS_SNMP_FAILURE_VALUE_NOT_WRITABLE:
835 case FR_FREERADIUS_SNMP_FAILURE_VALUE_WRONG_TYPE:
836 case FR_FREERADIUS_SNMP_FAILURE_VALUE_WRONG_LENGTH:
837 case FR_FREERADIUS_SNMP_FAILURE_VALUE_WRONG_VALUE:
838 case FR_FREERADIUS_SNMP_FAILURE_VALUE_INCONSISTENT_VALUE:
840 vp->vp_uint32 = -(ret);
875 fr_snmp_map_t const *map,
void *snmp_ctx,
unsigned int snmp_op)
887 if (snmp_op != FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT) {
903 map, snmp_ctx, snmp_op);
913 map, snmp_ctx, snmp_op);
922 map, snmp_ctx, snmp_op);
927 fr_dcursor_t request_cursor, op_cursor, out_cursor, reply_cursor;
946 RDEBUG2(
"Processing SNMP stats request");
961 if (!
vp->
da->flags.is_unknown)
continue;
965 WARN(
"Failed converting \"%s\" to a known attribute",
vp->
da->name);
969 RDEBUG2(
"Unknown attribute \"%s\" resolves to \"%s\"",
vp->
da->name, da->name);
977 RPWARN(
"Failed converting unknown attribute to known attribute");
1010 switch (op->vp_uint32) {
1011 case FR_FREERADIUS_SNMP_OPERATION_VALUE_PING:
1012 case FR_FREERADIUS_SNMP_OPERATION_VALUE_GET:
1013 case FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT:
1014 case FR_FREERADIUS_SNMP_OPERATION_VALUE_SET:
1018 ERROR(
"Invalid operation %u",
vp->vp_uint32);
1040 da_stack.
da[da_stack.
depth - 1],
false);
1062 for (i = 0; map[i].
name; i++) {
1070 ERROR(
"Incomplete dictionary: Missing definition for \"%s\"", map[i].
name);
1075 if (ret < 0)
return -1;
1082 ERROR(
"Incomplete dictionary: Missing definition for \"%s\"", map[i].
name);
1094 memmove(&map[1], map,
sizeof(*map) * i);
1095 memset(&map[0], 0,
sizeof(*map));
1096 map[0].
name =
"Not the map offset you were looking for";
1097 map[0].last = &map[i];
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
static void fr_dcursor_merge(fr_dcursor_t *cursor, fr_dcursor_t *to_append)
Moves items from one cursor to another.
static void * fr_dcursor_next_peek(fr_dcursor_t *cursor)
Return the next iterator item without advancing the cursor.
fr_dcursor_eval_t void const * uctx
static int fr_dcursor_prepend(fr_dcursor_t *cursor, void *v)
Insert a single item at the start of the list.
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
static void * fr_dcursor_head(fr_dcursor_t *cursor)
Rewind cursor to the start of the list.
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
char const * radiusd_version_short
#define fr_dict_autofree(_to_free)
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
struct value_box_s fr_value_box_t
fr_dict_attr_t const * fr_dict_attr_common_parent(fr_dict_attr_t const *a, fr_dict_attr_t const *b, bool is_ancestor)
Find a common ancestor that two TLV type attributes share.
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
fr_dict_attr_t const * fr_dict_attr_unknown_resolve(fr_dict_t const *dict, fr_dict_attr_t const *da)
Check to see if we can convert a nested TLV structure to known attributes.
#define fr_dict_autoload(_to_load)
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
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.
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
fr_stats_t auth
Authentication stats.
char const * longname
Client identifier.
int number
Unique client number.
Describes a host allowed to send packets to the server.
#define REMARKER(_str, _marker_idx, _marker,...)
Output string with error marker, showing where format error occurred.
void main_loop_signal_raise(int flag)
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
ssize_t fr_dict_attr_oid_print(fr_sbuff_t *out, fr_dict_attr_t const *ancestor, fr_dict_attr_t const *da, bool numeric)
static uint8_t depth(fr_minmax_heap_index_t i)
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.
int fr_pair_reinit_from_da(fr_pair_list_t *list, fr_pair_t *vp, fr_dict_attr_t const *da)
Re-initialise an attribute with a different da.
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.
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_sbuff_in_char(_sbuff,...)
fr_stats_t radius_auth_stats
fr_snmp_get_func_t get
Function to retrieve value.
static fr_snmp_map_t snmp_auth_serv[]
fr_snmp_index_func_t index
Function for traversing indexes.
static fr_snmp_map_t snmp_radius_mib[]
static ssize_t snmp_process_tlv(fr_dcursor_t *out, request_t *request, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
static fr_snmp_map_t snmp_auth_client_entry[]
static fr_snmp_map_t snmp_mgmt[]
static fr_snmp_map_t const * snmp_map_search(fr_snmp_map_t const map[], fr_dict_attr_t const *da)
Perform a binary search to find a map matching a da.
static int _fr_snmp_init(UNUSED void *uctx)
static fr_snmp_map_t snmp_auth_serv_mib[]
static int snmp_value_uptime_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out, NDEBUG_UNUSED fr_snmp_map_t const *map, UNUSED void *snmp_ctx)
static fr_time_t start_time
static int snmp_config_reset_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out, NDEBUG_UNUSED fr_snmp_map_t const *map, UNUSED void *snmp_ctx)
char const * name
Attribute number.
static int snmp_auth_client_stats_offset_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out, fr_snmp_map_t const *map, void *snmp_ctx)
fr_snmp_set_func_t set
Function to write a new value.
static fr_time_t reset_time
static fr_dict_t const * dict_snmp
static fr_dict_attr_t const * attr_snmp_root
static fr_snmp_map_t snmp_auth_serv_counters[]
static void snmp_next_leaf(fr_da_stack_t *da_stack, unsigned int depth, fr_snmp_map_t const *map)
Perform depth first traversal of the tree until we hit a leaf node.
int(* fr_snmp_index_func_t)(TALLOC_CTX *ctx, void **snmp_ctx_out, fr_snmp_map_t const *map, void const *snmp_ctx_in, uint32_t index)
int(* fr_snmp_set_func_t)(fr_snmp_map_t const *map, void *snmp_ctx, fr_value_box_t *data)
#define FR_FREERADIUS_SNMP_TYPE_OBJECT
static ssize_t snmp_process_index(fr_dcursor_t *out, request_t *request, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t cursor, fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op, uint32_t index_num)
static int snmp_client_ipv4addr_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out, NDEBUG_UNUSED fr_snmp_map_t const *map, void *snmp_ctx)
static fr_snmp_map_t snmp_iso[]
static int _fr_snmp_init_r(fr_snmp_map_t map[], fr_dict_attr_t const *parent)
Internal SNMP initialisation function (used for recursion)
static fr_snmp_map_t snmp_mib_2[]
fr_dict_attr_autoload_t snmp_dict_attr[]
int fr_snmp_process(request_t *request)
static int snmp_config_reset_set(NDEBUG_UNUSED fr_snmp_map_t const *map, UNUSED void *snmp_ctx, fr_value_box_t *in)
static ssize_t snmp_process_leaf(fr_dcursor_t *out, request_t *request, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
static fr_snmp_map_t snmp_authentication[]
static int snmp_auth_stats_offset_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out, fr_snmp_map_t const *map, UNUSED void *snmp_ctx)
static int snmp_client_index_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out, UNUSED fr_snmp_map_t const *map, void *snmp_ctx)
int(* fr_snmp_get_func_t)(TALLOC_CTX *ctx, fr_value_box_t *out, fr_snmp_map_t const *map, void *snmp_ctx)
static int _fr_snmp_free(UNUSED void *uctx)
static fr_snmp_map_t snmp_org[]
static int snmp_client_index(UNUSED TALLOC_CTX *ctx, void **snmp_ctx_out, UNUSED fr_snmp_map_t const *map, NDEBUG_UNUSED void const *snmp_ctx_in, uint32_t index_num)
static fr_snmp_map_t snmp_dod[]
static int snmp_value_serv_ident_get(TALLOC_CTX *ctx, fr_value_box_t *out, NDEBUG_UNUSED fr_snmp_map_t const *map, UNUSED void *snmp_ctx)
int fr_snmp_init(void)
Initialise the tree of SNMP map structures used to attach callbacks to OIDs.
static fr_dict_attr_t const * attr_snmp_failure
unsigned int type
SNMP type - More specific than attribute type.
static fr_dict_attr_t const * attr_snmp_type
static ssize_t snmp_process(fr_dcursor_t *out, request_t *request, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
Traverse a tree of SNMP maps.
fr_dict_autoload_t snmp_dict[]
fr_snmp_map_t * child
Child map.
static int snmp_config_reset_time_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out, NDEBUG_UNUSED fr_snmp_map_t const *map, UNUSED void *snmp_ctx)
static ssize_t snmp_process_index_attr(fr_dcursor_t *out, request_t *request, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
fr_dict_attr_t const * da
Dictionary attribute (resolved from attribute number).
static int snmp_client_id_get(TALLOC_CTX *ctx, fr_value_box_t *out, NDEBUG_UNUSED fr_snmp_map_t const *map, void *snmp_ctx)
static fr_dict_attr_t const * attr_snmp_operation
static fr_snmp_map_t snmp_auth_serv_mib_objects[]
static fr_snmp_map_t snmp_internet[]
#define SNMP_MAP_TERMINATOR
static fr_snmp_map_t snmp_auth_client_entry_counters[]
Maps a fr_pair_t to the source of a value.
fr_client_t * client_findbynumber(UNUSED const fr_client_list_t *clients, UNUSED int number)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_aka_sim_id_type_t type
#define fr_time()
Allow us to arbitrarily manipulate time.
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 int64_t fr_time_delta_to_csec(fr_time_delta_t delta)
#define fr_time_sub(_a, _b)
Subtract one time from another.
A time delta, a difference in time measured in nanoseconds.
#define fr_pair_dcursor_by_da_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes matching the specified fr_dict_attr_t.
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by 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_pair_dcursor_by_ancestor_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes descended from the specified fr_dict_attr_t.
#define FR_PROTO_STACK_PRINT(_stack, _depth)
uint8_t depth
Deepest attribute in the stack.
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Structure for holding the stack of dictionary attributes being encoded.
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
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.
int fr_value_box_bstrdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated talloced buffer to a fr_value_box_t.
int fr_value_box_asprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted, char const *fmt,...)
Print a formatted string using our internal printf wrapper and assign it to a value box.
int fr_value_box_steal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t *src)
Copy value data verbatim moving any buffers to the specified context.
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
static size_t char ** out