aboutsummaryrefslogtreecommitdiffstats
path: root/src
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 /src
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 'src')
-rw-r--r--src/libosmo-gtlv/gtlv.c94
-rw-r--r--src/libosmo-gtlv/gtlv_dec_enc.c69
-rw-r--r--src/libosmo-gtlv/gtlv_gen.c13
3 files changed, 127 insertions, 49 deletions
diff --git a/src/libosmo-gtlv/gtlv.c b/src/libosmo-gtlv/gtlv.c
index 997a67a..9bdbe75 100644
--- a/src/libosmo-gtlv/gtlv.c
+++ b/src/libosmo-gtlv/gtlv.c
@@ -27,6 +27,45 @@
#include <osmocom/core/msgb.h>
#include <osmocom/gtlv/gtlv.h>
+int osmo_gtlv_tag_inst_cmp(const struct osmo_gtlv_tag_inst *a, const struct osmo_gtlv_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_gtlv_tag_inst_to_str_buf(char *buf, size_t buflen, const struct osmo_gtlv_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_gtlv_tag_inst_to_str_c(void *ctx, const struct osmo_gtlv_tag_inst *ti,
+ const struct value_string *tag_names)
+{
+ OSMO_NAME_C_IMPL(ctx, 64, "ERROR", osmo_gtlv_tag_inst_to_str_buf, ti, tag_names)
+}
+
static int next_tl_valid(const struct osmo_gtlv_load *gtlv, const uint8_t **ie_start_p, size_t *buflen_left_p)
{
const uint8_t *ie_start;
@@ -102,6 +141,7 @@ int osmo_gtlv_load_next(struct osmo_gtlv_load *gtlv)
/* Locate next IE */
OSMO_ASSERT(gtlv->cfg->load_tl);
+ gtlv->ti = (struct osmo_gtlv_tag_inst){};
rc = gtlv->cfg->load_tl(gtlv, ie_start, buflen_left);
if (rc)
return rc;
@@ -117,16 +157,19 @@ int osmo_gtlv_load_next(struct osmo_gtlv_load *gtlv)
/* Return the tag of the IE that osmo_gtlv_next() would yield, do not change the gtlv state.
*
* \param[in] gtlv 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_GTLV_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_gtlv_load_peek_tag(const struct osmo_gtlv_load *gtlv)
+int osmo_gtlv_load_peek_tag(const struct osmo_gtlv_load *gtlv, struct osmo_gtlv_tag_inst *ti)
{
const uint8_t *ie_start;
size_t buflen_left;
int rc;
/* Guard against modification by load_tl(). */
struct osmo_gtlv_load mtlv = *gtlv;
+ mtlv.ti = (struct osmo_gtlv_tag_inst){};
rc = next_tl_valid(&mtlv, &ie_start, &buflen_left);
if (rc)
@@ -140,16 +183,26 @@ int osmo_gtlv_load_peek_tag(const struct osmo_gtlv_load *gtlv)
rc = gtlv->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_gtlv_load_next(), but skip any IEs until the given tag is reached. Change the gtlv state only when success
* is returned.
* \param[out] gtlv 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_GTLV_NO_INSTANCE.
* \return 0 when the tag is found. Return -ENOENT when no such tag follows and keep the gtlv unchanged. */
int osmo_gtlv_load_next_by_tag(struct osmo_gtlv_load *gtlv, unsigned int tag)
{
+ struct osmo_gtlv_tag_inst ti = { .tag = tag };
+ return osmo_gtlv_load_next_by_tag_inst(gtlv, &ti);
+}
+
+int osmo_gtlv_load_next_by_tag_inst(struct osmo_gtlv_load *gtlv, const struct osmo_gtlv_tag_inst *ti)
+{
struct osmo_gtlv_load work = *gtlv;
for (;;) {
int rc = osmo_gtlv_load_next(&work);
@@ -157,7 +210,7 @@ int osmo_gtlv_load_next_by_tag(struct osmo_gtlv_load *gtlv, unsigned int tag)
return rc;
if (!work.val)
return -ENOENT;
- if (work.tag == tag) {
+ if (!osmo_gtlv_tag_inst_cmp(&work.ti, ti)) {
*gtlv = work;
return 0;
}
@@ -190,16 +243,25 @@ int osmo_gtlv_load_next_by_tag(struct osmo_gtlv_load *gtlv, unsigned int tag)
*/
int osmo_gtlv_put_tl(struct osmo_gtlv_put *gtlv, unsigned int tag, size_t len)
{
+ struct osmo_gtlv_tag_inst ti = { .tag = tag };
+ return osmo_gtlv_put_tli(gtlv, &ti, len);
+}
+
+/* Put tag header, instance value and length at the end of the msgb, according to gtlv->cfg->store_tl().
+ * This is the same as osmo_gtlv_put_tl(), only osmo_gtlv_put_tl() passes instance = 0.
+ */
+int osmo_gtlv_put_tli(struct osmo_gtlv_put *gtlv, const struct osmo_gtlv_tag_inst *ti, size_t len)
+{
int rc;
uint8_t *last_tl;
OSMO_ASSERT(gtlv->cfg->store_tl);
last_tl = gtlv->dst->tail;
- rc = gtlv->cfg->store_tl(gtlv->dst->tail, msgb_tailroom(gtlv->dst), tag, len, gtlv);
+ rc = gtlv->cfg->store_tl(gtlv->dst->tail, msgb_tailroom(gtlv->dst), ti, len, gtlv);
if (rc < 0)
return rc;
if (rc > 0)
msgb_put(gtlv->dst, rc);
- gtlv->last_tag = tag;
+ gtlv->last_ti = *ti;
gtlv->last_tl = last_tl;
gtlv->last_val = gtlv->dst->tail;
return 0;
@@ -212,7 +274,7 @@ int osmo_gtlv_put_tl(struct osmo_gtlv_put *gtlv, unsigned int tag, size_t len)
int osmo_gtlv_put_update_tl(struct osmo_gtlv_put *gtlv)
{
size_t len = gtlv->dst->tail - gtlv->last_val;
- int rc = gtlv->cfg->store_tl(gtlv->last_tl, gtlv->last_val - gtlv->last_tl, gtlv->last_tag, len, gtlv);
+ int rc = gtlv->cfg->store_tl(gtlv->last_tl, gtlv->last_val - gtlv->last_tl, &gtlv->last_ti, len, gtlv);
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 @@ int osmo_gtlv_put_update_tl(struct osmo_gtlv_put *gtlv)
static int t8l8v_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->tag = src_data[0];
+ gtlv->ti.tag = src_data[0];
gtlv->len = src_data[1];
gtlv->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_gtlv_tag_inst *ti, size_t len,
struct osmo_gtlv_put *gtlv)
{
- 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 @@ const struct osmo_gtlv_cfg osmo_t8l8v_cfg = {
static int t16l16v_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 == 4. */
- gtlv->tag = osmo_load16be(src_data);
+ gtlv->ti.tag = osmo_load16be(src_data);
gtlv->len = osmo_load16be(src_data + 2);
gtlv->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_gtlv_tag_inst *ti, size_t len,
struct osmo_gtlv_put *gtlv)
{
- 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-gtlv/gtlv_dec_enc.c b/src/libosmo-gtlv/gtlv_dec_enc.c
index 28ee493..2e5509a 100644
--- a/src/libosmo-gtlv/gtlv_dec_enc.c
+++ b/src/libosmo-gtlv/gtlv_dec_enc.c
@@ -31,12 +31,21 @@
/* Reverse offsetof(): return the address of the struct member for a given osmo_gtlv_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 @@ static int osmo_gtlvs_decode_unordered(void *decoded_struct, unsigned int obj_of
#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, gtlv->tag, \
+ RETURN_ERROR(-ENOTSUP, gtlv->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 @@ static int osmo_gtlvs_decode_unordered(void *decoded_struct, unsigned int obj_of
rc = osmo_gtlv_load_next(gtlv);
if (rc)
- RETURN_ERROR(rc, gtlv->tag, "Decoding IEs failed on or after this tag");
+ RETURN_ERROR(rc, gtlv->ti, "Decoding IEs failed on or after this tag");
if (!gtlv->val) {
/* End of the TLV structure */
break;
@@ -103,7 +112,9 @@ static int osmo_gtlvs_decode_unordered(void *decoded_struct, unsigned int obj_of
do {
/* Find the IE coding for this tag */
- for (iec = ie_coding; !osmo_gtlv_coding_end(iec) && iec->tag != gtlv->tag; iec++);
+ for (iec = ie_coding;
+ !osmo_gtlv_coding_end(iec) && osmo_gtlv_tag_inst_cmp(&iec->ti, &gtlv->ti);
+ iec++);
/* No such IE coding found. */
if (osmo_gtlv_coding_end(iec))
break;
@@ -128,7 +139,7 @@ static int osmo_gtlvs_decode_unordered(void *decoded_struct, unsigned int obj_of
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, gtlv->tag, "Only %u instances of this IE are supported per message",
+ RETURN_ERROR(-ENOTSUP, gtlv->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 @@ static int osmo_gtlvs_decode_unordered(void *decoded_struct, unsigned int obj_of
rc = osmo_gtlvs_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, gtlv->tag, "Error while decoding TLV structure nested inside this IE");
+ RETURN_ERROR(rc, gtlv->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, gtlv->tag, "IE definition lacks a dec_func()");
+ RETURN_ERROR(-EIO, gtlv->ti, "IE definition lacks a dec_func()");
rc = iec->dec_func(decoded_struct, MEMB(obj, memb_ofs), gtlv);
if (rc)
- RETURN_ERROR(rc, gtlv->tag, "Error while decoding this IE");
+ RETURN_ERROR(rc, gtlv->ti, "Error while decoding this IE");
}
if (multi_count_p) {
@@ -197,14 +208,14 @@ static int osmo_gtlvs_decode_unordered(void *decoded_struct, unsigned int obj_of
multi_count_p = iec->has_count ? MEMB(obj, iec->count_ofs) : NULL;
if (multi_count_p) {
if (*multi_count_p < iec->count_mandatory)
- 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_mandatory, *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 @@ static int osmo_gtlvs_decode_ordered(void *decoded_struct, unsigned int obj_ofs,
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_gtlv_tag_inst peek_ti;
- rc = osmo_gtlv_load_next_by_tag(gtlv, ie_coding->tag);
+ rc = osmo_gtlv_load_next_by_tag_inst(gtlv, &ie_coding->ti);
switch (rc) {
case 0:
break;
case -ENOENT:
if (!presence_flag && (!multi_count || *multi_count < ie_coding->count_mandatory))
- 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 @@ static int osmo_gtlvs_decode_ordered(void *decoded_struct, unsigned int obj_ofs,
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 @@ static int osmo_gtlvs_decode_ordered(void *decoded_struct, unsigned int obj_ofs,
rc = osmo_gtlvs_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), gtlv);
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 @@ static int osmo_gtlvs_decode_ordered(void *decoded_struct, unsigned int obj_ofs,
(*multi_count)++;
/* Does another one of these IEs follow? */
- if (osmo_gtlv_load_peek_tag(gtlv) != gtlv->tag) {
+ if (osmo_gtlv_load_peek_tag(gtlv, &peek_ti)
+ || osmo_gtlv_tag_inst_cmp(&peek_ti, &gtlv->ti)) {
/* Next tag is a different IE, end the repetition. */
break;
}
@@ -387,7 +400,7 @@ int osmo_gtlvs_encode(struct osmo_gtlv_put *gtlv, const void *decoded_struct, un
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 @@ int osmo_gtlvs_encode(struct osmo_gtlv_put *gtlv, const void *decoded_struct, un
for (i = 0; i < n; i++) {
unsigned int memb_ofs;
- osmo_gtlv_put_tl(gtlv, ie_coding->tag, 0);
+ osmo_gtlv_put_tli(gtlv, &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 @@ int osmo_gtlvs_encode(struct osmo_gtlv_put *gtlv, const void *decoded_struct, un
rc = osmo_gtlvs_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(gtlv, 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_gtlv_put_update_tl(gtlv);
@@ -467,7 +480,7 @@ int osmo_gtlvs_encode_to_str_buf(char *buf, size_t buflen, const void *decoded_s
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-gtlv/gtlv_gen.c b/src/libosmo-gtlv/gtlv_gen.c
index 3f499f7..fd3fbd9 100644
--- a/src/libosmo-gtlv/gtlv_gen.c
+++ b/src/libosmo-gtlv/gtlv_gen.c
@@ -249,7 +249,7 @@ static void write_extern_dec_enc(const struct osmo_gtlv_gen_ie_o *ies)
}
/* For a nested IE, write the struct osmo_gtlv_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,
@@ -263,10 +263,13 @@ static void write_ies_array(const char *indent, const struct osmo_gtlv_gen_ie_o
for (ie_o = ies; ie_o->ie; ie_o++) {
const struct osmo_gtlv_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);
@@ -291,7 +294,7 @@ static void write_ies_array(const char *indent, const struct osmo_gtlv_gen_ie_o
/* For a nested IE, write the struct osmo_gtlv_coding array of the inner IEs.
* static const struct osmo_gtlv_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,