mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-upf.git
synced 2025-10-23 08:12:03 +00:00
tliv wip
Change-Id: I76c0e3e60eff61354e580cb70ef8645f09a29ec8
This commit is contained in:
@@ -212,6 +212,7 @@ AC_OUTPUT(
|
||||
tests/atlocal
|
||||
tests/libosmo-tlv/Makefile
|
||||
tests/libosmo-tlv/test_tlv_gen/Makefile
|
||||
tests/libosmo-tlv/test_tliv/Makefile
|
||||
doc/Makefile
|
||||
doc/examples/Makefile
|
||||
doc/manuals/Makefile
|
||||
|
@@ -24,11 +24,23 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct msgb;
|
||||
struct osmo_tlv_load;
|
||||
struct osmo_tlv_put;
|
||||
|
||||
struct osmo_tlv_tag_inst {
|
||||
unsigned int tag;
|
||||
bool instance_present;
|
||||
unsigned int instance;
|
||||
};
|
||||
|
||||
int osmo_tlv_tag_inst_cmp(const struct osmo_tlv_tag_inst *a, const struct osmo_tlv_tag_inst *b);
|
||||
char *osmo_tlv_tag_inst_to_str_buf( asdf
|
||||
|
||||
|
||||
/*! TL configuration for osmo_tlv_load*() and osmo_tlv_put*(). Depending on these implementations provided by the caller,
|
||||
* osmo_tlv can load any sizes of tag and length fields (that don't surpass the value range of unsigned int and size_t,
|
||||
* respectively), as well as TV (fixed-length) or TvLV (variable-sized length).
|
||||
@@ -46,8 +58,9 @@ struct osmo_tlv_cfg {
|
||||
size_t tl_min_size;
|
||||
|
||||
/*! Read one TL from the start of src_data.
|
||||
* \param tlv Return the T value read from src_data in tlv->tag.
|
||||
* Return the L value read from src_data in tlv->len.
|
||||
* \param tlv Return the T (tag) value read from src_data in tlv->tag.
|
||||
* Return the L (length) value read from src_data in tlv->len.
|
||||
* Return the I (instance) value read from src_data in tlv->len; ignore if there is no I.
|
||||
* Return the position just after the TL in tlv->*val. If there is V data, point at the start of the
|
||||
* V data in src_data. If there is no V data, point at the byte just after the TL part in src_data.
|
||||
* \param src_data Part of raw message being decoded.
|
||||
@@ -67,12 +80,14 @@ struct osmo_tlv_cfg {
|
||||
* \param dst_data Write TL data to the start of this buffer.
|
||||
* \param dst_data_avail Remaining available space in dst_data.
|
||||
* \param tag The T value to store in dst_data.
|
||||
* \param instance The I value to store in dst_data (if this tag is a TLIV); ignore when not a TLIV.
|
||||
* \param len The L value to store in dst_data.
|
||||
* \param tlv Backpointer to the osmo_tlv_put struct, including tlv->dst, the underlying msgb.
|
||||
* \return the size of the TL part in bytes on success, -EINVAL if tag is invalid, -EMSGSIZE if len is too large
|
||||
* or dst_data_avail is too small for the TL.
|
||||
*/
|
||||
int (*store_tl)(uint8_t *dst_data, size_t dst_data_avail, unsigned int tag, size_t len, struct osmo_tlv_put *tlv);
|
||||
int (*store_tl)(uint8_t *dst_data, size_t dst_data_avail, const struct osmo_tlv_tag_inst *ti, size_t len,
|
||||
struct osmo_tlv_put *tlv);
|
||||
};
|
||||
|
||||
/*! Configuration that allows parsing an 8bit tag and 8bit length TLV. */
|
||||
@@ -96,7 +111,7 @@ struct osmo_tlv_load {
|
||||
} src;
|
||||
|
||||
/*! Return value from last invocation of osmo_tlv_load_next*(): tag value of parsed IE. */
|
||||
unsigned int tag;
|
||||
struct osmo_tlv_tag_inst ti;
|
||||
/*! Return value from last invocation of osmo_tlv_load_next*(): Start of the IE's payload data (after tag and
|
||||
* length). If the end of the src buffer is reached, val == NULL. If a TLV contained no value part, len == 0,
|
||||
* but this still points just after the TL. */
|
||||
@@ -113,8 +128,9 @@ static inline void osmo_tlv_load_start(struct osmo_tlv_load *tlv)
|
||||
}
|
||||
|
||||
int osmo_tlv_load_next(struct osmo_tlv_load *tlv);
|
||||
int osmo_tlv_load_peek_tag(const struct osmo_tlv_load *tlv);
|
||||
int osmo_tlv_load_peek_tag(const struct osmo_tlv_load *tlv, struct osmo_tlv_tag_inst *ti);
|
||||
int osmo_tlv_load_next_by_tag(struct osmo_tlv_load *tlv, unsigned int tag);
|
||||
int osmo_tlv_load_next_by_tag_inst(struct osmo_tlv_load *tlv, const struct osmo_tlv_tag_inst *ti);
|
||||
|
||||
/* State for storing a TLV structure into a msgb. */
|
||||
struct osmo_tlv_put {
|
||||
@@ -126,11 +142,12 @@ struct osmo_tlv_put {
|
||||
|
||||
/* msgb to append new TL to */
|
||||
struct msgb *dst;
|
||||
/* Where was the last TL head written */
|
||||
unsigned int last_tag;
|
||||
/* What was the last TL written and where are its TL and V */
|
||||
struct osmo_tlv_tag_inst last_ti;
|
||||
uint8_t *last_tl;
|
||||
uint8_t *last_val;
|
||||
};
|
||||
|
||||
int osmo_tlv_put_tl(struct osmo_tlv_put *tlv, unsigned int tag, size_t len);
|
||||
int osmo_tlv_put_tli(struct osmo_tlv_put *tlv, const struct osmo_tlv_tag_inst *ti, size_t len);
|
||||
int osmo_tlv_put_update_tl(struct osmo_tlv_put *tlv);
|
||||
|
@@ -77,8 +77,8 @@ enum osmo_tlv_coding_nested_ies_ordered {
|
||||
* that the decoded structs to match the IEs are also generated at the same time and thus always match the message
|
||||
* definitions. For an example, see tests/libosmo-tlv/test_tlv_gen/. */
|
||||
struct osmo_tlv_coding {
|
||||
/*! the IEI value */
|
||||
unsigned int tag;
|
||||
/*! the IEI discriminator, and optional instance number */
|
||||
struct osmo_tlv_tag_inst ti;
|
||||
|
||||
/*! Decoding function callback. Invoked for each defined and present IE encountered in the message.
|
||||
* Return 0 on success, negative on failure. */
|
||||
|
@@ -6,6 +6,8 @@
|
||||
|
||||
struct osmo_tlv_gen_ie;
|
||||
|
||||
#define OSMO_TLV_GEN_NO_INSTANCE INT_MAX
|
||||
|
||||
/*! Modifier for Mandatory/Optional/Multiple around an osmo_tlv_gen_ie. */
|
||||
struct osmo_tlv_gen_ie_o {
|
||||
/*! Whether to add a bool foo_present, and to skip the coding if false. */
|
||||
@@ -15,6 +17,11 @@ struct osmo_tlv_gen_ie_o {
|
||||
unsigned int multi;
|
||||
/*! Number of mandatory occurences of the IE */
|
||||
unsigned int multi_mandatory;
|
||||
|
||||
/* If any, the instance nr to match, in C that yields an unsigned int.
|
||||
* e.g. "1" or "MYPROTO_FOO_INST_ONE". */
|
||||
const char *instance;
|
||||
|
||||
/*! IE decoding / encoding instructions */
|
||||
const struct osmo_tlv_gen_ie *ie;
|
||||
};
|
||||
@@ -24,6 +31,8 @@ struct osmo_tlv_gen_ie_o {
|
||||
#define OSMO_TLV_GEN_O_MULTI(MAX, TLV_GEN_IE) { .multi = MAX, .ie = &(TLV_GEN_IE) }
|
||||
#define OSMO_TLV_GEN_M_MULTI(MAX, MAND_COUNT, TLV_GEN_IE) \
|
||||
{ .multi = MAX, .multi_mandatory = MAND_COUNT, .ie = &(TLV_GEN_IE) }
|
||||
#define OSMO_TLV_GEN_O_INST(INSTANCE, TLV_GEN_IE) { .optional = true, .instance = INSTANCE, .ie = &TLV_GEN_IE }
|
||||
#define OSMO_TLV_GEN_M_INST(INSTANCE, TLV_GEN_IE) { .instance = INSTANCE, .ie = &(TLV_GEN_IE) }
|
||||
|
||||
/*! Define decoding and encoding of a single IE, i.e. one full TLV. */
|
||||
struct osmo_tlv_gen_ie {
|
||||
|
@@ -261,9 +261,9 @@ static void osmo_pfcp_msg_set_memb_ofs(struct osmo_pfcp_msg *m)
|
||||
if (!mc)
|
||||
return;
|
||||
for (; !osmo_tlv_coding_end(mc) && (m->ofs_cause == 0 || m->ofs_node_id == 0); mc++) {
|
||||
if (mc->tag == OSMO_PFCP_IEI_CAUSE)
|
||||
if (mc->ti.tag == OSMO_PFCP_IEI_CAUSE)
|
||||
m->ofs_cause = offsetof(struct osmo_pfcp_msg, ies) + mc->memb_ofs;
|
||||
if (mc->tag == OSMO_PFCP_IEI_NODE_ID)
|
||||
if (mc->ti.tag == OSMO_PFCP_IEI_NODE_ID)
|
||||
m->ofs_node_id = offsetof(struct osmo_pfcp_msg, ies) + mc->memb_ofs;
|
||||
}
|
||||
|
||||
|
@@ -27,6 +27,26 @@
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/tlv/tlv.h>
|
||||
|
||||
int osmo_tlv_tag_inst_cmp(const struct osmo_tlv_tag_inst *a, const struct osmo_tlv_tag_inst *b)
|
||||
{
|
||||
int cmp;
|
||||
if (a == b)
|
||||
return 0;
|
||||
if (!a)
|
||||
return -1;
|
||||
if (!b)
|
||||
return 1;
|
||||
cmp = OSMO_CMP(a->tag, b->tag);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
cmp = OSMO_CMP(a->instance_present ? 1 : 0, b->instance_present ? 1 : 0);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
if (a->instance_present)
|
||||
return OSMO_CMP(a->instance, b->instance);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int next_tl_valid(const struct osmo_tlv_load *tlv, const uint8_t **ie_start_p, size_t *buflen_left_p)
|
||||
{
|
||||
const uint8_t *ie_start;
|
||||
@@ -102,6 +122,7 @@ int osmo_tlv_load_next(struct osmo_tlv_load *tlv)
|
||||
|
||||
/* Locate next IE */
|
||||
OSMO_ASSERT(tlv->cfg->load_tl);
|
||||
tlv->ti = (struct osmo_tlv_tag_inst){0};
|
||||
rc = tlv->cfg->load_tl(tlv, ie_start, buflen_left);
|
||||
if (rc)
|
||||
return rc;
|
||||
@@ -116,17 +137,20 @@ int osmo_tlv_load_next(struct osmo_tlv_load *tlv)
|
||||
|
||||
/* Return the tag of the IE that osmo_tlv_next() would yield, do not change the tlv state.
|
||||
*
|
||||
* \param[inout] tlv state for TLV parsing position.
|
||||
* \returns the tag number on success, negative on TLV parsing error, -ENOENT when no more tags
|
||||
* follow.
|
||||
* \param[in] tlv state for TLV parsing position; is not modified.
|
||||
* \param[out] tag the tag number on success, if NULL don't return the tag.
|
||||
* \param[out] instance the instance number or OSMO_TLV_NO_INSTANCE if there is no instance value,
|
||||
* if NULL don't return the instance value.
|
||||
* \returns 0 on success, negative on TLV parsing error, -ENOENT when no more tags follow.
|
||||
*/
|
||||
int osmo_tlv_load_peek_tag(const struct osmo_tlv_load *tlv)
|
||||
int osmo_tlv_load_peek_tag(const struct osmo_tlv_load *tlv, struct osmo_tlv_tag_inst *ti)
|
||||
{
|
||||
const uint8_t *ie_start;
|
||||
size_t buflen_left;
|
||||
int rc;
|
||||
/* Guard against modification by load_tl(). */
|
||||
struct osmo_tlv_load mtlv = *tlv;
|
||||
mtlv.ti = (struct osmo_tlv_tag_inst){0};
|
||||
|
||||
rc = next_tl_valid(&mtlv, &ie_start, &buflen_left);
|
||||
if (rc)
|
||||
@@ -140,13 +164,25 @@ int osmo_tlv_load_peek_tag(const struct osmo_tlv_load *tlv)
|
||||
rc = tlv->cfg->load_tl(&mtlv, ie_start, buflen_left);
|
||||
if (rc)
|
||||
return -EBADMSG;
|
||||
return mtlv.tag;
|
||||
if (ti)
|
||||
*ti = mtlv.ti;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Same as osmo_tlv_next(), but skip any IEs until the given tag is reached. Change the tlv state only when
|
||||
* success is returned.
|
||||
/* Same as osmo_tlv_load_next(), but skip any IEs until the given tag is reached. Change the tlv state only when success
|
||||
* is returned.
|
||||
* \param[out] tlv Return the next IE's TLV info.
|
||||
* \param[in] tag Tag value to match.
|
||||
* \param[in] instance Instance value to match; For IEs that have no instance value (no TLIV), pass
|
||||
* OSMO_TLV_NO_INSTANCE.
|
||||
* \return 0 when the tag is found. Return -ENOENT when no such tag follows and keep the tlv unchanged. */
|
||||
int osmo_tlv_load_next_by_tag(struct osmo_tlv_load *tlv, unsigned int tag)
|
||||
{
|
||||
struct osmo_tlv_tag_inst ti = { .tag = tag };
|
||||
return osmo_tlv_load_next_by_tag_inst(tlv, &ti);
|
||||
}
|
||||
|
||||
int osmo_tlv_load_next_by_tag_inst(struct osmo_tlv_load *tlv, const struct osmo_tlv_tag_inst *ti)
|
||||
{
|
||||
struct osmo_tlv_load work = *tlv;
|
||||
for (;;) {
|
||||
@@ -155,7 +191,7 @@ int osmo_tlv_load_next_by_tag(struct osmo_tlv_load *tlv, unsigned int tag)
|
||||
return rc;
|
||||
if (!work.val)
|
||||
return -ENOENT;
|
||||
if (work.tag == tag) {
|
||||
if (!osmo_tlv_tag_inst_cmp(&work.ti, ti)) {
|
||||
*tlv = work;
|
||||
return 0;
|
||||
}
|
||||
@@ -187,17 +223,26 @@ int osmo_tlv_load_next_by_tag(struct osmo_tlv_load *tlv, unsigned int tag)
|
||||
* Return 0 on success, -EINVAL if the tag value is invalid, -EMSGSIZE if len is too large.
|
||||
*/
|
||||
int osmo_tlv_put_tl(struct osmo_tlv_put *tlv, unsigned int tag, size_t len)
|
||||
{
|
||||
struct osmo_tlv_tag_inst ti = { .tag = tag };
|
||||
return osmo_tlv_put_tli(tlv, &ti, len);
|
||||
}
|
||||
|
||||
/* Put tag header, instance value and length at the end of the msgb, according to tlv->cfg->store_tl().
|
||||
* This is the same as osmo_tlv_put_tl(), only osmo_tlv_put_tl() passes instance = 0.
|
||||
*/
|
||||
int osmo_tlv_put_tli(struct osmo_tlv_put *tlv, const struct osmo_tlv_tag_inst *ti, size_t len)
|
||||
{
|
||||
int rc;
|
||||
uint8_t *last_tl;
|
||||
OSMO_ASSERT(tlv->cfg->store_tl);
|
||||
last_tl = tlv->dst->tail;
|
||||
rc = tlv->cfg->store_tl(tlv->dst->tail, msgb_tailroom(tlv->dst), tag, len, tlv);
|
||||
rc = tlv->cfg->store_tl(tlv->dst->tail, msgb_tailroom(tlv->dst), ti, len, tlv);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (rc > 0)
|
||||
msgb_put(tlv->dst, rc);
|
||||
tlv->last_tag = tag;
|
||||
tlv->last_ti = *ti;
|
||||
tlv->last_tl = last_tl;
|
||||
tlv->last_val = tlv->dst->tail;
|
||||
return 0;
|
||||
@@ -210,7 +255,7 @@ int osmo_tlv_put_tl(struct osmo_tlv_put *tlv, unsigned int tag, size_t len)
|
||||
int osmo_tlv_put_update_tl(struct osmo_tlv_put *tlv)
|
||||
{
|
||||
size_t len = tlv->dst->tail - tlv->last_val;
|
||||
int rc = tlv->cfg->store_tl(tlv->last_tl, tlv->last_val - tlv->last_tl, tlv->last_tag, len, tlv);
|
||||
int rc = tlv->cfg->store_tl(tlv->last_tl, tlv->last_val - tlv->last_tl, &tlv->last_ti, len, tlv);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
/* In case the TL has changed in size, hopefully the implementation has moved the msgb data. Make sure last_val
|
||||
@@ -222,22 +267,22 @@ int osmo_tlv_put_update_tl(struct osmo_tlv_put *tlv)
|
||||
static int t8l8v_load_tl(struct osmo_tlv_load *tlv, const uint8_t *src_data, size_t src_data_len)
|
||||
{
|
||||
/* already validated in next_tl_valid(): src_data_len >= cfg->tl_min_size == 2. */
|
||||
tlv->tag = src_data[0];
|
||||
tlv->ti.tag = src_data[0];
|
||||
tlv->len = src_data[1];
|
||||
tlv->val = src_data + 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int t8l8v_store_tl(uint8_t *dst_data, size_t dst_data_avail, unsigned int tag, size_t len,
|
||||
static int t8l8v_store_tl(uint8_t *dst_data, size_t dst_data_avail, const struct osmo_tlv_tag_inst *ti, size_t len,
|
||||
struct osmo_tlv_put *tlv)
|
||||
{
|
||||
if (tag > UINT8_MAX)
|
||||
if (ti->tag > UINT8_MAX)
|
||||
return -EINVAL;
|
||||
if (len > UINT8_MAX)
|
||||
return -EMSGSIZE;
|
||||
if (dst_data_avail < 2)
|
||||
return -ENOSPC;
|
||||
dst_data[0] = tag;
|
||||
dst_data[0] = ti->tag;
|
||||
dst_data[1] = len;
|
||||
return 2;
|
||||
}
|
||||
@@ -251,22 +296,22 @@ const struct osmo_tlv_cfg osmo_t8l8v_cfg = {
|
||||
static int t16l16v_load_tl(struct osmo_tlv_load *tlv, const uint8_t *src_data, size_t src_data_len)
|
||||
{
|
||||
/* already validated in next_tl_valid(): src_data_len >= cfg->tl_min_size == 4. */
|
||||
tlv->tag = osmo_load16be(src_data);
|
||||
tlv->ti.tag = osmo_load16be(src_data);
|
||||
tlv->len = osmo_load16be(src_data + 2);
|
||||
tlv->val = src_data + 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int t16l16v_store_tl(uint8_t *dst_data, size_t dst_data_avail, unsigned int tag, size_t len,
|
||||
static int t16l16v_store_tl(uint8_t *dst_data, size_t dst_data_avail, const struct osmo_tlv_tag_inst *ti, size_t len,
|
||||
struct osmo_tlv_put *tlv)
|
||||
{
|
||||
if (tag > UINT16_MAX)
|
||||
if (ti->tag > UINT16_MAX)
|
||||
return -EINVAL;
|
||||
if (len > UINT16_MAX)
|
||||
return -EMSGSIZE;
|
||||
if (dst_data_avail < 4)
|
||||
return -ENOSPC;
|
||||
osmo_store16be(tag, dst_data);
|
||||
osmo_store16be(ti->tag, dst_data);
|
||||
osmo_store16be(len, dst_data + 2);
|
||||
return 4;
|
||||
}
|
||||
|
@@ -31,11 +31,21 @@
|
||||
/* Reverse offsetof(): return the address of the struct member for a given osmo_tlv_msg and member ofs_foo value. */
|
||||
#define MEMB(M, MEMB_OFS) ((void *)((char *)(M) + (MEMB_OFS)))
|
||||
|
||||
#define RETURN_ERROR(RC, IEI, FMT, ARGS...) \
|
||||
#define RETURN_ERROR(RC, TAG_INST, FMT, ARGS...) \
|
||||
do {\
|
||||
if (err_cb) \
|
||||
err_cb(decoded_struct, __FILE__, __LINE__, "tag 0x%x = %s: " FMT " (%d: %s)\n", IEI, \
|
||||
get_value_string(iei_strs, IEI), ##ARGS, RC, strerror((RC) > 0 ? (RC) : -(RC))); \
|
||||
if (err_cb) { \
|
||||
if ((TAG_INST).instance_present) \
|
||||
err_cb(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(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)
|
||||
|
||||
@@ -70,7 +80,7 @@ static int osmo_tlvs_decode_unordered(void *decoded_struct, unsigned int obj_ofs
|
||||
#define CHECK_SEEN(IEC) do { \
|
||||
unsigned int ie_coding_idx = (IEC) - ie_coding; \
|
||||
if (ie_coding_idx >= ARRAY_SIZE(seen_ie_coding_entries)) \
|
||||
RETURN_ERROR(-ENOTSUP, tlv->tag, \
|
||||
RETURN_ERROR(-ENOTSUP, tlv->ti, \
|
||||
"Too many IE definitions for decoding an unordered TLV structure"); \
|
||||
seen_p = &seen_ie_coding_entries[ie_coding_idx]; \
|
||||
} while (0)
|
||||
@@ -89,7 +99,7 @@ static int osmo_tlvs_decode_unordered(void *decoded_struct, unsigned int obj_ofs
|
||||
|
||||
rc = osmo_tlv_load_next(tlv);
|
||||
if (rc)
|
||||
RETURN_ERROR(rc, tlv->tag, "Decoding IEs failed on or after this tag");
|
||||
RETURN_ERROR(rc, tlv->ti, "Decoding IEs failed on or after this tag");
|
||||
if (!tlv->val) {
|
||||
/* End of the TLV structure */
|
||||
break;
|
||||
@@ -101,7 +111,9 @@ static int osmo_tlvs_decode_unordered(void *decoded_struct, unsigned int obj_ofs
|
||||
|
||||
do {
|
||||
/* Find the IE coding for this tag */
|
||||
for (iec = ie_coding; !osmo_tlv_coding_end(iec) && iec->tag != tlv->tag; iec++);
|
||||
for (iec = ie_coding;
|
||||
!osmo_tlv_coding_end(iec) && osmo_tlv_tag_inst_cmp(&iec->ti, &tlv->ti);
|
||||
iec++);
|
||||
/* No such IE coding found. */
|
||||
if (osmo_tlv_coding_end(iec))
|
||||
break;
|
||||
@@ -126,7 +138,7 @@ static int osmo_tlvs_decode_unordered(void *decoded_struct, unsigned int obj_ofs
|
||||
if (ie_max_allowed_count) {
|
||||
/* There have been IE definitions for this IEI, but all slots to decode it are already
|
||||
* filled. */
|
||||
RETURN_ERROR(-ENOTSUP, tlv->tag, "Only %u instances of this IE are supported per message",
|
||||
RETURN_ERROR(-ENOTSUP, tlv->ti, "Only %u instances of this IE are supported per message",
|
||||
ie_max_allowed_count);
|
||||
}
|
||||
/* No such IE defined in ie_coding, just skip the TLV. */
|
||||
@@ -164,14 +176,14 @@ static int osmo_tlvs_decode_unordered(void *decoded_struct, unsigned int obj_ofs
|
||||
rc = osmo_tlvs_decode(decoded_struct, obj_ofs + memb_ofs, &inner_tlv, ordered, iec->nested_ies,
|
||||
err_cb, iei_strs);
|
||||
if (rc)
|
||||
RETURN_ERROR(rc, tlv->tag, "Error while decoding TLV structure nested inside this IE");
|
||||
RETURN_ERROR(rc, tlv->ti, "Error while decoding TLV structure nested inside this IE");
|
||||
} else {
|
||||
/* Normal IE, decode the specific IE data. */
|
||||
if (!iec->dec_func)
|
||||
RETURN_ERROR(-EIO, tlv->tag, "IE definition lacks a dec_func()");
|
||||
RETURN_ERROR(-EIO, tlv->ti, "IE definition lacks a dec_func()");
|
||||
rc = iec->dec_func(decoded_struct, MEMB(obj, memb_ofs), tlv);
|
||||
if (rc)
|
||||
RETURN_ERROR(rc, tlv->tag, "Error while decoding this IE");
|
||||
RETURN_ERROR(rc, tlv->ti, "Error while decoding this IE");
|
||||
}
|
||||
|
||||
if (multi_count_p) {
|
||||
@@ -195,14 +207,14 @@ static int osmo_tlvs_decode_unordered(void *decoded_struct, unsigned int obj_ofs
|
||||
multi_count_p = iec->has_count ? MEMB(obj, iec->count_ofs) : NULL;
|
||||
if (multi_count_p) {
|
||||
if (*multi_count_p < iec->count_madatory)
|
||||
RETURN_ERROR(-EINVAL, iec->tag, "%u instances of this IE are mandatory, got %u",
|
||||
RETURN_ERROR(-EINVAL, iec->ti, "%u instances of this IE are mandatory, got %u",
|
||||
iec->count_madatory, *multi_count_p);
|
||||
continue;
|
||||
}
|
||||
/* Neither an optional nor a multi member, hence it must be mandatory. */
|
||||
CHECK_SEEN(iec);
|
||||
if (!*seen_p)
|
||||
RETURN_ERROR(-EINVAL, iec->tag, "Missing mandatory IE");
|
||||
RETURN_ERROR(-EINVAL, iec->ti, "Missing mandatory IE");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -232,19 +244,20 @@ static int osmo_tlvs_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_tlv_tag_inst peek_ti;
|
||||
|
||||
rc = osmo_tlv_load_next_by_tag(tlv, ie_coding->tag);
|
||||
rc = osmo_tlv_load_next_by_tag_inst(tlv, &ie_coding->ti);
|
||||
switch (rc) {
|
||||
case 0:
|
||||
break;
|
||||
case -ENOENT:
|
||||
if (!presence_flag && (!multi_count || *multi_count < ie_coding->count_madatory))
|
||||
RETURN_ERROR(rc, ie_coding->tag, "Missing mandatory IE");
|
||||
RETURN_ERROR(rc, ie_coding->ti, "Missing mandatory IE");
|
||||
if (presence_flag)
|
||||
*presence_flag = false;
|
||||
continue;
|
||||
default:
|
||||
RETURN_ERROR(rc, ie_coding->tag, "Error in TLV structure");
|
||||
RETURN_ERROR(rc, ie_coding->ti, "Error in TLV structure");
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
@@ -254,7 +267,7 @@ static int osmo_tlvs_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 */
|
||||
@@ -283,15 +296,15 @@ static int osmo_tlvs_decode_ordered(void *decoded_struct, unsigned int obj_ofs,
|
||||
rc = osmo_tlvs_decode(decoded_struct, obj_ofs + memb_ofs, &inner_tlv, ordered,
|
||||
ie_coding->nested_ies, err_cb, iei_strs);
|
||||
if (rc)
|
||||
RETURN_ERROR(rc, ie_coding->tag,
|
||||
RETURN_ERROR(rc, ie_coding->ti,
|
||||
"Error while decoding TLV structure nested inside this IE");
|
||||
} else {
|
||||
/* Normal IE, decode the specific IE data. */
|
||||
if (!ie_coding->dec_func)
|
||||
RETURN_ERROR(-EIO, ie_coding->tag, "IE definition lacks a dec_func()");
|
||||
RETURN_ERROR(-EIO, ie_coding->ti, "IE definition lacks a dec_func()");
|
||||
rc = ie_coding->dec_func(decoded_struct, MEMB(obj, memb_ofs), tlv);
|
||||
if (rc)
|
||||
RETURN_ERROR(rc, ie_coding->tag, "Error while decoding this IE");
|
||||
RETURN_ERROR(rc, ie_coding->ti, "Error while decoding this IE");
|
||||
}
|
||||
|
||||
if (presence_flag)
|
||||
@@ -309,7 +322,8 @@ static int osmo_tlvs_decode_ordered(void *decoded_struct, unsigned int obj_ofs,
|
||||
(*multi_count)++;
|
||||
|
||||
/* Does another one of these IEs follow? */
|
||||
if (osmo_tlv_load_peek_tag(tlv) != tlv->tag) {
|
||||
if (osmo_tlv_load_peek_tag(tlv, &peek_ti)
|
||||
|| osmo_tlv_tag_inst_cmp(&peek_ti, &tlv->ti)) {
|
||||
/* Next tag is a different IE, end the repetition. */
|
||||
break;
|
||||
}
|
||||
@@ -381,7 +395,7 @@ int osmo_tlvs_encode(struct osmo_tlv_put *tlv, void *decoded_struct, unsigned in
|
||||
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 {
|
||||
@@ -391,11 +405,11 @@ int osmo_tlvs_encode(struct osmo_tlv_put *tlv, void *decoded_struct, unsigned in
|
||||
for (i = 0; i < n; i++) {
|
||||
unsigned int memb_ofs;
|
||||
|
||||
osmo_tlv_put_tl(tlv, ie_coding->tag, 0);
|
||||
osmo_tlv_put_tli(tlv, &ie_coding->ti, 0);
|
||||
|
||||
/* If this is a repeated IE, encode from the correct array index */
|
||||
if (multi_count_p && i >= ie_coding->count_max)
|
||||
RETURN_ERROR(-ENOTSUP, ie_coding->tag,
|
||||
RETURN_ERROR(-ENOTSUP, ie_coding->ti,
|
||||
"Only %u instances of this IE are supported per message", ie_coding->count_max);
|
||||
memb_ofs = ie_coding->memb_ofs + i * ie_coding->memb_array_pitch;
|
||||
|
||||
@@ -407,12 +421,12 @@ int osmo_tlvs_encode(struct osmo_tlv_put *tlv, void *decoded_struct, unsigned in
|
||||
rc = osmo_tlvs_encode(&nested_tlv, decoded_struct, obj_ofs + memb_ofs,
|
||||
ie_coding->nested_ies, err_cb, iei_strs);
|
||||
if (rc)
|
||||
RETURN_ERROR(rc, ie_coding->tag,
|
||||
RETURN_ERROR(rc, ie_coding->ti,
|
||||
"Error while encoding TLV structure nested inside this IE");
|
||||
} else {
|
||||
rc = ie_coding->enc_func(tlv, decoded_struct, MEMB(obj, memb_ofs));
|
||||
if (rc)
|
||||
RETURN_ERROR(rc, ie_coding->tag, "Error while encoding this IE");
|
||||
RETURN_ERROR(rc, ie_coding->ti, "Error while encoding this IE");
|
||||
}
|
||||
|
||||
osmo_tlv_put_update_tl(tlv);
|
||||
@@ -461,7 +475,7 @@ int osmo_tlvs_encode_to_str_buf(char *buf, size_t buflen, const void *decoded_st
|
||||
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, "{ ");
|
||||
|
||||
|
@@ -227,7 +227,7 @@ static void write_extern_dec_enc(const struct osmo_tlv_gen_ie_o *ies)
|
||||
}
|
||||
|
||||
/* For a nested IE, write the struct osmo_tlv_coding array of the inner IEs.
|
||||
* { MYPROTO_IEI_BAR,
|
||||
* { { MYPROTO_IEI_BAR },
|
||||
* .memb_ofs = offsetof(struct myproto_foo, bar),
|
||||
* .dec_func = myproto_dec_bar,
|
||||
* .enc_func = myproto_enc_bar,
|
||||
@@ -241,7 +241,10 @@ static void write_ies_array(const char *indent, const struct osmo_tlv_gen_ie_o *
|
||||
for (ie_o = ies; ie_o->ie; ie_o++) {
|
||||
const struct osmo_tlv_gen_ie *ie = ie_o->ie;
|
||||
const char *tag_name = ie->tag_name ? : ie->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)
|
||||
printi(", true, %s", ie_o->instance);
|
||||
printi(" },\n");
|
||||
printi(" .memb_ofs = offsetof(%s, %s%s),\n", obj_type, substruct, ie->name);
|
||||
if (ie->nested_ies) {
|
||||
printi(" .nested_ies = ies_in_%s,\n", ie->name);
|
||||
@@ -263,13 +266,17 @@ static void write_ies_array(const char *indent, const struct osmo_tlv_gen_ie_o *
|
||||
printi(" .has_presence_flag = true,\n");
|
||||
printi(" .presence_flag_ofs = offsetof(%s, %s%s_present),\n", obj_type, substruct, ie->name);
|
||||
}
|
||||
if (ie_o->instance) {
|
||||
printi(" .has_instance = true,\n");
|
||||
printi(" .instance = %s,\n", ie_o->instance);
|
||||
}
|
||||
printi("},\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* For a nested IE, write the struct osmo_tlv_coding array of the inner IEs.
|
||||
* static const struct osmo_tlv_coding ies_in_foo[] = {
|
||||
* { MYPROTO_IEI_BAR,
|
||||
* { {MYPROTO_IEI_BAR},
|
||||
* .memb_ofs = offsetof(struct myproto_foo, bar),
|
||||
* .dec_func = myproto_dec_bar,
|
||||
* .enc_func = myproto_enc_bar,
|
||||
@@ -291,7 +298,7 @@ static void write_nested_ies_array(const struct osmo_tlv_gen_ie_o *ies)
|
||||
|
||||
printf("\nstatic const struct osmo_tlv_coding ies_in_%s[] = {\n", ie->name);
|
||||
write_ies_array(indent, ie->nested_ies, decoded_type(ie), "");
|
||||
printi("{0}\n");
|
||||
printi("{}\n");
|
||||
printf("};\n");
|
||||
}
|
||||
}
|
||||
@@ -329,7 +336,7 @@ static void write_c()
|
||||
char *substruct = talloc_asprintf(NULL, "%s.", gen_msg->name);
|
||||
printf("\nstatic const struct osmo_tlv_coding ies_in_msg_%s[] = {\n", gen_msg->name);
|
||||
write_ies_array("\t", gen_msg->ies, obj_type, substruct);
|
||||
printf("\t{0}\n};\n");
|
||||
printf("\t{}\n};\n");
|
||||
talloc_free(substruct);
|
||||
talloc_free(obj_type);
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
SUBDIRS = \
|
||||
test_tlv_gen \
|
||||
test_tliv \
|
||||
$(NULL)
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
|
60
tests/libosmo-tlv/test_tliv/Makefile.am
Normal file
60
tests/libosmo-tlv/test_tliv/Makefile.am
Normal file
@@ -0,0 +1,60 @@
|
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(bulddir) \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
gen__myproto_ies_auto \
|
||||
tliv_test \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
myproto_ies_custom.h \
|
||||
tliv_test.ok \
|
||||
$(NULL)
|
||||
|
||||
BUILT_SOURCES = \
|
||||
myproto_ies_auto.h \
|
||||
myproto_ies_auto.c \
|
||||
$(NULL)
|
||||
|
||||
CLEANFILES = \
|
||||
myproto_ies_auto.h \
|
||||
myproto_ies_auto.c \
|
||||
$(NULL)
|
||||
|
||||
gen__myproto_ies_auto_SOURCES = \
|
||||
gen__myproto_ies_auto.c \
|
||||
myproto_ies_custom.c \
|
||||
$(NULL)
|
||||
|
||||
gen__myproto_ies_auto_LDADD = \
|
||||
$(top_builddir)/src/libosmo-tlv/libosmo-tlv.a \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
myproto_ies_auto.h: $(builddir)/gen__myproto_ies_auto
|
||||
$(builddir)/gen__myproto_ies_auto h > $(builddir)/myproto_ies_auto.h
|
||||
myproto_ies_auto.c: $(builddir)/gen__myproto_ies_auto
|
||||
$(builddir)/gen__myproto_ies_auto c > $(builddir)/myproto_ies_auto.c
|
||||
|
||||
tliv_test_SOURCES = \
|
||||
tliv_test.c \
|
||||
myproto_ies_custom.c \
|
||||
myproto_ies_auto.c \
|
||||
$(NULL)
|
||||
|
||||
tliv_test_LDADD = \
|
||||
$(top_builddir)/src/libosmo-tlv/libosmo-tlv.a \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
.PHONY: update_exp
|
||||
update_exp:
|
||||
$(builddir)/tliv_test >$(srcdir)/tliv_test.ok
|
75
tests/libosmo-tlv/test_tliv/gen__myproto_ies_auto.c
Normal file
75
tests/libosmo-tlv/test_tliv/gen__myproto_ies_auto.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* (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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/tlv/tlv_gen.h>
|
||||
|
||||
#define O OSMO_TLV_GEN_O
|
||||
#define M OSMO_TLV_GEN_M
|
||||
#define O_MULTI OSMO_TLV_GEN_O_MULTI
|
||||
#define M_MULTI OSMO_TLV_GEN_M_MULTI
|
||||
#define O_INST OSMO_TLV_GEN_O_INST
|
||||
#define M_INST OSMO_TLV_GEN_M_INST
|
||||
|
||||
static const struct osmo_tlv_gen_ie bar = {
|
||||
.name = "bar",
|
||||
/* uses 'struct ie_bar bar;' and dec_bar()/enc_bar() */
|
||||
.to_str = "bar", /* uses myproto_enc_to_str_bar() */
|
||||
};
|
||||
|
||||
static const struct osmo_tlv_gen_ie_o ies_in_moo_msg[] = {
|
||||
M_INST("5", bar),
|
||||
{0}
|
||||
};
|
||||
|
||||
static const struct osmo_tlv_gen_ie_o ies_in_goo_msg[] = {
|
||||
O_INST("3", bar),
|
||||
{0}
|
||||
};
|
||||
|
||||
static const struct osmo_tlv_gen_msg msg_defs[] = {
|
||||
{ "moo", ies_in_moo_msg },
|
||||
{ "goo", ies_in_goo_msg },
|
||||
{0}
|
||||
};
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
struct osmo_tlv_gen_cfg cfg = {
|
||||
.proto_name = "myproto",
|
||||
.message_type_enum = "enum myproto_msg_type",
|
||||
.message_type_prefix = "MYPROTO_MSGT_",
|
||||
.tag_enum = "enum myproto_iei",
|
||||
.tag_prefix = "MYPROTO_IEI_",
|
||||
.decoded_type_prefix = "struct myproto_ie_",
|
||||
.h_header = "#include \"myproto_ies_custom.h\"",
|
||||
.c_header = "#include <myproto_ies_auto.h>",
|
||||
.msg_defs = msg_defs,
|
||||
};
|
||||
return osmo_tlv_gen_main(&cfg, argc, argv);
|
||||
}
|
69
tests/libosmo-tlv/test_tliv/myproto_ies_custom.c
Normal file
69
tests/libosmo-tlv/test_tliv/myproto_ies_custom.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/* Example for defining custom IES for tlv_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 Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <osmocom/core/bits.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/tlv/tlv.h>
|
||||
|
||||
#include <myproto_ies_custom.h>
|
||||
|
||||
int myproto_dec_bar(void *decoded_struct, void *decode_to, const struct osmo_tlv_load *tlv)
|
||||
{
|
||||
struct myproto_ie_bar *bar = decode_to;
|
||||
if (tlv->len < 2)
|
||||
return -EINVAL;
|
||||
*bar = (struct myproto_ie_bar){
|
||||
.a = tlv->val[0],
|
||||
.b = (tlv->val[1] == 1),
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
int myproto_enc_bar(struct osmo_tlv_put *tlv, void *decoded_struct, void *encode_from)
|
||||
{
|
||||
struct myproto_ie_bar *bar = encode_from;
|
||||
msgb_put_u8(tlv->dst, bar->a);
|
||||
msgb_put_u8(tlv->dst, bar->b ? 1 : 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int myproto_enc_to_str_bar(char *buf, size_t buflen, void *encode_from)
|
||||
{
|
||||
struct myproto_ie_bar *bar = encode_from;
|
||||
return snprintf(buf, buflen, "%d,%s", bar->a, bar->b ? "true" : "false");
|
||||
}
|
||||
|
||||
const struct value_string myproto_msg_type_names[] = {
|
||||
{ MYPROTO_MSGT_MOO, "MOO" },
|
||||
{ MYPROTO_MSGT_GOO, "GOO" },
|
||||
{}
|
||||
};
|
||||
|
||||
const struct value_string myproto_iei_names[] = {
|
||||
{ MYPROTO_IEI_FOO, "FOO" },
|
||||
{ MYPROTO_IEI_BAR, "BAR" },
|
||||
{}
|
||||
};
|
42
tests/libosmo-tlv/test_tliv/myproto_ies_custom.h
Normal file
42
tests/libosmo-tlv/test_tliv/myproto_ies_custom.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* Definitions for decoded message IEs, to be used by the auto-generated tlv_gen_test_tlv.c. */
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
|
||||
enum myproto_msg_type {
|
||||
MYPROTO_MSGT_MOO = 1,
|
||||
MYPROTO_MSGT_GOO = 7,
|
||||
};
|
||||
|
||||
extern const struct value_string myproto_msg_type_names[];
|
||||
|
||||
enum myproto_iei {
|
||||
MYPROTO_IEI_FOO = 1,
|
||||
MYPROTO_IEI_BAR,
|
||||
};
|
||||
|
||||
extern const struct value_string myproto_iei_names[];
|
||||
|
||||
struct myproto_ie_bar {
|
||||
int a;
|
||||
bool b;
|
||||
};
|
||||
|
||||
union myproto_ie_bar_instances {
|
||||
struct {
|
||||
struct myproto_ie_bar bar[5];
|
||||
bool bar_present[5];
|
||||
} arr;
|
||||
struct {
|
||||
struct myproto_ie_bar bar_one;
|
||||
struct myproto_ie_bar bar_two;
|
||||
struct myproto_ie_bar different_bar;
|
||||
struct myproto_ie_bar fallback_bar;
|
||||
struct myproto_ie_bar final_bar;
|
||||
bool bar_one_present;
|
||||
bool bar_two_present;
|
||||
bool different_bar_present;
|
||||
bool fallback_bar_present;
|
||||
bool final_bar_present;
|
||||
} inst;
|
||||
};
|
142
tests/libosmo-tlv/test_tliv/tliv_test.c
Normal file
142
tests/libosmo-tlv/test_tliv/tliv_test.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/* (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
|
||||
#include <osmocom/tlv/tlv.h>
|
||||
|
||||
#include <myproto_ies_auto.h>
|
||||
|
||||
struct myproto_msg {
|
||||
enum myproto_msg_type type;
|
||||
union myproto_ies ies;
|
||||
};
|
||||
|
||||
static void err_cb(void *decoded_struct, const char *file, int line, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
//printf("ERR: %s:%d ", file, line);
|
||||
printf("ERR: ");
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static int myproto_msg_enc(struct msgb *dst, const struct myproto_msg *msg, const struct osmo_tlv_cfg *cfg)
|
||||
{
|
||||
struct osmo_tlv_put tlv = {
|
||||
.cfg = cfg,
|
||||
.dst = dst,
|
||||
};
|
||||
|
||||
msgb_put_u8(tlv.dst, msg->type);
|
||||
return myproto_ies_encode(&tlv, (void*)&msg->ies, msg->type, err_cb, myproto_iei_names);
|
||||
}
|
||||
|
||||
static int myproto_msg_dec(struct myproto_msg *msg, const uint8_t *data, size_t data_len,
|
||||
const struct osmo_tlv_cfg *cfg, bool ordered)
|
||||
{
|
||||
struct osmo_tlv_load tlv;
|
||||
if (data_len < 1)
|
||||
return -EINVAL;
|
||||
msg->type = data[0];
|
||||
tlv = (struct osmo_tlv_load){
|
||||
.cfg = cfg,
|
||||
.src = { data + 1, data_len - 1 },
|
||||
};
|
||||
return myproto_ies_decode(&msg->ies, &tlv, ordered, msg->type, err_cb, myproto_iei_names);
|
||||
}
|
||||
|
||||
void *ctx;
|
||||
|
||||
struct myproto_msg tests[] = {
|
||||
{
|
||||
MYPROTO_MSGT_MOO,
|
||||
{
|
||||
.moo = {
|
||||
.bar = { 23, true },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
int myproto_msg_to_str_buf(char *buf, size_t buflen, const struct myproto_msg *m)
|
||||
{
|
||||
struct osmo_strbuf sb = { .buf = buf, .len = buflen };
|
||||
OSMO_STRBUF_PRINTF(sb, "%s={", get_value_string(myproto_msg_type_names, m->type));
|
||||
OSMO_STRBUF_APPEND(sb, osmo_tlvs_encode_to_str_buf, &m->ies, 0, myproto_get_msg_coding(m->type),
|
||||
myproto_iei_names);
|
||||
OSMO_STRBUF_PRINTF(sb, " }");
|
||||
return sb.chars_needed;
|
||||
|
||||
}
|
||||
|
||||
char *myproto_msg_to_str(const struct myproto_msg *m)
|
||||
{
|
||||
OSMO_NAME_C_IMPL(ctx, 256, "ERROR", myproto_msg_to_str_buf, m)
|
||||
}
|
||||
|
||||
void test_enc_dec(const char *label, const struct osmo_tlv_cfg *cfg, bool ordered)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||
int rc;
|
||||
const struct myproto_msg *orig = &tests[i];
|
||||
struct myproto_msg parsed = {0};
|
||||
struct msgb *msg;
|
||||
|
||||
printf("\n=== start %s %s[%d]\n", label, __func__, i);
|
||||
printf("encoded: %s\n", myproto_msg_to_str(orig));
|
||||
|
||||
msg = msgb_alloc(1024, __func__),
|
||||
rc = myproto_msg_enc(msg, orig, cfg);
|
||||
printf("myproto_msg_enc() rc = %d\n", rc);
|
||||
printf("%s.\n", osmo_hexdump(msg->data, msg->len));
|
||||
|
||||
rc = myproto_msg_dec(&parsed, msg->data, msg->len, cfg, ordered);
|
||||
printf("myproto_msg_dec() rc = %d\n", rc);
|
||||
printf("decoded: %s\n", myproto_msg_to_str(&parsed));
|
||||
if (strcmp(myproto_msg_to_str(orig), myproto_msg_to_str(&parsed))) {
|
||||
printf(" ERROR: parsed != orig\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
msgb_free(msg);
|
||||
printf("=== end %s %s[%d]\n", label, __func__, i);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
ctx = talloc_named_const(NULL, 0, "test_gen_tlv");
|
||||
msgb_talloc_ctx_init(ctx, 0);
|
||||
|
||||
test_enc_dec("t8l8v ordered", &osmo_t8l8v_cfg, true);
|
||||
test_enc_dec("t8l8v unordered", &osmo_t8l8v_cfg, false);
|
||||
|
||||
test_enc_dec("t16l16v ordered", &osmo_t16l16v_cfg, true);
|
||||
test_enc_dec("t16l16v unordered", &osmo_t16l16v_cfg, false);
|
||||
|
||||
talloc_free(ctx);
|
||||
return 0;
|
||||
}
|
160
tests/libosmo-tlv/test_tliv/tliv_test.ok
Normal file
160
tests/libosmo-tlv/test_tliv/tliv_test.ok
Normal file
@@ -0,0 +1,160 @@
|
||||
|
||||
=== start t8l8v ordered test_enc_dec[0]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 01 02 00 17 02 0b 74 77 65 6e 74 79 74 68 72 65 65 .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" }
|
||||
=== end t8l8v ordered test_enc_dec[0]
|
||||
|
||||
=== start t8l8v ordered test_enc_dec[1]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 01 02 00 17 02 0b 74 77 65 6e 74 79 74 68 72 65 65 03 02 89 13 .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} }
|
||||
=== end t8l8v ordered test_enc_dec[1]
|
||||
|
||||
=== start t8l8v ordered test_enc_dec[2]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 01 02 00 17 02 0b 74 77 65 6e 74 79 74 68 72 65 65 03 02 89 13 04 02 00 01 04 02 00 02 04 02 7f ff .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } }
|
||||
=== end t8l8v ordered test_enc_dec[2]
|
||||
|
||||
=== start t8l8v ordered test_enc_dec[3]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } REPEAT_STRUCT={ {1001,true,R_A}, {1002,false,R_B} } MOO_NEST={ FOO=42 BAR="fortytwo" BAZ={4242,false} } }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 01 02 00 17 02 0b 74 77 65 6e 74 79 74 68 72 65 65 03 02 89 13 04 02 00 01 04 02 00 02 04 02 7f ff 05 03 03 e9 80 05 03 03 ea 01 06 12 01 02 00 2a 02 08 66 6f 72 74 79 74 77 6f 03 02 10 92 .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } REPEAT_STRUCT={ {1001,true,R_A}, {1002,false,R_B} } MOO_NEST={ FOO=42 BAR="fortytwo" BAZ={4242,false} } }
|
||||
=== end t8l8v ordered test_enc_dec[3]
|
||||
|
||||
=== start t8l8v ordered test_enc_dec[4]
|
||||
encoded: GOO={ FOO=17 BAR="gooei" GOO_NEST={ { VAL=0x123456789abcdef MOO_NEST={ FOO=11 BAR="eleven" BAZ={1111,true} } }, { MOO_NEST={ FOO=12 BAR="twelve" BAZ={1212,false} } } } }
|
||||
myproto_msg_enc() rc = 0
|
||||
07 01 02 00 11 02 05 67 6f 6f 65 69 08 1c 07 08 01 23 45 67 89 ab cd ef 06 10 01 02 00 0b 02 06 65 6c 65 76 65 6e 03 02 84 57 08 12 06 10 01 02 00 0c 02 06 74 77 65 6c 76 65 03 02 04 bc .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: GOO={ FOO=17 BAR="gooei" GOO_NEST={ { VAL=0x123456789abcdef MOO_NEST={ FOO=11 BAR="eleven" BAZ={1111,true} } }, { MOO_NEST={ FOO=12 BAR="twelve" BAZ={1212,false} } } } }
|
||||
=== end t8l8v ordered test_enc_dec[4]
|
||||
|
||||
=== start t8l8v unordered test_enc_dec[0]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 01 02 00 17 02 0b 74 77 65 6e 74 79 74 68 72 65 65 .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" }
|
||||
=== end t8l8v unordered test_enc_dec[0]
|
||||
|
||||
=== start t8l8v unordered test_enc_dec[1]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 01 02 00 17 02 0b 74 77 65 6e 74 79 74 68 72 65 65 03 02 89 13 .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} }
|
||||
=== end t8l8v unordered test_enc_dec[1]
|
||||
|
||||
=== start t8l8v unordered test_enc_dec[2]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 01 02 00 17 02 0b 74 77 65 6e 74 79 74 68 72 65 65 03 02 89 13 04 02 00 01 04 02 00 02 04 02 7f ff .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } }
|
||||
=== end t8l8v unordered test_enc_dec[2]
|
||||
|
||||
=== start t8l8v unordered test_enc_dec[3]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } REPEAT_STRUCT={ {1001,true,R_A}, {1002,false,R_B} } MOO_NEST={ FOO=42 BAR="fortytwo" BAZ={4242,false} } }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 01 02 00 17 02 0b 74 77 65 6e 74 79 74 68 72 65 65 03 02 89 13 04 02 00 01 04 02 00 02 04 02 7f ff 05 03 03 e9 80 05 03 03 ea 01 06 12 01 02 00 2a 02 08 66 6f 72 74 79 74 77 6f 03 02 10 92 .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } REPEAT_STRUCT={ {1001,true,R_A}, {1002,false,R_B} } MOO_NEST={ FOO=42 BAR="fortytwo" BAZ={4242,false} } }
|
||||
=== end t8l8v unordered test_enc_dec[3]
|
||||
|
||||
=== start t8l8v unordered test_enc_dec[4]
|
||||
encoded: GOO={ FOO=17 BAR="gooei" GOO_NEST={ { VAL=0x123456789abcdef MOO_NEST={ FOO=11 BAR="eleven" BAZ={1111,true} } }, { MOO_NEST={ FOO=12 BAR="twelve" BAZ={1212,false} } } } }
|
||||
myproto_msg_enc() rc = 0
|
||||
07 01 02 00 11 02 05 67 6f 6f 65 69 08 1c 07 08 01 23 45 67 89 ab cd ef 06 10 01 02 00 0b 02 06 65 6c 65 76 65 6e 03 02 84 57 08 12 06 10 01 02 00 0c 02 06 74 77 65 6c 76 65 03 02 04 bc .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: GOO={ FOO=17 BAR="gooei" GOO_NEST={ { VAL=0x123456789abcdef MOO_NEST={ FOO=11 BAR="eleven" BAZ={1111,true} } }, { MOO_NEST={ FOO=12 BAR="twelve" BAZ={1212,false} } } } }
|
||||
=== end t8l8v unordered test_enc_dec[4]
|
||||
|
||||
=== start t16l16v ordered test_enc_dec[0]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 00 01 00 02 00 17 00 02 00 0b 74 77 65 6e 74 79 74 68 72 65 65 .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" }
|
||||
=== end t16l16v ordered test_enc_dec[0]
|
||||
|
||||
=== start t16l16v ordered test_enc_dec[1]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 00 01 00 02 00 17 00 02 00 0b 74 77 65 6e 74 79 74 68 72 65 65 00 03 00 02 89 13 .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} }
|
||||
=== end t16l16v ordered test_enc_dec[1]
|
||||
|
||||
=== start t16l16v ordered test_enc_dec[2]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 00 01 00 02 00 17 00 02 00 0b 74 77 65 6e 74 79 74 68 72 65 65 00 03 00 02 89 13 00 04 00 02 00 01 00 04 00 02 00 02 00 04 00 02 7f ff .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } }
|
||||
=== end t16l16v ordered test_enc_dec[2]
|
||||
|
||||
=== start t16l16v ordered test_enc_dec[3]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } REPEAT_STRUCT={ {1001,true,R_A}, {1002,false,R_B} } MOO_NEST={ FOO=42 BAR="fortytwo" BAZ={4242,false} } }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 00 01 00 02 00 17 00 02 00 0b 74 77 65 6e 74 79 74 68 72 65 65 00 03 00 02 89 13 00 04 00 02 00 01 00 04 00 02 00 02 00 04 00 02 7f ff 00 05 00 03 03 e9 80 00 05 00 03 03 ea 01 00 06 00 18 00 01 00 02 00 2a 00 02 00 08 66 6f 72 74 79 74 77 6f 00 03 00 02 10 92 .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } REPEAT_STRUCT={ {1001,true,R_A}, {1002,false,R_B} } MOO_NEST={ FOO=42 BAR="fortytwo" BAZ={4242,false} } }
|
||||
=== end t16l16v ordered test_enc_dec[3]
|
||||
|
||||
=== start t16l16v ordered test_enc_dec[4]
|
||||
encoded: GOO={ FOO=17 BAR="gooei" GOO_NEST={ { VAL=0x123456789abcdef MOO_NEST={ FOO=11 BAR="eleven" BAZ={1111,true} } }, { MOO_NEST={ FOO=12 BAR="twelve" BAZ={1212,false} } } } }
|
||||
myproto_msg_enc() rc = 0
|
||||
07 00 01 00 02 00 11 00 02 00 05 67 6f 6f 65 69 00 08 00 26 00 07 00 08 01 23 45 67 89 ab cd ef 00 06 00 16 00 01 00 02 00 0b 00 02 00 06 65 6c 65 76 65 6e 00 03 00 02 84 57 00 08 00 1a 00 06 00 16 00 01 00 02 00 0c 00 02 00 06 74 77 65 6c 76 65 00 03 00 02 04 bc .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: GOO={ FOO=17 BAR="gooei" GOO_NEST={ { VAL=0x123456789abcdef MOO_NEST={ FOO=11 BAR="eleven" BAZ={1111,true} } }, { MOO_NEST={ FOO=12 BAR="twelve" BAZ={1212,false} } } } }
|
||||
=== end t16l16v ordered test_enc_dec[4]
|
||||
|
||||
=== start t16l16v unordered test_enc_dec[0]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 00 01 00 02 00 17 00 02 00 0b 74 77 65 6e 74 79 74 68 72 65 65 .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" }
|
||||
=== end t16l16v unordered test_enc_dec[0]
|
||||
|
||||
=== start t16l16v unordered test_enc_dec[1]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 00 01 00 02 00 17 00 02 00 0b 74 77 65 6e 74 79 74 68 72 65 65 00 03 00 02 89 13 .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} }
|
||||
=== end t16l16v unordered test_enc_dec[1]
|
||||
|
||||
=== start t16l16v unordered test_enc_dec[2]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 00 01 00 02 00 17 00 02 00 0b 74 77 65 6e 74 79 74 68 72 65 65 00 03 00 02 89 13 00 04 00 02 00 01 00 04 00 02 00 02 00 04 00 02 7f ff .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } }
|
||||
=== end t16l16v unordered test_enc_dec[2]
|
||||
|
||||
=== start t16l16v unordered test_enc_dec[3]
|
||||
encoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } REPEAT_STRUCT={ {1001,true,R_A}, {1002,false,R_B} } MOO_NEST={ FOO=42 BAR="fortytwo" BAZ={4242,false} } }
|
||||
myproto_msg_enc() rc = 0
|
||||
01 00 01 00 02 00 17 00 02 00 0b 74 77 65 6e 74 79 74 68 72 65 65 00 03 00 02 89 13 00 04 00 02 00 01 00 04 00 02 00 02 00 04 00 02 7f ff 00 05 00 03 03 e9 80 00 05 00 03 03 ea 01 00 06 00 18 00 01 00 02 00 2a 00 02 00 08 66 6f 72 74 79 74 77 6f 00 03 00 02 10 92 .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: MOO={ FOO=23 BAR="twentythree" BAZ={2323,true} REPEAT_INT={ 1, 2, 32767 } REPEAT_STRUCT={ {1001,true,R_A}, {1002,false,R_B} } MOO_NEST={ FOO=42 BAR="fortytwo" BAZ={4242,false} } }
|
||||
=== end t16l16v unordered test_enc_dec[3]
|
||||
|
||||
=== start t16l16v unordered test_enc_dec[4]
|
||||
encoded: GOO={ FOO=17 BAR="gooei" GOO_NEST={ { VAL=0x123456789abcdef MOO_NEST={ FOO=11 BAR="eleven" BAZ={1111,true} } }, { MOO_NEST={ FOO=12 BAR="twelve" BAZ={1212,false} } } } }
|
||||
myproto_msg_enc() rc = 0
|
||||
07 00 01 00 02 00 11 00 02 00 05 67 6f 6f 65 69 00 08 00 26 00 07 00 08 01 23 45 67 89 ab cd ef 00 06 00 16 00 01 00 02 00 0b 00 02 00 06 65 6c 65 76 65 6e 00 03 00 02 84 57 00 08 00 1a 00 06 00 16 00 01 00 02 00 0c 00 02 00 06 74 77 65 6c 76 65 00 03 00 02 04 bc .
|
||||
myproto_msg_dec() rc = 0
|
||||
decoded: GOO={ FOO=17 BAR="gooei" GOO_NEST={ { VAL=0x123456789abcdef MOO_NEST={ FOO=11 BAR="eleven" BAZ={1111,true} } }, { MOO_NEST={ FOO=12 BAR="twelve" BAZ={1212,false} } } } }
|
||||
=== end t16l16v unordered test_enc_dec[4]
|
@@ -199,21 +199,21 @@ int enc_to_str_repeat_struct(char *buf, size_t buflen, void *encode_from)
|
||||
|
||||
struct osmo_tlv_coding nested_inner_msg_ies[] = {
|
||||
{
|
||||
.tag = TAG_FOO,
|
||||
.ti = { TAG_FOO },
|
||||
.dec_func = dec_u16,
|
||||
.enc_func = enc_u16,
|
||||
.enc_to_str_func = enc_to_str_u16,
|
||||
.memb_ofs = offsetof(struct nested_inner_msg, foo),
|
||||
},
|
||||
{
|
||||
.tag = TAG_BAR,
|
||||
.ti = { TAG_BAR },
|
||||
.dec_func = dec_bar,
|
||||
.enc_func = enc_bar,
|
||||
.enc_to_str_func = enc_to_str_bar,
|
||||
.memb_ofs = offsetof(struct nested_inner_msg, bar),
|
||||
},
|
||||
{
|
||||
.tag = TAG_BAZ,
|
||||
.ti = { TAG_BAZ },
|
||||
.dec_func = dec_baz,
|
||||
.enc_func = enc_baz,
|
||||
.enc_to_str_func = enc_to_str_baz,
|
||||
@@ -224,21 +224,21 @@ struct osmo_tlv_coding nested_inner_msg_ies[] = {
|
||||
|
||||
struct osmo_tlv_coding msg_ie_coding[] = {
|
||||
{
|
||||
.tag = TAG_FOO,
|
||||
.ti = { TAG_FOO },
|
||||
.dec_func = dec_u16,
|
||||
.enc_func = enc_u16,
|
||||
.enc_to_str_func = enc_to_str_u16,
|
||||
.memb_ofs = offsetof(struct decoded_msg, foo),
|
||||
},
|
||||
{
|
||||
.tag = TAG_BAR,
|
||||
.ti = { TAG_BAR },
|
||||
.dec_func = dec_bar,
|
||||
.enc_func = enc_bar,
|
||||
.enc_to_str_func = enc_to_str_bar,
|
||||
.memb_ofs = offsetof(struct decoded_msg, bar),
|
||||
},
|
||||
{
|
||||
.tag = TAG_BAZ,
|
||||
.ti = { TAG_BAZ },
|
||||
.dec_func = dec_baz,
|
||||
.enc_func = enc_baz,
|
||||
.enc_to_str_func = enc_to_str_baz,
|
||||
@@ -247,7 +247,7 @@ struct osmo_tlv_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,
|
||||
@@ -258,7 +258,7 @@ struct osmo_tlv_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,
|
||||
@@ -269,7 +269,7 @@ struct osmo_tlv_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,
|
||||
|
@@ -28,7 +28,7 @@
|
||||
void *ctx;
|
||||
|
||||
struct ie {
|
||||
int tag;
|
||||
struct osmo_tlv_tag_inst ti;
|
||||
const char *val;
|
||||
};
|
||||
|
||||
@@ -43,7 +43,7 @@ struct msgb *test_tlv_enc(const struct osmo_tlv_cfg *cfg, const struct ie *ies)
|
||||
|
||||
for (ie = ies; ie->val; ie++) {
|
||||
/* put header without knowing length yet */
|
||||
OSMO_ASSERT(osmo_tlv_put_tl(&tlv, ie->tag, 0) == 0);
|
||||
OSMO_ASSERT(osmo_tlv_put_tli(&tlv, &ie->ti, 0) == 0);
|
||||
/* put value data, as much as desired */
|
||||
msgb_put(tlv.dst, osmo_hexparse(ie->val, tlv.dst->tail, msgb_tailroom(tlv.dst)));
|
||||
/* update header len from amount of written data */
|
||||
@@ -75,7 +75,10 @@ void test_tlv_dec(const struct osmo_tlv_cfg *cfg, const struct ie *ies, struct m
|
||||
/* end of TLV structure? */
|
||||
if (!tlv.val)
|
||||
break;
|
||||
printf(" T=%d L=%zu v=%s\n", tlv.tag, tlv.len, osmo_hexdump_nospc(tlv.val, tlv.len));
|
||||
printf(" T=%d L=%zu", tlv.tag, tlv.len);
|
||||
if (tlv.instance != OSMO_TLV_NO_INSTANCE)
|
||||
printf(" I=%u", tlv.instance);
|
||||
printf(" v=%s\n", osmo_hexdump_nospc(tlv.val, tlv.len));
|
||||
if (tlv.tag != ie->tag) {
|
||||
printf(" ERROR loading TLV structure: expected tag %d, got tag %d\n", ie->tag, tlv.tag);
|
||||
exit(1);
|
||||
@@ -102,22 +105,33 @@ void test_tlv_peek(const struct osmo_tlv_cfg *cfg, const struct ie *ies, struct
|
||||
ie = ies;
|
||||
while (1) {
|
||||
int rc;
|
||||
int next_tag = osmo_tlv_load_peek_tag(&tlv);
|
||||
if (next_tag == -ENOENT)
|
||||
printf(" peek T=-ENOENT\n");
|
||||
else
|
||||
printf(" peek T=%d\n", next_tag);
|
||||
unsigned int next_tag;
|
||||
unsigned int next_instance;
|
||||
rc = osmo_tlv_load_peek_tag(&tlv, &next_tag, &next_instance);
|
||||
if (rc == -ENOENT) {
|
||||
printf(" peek rc=-ENOENT\n");
|
||||
} else {
|
||||
printf(" peek T=%u", next_tag);
|
||||
if (next_instance != OSMO_TLV_NO_INSTANCE)
|
||||
printf(" I=%u", next_instance);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (ie->val && next_tag != ie->tag) {
|
||||
printf(" ERROR peeking tag: expected tag %d, got tag %d\n", ie->tag, next_tag);
|
||||
printf(" ERROR peeking tag: expected tag %u, got tag %u\n", ie->tag, next_tag);
|
||||
exit(1);
|
||||
}
|
||||
if (!ie->val && next_tag != -ENOENT) {
|
||||
printf(" ERROR peeking tag: expected -ENOENT, got tag %d\n", next_tag);
|
||||
if (ie->val && ie->instance && next_instance != ie->instance) {
|
||||
printf(" ERROR peeking tag: expected instance %u, got instance %u\n", ie->instance,
|
||||
next_instance);
|
||||
exit(1);
|
||||
}
|
||||
if (!ie->val && rc != -ENOENT) {
|
||||
printf(" ERROR peeking tag: expected -ENOENT, got rc=%d, tag %u\n", rc, next_tag);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (next_tag == -ENOENT)
|
||||
if (rc == -ENOENT)
|
||||
break;
|
||||
|
||||
/* go to the next TLV */
|
||||
@@ -151,7 +165,7 @@ void test_tlv_dec_by_tag(const struct osmo_tlv_cfg *cfg, const struct ie *ies, s
|
||||
for (ie = last_ie; ie >= ies; ie--) {
|
||||
/* each time, look from the beginning */
|
||||
osmo_tlv_load_start(&tlv);
|
||||
rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag);
|
||||
rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag, ie->instance ? : OSMO_TLV_NO_INSTANCE);
|
||||
if (rc) {
|
||||
printf(" ERROR loading TLV structure: osmo_tlv_load_next_by_tag(%d) rc = %d\n", ie->tag, rc);
|
||||
exit(1);
|
||||
@@ -167,9 +181,13 @@ void test_tlv_dec_by_tag(const struct osmo_tlv_cfg *cfg, const struct ie *ies, s
|
||||
}
|
||||
if (strcmp(ie->val, osmo_hexdump_nospc(tlv.val, tlv.len))) {
|
||||
while (1) {
|
||||
printf(" (mismatch: T=%d L=%zu v=%s, checking for another occurrence of T=%d)\n",
|
||||
tlv.tag, tlv.len, osmo_hexdump_nospc(tlv.val, tlv.len), tlv.tag);
|
||||
rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag);
|
||||
printf(" (mismatch: T=%u L=%zu", tlv.tag, tlv.len);
|
||||
if (tlv.instance != OSMO_TLV_NO_INSTANCE)
|
||||
printf(" I=%u", tlv.instance);
|
||||
printf(" v=%s, checking for another occurrence of T=%d)\n",
|
||||
osmo_hexdump_nospc(tlv.val, tlv.len), tlv.tag);
|
||||
|
||||
rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag, ie->instance ? : OSMO_TLV_NO_INSTANCE);
|
||||
if (rc || !tlv.val) {
|
||||
printf(" ERROR val not found\n");
|
||||
exit(1);
|
||||
@@ -179,7 +197,10 @@ void test_tlv_dec_by_tag(const struct osmo_tlv_cfg *cfg, const struct ie *ies, s
|
||||
}
|
||||
}
|
||||
}
|
||||
printf(" T=%d L=%zu v=%s\n", tlv.tag, tlv.len, osmo_hexdump_nospc(tlv.val, tlv.len));
|
||||
printf(" T=%d L=%zu", tlv.tag, tlv.len);
|
||||
if (tlv.instance != OSMO_TLV_NO_INSTANCE)
|
||||
printf(" I=%u", tlv.instance);
|
||||
printf(" v=%s\n", osmo_hexdump_nospc(tlv.val, tlv.len));
|
||||
}
|
||||
|
||||
printf("- decoding every second tag:\n");
|
||||
@@ -191,7 +212,7 @@ void test_tlv_dec_by_tag(const struct osmo_tlv_cfg *cfg, const struct ie *ies, s
|
||||
if (!ie->val)
|
||||
break;
|
||||
|
||||
rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag);
|
||||
rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag, ie->instance ? : OSMO_TLV_NO_INSTANCE);
|
||||
if (rc) {
|
||||
printf(" ERROR loading TLV structure: osmo_tlv_load_next_by_tag(%d) rc = %d\n", ie->tag, rc);
|
||||
exit(1);
|
||||
@@ -207,9 +228,13 @@ void test_tlv_dec_by_tag(const struct osmo_tlv_cfg *cfg, const struct ie *ies, s
|
||||
}
|
||||
if (strcmp(ie->val, osmo_hexdump_nospc(tlv.val, tlv.len))) {
|
||||
while (1) {
|
||||
printf(" (mismatch: T=%d L=%zu v=%s, checking for another occurrence of T=%d)\n",
|
||||
tlv.tag, tlv.len, osmo_hexdump_nospc(tlv.val, tlv.len), tlv.tag);
|
||||
rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag);
|
||||
printf(" (mismatch: T=%u L=%zu", tlv.tag, tlv.len);
|
||||
if (tlv.instance != OSMO_TLV_NO_INSTANCE)
|
||||
printf(" I=%u", tlv.instance);
|
||||
printf(" v=%s, checking for another occurrence of T=%d)\n",
|
||||
osmo_hexdump_nospc(tlv.val, tlv.len), tlv.tag);
|
||||
|
||||
rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag, ie->instance ? : OSMO_TLV_NO_INSTANCE);
|
||||
if (rc || !tlv.val) {
|
||||
printf(" ERROR val not found\n");
|
||||
exit(1);
|
||||
@@ -219,14 +244,17 @@ void test_tlv_dec_by_tag(const struct osmo_tlv_cfg *cfg, const struct ie *ies, s
|
||||
}
|
||||
}
|
||||
}
|
||||
printf(" T=%d L=%zu v=%s\n", tlv.tag, tlv.len, osmo_hexdump_nospc(tlv.val, tlv.len));
|
||||
printf(" T=%d L=%zu", tlv.tag, tlv.len);
|
||||
if (tlv.instance != OSMO_TLV_NO_INSTANCE)
|
||||
printf(" I=%u", tlv.instance);
|
||||
printf(" v=%s\n", osmo_hexdump_nospc(tlv.val, tlv.len));
|
||||
}
|
||||
|
||||
printf("- enforcing order: without restart, a past tag is not parsed again:\n");
|
||||
/* Try to read the first tag, expect that it isn't found because we're already halfway in the message data */
|
||||
ie = ies;
|
||||
rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag);
|
||||
printf(" osmo_tlv_load_next_by_tag(%d) rc=", ie->tag);
|
||||
rc = osmo_tlv_load_next_by_tag(&tlv, ie->tag, ie->instance ? : OSMO_TLV_NO_INSTANCE);
|
||||
printf(" osmo_tlv_load_next_by_tag(%u, %u) rc=%d", ie->tag, ie->instance ? : OSMO_TLV_NO_INSTANCE, rc);
|
||||
if (rc == -ENOENT) {
|
||||
printf("-ENOENT\n");
|
||||
} else {
|
||||
@@ -440,7 +468,8 @@ int txlxv_load_tl(struct osmo_tlv_load *tlv, const uint8_t *src_data, size_t src
|
||||
}
|
||||
|
||||
/* Example of defining a variable TL, where size of T and L depend on the actual tag and length values: store. */
|
||||
int txlxv_store_tl(uint8_t *dst_data, size_t dst_data_avail, unsigned int tag, size_t len, struct osmo_tlv_put *tlv)
|
||||
int txlxv_store_tl(uint8_t *dst_data, size_t dst_data_avail, unsigned int tag, unsigned int instance, size_t len,
|
||||
struct osmo_tlv_put *tlv)
|
||||
{
|
||||
uint8_t *pos = dst_data;
|
||||
uint8_t *end = dst_data + dst_data_avail;
|
||||
@@ -491,7 +520,92 @@ const struct osmo_tlv_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_tlv_load *tlv, const uint8_t *src_data, size_t src_data_len)
|
||||
{
|
||||
/* already validated in next_tl_valid(): src_data_len >= cfg->tl_min_size == 2. */
|
||||
tlv->tag = src_data[0];
|
||||
tlv->len = src_data[1];
|
||||
|
||||
switch (tlv->tag) {
|
||||
/* All tags that are TLIV go here */
|
||||
case 5:
|
||||
case 7:
|
||||
case 9:
|
||||
if (src_data_len < 3)
|
||||
return -ENOSPC;
|
||||
tlv->instance = src_data[2];
|
||||
tlv->val = src_data + 3;
|
||||
return 0;
|
||||
default:
|
||||
tlv->val = src_data + 2;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int tliv_store_tl(uint8_t *dst_data, size_t dst_data_avail, unsigned int tag, unsigned int instance, size_t len,
|
||||
struct osmo_tlv_put *tlv)
|
||||
{
|
||||
if (tag > UINT8_MAX)
|
||||
return -EINVAL;
|
||||
if (len > UINT8_MAX)
|
||||
return -EMSGSIZE;
|
||||
if (dst_data_avail < 2)
|
||||
return -ENOSPC;
|
||||
|
||||
dst_data[0] = tag;
|
||||
dst_data[1] = len;
|
||||
|
||||
switch (tag) {
|
||||
/* All tags that are TLIV go here */
|
||||
case 5:
|
||||
case 7:
|
||||
case 9:
|
||||
if (dst_data_avail < 3)
|
||||
return -ENOSPC;
|
||||
if (instance > UINT8_MAX)
|
||||
return -EINVAL;
|
||||
dst_data[2] = instance;
|
||||
return 3;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
const struct osmo_tlv_cfg osmo_tliv_cfg = {
|
||||
.tl_min_size = 2,
|
||||
.load_tl = tliv_load_tl,
|
||||
.store_tl = tliv_store_tl,
|
||||
};
|
||||
|
||||
struct ie tliv_test1[] = {
|
||||
/* TLV */
|
||||
{ 1, "0002" },
|
||||
/* TLIV */
|
||||
{ 5, "0017", 1 },
|
||||
/* TLIV */
|
||||
{ 5, "0018", 2 },
|
||||
/* TLIV */
|
||||
{ 5, "0019", 3 },
|
||||
/* TLV */
|
||||
{ 6, "001a" },
|
||||
/* TLIV */
|
||||
{ 7, "001b", 1 },
|
||||
/* TLIV */
|
||||
{ 9, "001c", 1 },
|
||||
{}
|
||||
};
|
||||
|
||||
struct ie *tliv_tests[] = {
|
||||
tliv_test1,
|
||||
};
|
||||
|
||||
void test_tliv()
|
||||
{
|
||||
test_tlv(__func__, tliv_tests, ARRAY_SIZE(tliv_tests), &osmo_tliv_cfg);
|
||||
}
|
||||
|
||||
int main()
|
||||
@@ -502,6 +616,7 @@ int main()
|
||||
test_t8l8v();
|
||||
test_t16l16v();
|
||||
test_txlxv();
|
||||
test_tliv();
|
||||
|
||||
talloc_free(ctx);
|
||||
return 0;
|
||||
|
Reference in New Issue
Block a user