aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorNeels Hofmeyr <nhofmeyr@sysmocom.de>2022-03-14 16:38:15 +0100
committerNeels Hofmeyr <neels@hofmeyr.de>2022-06-16 13:04:33 +0200
commit8b58faa4c2e1b52802293f4dce9fcc8dc3843b47 (patch)
tree45ac008dd575470212b72ac5d52df2cbc04e5d35 /tests
parente011b04c6b2e31bdc46320e5d8a4f48715681f15 (diff)
libosmo-gtlv: 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-gtlv/gtlv_test.c. A usage example for a generated TLIV protocol is found in tests/libosmo-gtlv/test_tliv/. Related: SYS#5599 Change-Id: I0a076e54dfba6038cc779cb7c8f3967d212226aa
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