summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2021-10-07 21:32:10 +0200
committerAleksander Morgado <aleksander@aleksander.es>2021-10-12 22:27:12 +0200
commit56983e658f961825ac948fd3e544108dd09b4d5f (patch)
treef0c9132ecebc4d7db667fdeeb6027d5709688114
parent8c781c81b1a18ba206dbc5df3595363f4f485c4c (diff)
libmbim-glib: new MbimTlv generic type
The Microsoft Extensions define a new generic TLV type that allows including any kind of data in it: from strings, to arrays of uints, to more complex types. We define support for the generic 'tlv' type and the generic 'tlv-list' type, which allow implementing the "unnamed IEs" that are appended to some new messages in the MS extensions. And we also define support for a more specific 'tlv-string', used exclusively when the TLVs are part of the named fields, so that we can provide strings in our libmbim-glib APIs, instead of requiring the user to build MbimTlv instances.
-rw-r--r--build-aux/mbim-codegen/Message.py143
-rw-r--r--build-aux/mbim-codegen/utils.py1
-rwxr-xr-xdata/mbim-service-ms-basic-connect-extensions.json12
-rwxr-xr-xdocs/reference/libmbim-glib/libmbim-glib-common.sections20
-rw-r--r--docs/reference/libmbim-glib/libmbim-glib-docs.xml1
-rw-r--r--src/libmbim-glib/generated/meson.build2
-rw-r--r--src/libmbim-glib/libmbim-glib.h1
-rw-r--r--src/libmbim-glib/mbim-message-private.h22
-rw-r--r--src/libmbim-glib/mbim-message.c162
-rw-r--r--src/libmbim-glib/mbim-tlv-private.h69
-rw-r--r--src/libmbim-glib/mbim-tlv.c259
-rw-r--r--src/libmbim-glib/mbim-tlv.h224
-rw-r--r--src/libmbim-glib/meson.build2
-rw-r--r--src/libmbim-glib/test/test-message-builder.c237
-rw-r--r--src/libmbim-glib/test/test-message-parser.c254
-rw-r--r--src/mbimcli/mbimcli-ms-basic-connect-extensions.c2
16 files changed, 1402 insertions, 9 deletions
diff --git a/build-aux/mbim-codegen/Message.py b/build-aux/mbim-codegen/Message.py
index 94c522b..29de874 100644
--- a/build-aux/mbim-codegen/Message.py
+++ b/build-aux/mbim-codegen/Message.py
@@ -86,6 +86,12 @@ def validate_fields(fields):
pass
elif field['format'] == 'ipv6-array':
flag_always_read_field(fields, field['array-size-field'])
+ elif field['format'] == 'tlv':
+ pass
+ elif field['format'] == 'tlv-string':
+ pass
+ elif field['format'] == 'tlv-list':
+ pass
else:
raise ValueError('Cannot handle field type \'%s\'' % field['format'])
@@ -278,6 +284,12 @@ class Message:
inner_template = (' * @${field}: (in): the \'${name}\' field, given as a #MbimIPv6.\n')
elif field['format'] == 'ipv6-array':
inner_template = (' * @${field}: (in)(array zero-terminated=1)(element-type MbimIPv6): the \'${name}\' field, given as an array of #MbimIPv6 items.\n')
+ elif field['format'] == 'tlv':
+ inner_template = (' * @${field}: (in)(transfer none): the \'${name}\' field, given as a #${struct} item.\n')
+ elif field['format'] == 'tlv-string':
+ inner_template = (' * @${field}: (in): the \'${name}\' field, given as a string.\n')
+ elif field['format'] == 'tlv-list':
+ inner_template = (' * @${field}: (in)(element-type MbimTlv)(transfer none): the \'${name}\' field, given as a list of #${struct} items.\n')
template += (string.Template(inner_template).substitute(translations))
@@ -340,6 +352,12 @@ class Message:
inner_template = (' const MbimIPv6 *${field},\n')
elif field['format'] == 'ipv6-array':
inner_template = (' const MbimIPv6 *${field},\n')
+ elif field['format'] == 'tlv':
+ inner_template = (' const MbimTlv *${field},\n')
+ elif field['format'] == 'tlv-string':
+ inner_template = (' const gchar *${field},\n')
+ elif field['format'] == 'tlv-list':
+ inner_template = (' const GList *${field},\n')
template += (string.Template(inner_template).substitute(translations))
@@ -401,6 +419,12 @@ class Message:
inner_template = (' const MbimIPv6 *${field},\n')
elif field['format'] == 'ipv6-array':
inner_template = (' const MbimIPv6 *${field},\n')
+ elif field['format'] == 'tlv':
+ inner_template = (' const MbimTlv *${field},\n')
+ elif field['format'] == 'tlv-string':
+ inner_template = (' const gchar *${field},\n')
+ elif field['format'] == 'tlv-list':
+ inner_template = (' const GList *${field},\n')
template += (string.Template(inner_template).substitute(translations))
@@ -477,6 +501,13 @@ class Message:
inner_template += (' _mbim_message_command_builder_append_ipv6 (builder, ${field}, TRUE);\n')
elif field['format'] == 'ipv6-array':
inner_template += (' _mbim_message_command_builder_append_ipv6_array (builder, ${field}, ${array_size_field});\n')
+ elif field['format'] == 'tlv':
+ inner_template += (' _mbim_message_command_builder_append_tlv (builder, ${field});\n')
+ elif field['format'] == 'tlv-string':
+ inner_template += (' _mbim_message_command_builder_append_tlv_string (builder, ${field});\n')
+ elif field['format'] == 'tlv-list':
+ inner_template += (' _mbim_message_command_builder_append_tlv_list (builder, ${field});\n')
+
else:
raise ValueError('Cannot handle field type \'%s\'' % field['format'])
@@ -557,6 +588,12 @@ class Message:
inner_template = (' * @out_${field}: (out)(optional)(transfer none): return location for a #MbimIPv6, or %NULL if the \'${name}\' field is not needed. Do not free the returned value, it is owned by @message.\n')
elif field['format'] == 'ipv6-array':
inner_template = (' * @out_${field}: (out)(optional)(transfer full)(array zero-terminated=1)(element-type MbimIPv6): return location for a newly allocated array of #MbimIPv6 items, or %NULL if the \'${name}\' field is not needed. Free the returned value with g_free().\n')
+ elif field['format'] == 'tlv':
+ inner_template = (' * @out_${field}: (out)(optional)(transfer full): return location for a newly allocated #MbimTlv, or %NULL if the \'${name}\' field is not needed. Free the returned value with mbim_tlv_unref().\n')
+ elif field['format'] == 'tlv-string':
+ inner_template = (' * @out_${field}: (out)(optional)(transfer full): return location for a newly allocated string, or %NULL if the \'${name}\' field is not needed. Free the returned value with g_free().\n')
+ elif field['format'] == 'tlv-list':
+ inner_template = (' * @out_${field}: (out)(optional)(element-type MbimTlv)(transfer full): return location for a newly allocated list of #MbimTlv items, or %NULL if the \'${name}\' field is not needed. Free the returned value with g_list_free_full() using mbim_tlv_unref() as #GDestroyNotify.\n')
template += (string.Template(inner_template).substitute(translations))
@@ -618,6 +655,12 @@ class Message:
inner_template = (' const MbimIPv6 **out_${field},\n')
elif field['format'] == 'ipv6-array':
inner_template = (' MbimIPv6 **out_${field},\n')
+ elif field['format'] == 'tlv':
+ inner_template = (' MbimTlv **out_${field},\n')
+ elif field['format'] == 'tlv-string':
+ inner_template = (' gchar **out_${field},\n')
+ elif field['format'] == 'tlv-list':
+ inner_template = (' GList **out_${field},\n')
else:
raise ValueError('Cannot handle field type \'%s\'' % field['format'])
@@ -679,6 +722,12 @@ class Message:
inner_template = (' const MbimIPv6 **out_${field},\n')
elif field['format'] == 'ipv6-array':
inner_template = (' MbimIPv6 **out_${field},\n')
+ elif field['format'] == 'tlv':
+ inner_template = (' MbimTlv **out_${field},\n')
+ elif field['format'] == 'tlv-string':
+ inner_template = (' gchar **out_${field},\n')
+ elif field['format'] == 'tlv-list':
+ inner_template = (' GList **out_${field},\n')
template += (string.Template(inner_template).substitute(translations))
@@ -727,6 +776,15 @@ class Message:
elif field['format'] == 'ipv6-array':
count_allocated_variables += 1
inner_template = (' MbimIPv6 *_${field} = NULL;\n')
+ elif field['format'] == 'tlv':
+ count_allocated_variables += 1
+ inner_template = (' MbimTlv *_${field} = NULL;\n')
+ elif field['format'] == 'tlv-string':
+ count_allocated_variables += 1
+ inner_template = (' gchar *_${field} = NULL;\n')
+ elif field['format'] == 'tlv-list':
+ count_allocated_variables += 1
+ inner_template = (' GList *_${field} = NULL;\n')
template += (string.Template(inner_template).substitute(translations))
if message_type == 'response':
@@ -1022,6 +1080,42 @@ class Message:
' if ((out_${field} != NULL) && !_mbim_message_read_ipv6_array (message, _${array_size_field}, offset, &_${field}, error))\n'
' goto out;\n'
' offset += 4;\n')
+ elif field['format'] == 'tlv':
+ inner_template += (
+ ' MbimTlv *tmp = NULL;\n'
+ ' guint32 bytes_read = 0;\n'
+ '\n'
+ ' if (!_mbim_message_read_tlv (message, offset, &tmp, &bytes_read, error))\n'
+ ' goto out;\n'
+ ' if (out_${field} != NULL)\n'
+ ' _${field} = tmp;\n'
+ ' else\n'
+ ' mbim_tlv_unref (tmp);\n'
+ ' offset += bytes_read;\n')
+ elif field['format'] == 'tlv-string':
+ inner_template += (
+ ' gchar *tmp = NULL;\n'
+ ' guint32 bytes_read = 0;\n'
+ '\n'
+ ' if (!_mbim_message_read_tlv_string (message, offset, &tmp, &bytes_read, error))\n'
+ ' goto out;\n'
+ ' if (out_${field} != NULL)\n'
+ ' _${field} = tmp;\n'
+ ' else\n'
+ ' g_free (tmp);\n'
+ ' offset += bytes_read;\n')
+ elif field['format'] == 'tlv-list':
+ inner_template += (
+ ' GList *tmp = NULL;\n'
+ ' guint32 bytes_read = 0;\n'
+ '\n'
+ ' if (!_mbim_message_read_tlv_list (message, offset, &tmp, &bytes_read, error))\n'
+ ' goto out;\n'
+ ' if (out_${field} != NULL)\n'
+ ' _${field} = tmp;\n'
+ ' else\n'
+ ' g_list_free_full (tmp, (GDestroyNotify)mbim_tlv_unref);\n'
+ ' offset += bytes_read;\n')
inner_template += (
' }\n')
@@ -1053,7 +1147,10 @@ class Message:
field['format'] == 'ref-struct-array' or \
field['format'] == 'ms-struct-array' or \
field['format'] == 'ipv4-array' or \
- field['format'] == 'ipv6-array':
+ field['format'] == 'ipv6-array' or \
+ field['format'] == 'tlv' or \
+ field['format'] == 'tlv-string' or \
+ field['format'] == 'tlv-list':
inner_template = (' if (out_${field} != NULL)\n'
' *out_${field} = _${field};\n')
template += (string.Template(inner_template).substitute(translations))
@@ -1066,7 +1163,8 @@ class Message:
inner_template = ''
if field['format'] == 'string' or \
field['format'] == 'ipv4-array' or \
- field['format'] == 'ipv6-array':
+ field['format'] == 'ipv6-array' or \
+ field['format'] == 'tlv-string':
inner_template = (' g_free (_${field});\n')
elif field['format'] == 'string-array':
inner_template = (' g_strfreev (_${field});\n')
@@ -1074,6 +1172,10 @@ class Message:
inner_template = (' ${struct_underscore}_free (_${field});\n')
elif field['format'] == 'struct-array' or field['format'] == 'ref-struct-array' or field['format'] == 'ms-struct-array':
inner_template = (' ${struct_underscore}_array_free (_${field});\n')
+ elif field['format'] == 'tlv':
+ inner_template = (' mbim_tlv_unref (_${field});\n')
+ elif field['format'] == 'tlv-list':
+ inner_template = (' g_list_free_full (_${field}, (GDestroyNotify)mbim_tlv_unref);\n')
template += (string.Template(inner_template).substitute(translations))
template += (
' }\n')
@@ -1476,6 +1578,43 @@ class Message:
' }\n'
' g_string_append (str, "\'");\n')
+ elif field['format'] == 'tlv' or field['format'] == 'tlv-string':
+ inner_template += (
+ ' g_autoptr(MbimTlv) tmp = NULL;\n'
+ ' guint32 bytes_read = 0;\n'
+ ' g_autofree gchar *tlv_str = NULL;\n'
+ ' g_autofree gchar *new_line_prefix = NULL;\n'
+ '\n'
+ ' if (!_mbim_message_read_tlv (message, offset, &tmp, &bytes_read, &inner_error))\n'
+ ' goto out;\n'
+ ' offset += bytes_read;\n'
+ '\n'
+ ' new_line_prefix = g_strdup_printf ("%s ", line_prefix);\n'
+ ' tlv_str = _mbim_tlv_print (tmp, new_line_prefix);\n'
+ ' g_string_append_printf (str, "\'%s\'", tlv_str);\n')
+
+ elif field['format'] == 'tlv-list':
+ inner_template += (
+ ' GList *tmp = NULL;\n'
+ ' GList *walker = NULL;\n'
+ ' guint32 bytes_read = 0;\n'
+ ' g_autofree gchar *new_line_prefix = NULL;\n'
+ '\n'
+ ' if (!_mbim_message_read_tlv_list (message, offset, &tmp, &bytes_read, &inner_error))\n'
+ ' goto out;\n'
+ ' offset += bytes_read;\n'
+ '\n'
+ ' new_line_prefix = g_strdup_printf ("%s ", line_prefix);\n'
+ ' g_string_append (str, "\'[ ");\n'
+ ' for (walker = tmp; walker; walker = g_list_next (walker)) {\n'
+ ' g_autofree gchar *tlv_str = NULL;\n'
+ '\n'
+ ' tlv_str = _mbim_tlv_print ((MbimTlv *)walker->data, new_line_prefix);\n'
+ ' g_string_append_printf (str, "%s,", tlv_str);\n'
+ ' }\n'
+ ' g_string_append_printf (str, "\\n%s ]\'", line_prefix);\n'
+ ' g_list_free_full (tmp, (GDestroyNotify)mbim_tlv_unref);\n')
+
else:
raise ValueError('Field format \'%s\' not printable' % field['format'])
diff --git a/build-aux/mbim-codegen/utils.py b/build-aux/mbim-codegen/utils.py
index c3a8ac3..5ed3ff0 100644
--- a/build-aux/mbim-codegen/utils.py
+++ b/build-aux/mbim-codegen/utils.py
@@ -76,6 +76,7 @@ def add_source_start(f, output_name):
"\n"
"#include \"${name}.h\"\n"
"#include \"mbim-message-private.h\"\n"
+ "#include \"mbim-tlv-private.h\"\n"
"#include \"mbim-enum-types.h\"\n"
"#include \"mbim-error-types.h\"\n"
"#include \"mbim-device.h\"\n"
diff --git a/data/mbim-service-ms-basic-connect-extensions.json b/data/mbim-service-ms-basic-connect-extensions.json
index b53f96c..9c544e8 100755
--- a/data/mbim-service-ms-basic-connect-extensions.json
+++ b/data/mbim-service-ms-basic-connect-extensions.json
@@ -367,9 +367,9 @@
"public-format" : "MbimDefaultPduActivationHint" },
{ "name" : "ReRegisterIfNedeed",
"format" : "guint32",
- "public-format" : "gboolean" }
- // Optional unnamed IEs encoded as MBIM_TLV_IE are currently ignored
- ],
+ "public-format" : "gboolean" },
+ { "name" : "UnnamedIes",
+ "format" : "tlv-list" } ],
"query" : [],
"response" : [ { "name" : "MicoMode",
"format" : "guint32",
@@ -385,9 +385,9 @@
"public-format" : "MbimDefaultPduActivationHint" },
{ "name" : "ReRegisterIfNedeed",
"format" : "guint32",
- "public-format" : "gboolean" }
- // Optional unnamed IEs encoded as MBIM_TLV_IE are currently ignored
- ] },
+ "public-format" : "gboolean" },
+ { "name" : "UnnamedIes",
+ "format" : "tlv-list" } ] },
// *********************************************************************************
{ "name" : "MbimCellInfoServingGsm",
diff --git a/docs/reference/libmbim-glib/libmbim-glib-common.sections b/docs/reference/libmbim-glib/libmbim-glib-common.sections
index ddc3b1a..121e83b 100755
--- a/docs/reference/libmbim-glib/libmbim-glib-common.sections
+++ b/docs/reference/libmbim-glib/libmbim-glib-common.sections
@@ -761,6 +761,26 @@ mbim_utils_set_traces_enabled
</SECTION>
<SECTION>
+<FILE>mbim-tlv</FILE>
+MbimTlv
+MbimTlvType
+<SUBSECTION Methods>
+mbim_tlv_new
+mbim_tlv_dup
+mbim_tlv_ref
+mbim_tlv_unref
+mbim_tlv_get_raw
+mbim_tlv_get_tlv_type
+mbim_tlv_get_tlv_data
+mbim_tlv_type_get_string
+<SUBSECTION Private>
+mbim_tlv_type_build_string_from_mask
+<SUBSECTION Standard>
+MBIM_TYPE_TLV
+mbim_tlv_get_type
+</SECTION>
+
+<SECTION>
<FILE>mbim-compat</FILE>
<SUBSECTION>
MBIM_CID_BASIC_CONNECT_DEVICE_SERVICE_SUBSCRIBER_LIST
diff --git a/docs/reference/libmbim-glib/libmbim-glib-docs.xml b/docs/reference/libmbim-glib/libmbim-glib-docs.xml
index 9974e5c..a9d5d31 100644
--- a/docs/reference/libmbim-glib/libmbim-glib-docs.xml
+++ b/docs/reference/libmbim-glib/libmbim-glib-docs.xml
@@ -59,6 +59,7 @@
<xi:include href="xml/mbim-enums.xml"/>
<xi:include href="xml/mbim-errors.xml"/>
<xi:include href="xml/mbim-utils.xml"/>
+ <xi:include href="xml/mbim-tlv.xml"/>
</chapter>
<chapter>
diff --git a/src/libmbim-glib/generated/meson.build b/src/libmbim-glib/generated/meson.build
index 8673609..744ce48 100644
--- a/src/libmbim-glib/generated/meson.build
+++ b/src/libmbim-glib/generated/meson.build
@@ -65,7 +65,7 @@ gen_headers += custom_target(
command: [
python,
mbim_mkenums,
- '--fhead', '#ifndef __LIBMBIM_GLIB_ENUM_TYPES_H__\n#define __LIBMBIM_GLIB_ENUM_TYPES_H__\n#include "mbim-uuid.h"\n#include "mbim-cid.h"\n#include "mbim-message.h"\n#include "mbim-enums.h"\n',
+ '--fhead', '#ifndef __LIBMBIM_GLIB_ENUM_TYPES_H__\n#define __LIBMBIM_GLIB_ENUM_TYPES_H__\n#include "mbim-uuid.h"\n#include "mbim-cid.h"\n#include "mbim-message.h"\n#include "mbim-enums.h"\n#include "mbim-tlv.h"\n',
'--template', files(templates_dir / enum_types + '.h.template'),
'--ftail', '#endif /* __LIBMBIM_GLIB_ENUM_TYPES_H__ */\n',
'@INPUT@'],
diff --git a/src/libmbim-glib/libmbim-glib.h b/src/libmbim-glib/libmbim-glib.h
index 7fdf8e0..ca5ac26 100644
--- a/src/libmbim-glib/libmbim-glib.h
+++ b/src/libmbim-glib/libmbim-glib.h
@@ -21,6 +21,7 @@
#include "mbim-device.h"
#include "mbim-enums.h"
#include "mbim-proxy.h"
+#include "mbim-tlv.h"
/* generated */
#include "mbim-enum-types.h"
diff --git a/src/libmbim-glib/mbim-message-private.h b/src/libmbim-glib/mbim-message-private.h
index c17046f..2a27c16 100644
--- a/src/libmbim-glib/mbim-message-private.h
+++ b/src/libmbim-glib/mbim-message-private.h
@@ -18,6 +18,7 @@
#include <glib.h>
#include "mbim-message.h"
+#include "mbim-tlv.h"
G_BEGIN_DECLS
@@ -247,6 +248,12 @@ void _mbim_message_command_builder_append_ipv6 (M
void _mbim_message_command_builder_append_ipv6_array (MbimMessageCommandBuilder *builder,
const MbimIPv6 *values,
guint32 n_values);
+void _mbim_message_command_builder_append_tlv (MbimMessageCommandBuilder *builder,
+ const MbimTlv *tlv);
+void _mbim_message_command_builder_append_tlv_string (MbimMessageCommandBuilder *builder,
+ const gchar *str);
+void _mbim_message_command_builder_append_tlv_list (MbimMessageCommandBuilder *builder,
+ const GList *tlvs);
/*****************************************************************************/
/* Message parser */
@@ -323,6 +330,21 @@ gboolean _mbim_message_read_string_tlv (const MbimMessage *self,
gchar **str,
guint32 *tpv_size,
GError **error);
+gboolean _mbim_message_read_tlv (const MbimMessage *self,
+ guint32 relative_offset,
+ MbimTlv **tlv,
+ guint32 *bytes_read,
+ GError **error);
+gboolean _mbim_message_read_tlv_string (const MbimMessage *self,
+ guint32 relative_offset,
+ gchar **str,
+ guint32 *bytes_read,
+ GError **error);
+gboolean _mbim_message_read_tlv_list (const MbimMessage *self,
+ guint32 relative_offset,
+ GList **tlv,
+ guint32 *bytes_read,
+ GError **error);
G_END_DECLS
diff --git a/src/libmbim-glib/mbim-message.c b/src/libmbim-glib/mbim-message.c
index 7bd23ac..27f9c35 100644
--- a/src/libmbim-glib/mbim-message.c
+++ b/src/libmbim-glib/mbim-message.c
@@ -16,6 +16,7 @@
#include "mbim-message-private.h"
#include "mbim-error-types.h"
#include "mbim-enum-types.h"
+#include "mbim-tlv-private.h"
#include "mbim-basic-connect.h"
#include "mbim-auth.h"
@@ -885,6 +886,126 @@ _mbim_message_read_ipv6_array (const MbimMessage *self,
return TRUE;
}
+gboolean
+_mbim_message_read_tlv (const MbimMessage *self,
+ guint32 relative_offset,
+ MbimTlv **tlv,
+ guint32 *bytes_read,
+ GError **error)
+{
+ guint32 information_buffer_offset;
+ guint64 tlv_offset;
+ guint64 required_size;
+ const guint8 *tlv_raw;
+ guint64 tlv_size;
+
+ information_buffer_offset = _mbim_message_get_information_buffer_offset (self);
+ tlv_offset = (guint64)information_buffer_offset + (guint64)relative_offset;
+ tlv_raw = (const guint8 *) G_STRUCT_MEMBER_P (self->data, tlv_offset);
+ tlv_size = ((guint64)sizeof (struct tlv) +
+ (guint64)GUINT32_FROM_LE (((struct tlv *)tlv_raw)->data_length) +
+ (guint64)((struct tlv *)tlv_raw)->padding_length);
+
+ required_size = tlv_offset + tlv_size;
+ if ((guint64)self->len < required_size) {
+ g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_MESSAGE,
+ "cannot read TLV (%" G_GUINT64_FORMAT " bytes) (%u < %" G_GUINT64_FORMAT ")",
+ tlv_size, self->len, required_size);
+ return FALSE;
+ }
+
+ *tlv = _mbim_tlv_new_from_raw (tlv_raw, (guint32)tlv_size, bytes_read, error);
+ return (*tlv) ? TRUE : FALSE;
+}
+
+gboolean
+_mbim_message_read_tlv_string (const MbimMessage *self,
+ guint32 relative_offset,
+ gchar **str,
+ guint32 *bytes_read,
+ GError **error)
+{
+ g_autoptr(MbimTlv) tlv = NULL;
+ guint32 tlv_bytes_read = 0;
+ gchar *tlv_str;
+
+ if (!_mbim_message_read_tlv (self,
+ relative_offset,
+ &tlv,
+ &tlv_bytes_read,
+ error))
+ return FALSE;
+
+ tlv_str = mbim_tlv_string_get (tlv, error);
+ if (!tlv_str)
+ return FALSE;
+
+ *str = tlv_str;
+ *bytes_read = tlv_bytes_read;
+ return TRUE;
+}
+
+gboolean
+_mbim_message_read_tlv_list (const MbimMessage *self,
+ guint32 relative_offset,
+ GList **tlv_list,
+ guint32 *bytes_read,
+ GError **error)
+{
+ guint32 information_buffer_offset;
+ guint64 tlv_list_offset;
+ const guint8 *tlv_list_raw;
+ guint32 tlv_list_raw_size;
+ GList *list = NULL;
+ guint32 total_bytes_read = 0;
+ GError *inner_error = NULL;
+
+ information_buffer_offset = _mbim_message_get_information_buffer_offset (self);
+ tlv_list_offset = (guint64)information_buffer_offset + (guint64)relative_offset;
+
+ /* TLV list always at the end of the message */
+ if ((guint64)self->len < tlv_list_offset) {
+ g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_MESSAGE,
+ "cannot read TLV at offset (%u < %" G_GUINT64_FORMAT ")",
+ self->len, tlv_list_offset);
+ return FALSE;
+ }
+
+ tlv_list_raw_size = self->len - (guint32)tlv_list_offset;
+ tlv_list_raw = (const guint8 *) G_STRUCT_MEMBER_P (self->data, tlv_list_offset);
+
+ while ((tlv_list_raw_size > 0) && !inner_error) {
+ MbimTlv *tlv;
+ guint32 tlv_size;
+
+ if (tlv_list_raw_size < sizeof (struct tlv)) {
+ g_warning ("Left %u bytes unused after the TLV list", tlv_list_raw_size);
+ break;
+ }
+
+ tlv = _mbim_tlv_new_from_raw (tlv_list_raw, tlv_list_raw_size, &tlv_size, &inner_error);
+ if (!tlv)
+ break;
+
+ list = g_list_append (list, tlv);
+ total_bytes_read += tlv_size;
+
+ g_assert (tlv_list_raw_size >= tlv_size);
+ tlv_list_raw += tlv_size;
+ tlv_list_raw_size -= tlv_size;
+ }
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ g_list_free_full (list, (GDestroyNotify)mbim_tlv_unref);
+ return FALSE;
+ }
+
+ *bytes_read = total_bytes_read;
+ *tlv_list = list;
+ return TRUE;
+}
+
/*****************************************************************************/
/* Struct builder interface
*
@@ -1446,6 +1567,47 @@ _mbim_message_command_builder_append_ipv6_array (MbimMessageCommandBuilder *buil
}
/*****************************************************************************/
+/* TLVs only expected as primary message fields, not inside structs */
+
+void
+_mbim_message_command_builder_append_tlv (MbimMessageCommandBuilder *builder,
+ const MbimTlv *tlv)
+{
+ const guint8 *raw_tlv;
+ guint32 raw_tlv_size;
+
+ raw_tlv = mbim_tlv_get_raw (tlv, &raw_tlv_size, NULL);
+ _mbim_struct_builder_append_byte_array (builder->contents_builder,
+ FALSE, FALSE, FALSE,
+ raw_tlv, raw_tlv_size,
+ FALSE);
+}
+
+void
+_mbim_message_command_builder_append_tlv_string (MbimMessageCommandBuilder *builder,
+ const gchar *str)
+{
+ g_autoptr(MbimTlv) tlv = NULL;
+ g_autoptr(GError) error = NULL;
+
+ tlv = mbim_tlv_string_new (str, &error);
+ if (!tlv)
+ g_warning ("Error appending TLV: %s", error->message);
+ else
+ _mbim_message_command_builder_append_tlv (builder, tlv);
+}
+
+void
+_mbim_message_command_builder_append_tlv_list (MbimMessageCommandBuilder *builder,
+ const GList *tlvs)
+{
+ const GList *l;
+
+ for (l = tlvs; l; l = g_list_next (l))
+ _mbim_message_command_builder_append_tlv (builder, (MbimTlv *)(l->data));
+}
+
+/*****************************************************************************/
/* Generic message interface */
MbimMessage *
diff --git a/src/libmbim-glib/mbim-tlv-private.h b/src/libmbim-glib/mbim-tlv-private.h
new file mode 100644
index 0000000..7dc2d8f
--- /dev/null
+++ b/src/libmbim-glib/mbim-tlv-private.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * Copyright (C) 2021 Aleksander Morgado <aleksander@aleksander.es>
+ * Copyright (C) 2021 Intel Corporation
+ *
+ * This is a private non-installed header
+ */
+
+#ifndef _LIBMBIM_GLIB_MBIM_TLV_PRIVATE_H_
+#define _LIBMBIM_GLIB_MBIM_TLV_PRIVATE_H_
+
+#if !defined (LIBMBIM_GLIB_COMPILATION)
+#error "This is a private header!!"
+#endif
+
+#include <glib.h>
+
+#include "mbim-tlv.h"
+
+G_BEGIN_DECLS
+
+/*****************************************************************************/
+/* The MbimTlv */
+
+/* Defined in the same way as GByteArray */
+struct _MbimTlv {
+ guint8 *data;
+ guint len;
+};
+
+struct tlv {
+ guint16 type;
+ guint8 reserved;
+ guint8 padding_length;
+ guint32 data_length;
+ guint8 data[];
+} __attribute__((packed));
+
+#define MBIM_TLV_HEADER(self) ((struct tlv *)(((MbimTlv *)self)->data))
+
+#define MBIM_TLV_FIELD_TYPE(self) MBIM_TLV_HEADER (self)->type
+#define MBIM_TLV_FIELD_RESERVED(self) MBIM_TLV_HEADER (self)->reserved
+#define MBIM_TLV_FIELD_PADDING_LENGTH(self) MBIM_TLV_HEADER (self)->padding_length
+#define MBIM_TLV_FIELD_DATA_LENGTH(self) MBIM_TLV_HEADER (self)->data_length
+#define MBIM_TLV_FIELD_DATA(self) MBIM_TLV_HEADER (self)->data
+
+#define MBIM_TLV_GET_TLV_TYPE(self) (MbimTlvType) GUINT16_FROM_LE (MBIM_TLV_FIELD_TYPE (self))
+#define MBIM_TLV_GET_DATA_LENGTH(self) GUINT32_FROM_LE (MBIM_TLV_FIELD_DATA_LENGTH (self))
+
+/*****************************************************************************/
+/* Print support */
+
+gchar *_mbim_tlv_print (const MbimTlv *tlv,
+ const gchar *line_prefix);
+
+/*****************************************************************************/
+/* Parsing support */
+
+MbimTlv *_mbim_tlv_new_from_raw (const guint8 *raw,
+ guint32 raw_length,
+ guint32 *bytes_read,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* _LIBMBIM_GLIB_MBIM_TLV_PRIVATE_H_ */
diff --git a/src/libmbim-glib/mbim-tlv.c b/src/libmbim-glib/mbim-tlv.c
new file mode 100644
index 0000000..df5fba6
--- /dev/null
+++ b/src/libmbim-glib/mbim-tlv.c
@@ -0,0 +1,259 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * Copyright (C) 2021 Aleksander Morgado <aleksander@aleksander.es>
+ * Copyright (C) 2021 Intel Corporation
+ */
+
+#include <glib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <endian.h>
+
+#include "mbim-tlv.h"
+#include "mbim-tlv-private.h"
+#include "mbim-error-types.h"
+#include "mbim-enum-types.h"
+#include "mbim-common.h"
+
+/*****************************************************************************/
+
+GType
+mbim_tlv_get_type (void)
+{
+ static gsize g_define_type_id_initialized = 0;
+
+ if (g_once_init_enter (&g_define_type_id_initialized)) {
+ GType g_define_type_id =
+ g_boxed_type_register_static (g_intern_static_string ("MbimTlv"),
+ (GBoxedCopyFunc) mbim_tlv_ref,
+ (GBoxedFreeFunc) mbim_tlv_unref);
+
+ g_once_init_leave (&g_define_type_id_initialized, g_define_type_id);
+ }
+
+ return g_define_type_id_initialized;
+}
+
+/*****************************************************************************/
+
+gchar *
+_mbim_tlv_print (const MbimTlv *tlv,
+ const gchar *line_prefix)
+{
+ GString *str;
+ MbimTlvType tlv_type;
+ const gchar *tlv_type_str;
+ const guint8 *tlv_data;
+ guint32 tlv_data_size;
+ g_autofree gchar *tlv_data_str = NULL;
+
+ tlv_type = mbim_tlv_get_tlv_type (tlv);
+ tlv_type_str = mbim_tlv_type_get_string (tlv_type);
+
+ str = g_string_new ("");
+ g_string_append_printf (str, "{\n");
+ g_string_append_printf (str, "%s tlv type = %s (0x%04x)\n", line_prefix, tlv_type_str ? tlv_type_str : "unknown", tlv_type);
+
+ tlv_data = mbim_tlv_get_tlv_data (tlv, &tlv_data_size);
+ tlv_data_str = mbim_common_str_hex (tlv_data, tlv_data_size, ':');
+ g_string_append_printf (str, "%s tlv data = %s\n", line_prefix, tlv_data_str ? tlv_data_str : "");
+
+ if (tlv_type == MBIM_TLV_TYPE_WCHAR_STR) {
+ g_autoptr(GError) error = NULL;
+ g_autofree gchar *tlv_data_string_str = NULL;
+
+ tlv_data_string_str = mbim_tlv_string_get (tlv, &error);
+ if (!tlv_data_string_str)
+ tlv_data_string_str = g_strdup_printf ("*** error: %s", error->message);
+ g_string_append_printf (str, "%s tlv string = %s\n", line_prefix, tlv_data_string_str ? tlv_data_string_str : "");
+ }
+
+ g_string_append_printf (str, "%s}", line_prefix);
+
+ return g_string_free (str, FALSE);
+}
+
+/*****************************************************************************/
+
+MbimTlv *
+mbim_tlv_new (MbimTlvType tlv_type,
+ const guint8 *tlv_data,
+ guint32 tlv_data_length)
+{
+ GByteArray *self;
+ guint32 tlv_size;
+ guint32 padding_size;
+
+ g_return_val_if_fail (tlv_type != MBIM_TLV_TYPE_INVALID, NULL);
+
+ /* Compute size of the TLV and allocate heap for it */
+ padding_size = (tlv_data_length % 4) ? (4 - (tlv_data_length % 4)) : 0;
+ tlv_size = sizeof (struct tlv) + tlv_data_length + padding_size;
+ self = g_byte_array_sized_new (tlv_size);
+ g_byte_array_set_size (self, tlv_size);
+
+ /* Set TLV header */
+ MBIM_TLV_FIELD_TYPE (self) = GUINT16_TO_LE (tlv_type);
+ MBIM_TLV_FIELD_RESERVED (self) = 0;
+ MBIM_TLV_FIELD_PADDING_LENGTH (self) = padding_size;
+ MBIM_TLV_FIELD_DATA_LENGTH (self) = GUINT32_TO_LE (tlv_data_length);
+
+ if (tlv_data && tlv_data_length) {
+ memcpy (MBIM_TLV_FIELD_DATA (self), tlv_data, tlv_data_length);
+ if (padding_size)
+ memset (MBIM_TLV_FIELD_DATA (self) + tlv_data_length, 0, padding_size);
+ }
+
+ return (MbimTlv *)self;
+}
+
+MbimTlv *
+_mbim_tlv_new_from_raw (const guint8 *raw,
+ guint32 raw_length,
+ guint32 *bytes_read,
+ GError **error)
+{
+ guint32 tlv_size;
+
+ g_assert (raw_length >= sizeof (struct tlv));
+ tlv_size = sizeof (struct tlv) + GUINT32_FROM_LE (((struct tlv *)raw)->data_length) + ((struct tlv *)raw)->padding_length;
+
+ *bytes_read = tlv_size;
+ return (MbimTlv *) g_byte_array_append (g_byte_array_sized_new (tlv_size), raw, tlv_size);
+}
+
+MbimTlv *
+mbim_tlv_dup (const MbimTlv *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+
+ return mbim_tlv_new (MBIM_TLV_GET_TLV_TYPE (self),
+ MBIM_TLV_FIELD_DATA (self),
+ MBIM_TLV_GET_DATA_LENGTH (self));
+}
+
+MbimTlv *
+mbim_tlv_ref (MbimTlv *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+
+ return (MbimTlv *) g_byte_array_ref ((GByteArray *)self);
+}
+
+void
+mbim_tlv_unref (MbimTlv *self)
+{
+ g_return_if_fail (self != NULL);
+
+ g_byte_array_unref ((GByteArray *)self);
+}
+
+MbimTlvType
+mbim_tlv_get_tlv_type (const MbimTlv *self)
+{
+ g_return_val_if_fail (self != NULL, MBIM_TLV_TYPE_INVALID);
+
+ return MBIM_TLV_GET_TLV_TYPE (self);
+}
+
+const guint8 *
+mbim_tlv_get_tlv_data (const MbimTlv *self,
+ guint32 *out_length)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (out_length != NULL, NULL);
+
+ *out_length = MBIM_TLV_GET_DATA_LENGTH (self);
+ return MBIM_TLV_FIELD_DATA (self);
+}
+
+const guint8 *
+mbim_tlv_get_raw (const MbimTlv *self,
+ guint32 *length,
+ GError **error)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (length != NULL, NULL);
+
+ if (!self->data || !self->len) {
+ g_set_error_literal (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, "TLV is invalid");
+ return NULL;
+ }
+
+ *length = (guint32) self->len;
+ return self->data;
+}
+
+/*****************************************************************************/
+
+MbimTlv *
+mbim_tlv_string_new (const gchar *str,
+ GError **error)
+{
+ g_autofree gunichar2 *utf16 = NULL;
+ guint32 utf16_bytes = 0;
+
+ /* Convert the string from UTF-8 to UTF-16HE */
+ if (str && str[0]) {
+ glong items_written = 0;
+
+ utf16 = g_utf8_to_utf16 (str,
+ -1,
+ NULL, /* bytes */
+ &items_written, /* gunichar2 */
+ error);
+ if (!utf16)
+ return NULL;
+
+ utf16_bytes = items_written * 2;
+
+ /* For BE systems, convert from BE to LE */
+ if (G_BYTE_ORDER == G_BIG_ENDIAN) {
+ guint i;
+
+ for (i = 0; i < items_written; i++)
+ utf16[i] = GUINT16_TO_LE (utf16[i]);
+ }
+ }
+
+ return mbim_tlv_new (MBIM_TLV_TYPE_WCHAR_STR, (const guint8 *)utf16, utf16_bytes);
+}
+
+gchar *
+mbim_tlv_string_get (const MbimTlv *self,
+ GError **error)
+{
+ const gunichar2 *utf16 = NULL;
+ g_autofree gunichar2 *utf16d = NULL;
+ guint32 size;
+
+ g_return_val_if_fail (self != NULL, NULL);
+
+ if (MBIM_TLV_GET_TLV_TYPE (self) != MBIM_TLV_TYPE_WCHAR_STR) {
+ g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS,
+ "TLV is not a WCHAR string");
+ return NULL;
+ }
+
+ utf16 = (const gunichar2 *) MBIM_TLV_FIELD_DATA (self);
+ size = MBIM_TLV_FIELD_DATA_LENGTH (self);
+
+ /* For BE systems, convert from LE to BE */
+ if (G_BYTE_ORDER == G_BIG_ENDIAN) {
+ guint i;
+
+ utf16d = (gunichar2 *) g_malloc (size);
+ for (i = 0; i < (size / 2); i++)
+ utf16d[i] = GUINT16_FROM_LE (utf16[i]);
+ }
+
+ return g_utf16_to_utf8 (utf16d ? utf16d : utf16,
+ size / 2,
+ NULL,
+ NULL,
+ error);
+}
diff --git a/src/libmbim-glib/mbim-tlv.h b/src/libmbim-glib/mbim-tlv.h
new file mode 100644
index 0000000..2300cd5
--- /dev/null
+++ b/src/libmbim-glib/mbim-tlv.h
@@ -0,0 +1,224 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * Copyright (C) 2021 Aleksander Morgado <aleksander@aleksander.es>
+ * Copyright (C) 2021 Intel Corporation
+ */
+
+#ifndef _LIBMBIM_GLIB_MBIM_TLV_H_
+#define _LIBMBIM_GLIB_MBIM_TLV_H_
+
+#if !defined (__LIBMBIM_GLIB_H_INSIDE__) && !defined (LIBMBIM_GLIB_COMPILATION)
+#error "Only <libmbim-glib.h> can be included directly."
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/**
+ * SECTION:mbim-tlv
+ * @title: MbimTlv
+ * @short_description: A variable-sized data structure specified in Microsoft MBIM extensions.
+ *
+ * The #MbimTlv structure is capable of exchanging a wide range of information
+ * between an MBIM host and an MBIM device.
+ *
+ * CID payloads for requests, responses, and/or notifications may contain zero
+ * or more unnamed and optional Information Elements (IE) encoded as #MbimTlv
+ * fields.
+ */
+
+/**
+ * MbimTlv:
+ *
+ * An opaque type representing a MBIM TLV.
+ *
+ * Since: 1.28
+ */
+typedef struct _MbimTlv MbimTlv;
+
+GType mbim_tlv_get_type (void) G_GNUC_CONST;
+#define MBIM_TYPE_TLV (mbim_tlv_get_type ())
+
+/*****************************************************************************/
+/* Generic TLV interface */
+
+/**
+ * MbimTlvType:
+ * @MBIM_TLV_TYPE_INVALID: Invalid TLV type.
+ * @MBIM_TLV_TYPE_UE_POLICITES: UE policies.
+ * @MBIM_TLV_TYPE_SINGLE_NSSAI: Single NSSAI.
+ * @MBIM_TLV_TYPE_ALLOWED_NSSAI: Allowed NSSAI.
+ * @MBIM_TLV_TYPE_CFG_NSSAI: Configured NSSAI.
+ * @MBIM_TLV_TYPE_DFLT_CFG_NSSAI: Default configured NSSAI.
+ * @MBIM_TLV_TYPE_PRECFG_DFLT_CFG_NSSAI: Preconfigured default configured NSSAI.
+ * @MBIM_TLV_TYPE_REJ_NSSAI: Rejected NSSAI.
+ * @MBIM_TLV_TYPE_LADN: Local Area Data Network (LADN).
+ * @MBIM_TLV_TYPE_TAI: Tracking Area Identity (TAI).
+ * @MBIM_TLV_TYPE_WCHAR_STR: WCHAR string.
+ * @MBIM_TLV_TYPE_UINT16_TBL: Array of 1 or more @guint16 entries.
+ * @MBIM_TLV_TYPE_EAP_PACKET: Extensible Authentication Protocol packet.
+ * @MBIM_TLV_TYPE_PCO: Protocol Configuration Option (PCO).
+ * @MBIM_TLV_TYPE_ROUTE_SELECTION_DESCRIPTORS: One or more route selection descriptors.
+ * @MBIM_TLV_TYPE_TRAFFIC_PARAMETERS: A traffic parameters record.
+ * @MBIM_TLV_TYPE_WAKE_COMMAND: Wake command.
+ * @MBIM_TLV_TYPE_WAKE_PACKET: Wake packet.
+ *
+ * Type of the MBIM TLV.
+ *
+ * Since: 1.28
+ */
+typedef enum {
+ MBIM_TLV_TYPE_INVALID = 0,
+ MBIM_TLV_TYPE_UE_POLICITES = 1,
+ MBIM_TLV_TYPE_SINGLE_NSSAI = 2,
+ MBIM_TLV_TYPE_ALLOWED_NSSAI = 3,
+ MBIM_TLV_TYPE_CFG_NSSAI = 4,
+ MBIM_TLV_TYPE_DFLT_CFG_NSSAI = 5,
+ MBIM_TLV_TYPE_PRECFG_DFLT_CFG_NSSAI = 6,
+ MBIM_TLV_TYPE_REJ_NSSAI = 7,
+ MBIM_TLV_TYPE_LADN = 8,
+ MBIM_TLV_TYPE_TAI = 9,
+ MBIM_TLV_TYPE_WCHAR_STR = 10,
+ MBIM_TLV_TYPE_UINT16_TBL = 11,
+ MBIM_TLV_TYPE_EAP_PACKET = 12,
+ MBIM_TLV_TYPE_PCO = 13,
+ MBIM_TLV_TYPE_ROUTE_SELECTION_DESCRIPTORS = 14,
+ MBIM_TLV_TYPE_TRAFFIC_PARAMETERS = 15,
+ MBIM_TLV_TYPE_WAKE_COMMAND = 16,
+ MBIM_TLV_TYPE_WAKE_PACKET = 17,
+} MbimTlvType;
+
+/**
+ * mbim_tlv_new:
+ * @type: a #MbimTlvType.
+ * @data: contents of the TLV.
+ * @data_length: length of the message.
+ *
+ * Create a #MbimTlv with the given contents.
+ *
+ * Returns: (transfer full): a newly created #MbimTlv, which should be freed with mbim_tlv_unref().
+ *
+ * Since: 1.28
+ */
+MbimTlv *mbim_tlv_new (MbimTlvType type,
+ const guint8 *data,
+ guint32 data_length);
+
+/**
+ * mbim_tlv_dup:
+ * @self: a #MbimTlv to duplicate.
+ *
+ * Create a #MbimTlv with the same contents as @self.
+ *
+ * Returns: (transfer full): a newly created #MbimTlv, which should be freed with mbim_tlv_unref().
+ *
+ * Since: 1.28
+ */
+MbimTlv *mbim_tlv_dup (const MbimTlv *self);
+
+/**
+ * mbim_tlv_ref:
+ * @self: a #MbimTlv.
+ *
+ * Atomically increments the reference count of @self by one.
+ *
+ * Returns: (transfer full): the new reference to @self.
+ *
+ * Since: 1.28
+ */
+MbimTlv *mbim_tlv_ref (MbimTlv *self);
+
+/**
+ * mbim_tlv_unref:
+ * @self: a #MbimTlv.
+ *
+ * Atomically decrements the reference count of @self by one.
+ * If the reference count drops to 0, @self is completely disposed.
+ *
+ * Since: 1.28
+ */
+void mbim_tlv_unref (MbimTlv *self);
+
+/**
+ * mbim_tlv_get_raw:
+ * @self: a #MbimTlv.
+ * @length: (out): return location for the size of the output buffer.
+ * @error: return location for error or %NULL.
+ *
+ * Gets the whole raw data buffer of the #MbimTlv.
+ *
+ * Returns: The raw data buffer, or #NULL if @error is set.
+ *
+ * Since: 1.28
+ */
+const guint8 *mbim_tlv_get_raw (const MbimTlv *self,
+ guint32 *length,
+ GError **error);
+
+/**
+ * mbim_tlv_get_tlv_type:
+ * @self: a #MbimTlv.
+ *
+ * Gets the message type.
+ *
+ * Returns: a #MbimTlvType.
+ *
+ * Since: 1.28
+ */
+MbimTlvType mbim_tlv_get_tlv_type (const MbimTlv *self);
+
+/**
+ * mbim_tlv_get_tlv_data:
+ * @self: a #MbimTlv.
+ * @out_length: (out): return location for the size of the output buffer.
+ *
+ * Gets the TLV raw data.
+ *
+ * Returns: (transfer none): The raw data buffer, or #NULL if empty.
+ *
+ * Since: 1.28
+ */
+const guint8 *mbim_tlv_get_tlv_data (const MbimTlv *self,
+ guint32 *out_length);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (MbimTlv, mbim_tlv_unref)
+
+/*****************************************************************************/
+/* String TLV type helpers */
+
+/**
+ * mbim_tlv_string_new:
+ * @str: a string.
+ * @error: return location for error or %NULL.
+ *
+ * Create a #MbimTlv of type %MBIM_TLV_TYPE_WCHAR_STR with the given contents.
+ *
+ * Returns: (transfer full): a newly created #MbimTlv which should be freed with mbim_tlv_unref(), or %NULL if @error is set.
+ *
+ * Since: 1.28
+ */
+MbimTlv *mbim_tlv_string_new (const gchar *str,
+ GError **error);
+
+/**
+ * mbim_tlv_string_get:
+ * @self: a #MbimTlv of type %MBIM_TLV_TYPE_WCHAR_STR.
+ * @error: return location for error or %NULL.
+ *
+ * Get a string with the contents in the #MbimTlv.
+ *
+ * Returns: (transfer full): a newly created string, which should be freed with g_free(), or %NULL if @error is set.
+ *
+ * Since: 1.28
+ */
+gchar *mbim_tlv_string_get (const MbimTlv *self,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* _LIBMBIM_GLIB_MBIM_TLV_H_ */
diff --git a/src/libmbim-glib/meson.build b/src/libmbim-glib/meson.build
index 211836c..7574f5b 100644
--- a/src/libmbim-glib/meson.build
+++ b/src/libmbim-glib/meson.build
@@ -10,6 +10,7 @@ mbim_enums_headers = files(
'mbim-enums.h',
'mbim-message.h',
'mbim-uuid.h',
+ 'mbim-tlv.h',
)
subdir('generated')
@@ -44,6 +45,7 @@ sources = files(
'mbim-proxy-helpers.c',
'mbim-utils.c',
'mbim-uuid.c',
+ 'mbim-tlv.c',
)
deps = [
diff --git a/src/libmbim-glib/test/test-message-builder.c b/src/libmbim-glib/test/test-message-builder.c
index 45442d7..2b5784f 100644
--- a/src/libmbim-glib/test/test-message-builder.c
+++ b/src/libmbim-glib/test/test-message-builder.c
@@ -18,6 +18,7 @@
#include "mbim-stk.h"
#include "mbim-dss.h"
#include "mbim-ms-host-shutdown.h"
+#include "mbim-ms-basic-connect-extensions.h"
#if defined ENABLE_TEST_MESSAGE_TRACES
static void
@@ -1337,6 +1338,239 @@ test_message_builder_ms_host_shutdown_notify_set (void)
mbim_message_unref (message);
}
+static void
+test_message_builder_ms_basic_connect_extensions_registration_parameters_set_0_unnamed_tlvs (void)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(MbimMessage) message = NULL;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x44, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_done_message */
+ 0x3D, 0x01, 0xDC, 0xC5, /* service id */
+ 0xFE, 0xF5, 0x4D, 0x05,
+ 0x0D, 0x3A, 0xBE, 0xF7,
+ 0x05, 0x8E, 0x9A, 0xAF,
+ 0x11, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x14, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x00, 0x00, 0x00, 0x00, /* mico mode */
+ 0x00, 0x00, 0x00, 0x00, /* drx cycle */
+ 0x00, 0x00, 0x00, 0x00, /* ladn info */
+ 0x01, 0x00, 0x00, 0x00, /* pdu hint */
+ 0x01, 0x00, 0x00, 0x00, /* re register if needed */
+ /* no unnamed TLVs */
+ };
+
+ message = (mbim_message_ms_basic_connect_extensions_registration_parameters_set_new (
+ MBIM_MICO_MODE_DISABLED,
+ MBIM_DRX_CYCLE_NOT_SPECIFIED,
+ MBIM_LADN_INFO_NOT_NEEDED,
+ MBIM_DEFAULT_PDU_ACTIVATION_HINT_LIKELY,
+ TRUE,
+ NULL, /* 0 unnamed ies */
+ &error));
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_MS_BASIC_CONNECT_EXTENSIONS);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_MS_BASIC_CONNECT_EXTENSIONS_REGISTRATION_PARAMETERS);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+}
+
+static void
+test_message_builder_ms_basic_connect_extensions_registration_parameters_set_1_unnamed_tlv (void)
+{
+ MbimTlv *tlv;
+ GList *tlv_list = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(MbimMessage) message = NULL;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x58, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_done_message */
+ 0x3D, 0x01, 0xDC, 0xC5, /* service id */
+ 0xFE, 0xF5, 0x4D, 0x05,
+ 0x0D, 0x3A, 0xBE, 0xF7,
+ 0x05, 0x8E, 0x9A, 0xAF,
+ 0x11, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x28, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x00, 0x00, 0x00, 0x00, /* mico mode */
+ 0x00, 0x00, 0x00, 0x00, /* drx cycle */
+ 0x00, 0x00, 0x00, 0x00, /* ladn info */
+ 0x01, 0x00, 0x00, 0x00, /* pdu hint */
+ 0x01, 0x00, 0x00, 0x00, /* re register if needed */
+ /* First unnamed TLV */
+ 0x0A, 0x00, 0x00, 0x00, /* TLV type MBIM_TLV_TYPE_WCHAR_STR, no padding */
+ 0x0C, 0x00, 0x00, 0x00, /* TLV data length */
+ 0x4F, 0x00, 0x72, 0x00, /* TLV data string */
+ 0x61, 0x00, 0x6E, 0x00,
+ 0x67, 0x00, 0x65, 0x00,
+ };
+
+ tlv = mbim_tlv_string_new ("Orange", &error);
+ g_assert_no_error (error);
+ g_assert (tlv);
+ tlv_list = g_list_append (tlv_list, tlv);
+
+ message = (mbim_message_ms_basic_connect_extensions_registration_parameters_set_new (
+ MBIM_MICO_MODE_DISABLED,
+ MBIM_DRX_CYCLE_NOT_SPECIFIED,
+ MBIM_LADN_INFO_NOT_NEEDED,
+ MBIM_DEFAULT_PDU_ACTIVATION_HINT_LIKELY,
+ TRUE,
+ tlv_list,
+ &error));
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_MS_BASIC_CONNECT_EXTENSIONS);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_MS_BASIC_CONNECT_EXTENSIONS_REGISTRATION_PARAMETERS);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ g_list_free_full (tlv_list, (GDestroyNotify)mbim_tlv_unref);
+}
+
+static void
+test_message_builder_ms_basic_connect_extensions_registration_parameters_set_3_unnamed_tlvs (void)
+{
+ MbimTlv *tlv;
+ GList *tlv_list = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(MbimMessage) message = NULL;
+ const guint8 pco[] = {
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B };
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x80, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_done_message */
+ 0x3D, 0x01, 0xDC, 0xC5, /* service id */
+ 0xFE, 0xF5, 0x4D, 0x05,
+ 0x0D, 0x3A, 0xBE, 0xF7,
+ 0x05, 0x8E, 0x9A, 0xAF,
+ 0x11, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x50, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x00, 0x00, 0x00, 0x00, /* mico mode */
+ 0x00, 0x00, 0x00, 0x00, /* drx cycle */
+ 0x00, 0x00, 0x00, 0x00, /* ladn info */
+ 0x01, 0x00, 0x00, 0x00, /* pdu hint */
+ 0x01, 0x00, 0x00, 0x00, /* re register if needed */
+ /* First unnamed TLV */
+ 0x0A, 0x00, 0x00, 0x02, /* TLV type MBIM_TLV_TYPE_WCHAR_STR, padding 2 */
+ 0x0A, 0x00, 0x00, 0x00, /* TLV data length */
+ 0x61, 0x00, 0x62, 0x00, /* TLV data string */
+ 0x63, 0x00, 0x64, 0x00,
+ 0x65, 0x00, 0x00, 0x00,
+ /* Second unnamed TLV */
+ 0x0A, 0x00, 0x00, 0x00, /* TLV type MBIM_TLV_TYPE_WCHAR_STR, no padding */
+ 0x0C, 0x00, 0x00, 0x00, /* TLV data length */
+ 0x4F, 0x00, 0x72, 0x00, /* TLV data string */
+ 0x61, 0x00, 0x6E, 0x00,
+ 0x67, 0x00, 0x65, 0x00,
+ /* Third unnamed TLV */
+ 0x0D, 0x00, 0x00, 0x01, /* TLV type MBIM_TLV_TYPE_PCO, padding 1 */
+ 0x0B, 0x00, 0x00, 0x00, /* TLV data length */
+ 0x01, 0x02, 0x03, 0x04, /* TLV data bytes */
+ 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x00,
+ };
+
+ tlv = mbim_tlv_string_new ("abcde", &error);
+ g_assert_no_error (error);
+ g_assert (tlv);
+ tlv_list = g_list_append (tlv_list, tlv);
+
+ tlv = mbim_tlv_string_new ("Orange", &error);
+ g_assert_no_error (error);
+ g_assert (tlv);
+ tlv_list = g_list_append (tlv_list, tlv);
+
+ tlv = mbim_tlv_new (MBIM_TLV_TYPE_PCO, pco, sizeof (pco));
+ g_assert (tlv);
+ tlv_list = g_list_append (tlv_list, tlv);
+
+ message = (mbim_message_ms_basic_connect_extensions_registration_parameters_set_new (
+ MBIM_MICO_MODE_DISABLED,
+ MBIM_DRX_CYCLE_NOT_SPECIFIED,
+ MBIM_LADN_INFO_NOT_NEEDED,
+ MBIM_DEFAULT_PDU_ACTIVATION_HINT_LIKELY,
+ TRUE,
+ tlv_list,
+ &error));
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_MS_BASIC_CONNECT_EXTENSIONS);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_MS_BASIC_CONNECT_EXTENSIONS_REGISTRATION_PARAMETERS);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ g_list_free_full (tlv_list, (GDestroyNotify)mbim_tlv_unref);
+}
+
int main (int argc, char **argv)
{
g_test_init (&argc, &argv, NULL);
@@ -1358,6 +1592,9 @@ int main (int argc, char **argv)
g_test_add_func ("/libmbim-glib/message/builder/dss/connect/set", test_message_builder_dss_connect_set);
g_test_add_func ("/libmbim-glib/message/builder/basic-connect/multicarrier-providers/set", test_message_builder_basic_connect_multicarrier_providers_set);
g_test_add_func ("/libmbim-glib/message/builder/ms-host-shutdown/notify/set", test_message_builder_ms_host_shutdown_notify_set);
+ g_test_add_func ("/libmbim-glib/message/builder/ms-basic-connect-extensions/registration-parameters/set/0-unnamed-tlvs", test_message_builder_ms_basic_connect_extensions_registration_parameters_set_0_unnamed_tlvs);
+ g_test_add_func ("/libmbim-glib/message/builder/ms-basic-connect-extensions/registration-parameters/set/1-unnamed-tlv", test_message_builder_ms_basic_connect_extensions_registration_parameters_set_1_unnamed_tlv);
+ g_test_add_func ("/libmbim-glib/message/builder/ms-basic-connect-extensions/registration-parameters/set/3-unnamed-tlvs", test_message_builder_ms_basic_connect_extensions_registration_parameters_set_3_unnamed_tlvs);
return g_test_run ();
}
diff --git a/src/libmbim-glib/test/test-message-parser.c b/src/libmbim-glib/test/test-message-parser.c
index 96109f6..fe850a6 100644
--- a/src/libmbim-glib/test/test-message-parser.c
+++ b/src/libmbim-glib/test/test-message-parser.c
@@ -15,6 +15,7 @@
#include "mbim-ms-firmware-id.h"
#include "mbim-ms-basic-connect-extensions.h"
#include "mbim-message.h"
+#include "mbim-tlv.h"
#include "mbim-cid.h"
#include "mbim-common.h"
#include "mbim-error-types.h"
@@ -1975,6 +1976,256 @@ test_message_parser_ms_basic_connect_extensions_base_stations (void)
g_assert_null (cdma_cells);
}
+static void
+test_message_parser_ms_basic_connect_extensions_registration_parameters_0_unnamed_tlvs (void)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(MbimMessage) response = NULL;
+ gboolean result;
+ MbimMicoMode mico_mode;
+ MbimDrxCycle drx_cycle;
+ MbimLadnInfo ladn_info;
+ MbimDefaultPduActivationHint pdu_hint;
+ gboolean re_register_if_needed;
+ GList *unnamed_ies = NULL;
+
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0x44, 0x00, 0x00, 0x00, /* length */
+ 0x04, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_done_message */
+ 0x3D, 0x01, 0xDC, 0xC5, /* service id */
+ 0xFE, 0xF5, 0x4D, 0x05,
+ 0x0D, 0x3A, 0xBE, 0xF7,
+ 0x05, 0x8E, 0x9A, 0xAF,
+ 0x11, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x14, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x00, 0x00, 0x00, 0x00, /* mico mode */
+ 0x00, 0x00, 0x00, 0x00, /* drx cycle */
+ 0x00, 0x00, 0x00, 0x00, /* ladn info */
+ 0x01, 0x00, 0x00, 0x00, /* pdu hint */
+ 0x01, 0x00, 0x00, 0x00, /* re register if needed */
+ /* no unnamed TLVs */
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ result = (mbim_message_ms_basic_connect_extensions_registration_parameters_response_parse (
+ response,
+ &mico_mode,
+ &drx_cycle,
+ &ladn_info,
+ &pdu_hint,
+ &re_register_if_needed,
+ &unnamed_ies,
+ &error));
+
+ g_assert_no_error (error);
+ g_assert (result);
+
+ g_assert_cmpuint (mico_mode, ==, MBIM_MICO_MODE_DISABLED);
+ g_assert_cmpuint (drx_cycle, ==, MBIM_DRX_CYCLE_NOT_SPECIFIED);
+ g_assert_cmpuint (ladn_info, ==, MBIM_LADN_INFO_NOT_NEEDED);
+ g_assert_cmpuint (pdu_hint, ==, MBIM_DEFAULT_PDU_ACTIVATION_HINT_LIKELY);
+ g_assert_cmpuint (re_register_if_needed, ==, TRUE);
+ g_assert_cmpuint (g_list_length (unnamed_ies), ==, 0);
+}
+
+static void
+test_message_parser_ms_basic_connect_extensions_registration_parameters_1_unnamed_tlv (void)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(MbimMessage) response = NULL;
+ gboolean result;
+ MbimMicoMode mico_mode;
+ MbimDrxCycle drx_cycle;
+ MbimLadnInfo ladn_info;
+ MbimDefaultPduActivationHint pdu_hint;
+ gboolean re_register_if_needed;
+ GList *unnamed_ies = NULL;
+ MbimTlv *tlv;
+ g_autofree gchar *tlv_str = NULL;
+
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0x58, 0x00, 0x00, 0x00, /* length */
+ 0x04, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_done_message */
+ 0x3D, 0x01, 0xDC, 0xC5, /* service id */
+ 0xFE, 0xF5, 0x4D, 0x05,
+ 0x0D, 0x3A, 0xBE, 0xF7,
+ 0x05, 0x8E, 0x9A, 0xAF,
+ 0x11, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x28, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x00, 0x00, 0x00, 0x00, /* mico mode */
+ 0x00, 0x00, 0x00, 0x00, /* drx cycle */
+ 0x00, 0x00, 0x00, 0x00, /* ladn info */
+ 0x01, 0x00, 0x00, 0x00, /* pdu hint */
+ 0x01, 0x00, 0x00, 0x00, /* re register if needed */
+ /* First unnamed TLV */
+ 0x0A, 0x00, 0x00, 0x00, /* TLV type MBIM_TLV_TYPE_WCHAR_STR, no padding */
+ 0x0C, 0x00, 0x00, 0x00, /* TLV data length */
+ 0x4F, 0x00, 0x72, 0x00, /* TLV data string */
+ 0x61, 0x00, 0x6E, 0x00,
+ 0x67, 0x00, 0x65, 0x00,
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ result = (mbim_message_ms_basic_connect_extensions_registration_parameters_response_parse (
+ response,
+ &mico_mode,
+ &drx_cycle,
+ &ladn_info,
+ &pdu_hint,
+ &re_register_if_needed,
+ &unnamed_ies,
+ &error));
+
+ g_assert_no_error (error);
+ g_assert (result);
+
+ g_assert_cmpuint (mico_mode, ==, MBIM_MICO_MODE_DISABLED);
+ g_assert_cmpuint (drx_cycle, ==, MBIM_DRX_CYCLE_NOT_SPECIFIED);
+ g_assert_cmpuint (ladn_info, ==, MBIM_LADN_INFO_NOT_NEEDED);
+ g_assert_cmpuint (pdu_hint, ==, MBIM_DEFAULT_PDU_ACTIVATION_HINT_LIKELY);
+ g_assert_cmpuint (re_register_if_needed, ==, TRUE);
+ g_assert_cmpuint (g_list_length (unnamed_ies), ==, 1);
+
+ tlv = (MbimTlv *)(unnamed_ies->data);
+ g_assert_cmpuint (mbim_tlv_get_tlv_type (tlv), ==, MBIM_TLV_TYPE_WCHAR_STR);
+
+ tlv_str = mbim_tlv_string_get (tlv, &error);
+ g_assert_no_error (error);
+ g_assert_cmpstr (tlv_str, ==, "Orange");
+
+ g_list_free_full (unnamed_ies, (GDestroyNotify)mbim_tlv_unref);
+}
+
+static void
+test_message_parser_ms_basic_connect_extensions_registration_parameters_3_unnamed_tlvs (void)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(MbimMessage) response = NULL;
+ gboolean result;
+ MbimMicoMode mico_mode;
+ MbimDrxCycle drx_cycle;
+ MbimLadnInfo ladn_info;
+ MbimDefaultPduActivationHint pdu_hint;
+ gboolean re_register_if_needed;
+ GList *unnamed_ies = NULL;
+ GList *iter;
+ MbimTlv *tlv;
+ g_autofree gchar *tlv_str_1 = NULL;
+ const gchar *expected_tlv_str_1 = "abcde";
+ g_autofree gchar *tlv_str_2 = NULL;
+ const gchar *expected_tlv_str_2 = "Orange";
+ const guint8 *pco_3 = NULL;
+ guint32 pco_3_size = 0;
+ const guint8 expected_pco[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B };
+
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0x80, 0x00, 0x00, 0x00, /* length */
+ 0x04, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_done_message */
+ 0x3D, 0x01, 0xDC, 0xC5, /* service id */
+ 0xFE, 0xF5, 0x4D, 0x05,
+ 0x0D, 0x3A, 0xBE, 0xF7,
+ 0x05, 0x8E, 0x9A, 0xAF,
+ 0x11, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x50, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x00, 0x00, 0x00, 0x00, /* mico mode */
+ 0x00, 0x00, 0x00, 0x00, /* drx cycle */
+ 0x00, 0x00, 0x00, 0x00, /* ladn info */
+ 0x01, 0x00, 0x00, 0x00, /* pdu hint */
+ 0x01, 0x00, 0x00, 0x00, /* re register if needed */
+ /* First unnamed TLV */
+ 0x0A, 0x00, 0x00, 0x02, /* TLV type MBIM_TLV_TYPE_WCHAR_STR, padding 2 */
+ 0x0A, 0x00, 0x00, 0x00, /* TLV data length */
+ 0x61, 0x00, 0x62, 0x00, /* TLV data string */
+ 0x63, 0x00, 0x64, 0x00,
+ 0x65, 0x00, 0x00, 0x00,
+ /* Second unnamed TLV */
+ 0x0A, 0x00, 0x00, 0x00, /* TLV type MBIM_TLV_TYPE_WCHAR_STR, no padding */
+ 0x0C, 0x00, 0x00, 0x00, /* TLV data length */
+ 0x4F, 0x00, 0x72, 0x00, /* TLV data string */
+ 0x61, 0x00, 0x6E, 0x00,
+ 0x67, 0x00, 0x65, 0x00,
+ /* Third unnamed TLV */
+ 0x0D, 0x00, 0x00, 0x01, /* TLV type MBIM_TLV_TYPE_PCO, padding 1 */
+ 0x0B, 0x00, 0x00, 0x00, /* TLV data length */
+ 0x01, 0x02, 0x03, 0x04, /* TLV data bytes */
+ 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x00,
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ result = (mbim_message_ms_basic_connect_extensions_registration_parameters_response_parse (
+ response,
+ &mico_mode,
+ &drx_cycle,
+ &ladn_info,
+ &pdu_hint,
+ &re_register_if_needed,
+ &unnamed_ies,
+ &error));
+
+ g_assert_no_error (error);
+ g_assert (result);
+
+ g_assert_cmpuint (mico_mode, ==, MBIM_MICO_MODE_DISABLED);
+ g_assert_cmpuint (drx_cycle, ==, MBIM_DRX_CYCLE_NOT_SPECIFIED);
+ g_assert_cmpuint (ladn_info, ==, MBIM_LADN_INFO_NOT_NEEDED);
+ g_assert_cmpuint (pdu_hint, ==, MBIM_DEFAULT_PDU_ACTIVATION_HINT_LIKELY);
+ g_assert_cmpuint (re_register_if_needed, ==, TRUE);
+ g_assert_cmpuint (g_list_length (unnamed_ies), ==, 3);
+
+ iter = unnamed_ies;
+ tlv = (MbimTlv *)(iter->data);
+ g_assert_cmpuint (mbim_tlv_get_tlv_type (tlv), ==, MBIM_TLV_TYPE_WCHAR_STR);
+ tlv_str_1 = mbim_tlv_string_get (tlv, &error);
+ g_assert_no_error (error);
+ g_assert_cmpstr (tlv_str_1, ==, expected_tlv_str_1);
+
+ iter = g_list_next (iter);
+ tlv = (MbimTlv *)(iter->data);
+ g_assert_cmpuint (mbim_tlv_get_tlv_type (tlv), ==, MBIM_TLV_TYPE_WCHAR_STR);
+ tlv_str_2 = mbim_tlv_string_get (tlv, &error);
+ g_assert_no_error (error);
+ g_assert_cmpstr (tlv_str_2, ==, expected_tlv_str_2);
+
+ iter = g_list_next (iter);
+ tlv = (MbimTlv *)(iter->data);
+ g_assert_cmpuint (mbim_tlv_get_tlv_type (tlv), ==, MBIM_TLV_TYPE_PCO);
+ pco_3 = mbim_tlv_get_tlv_data (tlv, &pco_3_size);
+ g_assert_cmpuint (pco_3_size, ==, sizeof (expected_pco));
+ g_assert (memcmp (pco_3, expected_pco, sizeof (expected_pco)) == 0);
+
+ g_list_free_full (unnamed_ies, (GDestroyNotify)mbim_tlv_unref);
+}
+
int main (int argc, char **argv)
{
g_test_init (&argc, &argv, NULL);
@@ -2002,6 +2253,9 @@ int main (int argc, char **argv)
g_test_add_func ("/libmbim-glib/message/parser/basic-connect/connect/short", test_message_parser_basic_connect_connect_short);
g_test_add_func ("/libmbim-glib/message/parser/basic-connect/visible-providers/overflow", test_message_parser_basic_connect_visible_providers_overflow);
g_test_add_func ("/libmbim-glib/message/parser/basic-connect-extensions/base-stations", test_message_parser_ms_basic_connect_extensions_base_stations);
+ g_test_add_func ("/libmbim-glib/message/parser/basic-connect-extensions/registration-parameters/0-unnamed-tlvs", test_message_parser_ms_basic_connect_extensions_registration_parameters_0_unnamed_tlvs);
+ g_test_add_func ("/libmbim-glib/message/parser/basic-connect-extensions/registration-parameters/1-unnamed-tlv", test_message_parser_ms_basic_connect_extensions_registration_parameters_1_unnamed_tlv);
+ g_test_add_func ("/libmbim-glib/message/parser/basic-connect-extensions/registration-parameters/3-unnamed-tlvs", test_message_parser_ms_basic_connect_extensions_registration_parameters_3_unnamed_tlvs);
return g_test_run ();
}
diff --git a/src/mbimcli/mbimcli-ms-basic-connect-extensions.c b/src/mbimcli/mbimcli-ms-basic-connect-extensions.c
index b6face8..4240952 100644
--- a/src/mbimcli/mbimcli-ms-basic-connect-extensions.c
+++ b/src/mbimcli/mbimcli-ms-basic-connect-extensions.c
@@ -1052,6 +1052,7 @@ registration_parameters_ready (MbimDevice *device,
&ladn_info,
&pdu_hint,
&re_register_if_nedeed,
+ NULL, /* ignore unnamed IEs for now */
&error)) {
g_printerr ("error: couldn't parse response message: %s\n", error->message);
shutdown (FALSE);
@@ -1750,6 +1751,7 @@ mbimcli_ms_basic_connect_extensions_run (MbimDevice *device,
params.ladn_info,
params.pdu_hint,
params.re_register_if_needed,
+ NULL, /* ignore unnamed IEs for now */
NULL);
mbim_device_command (ctx->device,
request,