From: Alan T. DeKok Date: Fri, 22 Apr 2022 19:14:02 +0000 (-0400) Subject: move encode_array() to common function X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ff7a0289a5b90a39aa328ab1edf543c9164de7b3;p=thirdparty%2Ffreeradius-server.git move encode_array() to common function which further shrinks and simplifies the protocol-specific encoders. --- diff --git a/src/lib/util/encode.c b/src/lib/util/encode.c new file mode 100644 index 00000000000..822b48cdf10 --- /dev/null +++ b/src/lib/util/encode.c @@ -0,0 +1,68 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * + * @file src/lib/util/encode.c + * @brief Generic functions for decoding protocols. + * + * @copyright 2022 Network RADIUS SAS (legal@networkradius.com) + */ +#include +#include +#include + +/** Encode an array of values from the network + * + * @param[out] dbuff buffer to write the TLV to. + * @param[in] da_stack Describing nesting of options. + * @param[in] depth in the da_stack. + * @param[in,out] cursor Current attribute we're encoding. + * @param[in] encode_ctx Containing DHCPv4 dictionary. + * @return + * - >0 length of data encoded. + * - 0 if we ran out of space. + * - < 0 on error. + */ +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_proto_encode_value_t encode_value) +{ + ssize_t slen; + fr_dbuff_t work_dbuff = FR_DBUFF(dbuff); + fr_pair_t *vp; + fr_dict_attr_t const *da = da_stack->da[depth]; + + FR_PROTO_STACK_PRINT(da_stack, depth); + + if (!fr_cond_assert_msg(da->flags.array, + "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set", + __FUNCTION__, da->name)) return PAIR_ENCODE_FATAL_ERROR; + + while (fr_dbuff_extend(&work_dbuff)) { + fr_dbuff_t element_dbuff = FR_DBUFF(&work_dbuff); + + slen = encode_value(&element_dbuff, da_stack, depth, cursor, encode_ctx); + if (slen < 0) return slen; + + fr_dbuff_set(&work_dbuff, &element_dbuff); + + vp = fr_dcursor_current(cursor); + if (!vp || (vp->da != da)) break; /* Stop if we have an attribute of a different type */ + } + + return fr_dbuff_set(dbuff, &work_dbuff); +} diff --git a/src/lib/util/encode.h b/src/lib/util/encode.h index 3d40ddc89ef..ee421ed9aca 100644 --- a/src/lib/util/encode.h +++ b/src/lib/util/encode.h @@ -15,11 +15,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -/** Protocol decoder support functions +/** Protocol encoder support functions * * @file src/lib/util/encode.h * - * @copyright 2021 Network RADIUS SAS + * @copyright 2022 Network RADIUS SAS */ RCSIDH(encode_h, "$Id$") @@ -34,13 +34,15 @@ extern "C" { /** Typedefs for simplifying the use and declaration of protocol encoders * */ -typedef struct fr_proto_encode_ctx_s fr_proto_encode_ctx_t; - -typedef ssize_t (*fr_proto_encode_pair_t)(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, - fr_dcursor_t *cursor, fr_proto_encode_ctx_t *encode_ctx); +typedef ssize_t (*fr_proto_encode_value_t)(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, + fr_dcursor_t *cursor, void *encode_ctx); #define PROTO_ENCODE_FUNC(_name) static ssize_t _name(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, \ - fr_dcursor_t *cursor, fr_proto_encode_ctx_t *encode_ctx); + fr_dcursor_t *cursor, void *encode_ctx); + +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_proto_encode_value_t encode_value); + #ifdef __cplusplus } diff --git a/src/lib/util/libfreeradius-util.mk b/src/lib/util/libfreeradius-util.mk index 22a0cf8c4b0..389d45efdf2 100644 --- a/src/lib/util/libfreeradius-util.mk +++ b/src/lib/util/libfreeradius-util.mk @@ -26,6 +26,7 @@ SOURCES := \ dl.c \ dns.c \ edit.c \ + encode.c \ event.c \ ext.c \ fifo.c \ diff --git a/src/lib/util/struct.c b/src/lib/util/struct.c index 33f6f237d23..562074d170e 100644 --- a/src/lib/util/struct.c +++ b/src/lib/util/struct.c @@ -24,6 +24,7 @@ RCSID("$Id$") #include +#include /** Convert a STRUCT to one or more VPs * @@ -676,11 +677,17 @@ ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, * Call the protocol encoder for non-bit fields. */ fr_proto_da_stack_build(da_stack, child); - len = encode_value(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx); + + if (child->flags.array) { + len = fr_pair_array_to_network(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx, encode_value); + } else { + len = encode_value(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx); + } if (len < 0) return len; vp = fr_dcursor_current(cursor); } else { + redo: /* * Hack until we find all places that don't set data.enumv */ @@ -701,6 +708,8 @@ ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, vp = fr_dcursor_next(cursor); if (!vp || !vp->da->flags.internal) break; } while (vp != NULL); + + if (child->flags.array && (vp->da == child)) goto redo; } next: diff --git a/src/protocols/dhcpv4/encode.c b/src/protocols/dhcpv4/encode.c index 5634164d7b0..160e3b38a27 100644 --- a/src/protocols/dhcpv4/encode.c +++ b/src/protocols/dhcpv4/encode.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "dhcpv4.h" #include "attrs.h" @@ -45,26 +46,6 @@ static ssize_t encode_tlv(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx); -static ssize_t encode_array(fr_dbuff_t *dbuff, - fr_da_stack_t *da_stack, int depth, - fr_dcursor_t *cursor, void *encode_ctx); - -static ssize_t encode_value_trampoline(fr_dbuff_t *dbuff, - fr_da_stack_t *da_stack, unsigned int depth, - fr_dcursor_t *cursor, void *encode_ctx) -{ - fr_dict_attr_t const *da = da_stack->da[depth]; - - /* - * Write out the option's value - */ - if (da->flags.array) { - return encode_array(dbuff, da_stack, depth, cursor, encode_ctx); - } - - return encode_value(dbuff, da_stack, depth, cursor, encode_ctx); -} - /** Write DHCP option value into buffer * * Does not include DHCP option length or number. @@ -95,7 +76,7 @@ static ssize_t encode_value(fr_dbuff_t *dbuff, * Structures are special. */ if ((vp->da->type == FR_TYPE_STRUCT) || (da->type == FR_TYPE_STRUCT)) { - slen = fr_struct_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value_trampoline, encode_tlv); + slen = fr_struct_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value, encode_tlv); if (slen <= 0) return slen; /* @@ -195,36 +176,6 @@ static ssize_t encode_value(fr_dbuff_t *dbuff, } -static ssize_t encode_array(fr_dbuff_t *dbuff, - fr_da_stack_t *da_stack, int depth, - fr_dcursor_t *cursor, void *encode_ctx) -{ - ssize_t slen; - fr_dbuff_t work_dbuff = FR_DBUFF(dbuff); - fr_pair_t *vp; - fr_dict_attr_t const *da = da_stack->da[depth]; - - FR_PROTO_STACK_PRINT(da_stack, depth); - - if (!fr_cond_assert_msg(da->flags.array, - "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set", - __FUNCTION__, da->name)) return PAIR_ENCODE_FATAL_ERROR; - - while (fr_dbuff_extend(&work_dbuff)) { - fr_dbuff_t element_dbuff = FR_DBUFF(&work_dbuff); - - slen = encode_value(&element_dbuff, da_stack, depth, cursor, encode_ctx); - if (slen < 0) return slen; - - fr_dbuff_set(&work_dbuff, &element_dbuff); - - vp = fr_dcursor_current(cursor); - if (!vp || (vp->da != da)) break; /* Stop if we have an attribute of a different type */ - } - - return fr_dbuff_set(dbuff, &work_dbuff); -} - /** Extend an encoded option in-place. * * @param[in] dbuff buffer containing the option @@ -402,7 +353,7 @@ static ssize_t encode_rfc_hdr(fr_dbuff_t *dbuff, * Write out the option's value */ if (da->flags.array) { - len = encode_array(&work_dbuff, da_stack, depth, cursor, encode_ctx); + len = fr_pair_array_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value); if (len < 0) return -1; } else if (da->parent && (da->parent->type != FR_TYPE_VENDOR)) { diff --git a/src/protocols/dhcpv6/encode.c b/src/protocols/dhcpv6/encode.c index 31b3a0ac8c0..98ebe4c1fd2 100644 --- a/src/protocols/dhcpv6/encode.c +++ b/src/protocols/dhcpv6/encode.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "dhcpv6.h" #include "attrs.h" @@ -76,26 +77,6 @@ static inline ssize_t encode_option_hdr(fr_dbuff_marker_t *m, uint16_t option, s } -static inline ssize_t encode_array(fr_dbuff_t *dbuff, - fr_da_stack_t *da_stack, int depth, - fr_dcursor_t *cursor, void *encode_ctx); - -static ssize_t encode_value_trampoline(fr_dbuff_t *dbuff, - fr_da_stack_t *da_stack, unsigned int depth, - fr_dcursor_t *cursor, void *encode_ctx) -{ - fr_dict_attr_t const *da = da_stack->da[depth]; - - /* - * Write out the option's value - */ - if (da->flags.array) { - return encode_array(dbuff, da_stack, depth, cursor, encode_ctx); - } - - return encode_value(dbuff, da_stack, depth, cursor, encode_ctx); -} - static ssize_t encode_value(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx) @@ -112,7 +93,7 @@ static ssize_t encode_value(fr_dbuff_t *dbuff, * Pack multiple attributes into into a single option */ if ((vp->da->type == FR_TYPE_STRUCT) || (da->type == FR_TYPE_STRUCT)) { - slen = fr_struct_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value_trampoline, encode_tlv); + slen = fr_struct_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value, encode_tlv); if (slen <= 0) return slen; /* @@ -388,33 +369,6 @@ static ssize_t encode_value(fr_dbuff_t *dbuff, return fr_dbuff_set(dbuff, &work_dbuff); } -static inline ssize_t encode_array(fr_dbuff_t *dbuff, - fr_da_stack_t *da_stack, int depth, - fr_dcursor_t *cursor, void *encode_ctx) -{ - ssize_t slen; - fr_dbuff_t work_dbuff = FR_DBUFF(dbuff); - fr_pair_t *vp; - fr_dict_attr_t const *da = da_stack->da[depth]; - - if (!fr_cond_assert_msg(da->flags.array, - "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set", - __FUNCTION__, da->name)) return PAIR_ENCODE_FATAL_ERROR; - - while (fr_dbuff_extend(&work_dbuff)) { - fr_dbuff_t element_dbuff = FR_DBUFF(&work_dbuff); - - slen = encode_value(&element_dbuff, da_stack, depth, cursor, encode_ctx); - if (slen < 0) return slen; - - fr_dbuff_set(&work_dbuff, &element_dbuff); - - vp = fr_dcursor_current(cursor); - if (!vp || (vp->da != da)) break; /* Stop if we have an attribute of a different type */ - } - - return fr_dbuff_set(dbuff, &work_dbuff); -} static ssize_t encode_vsio_hdr(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, @@ -562,7 +516,7 @@ static ssize_t encode_rfc_hdr(fr_dbuff_t *dbuff, * Write out the option's value */ if (da->flags.array) { - len = encode_array(&work_dbuff, da_stack, depth, cursor, encode_ctx); + len = fr_pair_array_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value); } else { len = encode_value(&work_dbuff, da_stack, depth, cursor, encode_ctx); } diff --git a/src/protocols/dns/encode.c b/src/protocols/dns/encode.c index 849eefc465f..63c484119d6 100644 --- a/src/protocols/dns/encode.c +++ b/src/protocols/dns/encode.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "dns.h" #include "attrs.h" @@ -75,26 +76,6 @@ static inline ssize_t encode_option_hdr(fr_dbuff_marker_t *m, uint16_t option, s } -static inline ssize_t encode_array(fr_dbuff_t *dbuff, - fr_da_stack_t *da_stack, int depth, - fr_dcursor_t *cursor, void *encode_ctx); - -static ssize_t encode_value_trampoline(fr_dbuff_t *dbuff, - fr_da_stack_t *da_stack, unsigned int depth, - fr_dcursor_t *cursor, void *encode_ctx) -{ - fr_dict_attr_t const *da = da_stack->da[depth]; - - /* - * Write out the option's value - */ - if (da->flags.array) { - return encode_array(dbuff, da_stack, depth, cursor, encode_ctx); - } - - return encode_value(dbuff, da_stack, depth, cursor, encode_ctx); -} - static ssize_t encode_value(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx) @@ -116,7 +97,7 @@ static ssize_t encode_value(fr_dbuff_t *dbuff, fr_pair_dcursor_init(&child_cursor, &vp->vp_group); - slen = fr_struct_to_network(&work_dbuff, da_stack, depth, &child_cursor, encode_ctx, encode_value_trampoline, encode_tlv); + slen = fr_struct_to_network(&work_dbuff, da_stack, depth, &child_cursor, encode_ctx, encode_value, encode_tlv); if (slen < 0) return slen; /* @@ -131,7 +112,7 @@ static ssize_t encode_value(fr_dbuff_t *dbuff, * Flat-list */ if (da->type == FR_TYPE_STRUCT) { - slen = fr_struct_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value_trampoline, encode_tlv); + slen = fr_struct_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value, encode_tlv); if (slen <= 0) return slen; /* @@ -247,36 +228,6 @@ static ssize_t encode_value(fr_dbuff_t *dbuff, return fr_dbuff_set(dbuff, &work_dbuff); } -static inline ssize_t encode_array(fr_dbuff_t *dbuff, - fr_da_stack_t *da_stack, int depth, - fr_dcursor_t *cursor, void *encode_ctx) -{ - ssize_t slen; - fr_dbuff_t work_dbuff = FR_DBUFF(dbuff); - fr_pair_t *vp; - fr_dict_attr_t const *da = da_stack->da[depth]; - - FR_PROTO_STACK_PRINT(da_stack, depth); - - if (!fr_cond_assert_msg(da->flags.array, - "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set", - __FUNCTION__, da->name)) return PAIR_ENCODE_FATAL_ERROR; - - while (fr_dbuff_extend(&work_dbuff)) { - fr_dbuff_t element_dbuff = FR_DBUFF(&work_dbuff); - - slen = encode_value(&element_dbuff, da_stack, depth, cursor, encode_ctx); - if (slen < 0) return slen; - - fr_dbuff_set(&work_dbuff, &element_dbuff); - - vp = fr_dcursor_current(cursor); - if (!vp || (vp->da != da)) break; /* Stop if we have an attribute of a different type */ - } - - return fr_dbuff_set(dbuff, &work_dbuff); -} - static ssize_t encode_option_data(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx) @@ -410,7 +361,7 @@ static ssize_t encode_rfc_hdr(fr_dbuff_t *dbuff, * Write out the option's value */ if (da->flags.array) { - len = encode_array(&work_dbuff, da_stack, depth, cursor, encode_ctx); + len = fr_pair_array_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value); } else { len = encode_value(&work_dbuff, da_stack, depth, cursor, encode_ctx); } @@ -499,12 +450,12 @@ static ssize_t fr_dns_encode_rr(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *e fr_pair_dcursor_init(&child_cursor, &vp->vp_group); - slen = fr_struct_to_network(&work_dbuff, &da_stack, 0, &child_cursor, encode_ctx, encode_value_trampoline, encode_tlv); + slen = fr_struct_to_network(&work_dbuff, &da_stack, 0, &child_cursor, encode_ctx, encode_value, encode_tlv); if (slen <= 0) return slen; (void) fr_dcursor_next(cursor); } else { - slen = fr_struct_to_network(&work_dbuff, &da_stack, 0, cursor, encode_ctx, encode_value_trampoline, encode_tlv); + slen = fr_struct_to_network(&work_dbuff, &da_stack, 0, cursor, encode_ctx, encode_value, encode_tlv); if (slen <= 0) return slen; } @@ -536,7 +487,7 @@ static ssize_t encode_record(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, fr_pair fr_dcursor_t child_cursor; fr_pair_dcursor_init(&child_cursor, &vp->vp_group); - slen = fr_struct_to_network(&work_dbuff, da_stack, 0, &child_cursor, packet_ctx, encode_value_trampoline, encode_tlv); + slen = fr_struct_to_network(&work_dbuff, da_stack, 0, &child_cursor, packet_ctx, encode_value, encode_tlv); if (slen <= 0) return slen; count++; @@ -582,7 +533,7 @@ ssize_t fr_dns_encode(fr_dbuff_t *dbuff, fr_pair_list_t *vps, fr_dns_ctx_t *pack fr_pair_dcursor_init(&child_cursor, &vp->vp_group); fr_proto_da_stack_build(&da_stack, attr_dns_packet); - slen = fr_struct_to_network(&work_dbuff, &da_stack, 0, &cursor, packet_ctx, encode_value_trampoline, NULL); + slen = fr_struct_to_network(&work_dbuff, &da_stack, 0, &cursor, packet_ctx, encode_value, NULL); if (slen <= 0) return slen; fr_assert(slen == DNS_HDR_LEN);