aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/libosmo-gtlv/Makefile.am2
-rw-r--r--tests/libosmo-gtlv/gtlv_dec_enc_test.c18
-rw-r--r--tests/libosmo-gtlv/gtlv_test.c300
-rw-r--r--tests/libosmo-gtlv/gtlv_test.ok67
-rw-r--r--tests/libosmo-gtlv/test_tliv/Makefile.am60
-rw-r--r--tests/libosmo-gtlv/test_tliv/gen__myproto_ies_auto.c71
-rw-r--r--tests/libosmo-gtlv/test_tliv/myproto_ies_custom.c68
-rw-r--r--tests/libosmo-gtlv/test_tliv/myproto_ies_custom.h50
-rw-r--r--tests/libosmo-gtlv/test_tliv/tliv_test.c217
-rw-r--r--tests/libosmo-gtlv/test_tliv/tliv_test.ok32
-rw-r--r--tests/testsuite.at6
11 files changed, 774 insertions, 117 deletions
diff --git a/tests/libosmo-gtlv/Makefile.am b/tests/libosmo-gtlv/Makefile.am
index 392a73e..45d6ec2 100644
--- a/tests/libosmo-gtlv/Makefile.am
+++ b/tests/libosmo-gtlv/Makefile.am
@@ -1,5 +1,6 @@
SUBDIRS = \
test_gtlv_gen \
+ test_tliv \
$(NULL)
AM_CPPFLAGS = \
@@ -45,3 +46,4 @@ update_exp:
$(builddir)/gtlv_test >$(srcdir)/gtlv_test.ok
$(builddir)/gtlv_dec_enc_test >$(srcdir)/gtlv_dec_enc_test.ok
$(MAKE) -C test_gtlv_gen update_exp
+ $(MAKE) -C test_tliv update_exp
diff --git a/tests/libosmo-gtlv/gtlv_dec_enc_test.c b/tests/libosmo-gtlv/gtlv_dec_enc_test.c
index 89b4011..e02a2e5 100644
--- a/tests/libosmo-gtlv/gtlv_dec_enc_test.c
+++ b/tests/libosmo-gtlv/gtlv_dec_enc_test.c
@@ -205,21 +205,21 @@ int enc_to_str_repeat_struct(char *buf, size_t buflen, const void *encode_from)
struct osmo_gtlv_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,
@@ -230,21 +230,21 @@ struct osmo_gtlv_coding nested_inner_msg_ies[] = {
struct osmo_gtlv_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,
@@ -253,7 +253,7 @@ struct osmo_gtlv_coding msg_ie_coding[] = {
.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,
@@ -264,7 +264,7 @@ struct osmo_gtlv_coding msg_ie_coding[] = {
.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,
@@ -275,7 +275,7 @@ struct osmo_gtlv_coding msg_ie_coding[] = {
.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-gtlv/gtlv_test.c b/tests/libosmo-gtlv/gtlv_test.c
index c009850..8023699 100644
--- a/tests/libosmo-gtlv/gtlv_test.c
+++ b/tests/libosmo-gtlv/gtlv_test.c
@@ -33,7 +33,7 @@
void *ctx;
struct ie {
- int tag;
+ struct osmo_gtlv_tag_inst ti;
const char *val;
};
@@ -48,7 +48,7 @@ struct msgb *test_tlv_enc(const struct osmo_gtlv_cfg *cfg, const struct ie *ies)
for (ie = ies; ie->val; ie++) {
/* put header without knowing length yet */
- OSMO_ASSERT(osmo_gtlv_put_tl(&gtlv, ie->tag, 0) == 0);
+ OSMO_ASSERT(osmo_gtlv_put_tli(&gtlv, &ie->ti, 0) == 0);
/* put value data, as much as desired */
msgb_put(gtlv.dst, osmo_hexparse(ie->val, gtlv.dst->tail, msgb_tailroom(gtlv.dst)));
/* update header len from amount of written data */
@@ -80,9 +80,10 @@ void test_tlv_dec(const struct osmo_gtlv_cfg *cfg, const struct ie *ies, struct
/* end of TLV structure? */
if (!gtlv.val)
break;
- printf(" T=%d L=%zu v=%s\n", gtlv.tag, gtlv.len, osmo_hexdump_nospc(gtlv.val, gtlv.len));
- if (gtlv.tag != ie->tag) {
- printf(" ERROR loading TLV structure: expected tag %d, got tag %d\n", ie->tag, gtlv.tag);
+ printf(" T=%s L=%zu", osmo_gtlv_tag_inst_to_str_c(ctx, &gtlv.ti, NULL), gtlv.len);
+ printf(" v=%s\n", osmo_hexdump_nospc(gtlv.val, gtlv.len));
+ if (gtlv.ti.tag != ie->ti.tag) {
+ printf(" ERROR loading TLV structure: expected tag %u, got tag %u\n", ie->ti.tag, gtlv.ti.tag);
exit(1);
}
if (strcmp(ie->val, osmo_hexdump_nospc(gtlv.val, gtlv.len))) {
@@ -107,22 +108,28 @@ void test_tlv_peek(const struct osmo_gtlv_cfg *cfg, const struct ie *ies, struct
ie = ies;
while (1) {
int rc;
- int next_tag = osmo_gtlv_load_peek_tag(&gtlv);
- if (next_tag == -ENOENT)
- printf(" peek T=-ENOENT\n");
- else
- printf(" peek T=%d\n", next_tag);
-
- if (ie->val && next_tag != ie->tag) {
- printf(" ERROR peeking tag: expected tag %d, got tag %d\n", ie->tag, next_tag);
+ struct osmo_gtlv_tag_inst next_tag;
+ rc = osmo_gtlv_load_peek_tag(&gtlv, &next_tag);
+ if (rc == -ENOENT) {
+ printf(" peek rc=-ENOENT\n");
+ } else {
+ printf(" peek T=%s", osmo_gtlv_tag_inst_to_str_c(ctx, &next_tag, NULL));
+ printf("\n");
+ }
+
+ if (ie->val && osmo_gtlv_tag_inst_cmp(&next_tag, &ie->ti)) {
+ printf(" ERROR peeking tag: expected tag %s, got tag %s\n",
+ osmo_gtlv_tag_inst_to_str_c(ctx, &ie->ti, NULL),
+ osmo_gtlv_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_gtlv_tag_inst_to_str_c(ctx, &next_tag, NULL));
exit(1);
}
- if (next_tag == -ENOENT)
+ if (rc == -ENOENT)
break;
/* go to the next TLV */
@@ -156,25 +163,32 @@ void test_tlv_dec_by_tag(const struct osmo_gtlv_cfg *cfg, const struct ie *ies,
for (ie = last_ie; ie >= ies; ie--) {
/* each time, look from the beginning */
osmo_gtlv_load_start(&gtlv);
- rc = osmo_gtlv_load_next_by_tag(&gtlv, ie->tag);
+ rc = osmo_gtlv_load_next_by_tag_inst(&gtlv, &ie->ti);
if (rc) {
- printf(" ERROR loading TLV structure: osmo_gtlv_load_next_by_tag(%d) rc = %d\n", ie->tag, rc);
+ printf(" ERROR loading TLV structure: osmo_gtlv_load_next_by_tag_inst(%s) rc = %d\n",
+ osmo_gtlv_tag_inst_to_str_c(ctx, &ie->ti, NULL), rc);
exit(1);
}
if (!gtlv.val) {
- printf(" ERROR loading TLV structure: osmo_gtlv_load_next_by_tag(%d) returned NULL val\n",
- ie->tag);
+ printf(" ERROR loading TLV structure: osmo_gtlv_load_next_by_tag_inst(%s) returned NULL val\n",
+ osmo_gtlv_tag_inst_to_str_c(ctx, &ie->ti, NULL));
exit(1);
}
- if (gtlv.tag != ie->tag) {
- printf(" ERROR loading TLV structure: expected tag %d, got tag %d\n", ie->tag, gtlv.tag);
+ if (osmo_gtlv_tag_inst_cmp(&gtlv.ti, &ie->ti)) {
+ printf(" ERROR loading TLV structure: expected tag %s, got tag %s\n",
+ osmo_gtlv_tag_inst_to_str_c(ctx, &ie->ti, NULL),
+ osmo_gtlv_tag_inst_to_str_c(ctx, &gtlv.ti, NULL));
exit(1);
}
if (strcmp(ie->val, osmo_hexdump_nospc(gtlv.val, gtlv.len))) {
while (1) {
- printf(" (mismatch: T=%d L=%zu v=%s, checking for another occurrence of T=%d)\n",
- gtlv.tag, gtlv.len, osmo_hexdump_nospc(gtlv.val, gtlv.len), gtlv.tag);
- rc = osmo_gtlv_load_next_by_tag(&gtlv, ie->tag);
+ printf(" (mismatch: T=%s L=%zu v=%s, checking for another occurrence of T=%s)\n",
+ osmo_gtlv_tag_inst_to_str_c(ctx, &gtlv.ti, NULL),
+ gtlv.len,
+ osmo_hexdump_nospc(gtlv.val, gtlv.len),
+ osmo_gtlv_tag_inst_to_str_c(ctx, &gtlv.ti, NULL));
+
+ rc = osmo_gtlv_load_next_by_tag_inst(&gtlv, &ie->ti);
if (rc || !gtlv.val) {
printf(" ERROR val not found\n");
exit(1);
@@ -184,7 +198,9 @@ void test_tlv_dec_by_tag(const struct osmo_gtlv_cfg *cfg, const struct ie *ies,
}
}
}
- printf(" T=%d L=%zu v=%s\n", gtlv.tag, gtlv.len, osmo_hexdump_nospc(gtlv.val, gtlv.len));
+ printf(" T=%s L=%zu v=%s\n",
+ osmo_gtlv_tag_inst_to_str_c(ctx, &gtlv.ti, NULL),
+ gtlv.len, osmo_hexdump_nospc(gtlv.val, gtlv.len));
}
printf("- decoding every second tag:\n");
@@ -196,25 +212,32 @@ void test_tlv_dec_by_tag(const struct osmo_gtlv_cfg *cfg, const struct ie *ies,
if (!ie->val)
break;
- rc = osmo_gtlv_load_next_by_tag(&gtlv, ie->tag);
+ rc = osmo_gtlv_load_next_by_tag_inst(&gtlv, &ie->ti);
if (rc) {
- printf(" ERROR loading TLV structure: osmo_gtlv_load_next_by_tag(%d) rc = %d\n", ie->tag, rc);
+ printf(" ERROR loading TLV structure: osmo_gtlv_load_next_by_tag_inst(%s) rc = %d\n",
+ osmo_gtlv_tag_inst_to_str_c(ctx, &ie->ti, NULL), rc);
exit(1);
}
if (!gtlv.val) {
- printf(" ERROR loading TLV structure: osmo_gtlv_load_next_by_tag(%d) returned NULL val\n",
- ie->tag);
+ printf(" ERROR loading TLV structure: osmo_gtlv_load_next_by_tag_inst(%s) returned NULL val\n",
+ osmo_gtlv_tag_inst_to_str_c(ctx, &ie->ti, NULL));
exit(1);
}
- if (gtlv.tag != ie->tag) {
- printf(" ERROR loading TLV structure: expected tag %d, got tag %d\n", ie->tag, gtlv.tag);
+ if (osmo_gtlv_tag_inst_cmp(&gtlv.ti, &ie->ti)) {
+ printf(" ERROR loading TLV structure: expected tag %s, got tag %s\n",
+ osmo_gtlv_tag_inst_to_str_c(ctx, &ie->ti, NULL),
+ osmo_gtlv_tag_inst_to_str_c(ctx, &gtlv.ti, NULL));
exit(1);
}
if (strcmp(ie->val, osmo_hexdump_nospc(gtlv.val, gtlv.len))) {
while (1) {
- printf(" (mismatch: T=%d L=%zu v=%s, checking for another occurrence of T=%d)\n",
- gtlv.tag, gtlv.len, osmo_hexdump_nospc(gtlv.val, gtlv.len), gtlv.tag);
- rc = osmo_gtlv_load_next_by_tag(&gtlv, ie->tag);
+ printf(" (mismatch: T=%s L=%zu v=%s, checking for another occurrence of T=%s)\n",
+ osmo_gtlv_tag_inst_to_str_c(ctx, &gtlv.ti, NULL),
+ gtlv.len,
+ osmo_hexdump_nospc(gtlv.val, gtlv.len),
+ osmo_gtlv_tag_inst_to_str_c(ctx, &gtlv.ti, NULL));
+
+ rc = osmo_gtlv_load_next_by_tag_inst(&gtlv, &ie->ti);
if (rc || !gtlv.val) {
printf(" ERROR val not found\n");
exit(1);
@@ -224,14 +247,16 @@ void test_tlv_dec_by_tag(const struct osmo_gtlv_cfg *cfg, const struct ie *ies,
}
}
}
- printf(" T=%d L=%zu v=%s\n", gtlv.tag, gtlv.len, osmo_hexdump_nospc(gtlv.val, gtlv.len));
+ printf(" T=%s L=%zu v=%s\n",
+ osmo_gtlv_tag_inst_to_str_c(ctx, &gtlv.ti, NULL),
+ gtlv.len, osmo_hexdump_nospc(gtlv.val, gtlv.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_gtlv_load_next_by_tag(&gtlv, ie->tag);
- printf(" osmo_gtlv_load_next_by_tag(%d) rc=", ie->tag);
+ rc = osmo_gtlv_load_next_by_tag_inst(&gtlv, &ie->ti);
+ printf(" osmo_gtlv_load_next_by_tag_inst(%s) rc=", osmo_gtlv_tag_inst_to_str_c(ctx, &ie->ti, NULL));
if (rc == -ENOENT) {
printf("-ENOENT\n");
} else {
@@ -262,14 +287,14 @@ void test_tlv(const char *label, struct ie *tests[], size_t tests_len, const str
struct ie t8l8v_test1[] = {
/* smallest T */
- { 0, "2342" },
+ { {}, "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"
@@ -280,22 +305,22 @@ struct ie t8l8v_test1[] = {
},
/* 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" },
{}
};
@@ -311,14 +336,14 @@ void test_t8l8v()
struct ie t16l16v_test1[] = {
/* smallest T */
- { 0, "2342" },
+ { {}, "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"
@@ -329,22 +354,22 @@ struct ie t16l16v_test1[] = {
},
/* 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" },
{}
};
@@ -360,18 +385,18 @@ void test_t16l16v()
struct ie txlxv_test1[] = {
/* smallest T */
- { 0, "2342" },
+ { {}, "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"
@@ -382,21 +407,21 @@ struct ie txlxv_test1[] = {
},
/* 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" },
{}
};
@@ -413,14 +438,14 @@ int txlxv_load_tl(struct osmo_gtlv_load *gtlv, const uint8_t *src_data, size_t s
if (pos[0] & 0x80) {
if (pos + 2 > end)
return -EINVAL;
- gtlv->tag = (((int)pos[1]) << 7) + (pos[0] & 0x7f);
+ gtlv->ti.tag = (((int)pos[1]) << 7) + (pos[0] & 0x7f);
pos += 2;
} else {
- gtlv->tag = pos[0];
+ gtlv->ti.tag = pos[0];
pos++;
}
- switch (gtlv->tag) {
+ switch (gtlv->ti.tag) {
case 1002:
/* fixed-length IE */
gtlv->len = 2;
@@ -445,10 +470,12 @@ int txlxv_load_tl(struct osmo_gtlv_load *gtlv, const uint8_t *src_data, size_t s
}
/* 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_gtlv_put *gtlv)
+int txlxv_store_tl(uint8_t *dst_data, size_t dst_data_avail, const struct osmo_gtlv_tag_inst *ti, size_t len,
+ struct osmo_gtlv_put *gtlv)
{
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;
@@ -496,7 +523,95 @@ const struct osmo_gtlv_cfg txlxv_cfg = {
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_gtlv_load *gtlv, const uint8_t *src_data, size_t src_data_len)
+{
+ /* already validated in next_tl_valid(): src_data_len >= cfg->tl_min_size == 2. */
+ gtlv->ti.tag = src_data[0];
+ gtlv->len = src_data[1];
+
+ switch (gtlv->ti.tag) {
+ /* All tags that are TLIV go here */
+ case 5:
+ case 7:
+ case 9:
+ if (src_data_len < 3)
+ return -ENOSPC;
+ gtlv->ti.instance_present = true;
+ gtlv->ti.instance = src_data[2];
+ gtlv->val = src_data + 3;
+ return 0;
+ default:
+ gtlv->val = src_data + 2;
+ return 0;
+ }
+}
+
+static int tliv_store_tl(uint8_t *dst_data, size_t dst_data_avail, const struct osmo_gtlv_tag_inst *ti, size_t len,
+ struct osmo_gtlv_put *gtlv)
+{
+ 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_gtlv_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()
@@ -507,6 +622,7 @@ int main()
test_t8l8v();
test_t16l16v();
test_txlxv();
+ test_tliv();
talloc_free(ctx);
return 0;
diff --git a/tests/libosmo-gtlv/gtlv_test.ok b/tests/libosmo-gtlv/gtlv_test.ok
index 3cebd7e..edc6ff3 100644
--- a/tests/libosmo-gtlv/gtlv_test.ok
+++ b/tests/libosmo-gtlv/gtlv_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_gtlv_load_next_by_tag(0) rc=-ENOENT
+ osmo_gtlv_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_gtlv_load_next_by_tag(42) rc=-ENOENT
+ osmo_gtlv_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_gtlv_load_next_by_tag(0) rc=-ENOENT
+ osmo_gtlv_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_gtlv_load_next_by_tag(1042) rc=-ENOENT
+ osmo_gtlv_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_gtlv_load_next_by_tag(0) rc=-ENOENT
-=== end: txlxv_tests[0]
+ osmo_gtlv_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_gtlv_load_next_by_tag(1042) rc=-ENOENT
-=== end: txlxv_tests[1]
+ osmo_gtlv_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_gtlv_load_next_by_tag_inst(1) rc=-ENOENT
+=== end: test_tliv[0]
diff --git a/tests/libosmo-gtlv/test_tliv/Makefile.am b/tests/libosmo-gtlv/test_tliv/Makefile.am
new file mode 100644
index 0000000..eb95e12
--- /dev/null
+++ b/tests/libosmo-gtlv/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-gtlv/libosmo-gtlv.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-gtlv/libosmo-gtlv.a \
+ $(LIBOSMOCORE_LIBS) \
+ $(NULL)
+
+.PHONY: update_exp
+update_exp:
+ $(builddir)/tliv_test >$(srcdir)/tliv_test.ok
diff --git a/tests/libosmo-gtlv/test_tliv/gen__myproto_ies_auto.c b/tests/libosmo-gtlv/test_tliv/gen__myproto_ies_auto.c
new file mode 100644
index 0000000..21e70d9
--- /dev/null
+++ b/tests/libosmo-gtlv/test_tliv/gen__myproto_ies_auto.c
@@ -0,0 +1,71 @@
+/*
+ * (C) 2021-2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved.
+ *
+ * Author: Neels Janosch Hofmeyr <nhofmeyr@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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/gtlv/gtlv_gen.h>
+
+#define O OSMO_GTLV_GEN_O
+#define M OSMO_GTLV_GEN_M
+#define O_MULTI OSMO_GTLV_GEN_O_MULTI
+#define M_MULTI OSMO_GTLV_GEN_M_MULTI
+#define O_INST OSMO_GTLV_GEN_O_INST
+#define M_INST OSMO_GTLV_GEN_M_INST
+
+#define AUTO osmo_gtlv_gen_ie_auto
+
+static const struct osmo_gtlv_gen_ie bar = {
+ .tag_name = "bar",
+};
+
+static const struct osmo_gtlv_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"),
+ {}
+};
+
+static const struct osmo_gtlv_gen_msg msg_defs[] = {
+ { "moo", ies_in_moo_msg },
+ {}
+};
+
+int main(int argc, const char **argv)
+{
+ struct osmo_gtlv_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_gtlv_gen_main(&cfg, argc, argv);
+}
diff --git a/tests/libosmo-gtlv/test_tliv/myproto_ies_custom.c b/tests/libosmo-gtlv/test_tliv/myproto_ies_custom.c
new file mode 100644
index 0000000..54164ce
--- /dev/null
+++ b/tests/libosmo-gtlv/test_tliv/myproto_ies_custom.c
@@ -0,0 +1,68 @@
+/* Example for defining custom IES for gtlv_gen. */
+/*
+ * (C) 2021-2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved.
+ *
+ * Author: Neels Janosch Hofmeyr <nhofmeyr@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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/gtlv/gtlv.h>
+
+#include <myproto_ies_custom.h>
+
+int myproto_dec_bar(void *decoded_struct, void *decode_to, const struct osmo_gtlv_load *gtlv)
+{
+ struct myproto_ie_bar *bar = decode_to;
+ if (gtlv->len < 2)
+ return -EINVAL;
+ *bar = (struct myproto_ie_bar){
+ .a = gtlv->val[0],
+ .b = (gtlv->val[1] == 1),
+ };
+ return 0;
+}
+
+int myproto_enc_bar(struct osmo_gtlv_put *gtlv, void *decoded_struct, void *encode_from)
+{
+ struct myproto_ie_bar *bar = encode_from;
+ msgb_put_u8(gtlv->dst, bar->a);
+ msgb_put_u8(gtlv->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-gtlv/test_tliv/myproto_ies_custom.h b/tests/libosmo-gtlv/test_tliv/myproto_ies_custom.h
new file mode 100644
index 0000000..64e06ff
--- /dev/null
+++ b/tests/libosmo-gtlv/test_tliv/myproto_ies_custom.h
@@ -0,0 +1,50 @@
+/* Definitions for decoded message IEs, to be used by the auto-generated myproto_ies_auto.c. */
+/*
+ * (C) 2021-2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved.
+ *
+ * Author: Neels Janosch Hofmeyr <nhofmeyr@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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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-gtlv/test_tliv/tliv_test.c b/tests/libosmo-gtlv/test_tliv/tliv_test.c
new file mode 100644
index 0000000..fd4e310
--- /dev/null
+++ b/tests/libosmo-gtlv/test_tliv/tliv_test.c
@@ -0,0 +1,217 @@
+/*
+ * (C) 2021-2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved.
+ *
+ * Author: Neels Janosch Hofmeyr <nhofmeyr@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, 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/gtlv/gtlv.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_gtlv_cfg *cfg)
+{
+ struct osmo_gtlv_put gtlv = {
+ .cfg = cfg,
+ .dst = dst,
+ };
+
+ msgb_put_u8(gtlv.dst, msg->type);
+ return myproto_ies_encode(&gtlv, (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_gtlv_cfg *cfg, bool ordered)
+{
+ struct osmo_gtlv_load gtlv;
+ if (data_len < 1)
+ return -EINVAL;
+ msg->type = data[0];
+ gtlv = (struct osmo_gtlv_load){
+ .cfg = cfg,
+ .src = { data + 1, data_len - 1 },
+ };
+ return myproto_ies_decode(&msg->ies, &gtlv, 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_gtlvs_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_gtlv_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 = {};
+ 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_gtlv_load *gtlv, const uint8_t *src_data, size_t src_data_len)
+{
+ /* already validated in next_tl_valid(): src_data_len >= cfg->tl_min_size == 2. */
+ gtlv->ti.tag = src_data[0];
+ gtlv->len = src_data[1];
+
+ switch (gtlv->ti.tag) {
+ /* All tags that are TLIV go here */
+ case MYPROTO_IEI_BAR:
+ if (src_data_len < 3)
+ return -ENOSPC;
+ gtlv->ti.instance_present = true;
+ gtlv->ti.instance = src_data[2];
+ gtlv->val = src_data + 3;
+ /* In this example, the I is part of the len */
+ gtlv->len--;
+ return 0;
+ default:
+ gtlv->val = src_data + 2;
+ return 0;
+ }
+}
+
+static int tliv_store_tl(uint8_t *dst_data, size_t dst_data_avail, const struct osmo_gtlv_tag_inst *ti, size_t len,
+ struct osmo_gtlv_put *gtlv)
+{
+ 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_gtlv_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-gtlv/test_tliv/tliv_test.ok b/tests/libosmo-gtlv/test_tliv/tliv_test.ok
new file mode 100644
index 0000000..184ffa6
--- /dev/null
+++ b/tests/libosmo-gtlv/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/testsuite.at b/tests/testsuite.at
index 7cc652e..0d17305 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -18,3 +18,9 @@ AT_KEYWORDS([gtlv_gen])
cat $abs_srcdir/libosmo-gtlv/test_gtlv_gen/gtlv_gen_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/libosmo-gtlv/test_gtlv_gen/gtlv_gen_test], [], [expout], [ignore])
AT_CLEANUP
+
+AT_SETUP([tliv])
+AT_KEYWORDS([tliv])
+cat $abs_srcdir/libosmo-gtlv/test_tliv/tliv_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/libosmo-gtlv/test_tliv/tliv_test], [], [expout], [ignore])
+AT_CLEANUP