]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
move encode_array() to common function
authorAlan T. DeKok <aland@freeradius.org>
Fri, 22 Apr 2022 19:14:02 +0000 (15:14 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 22 Apr 2022 19:14:02 +0000 (15:14 -0400)
which further shrinks and simplifies the protocol-specific
encoders.

src/lib/util/encode.c [new file with mode: 0644]
src/lib/util/encode.h
src/lib/util/libfreeradius-util.mk
src/lib/util/struct.c
src/protocols/dhcpv4/encode.c
src/protocols/dhcpv6/encode.c
src/protocols/dns/encode.c

diff --git a/src/lib/util/encode.c b/src/lib/util/encode.c
new file mode 100644 (file)
index 0000000..822b48c
--- /dev/null
@@ -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 <freeradius-devel/io/test_point.h>
+#include <freeradius-devel/util/proto.h>
+#include <freeradius-devel/util/encode.h>
+
+/** 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);
+}
index 3d40ddc89ef02bb1cbd42eec1067d85d897bf691..ee421ed9aca8548724a021e409a0f018112797c9 100644 (file)
  *   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
 }
index 22a0cf8c4b0974402c19563f19164b9790052f66..389d45efdf2429cd22e54149df66b489ad4c378c 100644 (file)
@@ -26,6 +26,7 @@ SOURCES               := \
                   dl.c \
                   dns.c \
                   edit.c \
+                  encode.c \
                   event.c \
                   ext.c \
                   fifo.c \
index 33f6f237d23824368fc1b80b8013169de5063695..562074d170e2b45299b8636126635e37ea68e2f3 100644 (file)
@@ -24,6 +24,7 @@
 RCSID("$Id$")
 
 #include <freeradius-devel/util/struct.h>
+#include <freeradius-devel/util/encode.h>
 
 /** 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:
index 5634164d7b03db9c96b3ab5e6a1245bf6e28ecf2..160e3b38a272e248ca95b377a56c5817d7c3aed9 100644 (file)
@@ -29,6 +29,7 @@
 #include <freeradius-devel/util/proto.h>
 #include <freeradius-devel/util/struct.h>
 #include <freeradius-devel/util/dns.h>
+#include <freeradius-devel/util/encode.h>
 
 #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)) {
index 31b3a0ac8c0bbdb397cc90c7c7375f64ae33cad3..98ebe4c1fd29f718443666b4dda7487431a782fa 100644 (file)
@@ -32,6 +32,7 @@
 #include <freeradius-devel/util/dns.h>
 #include <freeradius-devel/util/proto.h>
 #include <freeradius-devel/util/struct.h>
+#include <freeradius-devel/util/encode.h>
 
 #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);
        }
index 849eefc465f982ca4b45d4ae1b6b813af15aae38..63c484119d6fa331ea3c9296d91dcd9c1d0699ee 100644 (file)
@@ -29,6 +29,7 @@
 #include <freeradius-devel/util/dns.h>
 #include <freeradius-devel/util/proto.h>
 #include <freeradius-devel/util/struct.h>
+#include <freeradius-devel/util/encode.h>
 
 #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);