]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
pass TLV stack to struct encoder
authorAlan T. DeKok <aland@freeradius.org>
Wed, 13 Nov 2019 21:27:59 +0000 (16:27 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 13 Nov 2019 21:28:36 +0000 (16:28 -0500)
along with a protocol-specific encode_value() callback.
Which for now is only used in limited cases, because of poor
interation between the requirements of the struct encoder,
and the tlv_stack magic.

src/lib/util/struct.c
src/lib/util/struct.h
src/protocols/dhcpv6/encode.c
src/protocols/radius/encode.c
src/tests/unit/protocols/dhcpv6/rfc4704.txt

index d30a3bf326d211dfc2ce5c4ac28c106ffc4469c5..f2ac117e6feb56266cde3ee40eabd57002e55b76 100644 (file)
@@ -258,13 +258,15 @@ done:
 
 
 ssize_t fr_struct_to_network(uint8_t *out, size_t outlen,
-                            fr_dict_attr_t const *parent, fr_cursor_t *cursor)
+                            fr_dict_attr_t const **tlv_stack, unsigned int depth,
+                            fr_cursor_t *cursor, void *encoder_ctx,
+                            fr_encode_value_t encode_value)
 {
        ssize_t                 len;
        unsigned int            child_num = 1;
        uint8_t                 *p = out;
        VALUE_PAIR const        *vp = fr_cursor_current(cursor);
-       fr_dict_attr_t const    *key_da;
+       fr_dict_attr_t const    *key_da, *parent;
 
        if (!vp) {
                fr_strerror_printf("%s: Can't encode empty struct", __FUNCTION__);
@@ -272,6 +274,7 @@ ssize_t fr_struct_to_network(uint8_t *out, size_t outlen,
        }
 
        VP_VERIFY(vp);
+       parent = tlv_stack[depth];
 
        if (parent->type != FR_TYPE_STRUCT) {
                fr_strerror_printf("%s: Expected type \"struct\" got \"%s\"", __FUNCTION__,
@@ -323,29 +326,49 @@ ssize_t fr_struct_to_network(uint8_t *out, size_t outlen,
                }
 
                /*
-                *      Encode fixed-size octets fields so that they
-                *      are exactly the fixed size, UNLESS the entire
-                *      output is truncated.
+                *      Call the protocol encoder, but ONLY if there
+                *      are special flags required.
                 */
-               if ((vp->da->type == FR_TYPE_OCTETS) && vp->da->flags.length) {
-                       size_t mylen = vp->da->flags.length;
+               if (encode_value && !child->flags.extra && child->flags.subtype) {
+                       ssize_t slen;
 
-                       if (mylen > outlen) mylen = outlen;
-
-                       if (vp->vp_length < mylen) {
-                               memcpy(p, vp->vp_ptr, vp->vp_length);
-                               memset(p + vp->vp_length, 0, mylen - vp->vp_length);
-                       } else {
-                               memcpy(p, vp->vp_ptr, mylen);
-                       }
-                       len = mylen;
+                       tlv_stack[depth + 1] = child;
+                       slen = encode_value(p, outlen, tlv_stack, depth + 1, cursor, encoder_ctx);
+                       if (slen < 0) return slen;
+                       len = slen;
+                       vp = fr_cursor_current(cursor);
 
                } else {
                        /*
-                        *      Determine the nested type and call the appropriate encoder
+                        *      Encode fixed-size octets fields so that they
+                        *      are exactly the fixed size, UNLESS the entire
+                        *      output is truncated.
                         */
-                       len = fr_value_box_to_network(NULL, p, outlen, &vp->data);
-                       if (len <= 0) return -1;
+                       if ((vp->da->type == FR_TYPE_OCTETS) && vp->da->flags.length) {
+                               size_t mylen = vp->da->flags.length;
+
+                               if (mylen > outlen) mylen = outlen;
+
+                               if (vp->vp_length < mylen) {
+                                       memcpy(p, vp->vp_ptr, vp->vp_length);
+                                       memset(p + vp->vp_length, 0, mylen - vp->vp_length);
+                               } else {
+                                       memcpy(p, vp->vp_ptr, mylen);
+                               }
+                               len = mylen;
+
+                       } else {
+                               /*
+                                *      Determine the nested type and call the appropriate encoder
+                                */
+                               len = fr_value_box_to_network(NULL, p, outlen, &vp->data);
+                               if (len <= 0) return -1;
+                       }
+
+                       do {
+                               vp = fr_cursor_next(cursor);
+                               if (!vp || !vp->da->flags.internal) break;
+                       } while (vp != NULL);
                }
 
                if (da_is_key_field(child)) {
@@ -356,11 +379,6 @@ ssize_t fr_struct_to_network(uint8_t *out, size_t outlen,
                outlen -= len;                          /* Subtract from the buffer we have available */
                child_num++;
 
-               do {
-                       vp = fr_cursor_next(cursor);
-                       if (!vp || !vp->da->flags.internal) break;
-               } while (vp != NULL);
-
                /*
                 *      Nothing more to do, or we've done all of the
                 *      entries in this structure, stop.
@@ -383,8 +401,9 @@ ssize_t fr_struct_to_network(uint8_t *out, size_t outlen,
                 */
                if ((vp->da->parent->parent == key_da) &&
                    (vp->da->parent->type == FR_TYPE_STRUCT)) {
-                       len = fr_struct_to_network(p, outlen,
-                                                  vp->da->parent, cursor);
+                       tlv_stack[depth + 1] = vp->da->parent; /* hackity hack */
+                       len = fr_struct_to_network(p, outlen, tlv_stack, depth + 1,
+                                                  cursor, encoder_ctx, encode_value);
                        if (len < 0) return len;
                        return (p - out) + len;
                }
index 0bc28a48030050e75859e449c276ebccd3596d65..1c4b016b75c70c2d4482498c9ba56f79fc65b252 100644 (file)
@@ -34,8 +34,13 @@ extern "C" {
 ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_cursor_t *cursor,
                               fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len,
                               fr_dict_attr_t const **child) CC_HINT(nonnull(2,3,4));
-ssize_t fr_struct_to_network(uint8_t *out, size_t outlen,
-                            fr_dict_attr_t const *parent, fr_cursor_t *cursor) CC_HINT(nonnull);
+
+typedef ssize_t (*fr_encode_value_t)(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth,
+                                    fr_cursor_t *cursor, void *encoder_ctx);
+
+ssize_t fr_struct_to_network(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth,
+                            fr_cursor_t *cursor, void *encoder_ctx,
+                            fr_encode_value_t encode_value) CC_HINT(nonnull(1,3,5));
 
 VALUE_PAIR *fr_unknown_from_network(TALLOC_CTX *ctx, fr_dict_attr_t const *parent,
                                    uint8_t const *data, size_t data_len) CC_HINT(nonnull);
index 62d010c0aea6e747d4eb4278c0c5d3800cbbffb7..b31a82372ee9fb77ef9e0c0f6209afc34d35cc14 100644 (file)
@@ -134,7 +134,7 @@ static inline ssize_t encode_option_hdr(uint8_t *out, size_t outlen, uint16_t op
 
 static ssize_t encode_struct(uint8_t *out, size_t outlen,
                             fr_dict_attr_t const **tlv_stack, unsigned int depth,
-                            fr_cursor_t *cursor, UNUSED void *encoder_ctx)
+                            fr_cursor_t *cursor, void *encoder_ctx)
 {
        VP_VERIFY(fr_cursor_current(cursor));
        FR_PROTO_STACK_PRINT(tlv_stack, depth);
@@ -150,7 +150,7 @@ static ssize_t encode_struct(uint8_t *out, size_t outlen,
                return PAIR_ENCODE_ERROR;
        }
 
-       return fr_struct_to_network(out, outlen, tlv_stack[depth], cursor);
+       return fr_struct_to_network(out, outlen, tlv_stack, depth, cursor, encoder_ctx, encode_value);
 }
 
 static ssize_t encode_value(uint8_t *out, size_t outlen,
index 0b1553ecdd812c98b0cfa8042f7e44efa9c4e6da..3de85cace97177312fd2cc08b0a477b53a6e1ba5 100644 (file)
@@ -33,7 +33,7 @@ RCSID("$Id$")
 static unsigned int salt_offset = 0;
 
 static ssize_t encode_value(uint8_t *out, size_t outlen,
-                           fr_dict_attr_t const **tlv_stack, int depth,
+                           fr_dict_attr_t const **tlv_stack, unsigned int depth,
                            fr_cursor_t *cursor, void *encoder_ctx);
 
 static ssize_t encode_rfc_hdr_internal(uint8_t *out, size_t outlen,
@@ -524,7 +524,7 @@ static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
  *     < 0, failure.
  */
 static ssize_t encode_value(uint8_t *out, size_t outlen,
-                           fr_dict_attr_t const **tlv_stack, int depth,
+                           fr_dict_attr_t const **tlv_stack, unsigned int depth,
                            fr_cursor_t *cursor, void *encoder_ctx)
 {
        size_t                  offset;
@@ -553,7 +553,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
        if (da->type == FR_TYPE_STRUCT) {
                ssize_t struct_len;
 
-               struct_len = fr_struct_to_network(out, outlen, tlv_stack[depth], cursor);
+               struct_len = fr_struct_to_network(out, outlen, tlv_stack, depth, cursor, encoder_ctx, encode_value);
                if (struct_len <= 0) return struct_len;
 
                vp = fr_cursor_current(cursor);
index a83452f30e3d5bb7c61d16f740fb8b6a21a14017..d4104098acd2444b38fb1d52d889275976726a56 100644 (file)
@@ -36,13 +36,13 @@ proto-dictionary dhcpv6
 #                    (with length option-len - 1)
 #
 
+encode-pair Client-FQDN-Flags = Server-Update, Client-FQDN-Domain-Name = "tapioca01"
+match 00 27 00 0c 01 09 74 61 70 69 6f 63 61 30 31 00
+
 #
 # TODO: The current API do not support 'struct' attributes with
 # fields like 'string encode=dns_label'. e.g: Client-FQDN-Domain-Name
 #
-encode-pair Client-FQDN-Flags = Server-Update, Client-FQDN-Domain-Name = "tapioca01"
-no match 00 27 00 0c 01 09 74 61 70 69 6f 63 61 30 31 00
-
 decode-pair -
 no match Client-FQDN-Flags = Server-Update, Client-FQDN-Domain-Name = "tapioca01"