neels has uploaded this change for review. (
https://gerrit.osmocom.org/c/osmo-upf/+/27529
)
Change subject: libosmo-tlv: add TLIV capability
......................................................................
libosmo-tlv: add TLIV capability
During code review, it was indicated that some TLV protocols that we
will likely deal with in the near future also employ an I, and instance
value of a tag. Add TLIV support.
A usage example for a manually implemented TLIV structure is found in
tests/libosmo-tlv/tlv_test.c.
A usage example for a generated TLIV protocol is found in
tests/libosmo-tlv/test_tliv/.
Related: SYS#5599
Change-Id: I0a076e54dfba6038cc779cb7c8f3967d212226aa
---
M configure.ac
M include/osmocom/tlv/tlv.h
M include/osmocom/tlv/tlv_dec_enc.h
M include/osmocom/tlv/tlv_gen.h
M src/libosmo-tlv/tlv.c
M src/libosmo-tlv/tlv_dec_enc.c
M src/libosmo-tlv/tlv_gen.c
M tests/libosmo-tlv/Makefile.am
A tests/libosmo-tlv/test_tliv/Makefile.am
A tests/libosmo-tlv/test_tliv/gen__myproto_ies_auto.c
A tests/libosmo-tlv/test_tliv/myproto_ies_custom.c
A tests/libosmo-tlv/test_tliv/myproto_ies_custom.h
A tests/libosmo-tlv/test_tliv/tliv_test.c
A tests/libosmo-tlv/test_tliv/tliv_test.ok
M tests/libosmo-tlv/tlv_dec_enc_test.c
M tests/libosmo-tlv/tlv_test.c
M tests/libosmo-tlv/tlv_test.ok
M tests/testsuite.at
18 files changed, 913 insertions(+), 175 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-upf refs/changes/29/27529/1
diff --git a/configure.ac b/configure.ac
index f9e85ce..f60387c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -206,6 +206,7 @@
tests/atlocal
tests/libosmo-tlv/Makefile
tests/libosmo-tlv/test_tlv_gen/Makefile
+ tests/libosmo-tlv/test_tliv/Makefile
doc/Makefile
doc/examples/Makefile
doc/manuals/Makefile
diff --git a/include/osmocom/tlv/tlv.h b/include/osmocom/tlv/tlv.h
index c732ebc..b47aa40 100644
--- a/include/osmocom/tlv/tlv.h
+++ b/include/osmocom/tlv/tlv.h
@@ -24,10 +24,25 @@
#include <stdint.h>
#include <stdio.h>
+#include <stdbool.h>
struct msgb;
struct osmo_tlv_load;
struct osmo_tlv_put;
+struct value_string;
+
+struct osmo_tlv_tag_inst {
+ unsigned int tag;
+ bool instance_present;
+ unsigned int instance;
+};
+
+int osmo_tlv_tag_inst_cmp(const struct osmo_tlv_tag_inst *a, const struct
osmo_tlv_tag_inst *b);
+
+int osmo_tlv_tag_inst_to_str_buf(char *buf, size_t buflen, const struct osmo_tlv_tag_inst
*ti,
+ const struct value_string *tag_names);
+char *osmo_tlv_tag_inst_to_str_c(void *ctx, const struct osmo_tlv_tag_inst *ti,
+ const struct value_string *tag_names);
/*! TL configuration for osmo_tlv_load*() and osmo_tlv_put*(). Depending on these
implementations provided by the caller,
* osmo_tlv can load any sizes of tag and length fields (that don't surpass the value
range of unsigned int and size_t,
@@ -48,6 +63,7 @@
/*! Read one TL from the start of src_data.
* \param tlv Return the T (tag) value read from src_data in tlv->tag.
* Return the L (length) value read from src_data in tlv->len.
+ * Return the I (instance) value read from src_data in tlv->len; ignore
if there is no I.
* Return the position just after the TL in tlv->*val. If there is V
data, point at the start of the
* V data in src_data. If there is no V data, point at the byte just after
the TL part in src_data.
* \param src_data Part of raw message being decoded.
@@ -67,12 +83,14 @@
* \param dst_data Write TL data to the start of this buffer.
* \param dst_data_avail Remaining available space in dst_data.
* \param tag The T value to store in dst_data.
+ * \param instance The I value to store in dst_data (if this tag is a TLIV); ignore
when not a TLIV.
* \param len The L value to store in dst_data.
* \param tlv Backpointer to the osmo_tlv_put struct, including tlv->dst, the
underlying msgb.
* \return the size of the TL part in bytes on success, -EINVAL if tag is invalid,
-EMSGSIZE if len is too large
* or dst_data_avail is too small for the TL.
*/
- int (*store_tl)(uint8_t *dst_data, size_t dst_data_avail, unsigned int tag, size_t len,
struct osmo_tlv_put *tlv);
+ int (*store_tl)(uint8_t *dst_data, size_t dst_data_avail, const struct osmo_tlv_tag_inst
*ti, size_t len,
+ struct osmo_tlv_put *tlv);
};
/*! Configuration that allows parsing an 8bit tag and 8bit length TLV. */
@@ -96,7 +114,7 @@
} src;
/*! Return value from last invocation of osmo_tlv_load_next*(): tag value of parsed IE.
*/
- unsigned int tag;
+ struct osmo_tlv_tag_inst ti;
/*! Return value from last invocation of osmo_tlv_load_next*(): Start of the IE's
payload data (after tag and
* length). If the end of the src buffer is reached, val == NULL. If a TLV contained no
value part, len == 0,
* but this still points just after the TL. */
@@ -113,8 +131,9 @@
}
int osmo_tlv_load_next(struct osmo_tlv_load *tlv);
-int osmo_tlv_load_peek_tag(const struct osmo_tlv_load *tlv);
+int osmo_tlv_load_peek_tag(const struct osmo_tlv_load *tlv, struct osmo_tlv_tag_inst
*ti);
int osmo_tlv_load_next_by_tag(struct osmo_tlv_load *tlv, unsigned int tag);
+int osmo_tlv_load_next_by_tag_inst(struct osmo_tlv_load *tlv, const struct
osmo_tlv_tag_inst *ti);
/* State for storing a TLV structure into a msgb. */
struct osmo_tlv_put {
@@ -127,10 +146,11 @@
/* msgb to append new TL to */
struct msgb *dst;
/* What was the last TL written and where are its TL and V */
- unsigned int last_tag;
+ struct osmo_tlv_tag_inst last_ti;
uint8_t *last_tl;
uint8_t *last_val;
};
int osmo_tlv_put_tl(struct osmo_tlv_put *tlv, unsigned int tag, size_t len);
+int osmo_tlv_put_tli(struct osmo_tlv_put *tlv, const struct osmo_tlv_tag_inst *ti, size_t
len);
int osmo_tlv_put_update_tl(struct osmo_tlv_put *tlv);
diff --git a/include/osmocom/tlv/tlv_dec_enc.h b/include/osmocom/tlv/tlv_dec_enc.h
index 37803ca..dcfc321 100644
--- a/include/osmocom/tlv/tlv_dec_enc.h
+++ b/include/osmocom/tlv/tlv_dec_enc.h
@@ -77,8 +77,8 @@
* that the decoded structs to match the IEs are also generated at the same time and thus
always match the message
* definitions. For an example, see tests/libosmo-tlv/test_tlv_gen/. */
struct osmo_tlv_coding {
- /*! the IEI value */
- unsigned int tag;
+ /*! the IEI discriminator, and optional instance number */
+ struct osmo_tlv_tag_inst ti;
/*! Decoding function callback. Invoked for each defined and present IE encountered in
the message.
* Return 0 on success, negative on failure. */
diff --git a/include/osmocom/tlv/tlv_gen.h b/include/osmocom/tlv/tlv_gen.h
index e9f550a..3cd860f 100644
--- a/include/osmocom/tlv/tlv_gen.h
+++ b/include/osmocom/tlv/tlv_gen.h
@@ -14,6 +14,10 @@
#define OSMO_TLV_GEN_O_MULTI(MAX, TLV_GEN_IE, MEMB_NAME) { MEMB_NAME, .multi = MAX, .ie =
&(TLV_GEN_IE) }
#define OSMO_TLV_GEN_M_MULTI(MAX, MAND_COUNT, TLV_GEN_IE, MEMB_NAME) \
{ MEMB_NAME, .multi = MAX, .multi_mandatory = MAND_COUNT, .ie = &(TLV_GEN_IE) }
+#define OSMO_TLV_GEN_O_INST(INSTANCE, TLV_GEN_IE, MEMB_NAME) { MEMB_NAME, .optional =
true, .instance = INSTANCE, .ie = &TLV_GEN_IE }
+#define OSMO_TLV_GEN_M_INST(INSTANCE, TLV_GEN_IE, MEMB_NAME) { MEMB_NAME, .instance =
INSTANCE, .ie = &(TLV_GEN_IE) }
+
+#define OSMO_TLV_GEN_NO_INSTANCE INT_MAX
/*! osmo_tlv_gen_ie with all members == NULL, so that all are derived from the member
name. */
extern const struct osmo_tlv_gen_ie osmo_tlv_gen_ie_auto;
@@ -58,6 +62,10 @@
/*! Number of mandatory occurences of the IE, only has an effect if .multi > 0. */
unsigned int multi_mandatory;
+ /* If any, the instance nr to match, in C that yields an unsigned int.
+ * e.g. "1" or "MYPROTO_FOO_INST_ONE". */
+ const char *instance;
+
/*! IE decoding / encoding instructions. If NULL, the entire IE definition is derived
from .name.
* 'MYPROTO_IEI_NAME', 'myproto_dec_name()',
'myproto_enc_name()', 'myproto_enc_to_str_name()'.
* Your myproto_ies_custom.h needs to define an enum value MYPROTO_IEI_NAME and*/
@@ -73,7 +81,9 @@
* When there are no nested IEs, the type needs to be defined manually by a
myproto_ies_custom.h. */
const char *decoded_type;
- /*! C name of this tag value, e.g. "MYPROTO_IEI_FOO". If NULL, take
"MYPROTO_IEI_"+upper(name) instead. */
+ /*! C name of this tag value, e.g. "foo" to use tag
"MYPROTO_IEI_FOO".
+ * If NULL, take "MYPROTO_IEI_"+upper(memb_name) instead, where memb_name
comes from the osmo_tlv_gen_ie_o.
+ * decoded_type and/or dec_enc may be derived from this, if they are NULL. */
const char *tag_name;
/*! Name suffix of the dec/enc functions. "foo" -> myproto_dec_foo(),
myproto_enc_foo(),
diff --git a/src/libosmo-tlv/tlv.c b/src/libosmo-tlv/tlv.c
index 38acbfa..d6494e9 100644
--- a/src/libosmo-tlv/tlv.c
+++ b/src/libosmo-tlv/tlv.c
@@ -27,6 +27,45 @@
#include <osmocom/core/msgb.h>
#include <osmocom/tlv/tlv.h>
+int osmo_tlv_tag_inst_cmp(const struct osmo_tlv_tag_inst *a, const struct
osmo_tlv_tag_inst *b)
+{
+ int cmp;
+ if (a == b)
+ return 0;
+ if (!a)
+ return -1;
+ if (!b)
+ return 1;
+ cmp = OSMO_CMP(a->tag, b->tag);
+ if (cmp)
+ return cmp;
+ cmp = OSMO_CMP(a->instance_present ? 1 : 0, b->instance_present ? 1 : 0);
+ if (cmp)
+ return cmp;
+ if (a->instance_present)
+ return OSMO_CMP(a->instance, b->instance);
+ return 0;
+}
+
+int osmo_tlv_tag_inst_to_str_buf(char *buf, size_t buflen, const struct osmo_tlv_tag_inst
*ti,
+ const struct value_string *tag_names)
+{
+ struct osmo_strbuf sb = { .buf = buf, .len = buflen };
+ if (!tag_names)
+ OSMO_STRBUF_PRINTF(sb, "%u", ti->tag);
+ else
+ OSMO_STRBUF_PRINTF(sb, "%s", get_value_string(tag_names, ti->tag));
+ if (ti->instance_present)
+ OSMO_STRBUF_PRINTF(sb, "[%u]", ti->instance);
+ return sb.chars_needed;
+}
+
+char *osmo_tlv_tag_inst_to_str_c(void *ctx, const struct osmo_tlv_tag_inst *ti,
+ const struct value_string *tag_names)
+{
+ OSMO_NAME_C_IMPL(ctx, 64, "ERROR", osmo_tlv_tag_inst_to_str_buf, ti,
tag_names)
+}
+
static int next_tl_valid(const struct osmo_tlv_load *tlv, const uint8_t **ie_start_p,
size_t *buflen_left_p)
{
const uint8_t *ie_start;
@@ -102,6 +141,7 @@
/* Locate next IE */
OSMO_ASSERT(tlv->cfg->load_tl);
+ tlv->ti = (struct osmo_tlv_tag_inst){0};
rc = tlv->cfg->load_tl(tlv, ie_start, buflen_left);
if (rc)
return rc;
@@ -117,16 +157,19 @@
/* Return the tag of the IE that osmo_tlv_next() would yield, do not change the tlv
state.
*
* \param[in] tlv state for TLV parsing position; is not modified.
- * \returns the tag number on success, negative on TLV parsing error, -ENOENT when no
more tags
- * follow.
+ * \param[out] tag the tag number on success, if NULL don't return the tag.
+ * \param[out] instance the instance number or OSMO_TLV_NO_INSTANCE if there is no
instance value,
+ * if NULL don't return the instance value.
+ * \returns 0 on success, negative on TLV parsing error, -ENOENT when no more tags
follow.
*/
-int osmo_tlv_load_peek_tag(const struct osmo_tlv_load *tlv)
+int osmo_tlv_load_peek_tag(const struct osmo_tlv_load *tlv, struct osmo_tlv_tag_inst
*ti)
{
const uint8_t *ie_start;
size_t buflen_left;
int rc;
/* Guard against modification by load_tl(). */
struct osmo_tlv_load mtlv = *tlv;
+ mtlv.ti = (struct osmo_tlv_tag_inst){0};
rc = next_tl_valid(&mtlv, &ie_start, &buflen_left);
if (rc)
@@ -140,16 +183,26 @@
rc = tlv->cfg->load_tl(&mtlv, ie_start, buflen_left);
if (rc)
return -EBADMSG;
- return mtlv.tag;
+ if (ti)
+ *ti = mtlv.ti;
+ return 0;
}
/* Same as osmo_tlv_load_next(), but skip any IEs until the given tag is reached. Change
the tlv state only when success
* is returned.
* \param[out] tlv Return the next IE's TLV info.
* \param[in] tag Tag value to match.
+ * \param[in] instance Instance value to match; For IEs that have no instance value (no
TLIV), pass
+ * OSMO_TLV_NO_INSTANCE.
* \return 0 when the tag is found. Return -ENOENT when no such tag follows and keep the
tlv unchanged. */
int osmo_tlv_load_next_by_tag(struct osmo_tlv_load *tlv, unsigned int tag)
{
+ struct osmo_tlv_tag_inst ti = { .tag = tag };
+ return osmo_tlv_load_next_by_tag_inst(tlv, &ti);
+}
+
+int osmo_tlv_load_next_by_tag_inst(struct osmo_tlv_load *tlv, const struct
osmo_tlv_tag_inst *ti)
+{
struct osmo_tlv_load work = *tlv;
for (;;) {
int rc = osmo_tlv_load_next(&work);
@@ -157,7 +210,7 @@
return rc;
if (!work.val)
return -ENOENT;
- if (work.tag == tag) {
+ if (!osmo_tlv_tag_inst_cmp(&work.ti, ti)) {
*tlv = work;
return 0;
}
@@ -190,16 +243,25 @@
*/
int osmo_tlv_put_tl(struct osmo_tlv_put *tlv, unsigned int tag, size_t len)
{
+ struct osmo_tlv_tag_inst ti = { .tag = tag };
+ return osmo_tlv_put_tli(tlv, &ti, len);
+}
+
+/* Put tag header, instance value and length at the end of the msgb, according to
tlv->cfg->store_tl().
+ * This is the same as osmo_tlv_put_tl(), only osmo_tlv_put_tl() passes instance = 0.
+ */
+int osmo_tlv_put_tli(struct osmo_tlv_put *tlv, const struct osmo_tlv_tag_inst *ti, size_t
len)
+{
int rc;
uint8_t *last_tl;
OSMO_ASSERT(tlv->cfg->store_tl);
last_tl = tlv->dst->tail;
- rc = tlv->cfg->store_tl(tlv->dst->tail, msgb_tailroom(tlv->dst), tag,
len, tlv);
+ rc = tlv->cfg->store_tl(tlv->dst->tail, msgb_tailroom(tlv->dst), ti, len,
tlv);
if (rc < 0)
return rc;
if (rc > 0)
msgb_put(tlv->dst, rc);
- tlv->last_tag = tag;
+ tlv->last_ti = *ti;
tlv->last_tl = last_tl;
tlv->last_val = tlv->dst->tail;
return 0;
@@ -212,7 +274,7 @@
int osmo_tlv_put_update_tl(struct osmo_tlv_put *tlv)
{
size_t len = tlv->dst->tail - tlv->last_val;
- int rc = tlv->cfg->store_tl(tlv->last_tl, tlv->last_val - tlv->last_tl,
tlv->last_tag, len, tlv);
+ int rc = tlv->cfg->store_tl(tlv->last_tl, tlv->last_val - tlv->last_tl,
&tlv->last_ti, len, tlv);
if (rc < 0)
return rc;
/* In case the TL has changed in size, hopefully the implementation has moved the msgb
data. Make sure last_val
@@ -224,22 +286,22 @@
static int t8l8v_load_tl(struct osmo_tlv_load *tlv, const uint8_t *src_data, size_t
src_data_len)
{
/* already validated in next_tl_valid(): src_data_len >= cfg->tl_min_size == 2.
*/
- tlv->tag = src_data[0];
+ tlv->ti.tag = src_data[0];
tlv->len = src_data[1];
tlv->val = src_data + 2;
return 0;
}
-static int t8l8v_store_tl(uint8_t *dst_data, size_t dst_data_avail, unsigned int tag,
size_t len,
+static int t8l8v_store_tl(uint8_t *dst_data, size_t dst_data_avail, const struct
osmo_tlv_tag_inst *ti, size_t len,
struct osmo_tlv_put *tlv)
{
- if (tag > UINT8_MAX)
+ if (ti->tag > UINT8_MAX)
return -EINVAL;
if (len > UINT8_MAX)
return -EMSGSIZE;
if (dst_data_avail < 2)
return -ENOSPC;
- dst_data[0] = tag;
+ dst_data[0] = ti->tag;
dst_data[1] = len;
return 2;
}
@@ -253,22 +315,22 @@
static int t16l16v_load_tl(struct osmo_tlv_load *tlv, const uint8_t *src_data, size_t
src_data_len)
{
/* already validated in next_tl_valid(): src_data_len >= cfg->tl_min_size == 4.
*/
- tlv->tag = osmo_load16be(src_data);
+ tlv->ti.tag = osmo_load16be(src_data);
tlv->len = osmo_load16be(src_data + 2);
tlv->val = src_data + 4;
return 0;
}
-static int t16l16v_store_tl(uint8_t *dst_data, size_t dst_data_avail, unsigned int tag,
size_t len,
+static int t16l16v_store_tl(uint8_t *dst_data, size_t dst_data_avail, const struct
osmo_tlv_tag_inst *ti, size_t len,
struct osmo_tlv_put *tlv)
{
- if (tag > UINT16_MAX)
+ if (ti->tag > UINT16_MAX)
return -EINVAL;
if (len > UINT16_MAX)
return -EMSGSIZE;
if (dst_data_avail < 4)
return -ENOSPC;
- osmo_store16be(tag, dst_data);
+ osmo_store16be(ti->tag, dst_data);
osmo_store16be(len, dst_data + 2);
return 4;
}
diff --git a/src/libosmo-tlv/tlv_dec_enc.c b/src/libosmo-tlv/tlv_dec_enc.c
index a59a9e3..63b494e 100644
--- a/src/libosmo-tlv/tlv_dec_enc.c
+++ b/src/libosmo-tlv/tlv_dec_enc.c
@@ -31,12 +31,21 @@
/* Reverse offsetof(): return the address of the struct member for a given osmo_tlv_msg
and member ofs_foo value. */
#define MEMB(M, MEMB_OFS) ((void *)((char *)(M) + (MEMB_OFS)))
-#define RETURN_ERROR(RC, IEI, FMT, ARGS...) \
+#define RETURN_ERROR(RC, TAG_INST, FMT, ARGS...) \
do {\
- if (err_cb) \
- err_cb(err_cb_data, (void*)decoded_struct, __FILE__, __LINE__, \
- "IE '%s' (0x%x): " FMT " (%d: %s)\n", \
- get_value_string(iei_strs, IEI), IEI, ##ARGS, RC, strerror((RC) > 0 ? (RC) :
-(RC))); \
+ if (err_cb) { \
+ if ((TAG_INST).instance_present) \
+ err_cb(err_cb_data, (void*)decoded_struct, __FILE__, __LINE__, \
+ "tag 0x%x = %s instance %u: " FMT " (%d: %s)\n", \
+ (TAG_INST).tag, get_value_string(iei_strs, (TAG_INST).tag), \
+ (TAG_INST).instance, ##ARGS, \
+ RC, strerror((RC) > 0 ? (RC) : -(RC))); \
+ else \
+ err_cb(err_cb_data, (void*)decoded_struct, __FILE__, __LINE__, \
+ "tag 0x%x = %s: " FMT " (%d: %s)\n", \
+ (TAG_INST).tag, get_value_string(iei_strs, (TAG_INST).tag), ##ARGS, \
+ RC, strerror((RC) > 0 ? (RC) : -(RC))); \
+ } \
return RC; \
} while (0)
@@ -72,7 +81,7 @@
#define CHECK_SEEN(IEC) do { \
unsigned int ie_coding_idx = (IEC) - ie_coding; \
if (ie_coding_idx >= ARRAY_SIZE(seen_ie_coding_entries)) \
- RETURN_ERROR(-ENOTSUP, tlv->tag, \
+ RETURN_ERROR(-ENOTSUP, tlv->ti, \
"Too many IE definitions for decoding an unordered TLV structure");
\
seen_p = &seen_ie_coding_entries[ie_coding_idx]; \
} while (0)
@@ -91,7 +100,7 @@
rc = osmo_tlv_load_next(tlv);
if (rc)
- RETURN_ERROR(rc, tlv->tag, "Decoding IEs failed on or after this tag");
+ RETURN_ERROR(rc, tlv->ti, "Decoding IEs failed on or after this tag");
if (!tlv->val) {
/* End of the TLV structure */
break;
@@ -103,7 +112,9 @@
do {
/* Find the IE coding for this tag */
- for (iec = ie_coding; !osmo_tlv_coding_end(iec) && iec->tag != tlv->tag;
iec++);
+ for (iec = ie_coding;
+ !osmo_tlv_coding_end(iec) && osmo_tlv_tag_inst_cmp(&iec->ti,
&tlv->ti);
+ iec++);
/* No such IE coding found. */
if (osmo_tlv_coding_end(iec))
break;
@@ -128,7 +139,7 @@
if (ie_max_allowed_count) {
/* There have been IE definitions for this IEI, but all slots to decode it are
already
* filled. */
- RETURN_ERROR(-ENOTSUP, tlv->tag, "Only %u instances of this IE are supported
per message",
+ RETURN_ERROR(-ENOTSUP, tlv->ti, "Only %u instances of this IE are supported
per message",
ie_max_allowed_count);
}
/* No such IE defined in ie_coding, just skip the TLV. */
@@ -166,14 +177,14 @@
rc = osmo_tlvs_decode(decoded_struct, obj_ofs + memb_ofs, &inner_tlv, ordered,
iec->nested_ies,
err_cb, err_cb_data, iei_strs);
if (rc)
- RETURN_ERROR(rc, tlv->tag, "Error while decoding TLV structure nested inside
this IE");
+ RETURN_ERROR(rc, tlv->ti, "Error while decoding TLV structure nested inside
this IE");
} else {
/* Normal IE, decode the specific IE data. */
if (!iec->dec_func)
- RETURN_ERROR(-EIO, tlv->tag, "IE definition lacks a dec_func()");
+ RETURN_ERROR(-EIO, tlv->ti, "IE definition lacks a dec_func()");
rc = iec->dec_func(decoded_struct, MEMB(obj, memb_ofs), tlv);
if (rc)
- RETURN_ERROR(rc, tlv->tag, "Error while decoding this IE");
+ RETURN_ERROR(rc, tlv->ti, "Error while decoding this IE");
}
if (multi_count_p) {
@@ -197,14 +208,14 @@
multi_count_p = iec->has_count ? MEMB(obj, iec->count_ofs) : NULL;
if (multi_count_p) {
if (*multi_count_p < iec->count_madatory)
- RETURN_ERROR(-EINVAL, iec->tag, "Error while decoding: %u instances of this
IE are mandatory, got %u",
+ RETURN_ERROR(-EINVAL, iec->ti, "%u instances of this IE are mandatory, got
%u",
iec->count_madatory, *multi_count_p);
continue;
}
/* Neither an optional nor a multi member, hence it must be mandatory. */
CHECK_SEEN(iec);
if (!*seen_p)
- RETURN_ERROR(-EINVAL, iec->tag, "Missing mandatory IE");
+ RETURN_ERROR(-EINVAL, iec->ti, "Missing mandatory IE");
}
return 0;
}
@@ -235,19 +246,20 @@
int rc;
bool *presence_flag = ie_coding->has_presence_flag ? MEMB(obj,
ie_coding->presence_flag_ofs) : NULL;
unsigned int *multi_count = ie_coding->has_count ? MEMB(obj,
ie_coding->count_ofs) : NULL;
+ struct osmo_tlv_tag_inst peek_ti;
- rc = osmo_tlv_load_next_by_tag(tlv, ie_coding->tag);
+ rc = osmo_tlv_load_next_by_tag_inst(tlv, &ie_coding->ti);
switch (rc) {
case 0:
break;
case -ENOENT:
if (!presence_flag && (!multi_count || *multi_count <
ie_coding->count_madatory))
- RETURN_ERROR(rc, ie_coding->tag, "Missing mandatory IE");
+ RETURN_ERROR(rc, ie_coding->ti, "Missing mandatory IE");
if (presence_flag)
*presence_flag = false;
continue;
default:
- RETURN_ERROR(rc, ie_coding->tag, "Error in TLV structure");
+ RETURN_ERROR(rc, ie_coding->ti, "Error in TLV structure");
}
for (;;) {
@@ -257,7 +269,7 @@
unsigned int memb_ofs = ie_coding->memb_ofs + memb_next_array_idx *
ie_coding->memb_array_pitch;
if (multi_count && memb_next_array_idx >= ie_coding->count_max)
- RETURN_ERROR(-ENOTSUP, ie_coding->tag, "Only %u instances of this IE are
supported per message",
+ RETURN_ERROR(-ENOTSUP, ie_coding->ti, "Only %u instances of this IE are
supported per message",
ie_coding->count_max);
/* Decode IE value part */
@@ -286,15 +298,15 @@
rc = osmo_tlvs_decode(decoded_struct, obj_ofs + memb_ofs, &inner_tlv, ordered,
ie_coding->nested_ies, err_cb, err_cb_data, iei_strs);
if (rc)
- RETURN_ERROR(rc, ie_coding->tag,
+ RETURN_ERROR(rc, ie_coding->ti,
"Error while decoding TLV structure nested inside this IE");
} else {
/* Normal IE, decode the specific IE data. */
if (!ie_coding->dec_func)
- RETURN_ERROR(-EIO, ie_coding->tag, "IE definition lacks a
dec_func()");
+ RETURN_ERROR(-EIO, ie_coding->ti, "IE definition lacks a dec_func()");
rc = ie_coding->dec_func(decoded_struct, MEMB(obj, memb_ofs), tlv);
if (rc)
- RETURN_ERROR(rc, ie_coding->tag, "Error while decoding this IE");
+ RETURN_ERROR(rc, ie_coding->ti, "Error while decoding this IE");
}
if (presence_flag)
@@ -312,7 +324,8 @@
(*multi_count)++;
/* Does another one of these IEs follow? */
- if (osmo_tlv_load_peek_tag(tlv) != tlv->tag) {
+ if (osmo_tlv_load_peek_tag(tlv, &peek_ti)
+ || osmo_tlv_tag_inst_cmp(&peek_ti, &tlv->ti)) {
/* Next tag is a different IE, end the repetition. */
break;
}
@@ -387,7 +400,7 @@
if (multi_count_p) {
n = *multi_count_p;
if (!ie_coding->memb_array_pitch)
- RETURN_ERROR(-EFAULT, ie_coding->tag,
+ RETURN_ERROR(-EFAULT, ie_coding->ti,
"Error in protocol definition: The ie_coding lacks a
memb_array_pitch"
" value, cannot be used as multi-IE\n");
} else {
@@ -397,11 +410,11 @@
for (i = 0; i < n; i++) {
unsigned int memb_ofs;
- osmo_tlv_put_tl(tlv, ie_coding->tag, 0);
+ osmo_tlv_put_tli(tlv, &ie_coding->ti, 0);
/* If this is a repeated IE, encode from the correct array index */
if (multi_count_p && i >= ie_coding->count_max)
- RETURN_ERROR(-ENOTSUP, ie_coding->tag,
+ RETURN_ERROR(-ENOTSUP, ie_coding->ti,
"Only %u instances of this IE are supported per message",
ie_coding->count_max);
memb_ofs = ie_coding->memb_ofs + i * ie_coding->memb_array_pitch;
@@ -413,12 +426,12 @@
rc = osmo_tlvs_encode(&nested_tlv, decoded_struct, obj_ofs + memb_ofs,
ie_coding->nested_ies, err_cb, err_cb_data, iei_strs);
if (rc)
- RETURN_ERROR(rc, ie_coding->tag,
+ RETURN_ERROR(rc, ie_coding->ti,
"Error while encoding TLV structure nested inside this IE");
} else {
rc = ie_coding->enc_func(tlv, decoded_struct, MEMB(obj, memb_ofs));
if (rc)
- RETURN_ERROR(rc, ie_coding->tag, "Error while encoding this IE");
+ RETURN_ERROR(rc, ie_coding->ti, "Error while encoding this IE");
}
osmo_tlv_put_update_tl(tlv);
@@ -467,7 +480,7 @@
if (!n)
continue;
- OSMO_STRBUF_PRINTF(sb, " '%s'=", get_value_string(iei_strs,
ie_coding->tag));
+ OSMO_STRBUF_PRINTF(sb, " '%s'=", get_value_string(iei_strs,
ie_coding->ti.tag));
if (multi_count_p)
OSMO_STRBUF_PRINTF(sb, "{ ");
diff --git a/src/libosmo-tlv/tlv_gen.c b/src/libosmo-tlv/tlv_gen.c
index 2bb02a7..d0fd321 100644
--- a/src/libosmo-tlv/tlv_gen.c
+++ b/src/libosmo-tlv/tlv_gen.c
@@ -33,7 +33,7 @@
static const struct osmo_tlv_gen_cfg *g_cfg = NULL;
-const struct osmo_tlv_gen_ie osmo_tlv_gen_ie_auto = {};
+const struct osmo_tlv_gen_ie osmo_tlv_gen_ie_auto = {0};
/* Helps avoid redundant defintions of the same type. */
struct seen_entry {
@@ -248,7 +248,7 @@
}
/* For a nested IE, write the struct osmo_tlv_coding array of the inner IEs.
- * { MYPROTO_IEI_BAR,
+ * { { MYPROTO_IEI_BAR },
* .memb_ofs = offsetof(struct myproto_foo, bar),
* .dec_func = myproto_dec_bar,
* .enc_func = myproto_enc_bar,
@@ -262,10 +262,13 @@
for (ie_o = ies; ie_o->ie; ie_o++) {
const struct osmo_tlv_gen_ie *ie = ie_o->ie;
const char *tag_name = (ie && ie->tag_name) ? ie->tag_name :
ie_o->name;
- printi("{ %s%s,\n", g_cfg->tag_prefix, osmo_str_toupper(tag_name));
+ printi("{ { %s%s", g_cfg->tag_prefix, osmo_str_toupper(tag_name));
+ if (ie_o->instance)
+ printf(", true, %s", ie_o->instance);
+ printf(" },\n");
printi(" .memb_ofs = offsetof(%s, %s%s),\n", obj_type, substruct,
ie_o->name);
- if (ie && ie->nested_ies) {
- printi(" .nested_ies = ies_in_%s,\n", ie->tag_name ? : ie_o->name);
+ if (ie->nested_ies) {
+ printi(" .nested_ies = ies_in_%s,\n", tag_name);
} else {
const char *dec_enc = ie->dec_enc ? : (ie->tag_name ? : ie_o->name);
printi(" .dec_func = %s_dec_%s,\n", g_cfg->proto_name, dec_enc);
@@ -290,7 +293,7 @@
/* For a nested IE, write the struct osmo_tlv_coding array of the inner IEs.
* static const struct osmo_tlv_coding ies_in_foo[] = {
- * { MYPROTO_IEI_BAR,
+ * { {MYPROTO_IEI_BAR},
* .memb_ofs = offsetof(struct myproto_foo, bar),
* .dec_func = myproto_dec_bar,
* .enc_func = myproto_enc_bar,
@@ -314,7 +317,7 @@
printf("\nstatic const struct osmo_tlv_coding ies_in_%s[] = {\n",
ies_in_name);
write_ies_array(indent, ie->nested_ies, decoded_type(ie_o), "");
- printi("{0}\n");
+ printi("{}\n");
printf("};\n");
}
}
@@ -352,7 +355,7 @@
char *substruct = talloc_asprintf(NULL, "%s.", gen_msg->name);
printf("\nstatic const struct osmo_tlv_coding ies_in_msg_%s[] = {\n",
gen_msg->name);
write_ies_array("\t", gen_msg->ies, obj_type, substruct);
- printf("\t{0}\n};\n");
+ printf("\t{}\n};\n");
talloc_free(substruct);
talloc_free(obj_type);
}
diff --git a/tests/libosmo-tlv/Makefile.am b/tests/libosmo-tlv/Makefile.am
index 64e3bdd..b27ba0c 100644
--- a/tests/libosmo-tlv/Makefile.am
+++ b/tests/libosmo-tlv/Makefile.am
@@ -1,5 +1,6 @@
SUBDIRS = \
test_tlv_gen \
+ test_tliv \
$(NULL)
AM_CPPFLAGS = \
@@ -45,3 +46,4 @@
$(builddir)/tlv_test >$(srcdir)/tlv_test.ok
$(builddir)/tlv_dec_enc_test >$(srcdir)/tlv_dec_enc_test.ok
$(MAKE) -C test_tlv_gen update_exp
+ $(MAKE) -C test_tliv update_exp
diff --git a/tests/libosmo-tlv/test_tliv/Makefile.am
b/tests/libosmo-tlv/test_tliv/Makefile.am
new file mode 100644
index 0000000..3b94619
--- /dev/null
+++ b/tests/libosmo-tlv/test_tliv/Makefile.am
@@ -0,0 +1,60 @@
+AM_CPPFLAGS = \
+ $(all_includes) \
+ -I$(top_srcdir)/include \
+ -I$(bulddir) \
+ $(NULL)
+
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(NULL)
+
+noinst_PROGRAMS = \
+ gen__myproto_ies_auto \
+ tliv_test \
+ $(NULL)
+
+EXTRA_DIST = \
+ myproto_ies_custom.h \
+ tliv_test.ok \
+ $(NULL)
+
+BUILT_SOURCES = \
+ myproto_ies_auto.h \
+ myproto_ies_auto.c \
+ $(NULL)
+
+CLEANFILES = \
+ myproto_ies_auto.h \
+ myproto_ies_auto.c \
+ $(NULL)
+
+gen__myproto_ies_auto_SOURCES = \
+ gen__myproto_ies_auto.c \
+ myproto_ies_custom.c \
+ $(NULL)
+
+gen__myproto_ies_auto_LDADD = \
+ $(top_builddir)/src/libosmo-tlv/libosmo-tlv.a \
+ $(LIBOSMOCORE_LIBS) \
+ $(NULL)
+
+myproto_ies_auto.h: $(builddir)/gen__myproto_ies_auto
+ $(builddir)/gen__myproto_ies_auto h > $(builddir)/myproto_ies_auto.h
+myproto_ies_auto.c: $(builddir)/gen__myproto_ies_auto
+ $(builddir)/gen__myproto_ies_auto c > $(builddir)/myproto_ies_auto.c
+
+tliv_test_SOURCES = \
+ tliv_test.c \
+ myproto_ies_custom.c \
+ myproto_ies_auto.c \
+ $(NULL)
+
+tliv_test_LDADD = \
+ $(top_builddir)/src/libosmo-tlv/libosmo-tlv.a \
+ $(LIBOSMOCORE_LIBS) \
+ $(NULL)
+
+.PHONY: update_exp
+update_exp:
+ $(builddir)/tliv_test >$(srcdir)/tliv_test.ok
diff --git a/tests/libosmo-tlv/test_tliv/gen__myproto_ies_auto.c
b/tests/libosmo-tlv/test_tliv/gen__myproto_ies_auto.c
new file mode 100644
index 0000000..522ab92
--- /dev/null
+++ b/tests/libosmo-tlv/test_tliv/gen__myproto_ies_auto.c
@@ -0,0 +1,72 @@
+/*
+ * (C) 2021-2022 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved.
+ *
+ * Author: Neels Janosch Hofmeyr <nhofmeyr(a)sysmocom.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/tlv/tlv_gen.h>
+
+#define O OSMO_TLV_GEN_O
+#define M OSMO_TLV_GEN_M
+#define O_MULTI OSMO_TLV_GEN_O_MULTI
+#define M_MULTI OSMO_TLV_GEN_M_MULTI
+#define O_INST OSMO_TLV_GEN_O_INST
+#define M_INST OSMO_TLV_GEN_M_INST
+
+#define AUTO osmo_tlv_gen_ie_auto
+
+static const struct osmo_tlv_gen_ie bar = {
+ .tag_name = "bar",
+};
+
+static const struct osmo_tlv_gen_ie_o ies_in_moo_msg[] = {
+ M_INST("MYPROTO_IEI_BAR_ALPHA", bar, "bar_alpha"),
+ O_INST("MYPROTO_IEI_BAR_BETA", bar, "bar_beta"),
+ M_INST("MYPROTO_IEI_BAR_GAMMA", bar, "bar_gamma"),
+ {0}
+};
+
+static const struct osmo_tlv_gen_msg msg_defs[] = {
+ { "moo", ies_in_moo_msg },
+ {0}
+};
+
+int main(int argc, const char **argv)
+{
+ struct osmo_tlv_gen_cfg cfg = {
+ .proto_name = "myproto",
+ .message_type_enum = "enum myproto_msg_type",
+ .message_type_prefix = "MYPROTO_MSGT_",
+ .tag_enum = "enum myproto_iei",
+ .tag_prefix = "MYPROTO_IEI_",
+ .decoded_type_prefix = "struct myproto_ie_",
+ .h_header = "#include \"myproto_ies_custom.h\"",
+ .c_header = "#include <myproto_ies_auto.h>",
+ .msg_defs = msg_defs,
+ .add_enc_to_str = true,
+ };
+ return osmo_tlv_gen_main(&cfg, argc, argv);
+}
diff --git a/tests/libosmo-tlv/test_tliv/myproto_ies_custom.c
b/tests/libosmo-tlv/test_tliv/myproto_ies_custom.c
new file mode 100644
index 0000000..d7af97b
--- /dev/null
+++ b/tests/libosmo-tlv/test_tliv/myproto_ies_custom.c
@@ -0,0 +1,67 @@
+/* Example for defining custom IES for tlv_gen.
+ *
+ * (C) 2021-2022 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved.
+ *
+ * Author: Neels Janosch Hofmeyr <nhofmeyr(a)sysmocom.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <errno.h>
+#include <inttypes.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/tlv/tlv.h>
+
+#include <myproto_ies_custom.h>
+
+int myproto_dec_bar(void *decoded_struct, void *decode_to, const struct osmo_tlv_load
*tlv)
+{
+ struct myproto_ie_bar *bar = decode_to;
+ if (tlv->len < 2)
+ return -EINVAL;
+ *bar = (struct myproto_ie_bar){
+ .a = tlv->val[0],
+ .b = (tlv->val[1] == 1),
+ };
+ return 0;
+}
+
+int myproto_enc_bar(struct osmo_tlv_put *tlv, void *decoded_struct, void *encode_from)
+{
+ struct myproto_ie_bar *bar = encode_from;
+ msgb_put_u8(tlv->dst, bar->a);
+ msgb_put_u8(tlv->dst, bar->b ? 1 : 0);
+ return 0;
+}
+
+int myproto_enc_to_str_bar(char *buf, size_t buflen, void *encode_from)
+{
+ struct myproto_ie_bar *bar = encode_from;
+ return snprintf(buf, buflen, "%d,%s", bar->a, bar->b ? "true"
: "false");
+}
+
+const struct value_string myproto_msg_type_names[] = {
+ { MYPROTO_MSGT_MOO, "MOO" },
+ {}
+};
+
+const struct value_string myproto_iei_names[] = {
+ { MYPROTO_IEI_BAR, "BAR" },
+ {}
+};
diff --git a/tests/libosmo-tlv/test_tliv/myproto_ies_custom.h
b/tests/libosmo-tlv/test_tliv/myproto_ies_custom.h
new file mode 100644
index 0000000..00203bc
--- /dev/null
+++ b/tests/libosmo-tlv/test_tliv/myproto_ies_custom.h
@@ -0,0 +1,27 @@
+/* Definitions for decoded message IEs, to be used by the auto-generated
tlv_gen_test_tlv.c. */
+#pragma once
+
+#include <osmocom/core/utils.h>
+
+enum myproto_msg_type {
+ MYPROTO_MSGT_MOO = 1,
+};
+
+extern const struct value_string myproto_msg_type_names[];
+
+enum myproto_iei {
+ MYPROTO_IEI_BAR = 1,
+};
+
+enum myproto_iei_bar_inst {
+ MYPROTO_IEI_BAR_ALPHA = 2,
+ MYPROTO_IEI_BAR_BETA = 3,
+ MYPROTO_IEI_BAR_GAMMA = 5,
+};
+
+extern const struct value_string myproto_iei_names[];
+
+struct myproto_ie_bar {
+ int a;
+ bool b;
+};
diff --git a/tests/libosmo-tlv/test_tliv/tliv_test.c
b/tests/libosmo-tlv/test_tliv/tliv_test.c
new file mode 100644
index 0000000..7761722
--- /dev/null
+++ b/tests/libosmo-tlv/test_tliv/tliv_test.c
@@ -0,0 +1,212 @@
+/* (C) 2022 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <osmocom/core/application.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+
+#include <osmocom/tlv/tlv.h>
+
+#include <myproto_ies_auto.h>
+
+struct myproto_msg {
+ enum myproto_msg_type type;
+ union myproto_ies ies;
+};
+
+static void err_cb(void *data, void *decoded_struct, const char *file, int line, const
char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ //printf("ERR: %s:%d ", file, line);
+ printf("ERR: ");
+ vprintf(fmt, args);
+ va_end(args);
+}
+
+static int myproto_msg_enc(struct msgb *dst, const struct myproto_msg *msg, const struct
osmo_tlv_cfg *cfg)
+{
+ struct osmo_tlv_put tlv = {
+ .cfg = cfg,
+ .dst = dst,
+ };
+
+ msgb_put_u8(tlv.dst, msg->type);
+ return myproto_ies_encode(&tlv, (void*)&msg->ies, msg->type, err_cb, NULL,
myproto_iei_names);
+}
+
+static int myproto_msg_dec(struct myproto_msg *msg, const uint8_t *data, size_t
data_len,
+ const struct osmo_tlv_cfg *cfg, bool ordered)
+{
+ struct osmo_tlv_load tlv;
+ if (data_len < 1)
+ return -EINVAL;
+ msg->type = data[0];
+ tlv = (struct osmo_tlv_load){
+ .cfg = cfg,
+ .src = { data + 1, data_len - 1 },
+ };
+ return myproto_ies_decode(&msg->ies, &tlv, ordered, msg->type, err_cb,
NULL, myproto_iei_names);
+}
+
+void *ctx;
+
+struct myproto_msg tests[] = {
+ {
+ MYPROTO_MSGT_MOO,
+ {
+ .moo = {
+ .bar_alpha = { 23, true },
+ .bar_gamma = { 42, false },
+ },
+ },
+ },
+ {
+ MYPROTO_MSGT_MOO,
+ {
+ .moo = {
+ .bar_alpha = { 11, true },
+ .bar_beta_present = true,
+ .bar_beta = { 22, false },
+ .bar_gamma = { 33, true },
+ },
+ },
+ },
+};
+
+int myproto_msg_to_str_buf(char *buf, size_t buflen, const struct myproto_msg *m)
+{
+ struct osmo_strbuf sb = { .buf = buf, .len = buflen };
+ OSMO_STRBUF_PRINTF(sb, "%s={", get_value_string(myproto_msg_type_names,
m->type));
+ OSMO_STRBUF_APPEND(sb, osmo_tlvs_encode_to_str_buf, &m->ies, 0,
myproto_get_msg_coding(m->type),
+ myproto_iei_names);
+ OSMO_STRBUF_PRINTF(sb, " }");
+ return sb.chars_needed;
+
+}
+
+char *myproto_msg_to_str(const struct myproto_msg *m)
+{
+ OSMO_NAME_C_IMPL(ctx, 256, "ERROR", myproto_msg_to_str_buf, m)
+}
+
+void test_enc_dec(const char *label, const struct osmo_tlv_cfg *cfg, bool ordered)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ int rc;
+ const struct myproto_msg *orig = &tests[i];
+ struct myproto_msg parsed = {0};
+ struct msgb *msg;
+
+ printf("\n=== start %s %s[%d]\n", label, __func__, i);
+ printf("encoded: %s\n", myproto_msg_to_str(orig));
+
+ msg = msgb_alloc(1024, __func__),
+ rc = myproto_msg_enc(msg, orig, cfg);
+ printf("myproto_msg_enc() rc = %d\n", rc);
+ printf("%s.\n", osmo_hexdump(msg->data, msg->len));
+
+ rc = myproto_msg_dec(&parsed, msg->data, msg->len, cfg, ordered);
+ printf("myproto_msg_dec() rc = %d\n", rc);
+ printf("decoded: %s\n", myproto_msg_to_str(&parsed));
+ if (strcmp(myproto_msg_to_str(orig), myproto_msg_to_str(&parsed))) {
+ printf(" ERROR: parsed != orig\n");
+ exit(1);
+ }
+
+ msgb_free(msg);
+ printf("=== end %s %s[%d]\n", label, __func__, i);
+ }
+}
+
+/* Example of defining a TLI, with an instance indicator */
+static int tliv_load_tl(struct osmo_tlv_load *tlv, const uint8_t *src_data, size_t
src_data_len)
+{
+ /* already validated in next_tl_valid(): src_data_len >= cfg->tl_min_size == 2.
*/
+ tlv->ti.tag = src_data[0];
+ tlv->len = src_data[1];
+
+ switch (tlv->ti.tag) {
+ /* All tags that are TLIV go here */
+ case MYPROTO_IEI_BAR:
+ if (src_data_len < 3)
+ return -ENOSPC;
+ tlv->ti.instance_present = true;
+ tlv->ti.instance = src_data[2];
+ tlv->val = src_data + 3;
+ /* In this example, the I is part of the len */
+ tlv->len--;
+ return 0;
+ default:
+ tlv->val = src_data + 2;
+ return 0;
+ }
+}
+
+static int tliv_store_tl(uint8_t *dst_data, size_t dst_data_avail, const struct
osmo_tlv_tag_inst *ti, size_t len,
+ struct osmo_tlv_put *tlv)
+{
+ if (ti->tag > UINT8_MAX)
+ return -EINVAL;
+ if (len > UINT8_MAX)
+ return -EMSGSIZE;
+ if (dst_data_avail < 2)
+ return -ENOSPC;
+
+ dst_data[0] = ti->tag;
+
+ switch (ti->tag) {
+ /* All tags that are TLIV go here */
+ case MYPROTO_IEI_BAR:
+ if (dst_data_avail < 3)
+ return -ENOSPC;
+ if (!ti->instance_present)
+ return -EINVAL;
+ if (ti->instance > UINT8_MAX)
+ return -EINVAL;
+ /* here, I is part of the len in L; the passed len reflects only the value, so add 1
for I */
+ dst_data[1] = len + 1;
+ dst_data[2] = ti->instance;
+ return 3;
+ default:
+ dst_data[1] = len;
+ return 2;
+ }
+}
+
+const struct osmo_tlv_cfg osmo_tliv_cfg = {
+ .tl_min_size = 2,
+ .load_tl = tliv_load_tl,
+ .store_tl = tliv_store_tl,
+};
+
+int main()
+{
+ ctx = talloc_named_const(NULL, 0, "test_gen_tlv");
+ msgb_talloc_ctx_init(ctx, 0);
+
+ test_enc_dec("tliv ordered", &osmo_tliv_cfg, true);
+ test_enc_dec("tliv unordered", &osmo_tliv_cfg, false);
+
+ talloc_free(ctx);
+ return 0;
+}
diff --git a/tests/libosmo-tlv/test_tliv/tliv_test.ok
b/tests/libosmo-tlv/test_tliv/tliv_test.ok
new file mode 100644
index 0000000..184ffa6
--- /dev/null
+++ b/tests/libosmo-tlv/test_tliv/tliv_test.ok
@@ -0,0 +1,32 @@
+
+=== start tliv ordered test_enc_dec[0]
+encoded: MOO={ 'BAR'=23,true 'BAR'=42,false }
+myproto_msg_enc() rc = 0
+01 01 03 02 17 01 01 03 05 2a 00 .
+myproto_msg_dec() rc = 0
+decoded: MOO={ 'BAR'=23,true 'BAR'=42,false }
+=== end tliv ordered test_enc_dec[0]
+
+=== start tliv ordered test_enc_dec[1]
+encoded: MOO={ 'BAR'=11,true 'BAR'=22,false 'BAR'=33,true }
+myproto_msg_enc() rc = 0
+01 01 03 02 0b 01 01 03 03 16 00 01 03 05 21 01 .
+myproto_msg_dec() rc = 0
+decoded: MOO={ 'BAR'=11,true 'BAR'=22,false 'BAR'=33,true }
+=== end tliv ordered test_enc_dec[1]
+
+=== start tliv unordered test_enc_dec[0]
+encoded: MOO={ 'BAR'=23,true 'BAR'=42,false }
+myproto_msg_enc() rc = 0
+01 01 03 02 17 01 01 03 05 2a 00 .
+myproto_msg_dec() rc = 0
+decoded: MOO={ 'BAR'=23,true 'BAR'=42,false }
+=== end tliv unordered test_enc_dec[0]
+
+=== start tliv unordered test_enc_dec[1]
+encoded: MOO={ 'BAR'=11,true 'BAR'=22,false 'BAR'=33,true }
+myproto_msg_enc() rc = 0
+01 01 03 02 0b 01 01 03 03 16 00 01 03 05 21 01 .
+myproto_msg_dec() rc = 0
+decoded: MOO={ 'BAR'=11,true 'BAR'=22,false 'BAR'=33,true }
+=== end tliv unordered test_enc_dec[1]
diff --git a/tests/libosmo-tlv/tlv_dec_enc_test.c b/tests/libosmo-tlv/tlv_dec_enc_test.c
index 2bfefc6..4b9eefd 100644
--- a/tests/libosmo-tlv/tlv_dec_enc_test.c
+++ b/tests/libosmo-tlv/tlv_dec_enc_test.c
@@ -200,21 +200,21 @@
struct osmo_tlv_coding nested_inner_msg_ies[] = {
{
- .tag = TAG_FOO,
+ .ti = { TAG_FOO },
.dec_func = dec_u16,
.enc_func = enc_u16,
.enc_to_str_func = enc_to_str_u16,
.memb_ofs = offsetof(struct nested_inner_msg, foo),
},
{
- .tag = TAG_BAR,
+ .ti = { TAG_BAR },
.dec_func = dec_bar,
.enc_func = enc_bar,
.enc_to_str_func = enc_to_str_bar,
.memb_ofs = offsetof(struct nested_inner_msg, bar),
},
{
- .tag = TAG_BAZ,
+ .ti = { TAG_BAZ },
.dec_func = dec_baz,
.enc_func = enc_baz,
.enc_to_str_func = enc_to_str_baz,
@@ -225,21 +225,21 @@
struct osmo_tlv_coding msg_ie_coding[] = {
{
- .tag = TAG_FOO,
+ .ti = { TAG_FOO },
.dec_func = dec_u16,
.enc_func = enc_u16,
.enc_to_str_func = enc_to_str_u16,
.memb_ofs = offsetof(struct decoded_msg, foo),
},
{
- .tag = TAG_BAR,
+ .ti = { TAG_BAR },
.dec_func = dec_bar,
.enc_func = enc_bar,
.enc_to_str_func = enc_to_str_bar,
.memb_ofs = offsetof(struct decoded_msg, bar),
},
{
- .tag = TAG_BAZ,
+ .ti = { TAG_BAZ },
.dec_func = dec_baz,
.enc_func = enc_baz,
.enc_to_str_func = enc_to_str_baz,
@@ -248,7 +248,7 @@
.presence_flag_ofs = offsetof(struct decoded_msg, baz_present),
},
{
- .tag = TAG_REPEAT_INT,
+ .ti = { TAG_REPEAT_INT },
.dec_func = dec_u16,
.enc_func = enc_u16,
.enc_to_str_func = enc_to_str_u16,
@@ -259,7 +259,7 @@
.count_max = ARRAY_SIZE( ((struct decoded_msg*)0)->repeat_int ),
},
{
- .tag = TAG_REPEAT_STRUCT,
+ .ti = { TAG_REPEAT_STRUCT },
.dec_func = dec_repeat_struct,
.enc_func = enc_repeat_struct,
.enc_to_str_func = enc_to_str_repeat_struct,
@@ -270,7 +270,7 @@
.count_max = ARRAY_SIZE( ((struct decoded_msg*)0)->repeat_struct ),
},
{
- .tag = TAG_NEST,
+ .ti = { TAG_NEST },
.memb_ofs = offsetof(struct decoded_msg, nest),
.nested_ies = nested_inner_msg_ies,
.has_presence_flag = true,
diff --git a/tests/libosmo-tlv/tlv_test.c b/tests/libosmo-tlv/tlv_test.c
index 20934db..8adae8a 100644
--- a/tests/libosmo-tlv/tlv_test.c
+++ b/tests/libosmo-tlv/tlv_test.c
@@ -28,7 +28,7 @@
void *ctx;
struct ie {
- int tag;
+ struct osmo_tlv_tag_inst ti;
const char *val;
};
@@ -43,7 +43,7 @@
for (ie = ies; ie->val; ie++) {
/* put header without knowing length yet */
- OSMO_ASSERT(osmo_tlv_put_tl(&tlv, ie->tag, 0) == 0);
+ OSMO_ASSERT(osmo_tlv_put_tli(&tlv, &ie->ti, 0) == 0);
/* put value data, as much as desired */
msgb_put(tlv.dst, osmo_hexparse(ie->val, tlv.dst->tail,
msgb_tailroom(tlv.dst)));
/* update header len from amount of written data */
@@ -75,9 +75,10 @@
/* end of TLV structure? */
if (!tlv.val)
break;
- printf(" T=%d L=%zu v=%s\n", tlv.tag, tlv.len, osmo_hexdump_nospc(tlv.val,
tlv.len));
- if (tlv.tag != ie->tag) {
- printf(" ERROR loading TLV structure: expected tag %d, got tag %d\n",
ie->tag, tlv.tag);
+ printf(" T=%s L=%zu", osmo_tlv_tag_inst_to_str_c(ctx, &tlv.ti, NULL),
tlv.len);
+ printf(" v=%s\n", osmo_hexdump_nospc(tlv.val, tlv.len));
+ if (tlv.ti.tag != ie->ti.tag) {
+ printf(" ERROR loading TLV structure: expected tag %u, got tag %u\n",
ie->ti.tag, tlv.ti.tag);
exit(1);
}
if (strcmp(ie->val, osmo_hexdump_nospc(tlv.val, tlv.len))) {
@@ -102,22 +103,28 @@
ie = ies;
while (1) {
int rc;
- int next_tag = osmo_tlv_load_peek_tag(&tlv);
- if (next_tag == -ENOENT)
- printf(" peek T=-ENOENT\n");
- else
- printf(" peek T=%d\n", next_tag);
+ struct osmo_tlv_tag_inst next_tag;
+ rc = osmo_tlv_load_peek_tag(&tlv, &next_tag);
+ if (rc == -ENOENT) {
+ printf(" peek rc=-ENOENT\n");
+ } else {
+ printf(" peek T=%s", osmo_tlv_tag_inst_to_str_c(ctx, &next_tag,
NULL));
+ printf("\n");
+ }
- if (ie->val && next_tag != ie->tag) {
- printf(" ERROR peeking tag: expected tag %d, got tag %d\n", ie->tag,
next_tag);
+ if (ie->val && osmo_tlv_tag_inst_cmp(&next_tag, &ie->ti)) {
+ printf(" ERROR peeking tag: expected tag %s, got tag %s\n",
+ osmo_tlv_tag_inst_to_str_c(ctx, &ie->ti, NULL),
+ osmo_tlv_tag_inst_to_str_c(ctx, &next_tag, NULL));
exit(1);
}
- if (!ie->val && next_tag != -ENOENT) {
- printf(" ERROR peeking tag: expected -ENOENT, got tag %d\n", next_tag);
+ if (!ie->val && rc != -ENOENT) {
+ printf(" ERROR peeking tag: expected -ENOENT, got rc=%d, tag %s\n", rc,
+ osmo_tlv_tag_inst_to_str_c(ctx, &next_tag, NULL));
exit(1);
}
- if (next_tag == -ENOENT)
+ if (rc == -ENOENT)
break;
/* go to the next TLV */
@@ -151,25 +158,32 @@
for (ie = last_ie; ie >= ies; ie--) {
/* each time, look from the beginning */
osmo_tlv_load_start(&tlv);
- rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag);
+ rc = osmo_tlv_load_next_by_tag_inst(&tlv, &ie->ti);
if (rc) {
- printf(" ERROR loading TLV structure: osmo_tlv_load_next_by_tag(%d) rc =
%d\n", ie->tag, rc);
+ printf(" ERROR loading TLV structure: osmo_tlv_load_next_by_tag_inst(%s) rc =
%d\n",
+ osmo_tlv_tag_inst_to_str_c(ctx, &ie->ti, NULL), rc);
exit(1);
}
if (!tlv.val) {
- printf(" ERROR loading TLV structure: osmo_tlv_load_next_by_tag(%d) returned
NULL val\n",
- ie->tag);
+ printf(" ERROR loading TLV structure: osmo_tlv_load_next_by_tag_inst(%s)
returned NULL val\n",
+ osmo_tlv_tag_inst_to_str_c(ctx, &ie->ti, NULL));
exit(1);
}
- if (tlv.tag != ie->tag) {
- printf(" ERROR loading TLV structure: expected tag %d, got tag %d\n",
ie->tag, tlv.tag);
+ if (osmo_tlv_tag_inst_cmp(&tlv.ti, &ie->ti)) {
+ printf(" ERROR loading TLV structure: expected tag %s, got tag %s\n",
+ osmo_tlv_tag_inst_to_str_c(ctx, &ie->ti, NULL),
+ osmo_tlv_tag_inst_to_str_c(ctx, &tlv.ti, NULL));
exit(1);
}
if (strcmp(ie->val, osmo_hexdump_nospc(tlv.val, tlv.len))) {
while (1) {
- printf(" (mismatch: T=%d L=%zu v=%s, checking for another occurrence of
T=%d)\n",
- tlv.tag, tlv.len, osmo_hexdump_nospc(tlv.val, tlv.len), tlv.tag);
- rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag);
+ printf(" (mismatch: T=%s L=%zu v=%s, checking for another occurrence of
T=%s)\n",
+ osmo_tlv_tag_inst_to_str_c(ctx, &tlv.ti, NULL),
+ tlv.len,
+ osmo_hexdump_nospc(tlv.val, tlv.len),
+ osmo_tlv_tag_inst_to_str_c(ctx, &tlv.ti, NULL));
+
+ rc = osmo_tlv_load_next_by_tag_inst(&tlv, &ie->ti);
if (rc || !tlv.val) {
printf(" ERROR val not found\n");
exit(1);
@@ -179,7 +193,9 @@
}
}
}
- printf(" T=%d L=%zu v=%s\n", tlv.tag, tlv.len, osmo_hexdump_nospc(tlv.val,
tlv.len));
+ printf(" T=%s L=%zu v=%s\n",
+ osmo_tlv_tag_inst_to_str_c(ctx, &tlv.ti, NULL),
+ tlv.len, osmo_hexdump_nospc(tlv.val, tlv.len));
}
printf("- decoding every second tag:\n");
@@ -191,25 +207,32 @@
if (!ie->val)
break;
- rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag);
+ rc = osmo_tlv_load_next_by_tag_inst(&tlv, &ie->ti);
if (rc) {
- printf(" ERROR loading TLV structure: osmo_tlv_load_next_by_tag(%d) rc =
%d\n", ie->tag, rc);
+ printf(" ERROR loading TLV structure: osmo_tlv_load_next_by_tag_inst(%s) rc =
%d\n",
+ osmo_tlv_tag_inst_to_str_c(ctx, &ie->ti, NULL), rc);
exit(1);
}
if (!tlv.val) {
- printf(" ERROR loading TLV structure: osmo_tlv_load_next_by_tag(%d) returned
NULL val\n",
- ie->tag);
+ printf(" ERROR loading TLV structure: osmo_tlv_load_next_by_tag_inst(%s)
returned NULL val\n",
+ osmo_tlv_tag_inst_to_str_c(ctx, &ie->ti, NULL));
exit(1);
}
- if (tlv.tag != ie->tag) {
- printf(" ERROR loading TLV structure: expected tag %d, got tag %d\n",
ie->tag, tlv.tag);
+ if (osmo_tlv_tag_inst_cmp(&tlv.ti, &ie->ti)) {
+ printf(" ERROR loading TLV structure: expected tag %s, got tag %s\n",
+ osmo_tlv_tag_inst_to_str_c(ctx, &ie->ti, NULL),
+ osmo_tlv_tag_inst_to_str_c(ctx, &tlv.ti, NULL));
exit(1);
}
if (strcmp(ie->val, osmo_hexdump_nospc(tlv.val, tlv.len))) {
while (1) {
- printf(" (mismatch: T=%d L=%zu v=%s, checking for another occurrence of
T=%d)\n",
- tlv.tag, tlv.len, osmo_hexdump_nospc(tlv.val, tlv.len), tlv.tag);
- rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag);
+ printf(" (mismatch: T=%s L=%zu v=%s, checking for another occurrence of
T=%s)\n",
+ osmo_tlv_tag_inst_to_str_c(ctx, &tlv.ti, NULL),
+ tlv.len,
+ osmo_hexdump_nospc(tlv.val, tlv.len),
+ osmo_tlv_tag_inst_to_str_c(ctx, &tlv.ti, NULL));
+
+ rc = osmo_tlv_load_next_by_tag_inst(&tlv, &ie->ti);
if (rc || !tlv.val) {
printf(" ERROR val not found\n");
exit(1);
@@ -219,14 +242,16 @@
}
}
}
- printf(" T=%d L=%zu v=%s\n", tlv.tag, tlv.len, osmo_hexdump_nospc(tlv.val,
tlv.len));
+ printf(" T=%s L=%zu v=%s\n",
+ osmo_tlv_tag_inst_to_str_c(ctx, &tlv.ti, NULL),
+ tlv.len, osmo_hexdump_nospc(tlv.val, tlv.len));
}
printf("- enforcing order: without restart, a past tag is not parsed
again:\n");
/* Try to read the first tag, expect that it isn't found because we're already
halfway in the message data */
ie = ies;
- rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag);
- printf(" osmo_tlv_load_next_by_tag(%d) rc=", ie->tag);
+ rc = osmo_tlv_load_next_by_tag_inst(&tlv, &ie->ti);
+ printf(" osmo_tlv_load_next_by_tag_inst(%s) rc=",
osmo_tlv_tag_inst_to_str_c(ctx, &ie->ti, NULL));
if (rc == -ENOENT) {
printf("-ENOENT\n");
} else {
@@ -257,14 +282,14 @@
struct ie t8l8v_test1[] = {
/* smallest T */
- { 0, "2342" },
+ { {0}, "2342" },
/* largest T */
- { 255, "2342" },
+ { {255}, "2342" },
/* smallest V (no V data) */
- { 1, "" },
+ { {1}, "" },
/* largest V, 255 bytes is the largest that an 8bit size length can express. */
- { 123, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ { {123}, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
@@ -275,22 +300,22 @@
},
/* arbitrary test data */
- { 101, "11" },
- { 102, "2222" },
- { 103, "333333" },
+ { {101}, "11" },
+ { {102}, "2222" },
+ { {103}, "333333" },
{}
};
struct ie t8l8v_test_multi[] = {
- { 42, "42" },
- { 2, "0101" },
- { 2, "2222" },
- { 3, "11" },
- { 3, "2222" },
- { 3, "333333" },
- { 23, "23" },
- { 42, "666f72747974776f" },
- { 23, "7477656e74797468726565" },
+ { {42}, "42" },
+ { {2}, "0101" },
+ { {2}, "2222" },
+ { {3}, "11" },
+ { {3}, "2222" },
+ { {3}, "333333" },
+ { {23}, "23" },
+ { {42}, "666f72747974776f" },
+ { {23}, "7477656e74797468726565" },
{}
};
@@ -306,14 +331,14 @@
struct ie t16l16v_test1[] = {
/* smallest T */
- { 0, "2342" },
+ { {0}, "2342" },
/* largest T */
- { 65535, "2342" },
+ { {65535}, "2342" },
/* smallest V (no V data) */
- { 1, "" },
+ { {1}, "" },
/* 256 bytes is one more than an 8bit size length can express. */
- { 123, "0000000000000000000000000000000000000000000000000000000000000000"
+ { {123}, "0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
@@ -324,22 +349,22 @@
},
/* arbitrary test data */
- { 1001, "11" },
- { 1002, "2222" },
- { 1003, "333333" },
+ { {1001}, "11" },
+ { {1002}, "2222" },
+ { {1003}, "333333" },
{}
};
struct ie t16l16v_test_multi[] = {
- { 1042, "42" },
- { 102, "0101" },
- { 102, "2222" },
- { 103, "11" },
- { 103, "2222" },
- { 103, "333333" },
- { 1023, "23" },
- { 1042, "666f72747974776f" },
- { 1023, "7477656e74797468726565" },
+ { {1042}, "42" },
+ { {102}, "0101" },
+ { {102}, "2222" },
+ { {103}, "11" },
+ { {103}, "2222" },
+ { {103}, "333333" },
+ { {1023}, "23" },
+ { {1042}, "666f72747974776f" },
+ { {1023}, "7477656e74797468726565" },
{}
};
@@ -355,18 +380,18 @@
struct ie txlxv_test1[] = {
/* smallest T */
- { 0, "2342" },
+ { {0}, "2342" },
/* largest T that still fits in one encoded octet (highest bit serves as flag) */
- { 0x7f, "2342" },
+ { {0x7f}, "2342" },
/* smallest T that needs two octets to be encoded (first octet = 0x80 flag + 0, second
octet = 0x1) */
- { 0x80, "2342" },
+ { {0x80}, "2342" },
/* largest T that can be encoded in 16bit - one flag bit. */
- { 0x7fff, "2342" },
+ { {0x7fff}, "2342" },
/* smallest V (no V data) */
- { 1, "" },
+ { {1}, "" },
/* 256 bytes is one more than an 8bit size length can express. */
- { 123, "0000000000000000000000000000000000000000000000000000000000000000"
+ { {123}, "0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
@@ -377,21 +402,21 @@
},
/* arbitrary test data */
- { 1002, "2222" },
- { 1003, "333333" },
+ { {1002}, "2222" },
+ { {1003}, "333333" },
{}
};
struct ie txlxv_test_multi[] = {
- { 1042, "42" },
- { 1002, "0101" },
- { 1002, "2222" },
- { 103, "11" },
- { 103, "2222" },
- { 103, "333333" },
- { 1023, "23" },
- { 1042, "666f72747974776f" },
- { 1023, "7477656e74797468726565" },
+ { {1042}, "42" },
+ { {1002}, "0101" },
+ { {1002}, "2222" },
+ { {103}, "11" },
+ { {103}, "2222" },
+ { {103}, "333333" },
+ { {1023}, "23" },
+ { {1042}, "666f72747974776f" },
+ { {1023}, "7477656e74797468726565" },
{}
};
@@ -408,14 +433,14 @@
if (pos[0] & 0x80) {
if (pos + 2 > end)
return -EINVAL;
- tlv->tag = (((int)pos[1]) << 7) + (pos[0] & 0x7f);
+ tlv->ti.tag = (((int)pos[1]) << 7) + (pos[0] & 0x7f);
pos += 2;
} else {
- tlv->tag = pos[0];
+ tlv->ti.tag = pos[0];
pos++;
}
- switch (tlv->tag) {
+ switch (tlv->ti.tag) {
case 1002:
/* fixed-length IE */
tlv->len = 2;
@@ -440,10 +465,12 @@
}
/* Example of defining a variable TL, where size of T and L depend on the actual tag and
length values: store. */
-int txlxv_store_tl(uint8_t *dst_data, size_t dst_data_avail, unsigned int tag, size_t
len, struct osmo_tlv_put *tlv)
+int txlxv_store_tl(uint8_t *dst_data, size_t dst_data_avail, const struct
osmo_tlv_tag_inst *ti, size_t len,
+ struct osmo_tlv_put *tlv)
{
uint8_t *pos = dst_data;
uint8_t *end = dst_data + dst_data_avail;
+ unsigned int tag = ti->tag;
if (tag < 0x80) {
if (pos + 1 > end)
return -ENOSPC;
@@ -491,7 +518,95 @@
void test_txlxv()
{
- test_tlv("txlxv_tests", txlxv_tests, ARRAY_SIZE(txlxv_tests),
&txlxv_cfg);
+ test_tlv(__func__, txlxv_tests, ARRAY_SIZE(txlxv_tests), &txlxv_cfg);
+}
+
+/* Example of defining a TLI, with an instance indicator */
+static int tliv_load_tl(struct osmo_tlv_load *tlv, const uint8_t *src_data, size_t
src_data_len)
+{
+ /* already validated in next_tl_valid(): src_data_len >= cfg->tl_min_size == 2.
*/
+ tlv->ti.tag = src_data[0];
+ tlv->len = src_data[1];
+
+ switch (tlv->ti.tag) {
+ /* All tags that are TLIV go here */
+ case 5:
+ case 7:
+ case 9:
+ if (src_data_len < 3)
+ return -ENOSPC;
+ tlv->ti.instance_present = true;
+ tlv->ti.instance = src_data[2];
+ tlv->val = src_data + 3;
+ return 0;
+ default:
+ tlv->val = src_data + 2;
+ return 0;
+ }
+}
+
+static int tliv_store_tl(uint8_t *dst_data, size_t dst_data_avail, const struct
osmo_tlv_tag_inst *ti, size_t len,
+ struct osmo_tlv_put *tlv)
+{
+ if (ti->tag > UINT8_MAX)
+ return -EINVAL;
+ if (len > UINT8_MAX)
+ return -EMSGSIZE;
+ if (dst_data_avail < 2)
+ return -ENOSPC;
+
+ dst_data[0] = ti->tag;
+ dst_data[1] = len;
+
+ switch (ti->tag) {
+ /* All tags that are TLIV go here */
+ case 5:
+ case 7:
+ case 9:
+ if (dst_data_avail < 3)
+ return -ENOSPC;
+ if (!ti->instance_present)
+ return -EINVAL;
+ if (ti->instance > UINT8_MAX)
+ return -EINVAL;
+ dst_data[2] = ti->instance;
+ return 3;
+ default:
+ return 2;
+ }
+}
+
+const struct osmo_tlv_cfg osmo_tliv_cfg = {
+ .tl_min_size = 2,
+ .load_tl = tliv_load_tl,
+ .store_tl = tliv_store_tl,
+};
+
+struct ie tliv_test1[] = {
+ /* TLV */
+ { {1}, "0002" },
+ /* TLIV */
+ { {5, true, 1}, "0017" },
+ /* TLIV */
+ { {5, true, 2}, "0018" },
+ /* TLIV */
+ { {5, true, 3}, "0019" },
+ /* TLV */
+ { {6}, "001a" },
+ /* TLIV */
+ { {7, true, 1}, "001b" },
+ /* TLIV */
+ { {9, true, 1}, "001c" },
+ {}
+};
+
+struct ie *tliv_tests[] = {
+ tliv_test1,
+};
+
+void test_tliv()
+{
+ test_tlv(__func__, tliv_tests, ARRAY_SIZE(tliv_tests), &osmo_tliv_cfg);
}
int main()
@@ -502,6 +617,7 @@
test_t8l8v();
test_t16l16v();
test_txlxv();
+ test_tliv();
talloc_free(ctx);
return 0;
diff --git a/tests/libosmo-tlv/tlv_test.ok b/tests/libosmo-tlv/tlv_test.ok
index e8d68cc..195136c 100644
--- a/tests/libosmo-tlv/tlv_test.ok
+++ b/tests/libosmo-tlv/tlv_test.ok
@@ -17,7 +17,7 @@
peek T=101
peek T=102
peek T=103
- peek T=-ENOENT
+ peek rc=-ENOENT
- decoding in reverse order:
T=103 L=3 v=333333
T=102 L=2 v=2222
@@ -31,7 +31,7 @@
T=123 L=255
v=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
T=102 L=2 v=2222
- enforcing order: without restart, a past tag is not parsed again:
- osmo_tlv_load_next_by_tag(0) rc=-ENOENT
+ osmo_tlv_load_next_by_tag_inst(0) rc=-ENOENT
=== end: test_t8l8v[0]
=== start: test_t8l8v[1]
@@ -56,7 +56,7 @@
peek T=23
peek T=42
peek T=23
- peek T=-ENOENT
+ peek rc=-ENOENT
- decoding in reverse order:
(mismatch: T=23 L=1 v=23, checking for another occurrence of T=23)
T=23 L=11 v=7477656e74797468726565
@@ -80,7 +80,7 @@
T=3 L=3 v=333333
T=42 L=8 v=666f72747974776f
- enforcing order: without restart, a past tag is not parsed again:
- osmo_tlv_load_next_by_tag(42) rc=-ENOENT
+ osmo_tlv_load_next_by_tag_inst(42) rc=-ENOENT
=== end: test_t8l8v[1]
=== start: test_t16l16v[0]
@@ -101,7 +101,7 @@
peek T=1001
peek T=1002
peek T=1003
- peek T=-ENOENT
+ peek rc=-ENOENT
- decoding in reverse order:
T=1003 L=3 v=333333
T=1002 L=2 v=2222
@@ -115,7 +115,7 @@
T=123 L=256
v=00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
T=1002 L=2 v=2222
- enforcing order: without restart, a past tag is not parsed again:
- osmo_tlv_load_next_by_tag(0) rc=-ENOENT
+ osmo_tlv_load_next_by_tag_inst(0) rc=-ENOENT
=== end: test_t16l16v[0]
=== start: test_t16l16v[1]
@@ -140,7 +140,7 @@
peek T=1023
peek T=1042
peek T=1023
- peek T=-ENOENT
+ peek rc=-ENOENT
- decoding in reverse order:
(mismatch: T=1023 L=1 v=23, checking for another occurrence of T=1023)
T=1023 L=11 v=7477656e74797468726565
@@ -164,10 +164,10 @@
T=103 L=3 v=333333
T=1042 L=8 v=666f72747974776f
- enforcing order: without restart, a past tag is not parsed again:
- osmo_tlv_load_next_by_tag(1042) rc=-ENOENT
+ osmo_tlv_load_next_by_tag_inst(1042) rc=-ENOENT
=== end: test_t16l16v[1]
-=== start: txlxv_tests[0]
+=== start: test_txlxv[0]
- encoded: 00 02 23 42 7f 02 23 42 80 01 02 23 42 ff ff 02 23 42 01 00 7b 01 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 ea 07 22 22 eb 07 03 33 33 33 .
- decoding:
T=0 L=2 v=2342
@@ -187,7 +187,7 @@
peek T=123
peek T=1002
peek T=1003
- peek T=-ENOENT
+ peek rc=-ENOENT
- decoding in reverse order:
T=1003 L=3 v=333333
T=1002 L=2 v=2222
@@ -203,10 +203,10 @@
T=123 L=256
v=00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
T=1003 L=3 v=333333
- enforcing order: without restart, a past tag is not parsed again:
- osmo_tlv_load_next_by_tag(0) rc=-ENOENT
-=== end: txlxv_tests[0]
+ osmo_tlv_load_next_by_tag_inst(0) rc=-ENOENT
+=== end: test_txlxv[0]
-=== start: txlxv_tests[1]
+=== start: test_txlxv[1]
- encoded: 92 08 01 42 ea 07 01 01 ea 07 22 22 67 01 11 67 02 22 22 67 03 33 33 33 ff 07
01 23 92 08 08 66 6f 72 74 79 74 77 6f ff 07 0b 74 77 65 6e 74 79 74 68 72 65 65 .
- decoding:
T=1042 L=1 v=42
@@ -228,7 +228,7 @@
peek T=1023
peek T=1042
peek T=1023
- peek T=-ENOENT
+ peek rc=-ENOENT
- decoding in reverse order:
(mismatch: T=1023 L=1 v=23, checking for another occurrence of T=1023)
T=1023 L=11 v=7477656e74797468726565
@@ -252,5 +252,40 @@
T=103 L=3 v=333333
T=1042 L=8 v=666f72747974776f
- enforcing order: without restart, a past tag is not parsed again:
- osmo_tlv_load_next_by_tag(1042) rc=-ENOENT
-=== end: txlxv_tests[1]
+ osmo_tlv_load_next_by_tag_inst(1042) rc=-ENOENT
+=== end: test_txlxv[1]
+
+=== start: test_tliv[0]
+- encoded: 01 02 00 02 05 02 01 00 17 05 02 02 00 18 05 02 03 00 19 06 02 00 1a 07 02 01
00 1b 09 02 01 00 1c .
+- decoding:
+ T=1 L=2 v=0002
+ T=5[1] L=2 v=0017
+ T=5[2] L=2 v=0018
+ T=5[3] L=2 v=0019
+ T=6 L=2 v=001a
+ T=7[1] L=2 v=001b
+ T=9[1] L=2 v=001c
+- peeking:
+ peek T=1
+ peek T=5[1]
+ peek T=5[2]
+ peek T=5[3]
+ peek T=6
+ peek T=7[1]
+ peek T=9[1]
+ peek rc=-ENOENT
+- decoding in reverse order:
+ T=9[1] L=2 v=001c
+ T=7[1] L=2 v=001b
+ T=6 L=2 v=001a
+ T=5[3] L=2 v=0019
+ T=5[2] L=2 v=0018
+ T=5[1] L=2 v=0017
+ T=1 L=2 v=0002
+- decoding every second tag:
+ T=5[1] L=2 v=0017
+ T=5[3] L=2 v=0019
+ T=7[1] L=2 v=001b
+- enforcing order: without restart, a past tag is not parsed again:
+ osmo_tlv_load_next_by_tag_inst(1) rc=-ENOENT
+=== end: test_tliv[0]
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 2df6e19..cfb1c2d 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -18,3 +18,9 @@
cat $abs_srcdir/libosmo-tlv/test_tlv_gen/tlv_gen_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/libosmo-tlv/test_tlv_gen/tlv_gen_test], [], [expout],
[ignore])
AT_CLEANUP
+
+AT_SETUP([tliv])
+AT_KEYWORDS([tliv])
+cat $abs_srcdir/libosmo-tlv/test_tliv/tliv_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/libosmo-tlv/test_tliv/tliv_test], [], [expout],
[ignore])
+AT_CLEANUP
--
To view, visit
https://gerrit.osmocom.org/c/osmo-upf/+/27529
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-upf
Gerrit-Branch: master
Gerrit-Change-Id: I0a076e54dfba6038cc779cb7c8f3967d212226aa
Gerrit-Change-Number: 27529
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-MessageType: newchange