Merge "Merge cros/upstream to cros/master"
diff --git a/build-aux/mbim-codegen/Message.py b/build-aux/mbim-codegen/Message.py
index 488bd48..6db9103 100644
--- a/build-aux/mbim-codegen/Message.py
+++ b/build-aux/mbim-codegen/Message.py
@@ -1024,13 +1024,15 @@
                 inner_template += (
                     '        offset += 8;\n')
             elif field['format'] == 'string':
+                translations['encoding'] = 'MBIM_STRING_ENCODING_UTF8' if 'encoding' in field and field['encoding'] == 'utf-8' else 'MBIM_STRING_ENCODING_UTF16'
                 inner_template += (
-                    '        if ((out_${field} != NULL) && !_mbim_message_read_string (message, 0, offset, &_${field}, error))\n'
+                    '        if ((out_${field} != NULL) && !_mbim_message_read_string (message, 0, offset, ${encoding}, &_${field}, error))\n'
                     '            goto out;\n'
                     '        offset += 8;\n')
             elif field['format'] == 'string-array':
+                translations['encoding'] = 'MBIM_STRING_ENCODING_UTF8' if 'encoding' in field and field['encoding'] == 'utf-8' else 'MBIM_STRING_ENCODING_UTF16'
                 inner_template += (
-                    '        if ((out_${field} != NULL) && !_mbim_message_read_string_array (message, _${array_size_field}, 0, offset, &_${field}, error))\n'
+                    '        if ((out_${field} != NULL) && !_mbim_message_read_string_array (message, _${array_size_field}, 0, offset, ${encoding}, &_${field}, error))\n'
                     '            goto out;\n'
                     '        offset += (8 * _${array_size_field});\n')
             elif field['format'] == 'struct':
@@ -1444,10 +1446,11 @@
                         '        }\n')
 
             elif field['format'] == 'string':
+                translations['encoding'] = 'MBIM_STRING_ENCODING_UTF8' if 'encoding' in field and field['encoding'] == 'utf-8' else 'MBIM_STRING_ENCODING_UTF16'
                 inner_template += (
                     '        g_autofree gchar *tmp = NULL;\n'
                     '\n'
-                    '        if (!_mbim_message_read_string (message, 0, offset, &tmp, &inner_error))\n'
+                    '        if (!_mbim_message_read_string (message, 0, offset, ${encoding}, &tmp, &inner_error))\n'
                     '            goto out;\n'
                     '        offset += 8;\n'
                     '        ${if_show_field}{\n'
@@ -1455,11 +1458,12 @@
                     '        }\n')
 
             elif field['format'] == 'string-array':
+                translations['encoding'] = 'MBIM_STRING_ENCODING_UTF8' if 'encoding' in field and field['encoding'] == 'utf-8' else 'MBIM_STRING_ENCODING_UTF16'
                 inner_template += (
                     '        g_auto(GStrv) tmp = NULL;\n'
                     '        guint i;\n'
                     '\n'
-                    '        if (!_mbim_message_read_string_array (message, _${array_size_field}, 0, offset, &tmp, &inner_error))\n'
+                    '        if (!_mbim_message_read_string_array (message, _${array_size_field}, 0, offset, ${encoding}, &tmp, &inner_error))\n'
                     '            goto out;\n'
                     '        offset += (8 * _${array_size_field});\n'
                     '\n'
diff --git a/build-aux/mbim-codegen/Struct.py b/build-aux/mbim-codegen/Struct.py
index 85dd474..a02004b 100644
--- a/build-aux/mbim-codegen/Struct.py
+++ b/build-aux/mbim-codegen/Struct.py
@@ -645,16 +645,18 @@
                     '        goto out;\n'
                     '    offset += 8;\n')
             elif field['format'] == 'string':
+                translations['encoding'] = 'MBIM_STRING_ENCODING_UTF8' if 'encoding' in field and field['encoding'] == 'utf-8' else 'MBIM_STRING_ENCODING_UTF16'
                 inner_template += (
                     '\n'
-                    '    if (!_mbim_message_read_string (self, relative_offset, offset, &out->${field_name_underscore}, error))\n'
+                    '    if (!_mbim_message_read_string (self, relative_offset, offset, ${encoding}, &out->${field_name_underscore}, error))\n'
                     '        goto out;\n'
                     '    offset += 8;\n')
             elif field['format'] == 'string-array':
+                translations['encoding'] = 'MBIM_STRING_ENCODING_UTF8' if 'encoding' in field and field['encoding'] == 'utf-8' else 'MBIM_STRING_ENCODING_UTF16'
                 translations['array_size_field_name_underscore'] = utils.build_underscore_name_from_camelcase(field['array-size-field'])
                 inner_template += (
                     '\n'
-                    '    if (!_mbim_message_read_string_array (self, out->${array_size_field_name_underscore}, relative_offset, offset, &out->${field_name_underscore}, error))\n'
+                    '    if (!_mbim_message_read_string_array (self, out->${array_size_field_name_underscore}, relative_offset, offset, ${encoding}, &out->${field_name_underscore}, error))\n'
                     '        goto out;\n'
                     '    offset += (8 * out->${array_size_field_name_underscore});\n')
             elif field['format'] == 'ipv4':
diff --git a/data/mbim-service-ms-uicc-low-level-access.json b/data/mbim-service-ms-uicc-low-level-access.json
index a9db9fe..212f44b 100644
--- a/data/mbim-service-ms-uicc-low-level-access.json
+++ b/data/mbim-service-ms-uicc-low-level-access.json
@@ -93,6 +93,135 @@
     "query"    : [],
     "response" : [ { "name"          : "PassThroughStatus",
                      "format"        : "guint32",
-                     "public-format" : "MbimUiccPassThroughStatus" } ] }
+                     "public-format" : "MbimUiccPassThroughStatus" } ] },
 
+  // *********************************************************************************
+
+  { "name"     : "MbimUiccApplication",
+    "type"     : "Struct",
+    "since"    : "1.28",
+    "contents" : [ { "name"          : "ApplicationType",
+                     "format"        : "guint32",
+                     "public-format" : "MbimUiccApplicationType" },
+                   { "name"   : "ApplicationId",
+                     "format" : "ref-byte-array" },
+                   { "name"     : "ApplicationName",
+                     "format"   : "string",
+                     "encoding" : "utf-8" },
+                   { "name"   : "PinKeyReferenceCount",
+                     "format" : "guint32" },
+                   { "name"   : "PinKeyReferences",
+                     "format" : "ref-byte-array" } ] },
+
+  { "name"     : "Application List",
+    "type"     : "Command",
+    "since"    : "1.28",
+    "query"    : [],
+    "response" : [ { "name"   : "Version",
+                     "format" : "guint32" },
+                   { "name"   : "ApplicationCount",
+                     "format" : "guint32" },
+                   { "name"   : "ActiveApplicationIndex",
+                     "format" : "guint32" },
+                   { "name"   : "ApplicationListSizeBytes",
+                     "format" : "guint32" },
+                   { "name"             : "Applications",
+                     "format"           : "ref-struct-array" ,
+                     "struct-type"      : "MbimUiccApplication",
+                     "array-size-field" : "ApplicationCount" } ] },
+
+  // *********************************************************************************
+
+  { "name"     : "File Status",
+    "type"     : "Command",
+    "since"    : "1.28",
+    "query"    : [ { "name"   : "Version",
+                     "format" : "guint32" },
+                   { "name"   : "ApplicationId",
+                     "format" : "ref-byte-array" },
+                   { "name"   : "FilePath",
+                     "format" : "ref-byte-array" } ],
+    "response" : [ { "name"   : "Version",
+                     "format" : "guint32" },
+                   { "name"   : "StatusWord1",
+                     "format" : "guint32" },
+                   { "name"   : "StatusWord2",
+                     "format" : "guint32" },
+                   { "name"          : "FileAccessibility",
+                     "format"        : "guint32",
+                     "public-format" : "MbimUiccFileAccessibility" },
+                   { "name"          : "FileType",
+                     "format"        : "guint32",
+                     "public-format" : "MbimUiccFileType" },
+                   { "name"          : "FileStructure",
+                     "format"        : "guint32",
+                     "public-format" : "MbimUiccFileStructure" },
+                   { "name"          : "FileItemCount",
+                     "format"        : "guint32" },
+                   { "name"          : "FileItemSize",
+                     "format"        : "guint32" },
+                   { "name"          : "AccessConditionRead",
+                     "format"        : "guint32",
+                     "public-format" : "MbimPinType" },
+                   { "name"          : "AccessConditionUpdate",
+                     "format"        : "guint32",
+                     "public-format" : "MbimPinType" },
+                   { "name"          : "AccessConditionActivate",
+                     "format"        : "guint32",
+                     "public-format" : "MbimPinType" },
+                   { "name"          : "AccessConditionDeactivate",
+                     "format"        : "guint32",
+                     "public-format" : "MbimPinType" } ] },
+
+  // *********************************************************************************
+  { "name"     : "Read Binary",
+    "type"     : "Command",
+    "since"    : "1.28",
+    "query"    : [ { "name"   : "Version",
+                     "format" : "guint32" },
+                   { "name"   : "ApplicationId",
+                     "format" : "ref-byte-array" },
+                   { "name"   : "FilePath",
+                     "format" : "ref-byte-array" },
+		   { "name"   : "ReadOffset",
+		     "format" : "guint32" },
+		   { "name"   : "ReadSize",
+		     "format" : "guint32" },
+		   { "name"   : "LocalPin",
+		     "format" : "string" },
+                   { "name"   : "Data",
+                     "format" : "ref-byte-array" } ],
+    "response" : [ { "name"   : "Version",
+                     "format" : "guint32" },
+                   { "name"   : "StatusWord1",
+                     "format" : "guint32" },
+                   { "name"   : "StatusWord2",
+                     "format" : "guint32" },
+                   { "name"   : "Data",
+                     "format" : "ref-byte-array" } ] },
+
+  // *********************************************************************************
+  { "name"     : "Read Record",
+    "type"     : "Command",
+    "since"    : "1.28",
+    "query"    : [ { "name"   : "Version",
+                     "format" : "guint32" },
+                   { "name"   : "ApplicationId",
+                     "format" : "ref-byte-array" },
+                   { "name"   : "FilePath",
+                     "format" : "ref-byte-array" },
+		   { "name"   : "RecordNumber",
+		     "format" : "guint32" },
+		   { "name"   : "LocalPin",
+		     "format" : "string" },
+                   { "name"   : "Data",
+                     "format" : "ref-byte-array" } ],
+    "response" : [ { "name"   : "Version",
+                     "format" : "guint32" },
+                   { "name"   : "StatusWord1",
+                     "format" : "guint32" },
+                   { "name"   : "StatusWord2",
+                     "format" : "guint32" },
+                   { "name"   : "Data",
+                     "format" : "ref-byte-array" } ] }
 ]
diff --git a/docs/reference/libmbim-glib/libmbim-glib-common.sections b/docs/reference/libmbim-glib/libmbim-glib-common.sections
index fe9d3b2..dd9c4ab 100644
--- a/docs/reference/libmbim-glib/libmbim-glib-common.sections
+++ b/docs/reference/libmbim-glib/libmbim-glib-common.sections
@@ -410,6 +410,10 @@
 MbimAccessMediaType
 MbimIntelServingCellInfo
 MbimIntelBootMode
+MbimUiccApplicationType
+MbimUiccFileAccessibility
+MbimUiccFileType
+MbimUiccFileStructure
 <SUBSECTION Methods>
 mbim_device_type_get_string
 mbim_cellular_class_build_string_from_mask
@@ -501,6 +505,10 @@
 mbim_access_media_type_get_string
 mbim_intel_serving_cell_info_get_string
 mbim_intel_boot_mode_get_string
+mbim_uicc_application_type_get_string
+mbim_uicc_file_accessibility_get_string
+mbim_uicc_file_type_get_string
+mbim_uicc_file_structure_get_string
 <SUBSECTION Private>
 mbim_device_type_build_string_from_mask
 mbim_cellular_class_get_string
@@ -594,6 +602,10 @@
 mbim_access_media_type_build_string_from_mask
 mbim_intel_serving_cell_info_build_string_from_mask
 mbim_intel_boot_mode_build_string_from_mask
+mbim_uicc_application_type_build_string_from_mask
+mbim_uicc_file_accessibility_build_string_from_mask
+mbim_uicc_file_type_build_string_from_mask
+mbim_uicc_file_structure_build_string_from_mask
 <SUBSECTION Standard>
 MBIM_TYPE_ACTIVATION_COMMAND
 MBIM_TYPE_ACTIVATION_STATE
@@ -690,6 +702,10 @@
 MBIM_TYPE_ACCESS_MEDIA_TYPE
 MBIM_TYPE_INTEL_SERVING_CELL_INFO
 MBIM_TYPE_INTEL_BOOT_MODE
+MBIM_TYPE_UICC_APPLICATION_TYPE
+MBIM_TYPE_UICC_FILE_ACCESSIBILITY
+MBIM_TYPE_UICC_FILE_TYPE
+MBIM_TYPE_UICC_FILE_STRUCTURE
 mbim_activation_command_get_type
 mbim_activation_state_get_type
 mbim_auth_protocol_get_type
@@ -785,6 +801,10 @@
 mbim_access_media_type_get_type
 mbim_intel_serving_cell_info_get_type
 mbim_intel_boot_mode_get_type
+mbim_uicc_application_type_get_type
+mbim_uicc_file_accessibility_get_type
+mbim_uicc_file_type_get_type
+mbim_uicc_file_structure_get_type
 </SECTION>
 
 <SECTION>
diff --git a/meson.build b/meson.build
index b367882..241fa40 100644
--- a/meson.build
+++ b/meson.build
@@ -3,7 +3,7 @@
 
 project(
   'libmbim', 'c',
-  version: '1.27.8',
+  version: '1.27.9',
   license: ['GPL-2.0-or-later', 'LGPL-2.1-or-later'],
   default_options: [
     'buildtype=debugoptimized',
diff --git a/src/libmbim-glib/mbim-cid.c b/src/libmbim-glib/mbim-cid.c
index ae77e52..d8aa377 100644
--- a/src/libmbim-glib/mbim-cid.c
+++ b/src/libmbim-glib/mbim-cid.c
@@ -179,7 +179,7 @@
 };
 
 /* Note: index of the array is CID-1 */
-#define MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_LAST MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_RESET
+#define MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_LAST MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_READ_RECORD
 static const CidConfig cid_ms_uicc_low_level_access_config [MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_LAST] = {
     { NO_SET,    QUERY,    NO_NOTIFY    }, /* MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_ATR */
     { SET,    NO_QUERY,    NO_NOTIFY    }, /* MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_OPEN_CHANNEL */
@@ -187,6 +187,10 @@
     { SET,    NO_QUERY,    NO_NOTIFY    }, /* MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_APDU */
     { SET,       QUERY,    NO_NOTIFY    }, /* MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_TERMINAL_CAPABILITY */
     { SET,       QUERY,    NO_NOTIFY    }, /* MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_RESET */
+    { NO_SET,    QUERY,    NO_NOTIFY    }, /* MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_APPLICATION_LIST */
+    { NO_SET,    QUERY,    NO_NOTIFY    }, /* MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_FILE_STATUS */
+    { SET,       QUERY,    NO_NOTIFY    }, /* MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_READ_BINARY */
+    { SET,       QUERY,    NO_NOTIFY    }, /* MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_READ_RECORD */
 };
 
 /* Note: index of the array is CID-1 */
diff --git a/src/libmbim-glib/mbim-cid.h b/src/libmbim-glib/mbim-cid.h
index a749f8b..c404271 100644
--- a/src/libmbim-glib/mbim-cid.h
+++ b/src/libmbim-glib/mbim-cid.h
@@ -377,6 +377,10 @@
  * @MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_APDU: Apdu.
  * @MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_TERMINAL_CAPABILITY: Terminal capabilities.
  * @MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_RESET: Reset.
+ * @MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_APPLICATION_LIST: Retrieve application list. Since 1.28.
+ * @MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_FILE_STATUS: Retrieve information about a specific UICC file. Since 1.28.
+ * @MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_READ_BINARY: Read a UICC binary file. Since 1.28.
+ * @MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_READ_RECORD: Read a UICC linear fixed or cyclic file. Since 1.28.
  *
  * MBIM commands in the %MBIM_SERVICE_MS_UICC_LOW_LEVEL_ACCESS service.
  *
@@ -390,6 +394,10 @@
     MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_APDU                 = 4,
     MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_TERMINAL_CAPABILITY  = 5,
     MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_RESET                = 6,
+    MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_APPLICATION_LIST     = 7,
+    MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_FILE_STATUS          = 8,
+    MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_READ_BINARY          = 9,
+    MBIM_CID_MS_UICC_LOW_LEVEL_ACCESS_READ_RECORD          = 10,
 } MbimCidMsUiccLowLevelAccess;
 
 /**
diff --git a/src/libmbim-glib/mbim-enums.h b/src/libmbim-glib/mbim-enums.h
index 9b14606..9dcdfd1 100644
--- a/src/libmbim-glib/mbim-enums.h
+++ b/src/libmbim-glib/mbim-enums.h
@@ -271,6 +271,8 @@
  * @MBIM_PIN_TYPE_NETWORK_SUBSET_PUK: The network subset personalization unlock key.
  * @MBIM_PIN_TYPE_SERVICE_PROVIDER_PUK: The service provider (SP) personalization unlock key.
  * @MBIM_PIN_TYPE_CORPORATE_PUK: The corporate personalization unlock key.
+ * @MBIM_PIN_TYPE_NEV: The NEV key (MS UICC low-level access). Since 1.28.
+ * @MBIM_PIN_TYPE_ADM: The administrative key (MS UICC low-level access). Since 1.28.
  *
  * PIN Types.
  *
@@ -294,7 +296,9 @@
     MBIM_PIN_TYPE_NETWORK_PUK          = 14,
     MBIM_PIN_TYPE_NETWORK_SUBSET_PUK   = 15,
     MBIM_PIN_TYPE_SERVICE_PROVIDER_PUK = 16,
-    MBIM_PIN_TYPE_CORPORATE_PUK        = 17
+    MBIM_PIN_TYPE_CORPORATE_PUK        = 17,
+    MBIM_PIN_TYPE_NEV                  = 18,
+    MBIM_PIN_TYPE_ADM                  = 19,
 } MbimPinType;
 
 /**
@@ -1925,6 +1929,84 @@
     MBIM_INTEL_BOOT_MODE_FAST_DOWNLOAD_MODE       = 5,
 } MbimIntelBootMode;
 
+/**
+ * MbimUiccApplicationType:
+ * @MBIM_UICC_APPLICATION_TYPE_UNKNOWN: Unknown.
+ * @MBIM_UICC_APPLICATION_TYPE_MF: Legacy SIM directories rooted at the MF.
+ * @MBIM_UICC_APPLICATION_TYPE_MF_SIM: Legacy SIM directories rooted at the DF_GSM.
+ * @MBIM_UICC_APPLICATION_TYPE_MF_RUIM: Legacy SIM directories rooted at the DF_CDMA.
+ * @MBIM_UICC_APPLICATION_TYPE_USIM: USIM application.
+ * @MBIM_UICC_APPLICATION_TYPE_CSIM: CSIM application.
+ * @MBIM_UICC_APPLICATION_TYPE_ISIM: ISIM application.
+ *
+ * Type of UICC application.
+ *
+ * Since: 1.28
+ */
+typedef enum { /*< since=1.28 >*/
+    MBIM_UICC_APPLICATION_TYPE_UNKNOWN = 0,
+    MBIM_UICC_APPLICATION_TYPE_MF      = 1,
+    MBIM_UICC_APPLICATION_TYPE_MF_SIM  = 2,
+    MBIM_UICC_APPLICATION_TYPE_MF_RUIM = 3,
+    MBIM_UICC_APPLICATION_TYPE_USIM    = 4,
+    MBIM_UICC_APPLICATION_TYPE_CSIM    = 5,
+    MBIM_UICC_APPLICATION_TYPE_ISIM    = 6,
+} MbimUiccApplicationType;
+
+/**
+ * MbimUiccFileAccessibility:
+ * @MBIM_UICC_FILE_ACCESSIBILITY_UNKNOWN: Unknown.
+ * @MBIM_UICC_FILE_ACCESSIBILITY_NOT_SHAREABLE: Not shareable.
+ * @MBIM_UICC_FILE_ACCESSIBILITY_SHAREABLE: Shareable.
+ *
+ * The UICC file accessibility.
+ *
+ * Since: 1.28
+ */
+typedef enum { /*< since=1.28 >*/
+    MBIM_UICC_FILE_ACCESSIBILITY_UNKNOWN       = 0,
+    MBIM_UICC_FILE_ACCESSIBILITY_NOT_SHAREABLE = 1,
+    MBIM_UICC_FILE_ACCESSIBILITY_SHAREABLE     = 2,
+} MbimUiccFileAccessibility;
+
+/**
+ * MbimUiccFileType:
+ * @MBIM_UICC_FILE_TYPE_UNKNOWN: Unknown.
+ * @MBIM_UICC_FILE_TYPE_WORKING_EF: Working EF.
+ * @MBIM_UICC_FILE_TYPE_INTERNAL_EF: Internal EF.
+ * @MBIM_UICC_FILE_TYPE_DF_OR_ADF: Dedicated file, DF or ADF.
+ *
+ * The UICC file type.
+ *
+ * Since: 1.28
+ */
+typedef enum { /*< since=1.28 >*/
+    MBIM_UICC_FILE_TYPE_UNKNOWN     = 0,
+    MBIM_UICC_FILE_TYPE_WORKING_EF  = 1,
+    MBIM_UICC_FILE_TYPE_INTERNAL_EF = 2,
+    MBIM_UICC_FILE_TYPE_DF_OR_ADF   = 3,
+} MbimUiccFileType;
+
+/**
+ * MbimUiccFileStructure:
+ * @MBIM_UICC_FILE_STRUCTURE_UNKNOWN: Unknown.
+ * @MBIM_UICC_FILE_STRUCTURE_TRANSPARENT: A single record of variable length.
+ * @MBIM_UICC_FILE_STRUCTURE_CYCLIC: A cyclic set of records, each of the same length.
+ * @MBIM_UICC_FILE_STRUCTURE_LINEAR: A linear set of records, each of the same length.
+ * @MBIM_UICC_FILE_STRUCTURE_BER_TLV: A set of data values accessible by tag.
+ *
+ * The UICC file structure.
+ *
+ * Since: 1.28
+ */
+typedef enum { /*< since=1.28 >*/
+    MBIM_UICC_FILE_STRUCTURE_UNKNOWN     = 0,
+    MBIM_UICC_FILE_STRUCTURE_TRANSPARENT = 1,
+    MBIM_UICC_FILE_STRUCTURE_CYCLIC      = 2,
+    MBIM_UICC_FILE_STRUCTURE_LINEAR      = 3,
+    MBIM_UICC_FILE_STRUCTURE_BER_TLV     = 4,
+} MbimUiccFileStructure;
+
 G_END_DECLS
 
 #endif /* _LIBMBIM_GLIB_MBIM_ENUMS_H_ */
diff --git a/src/libmbim-glib/mbim-message-private.h b/src/libmbim-glib/mbim-message-private.h
index 99e878c..9195073 100644
--- a/src/libmbim-glib/mbim-message-private.h
+++ b/src/libmbim-glib/mbim-message-private.h
@@ -258,6 +258,11 @@
 /*****************************************************************************/
 /* Message parser */
 
+typedef enum {
+    MBIM_STRING_ENCODING_UTF16,
+    MBIM_STRING_ENCODING_UTF8,
+} MbimStringEncoding;
+
 gboolean _mbim_message_read_byte_array    (const MbimMessage  *self,
                                            guint32             struct_start_offset,
                                            guint32             relative_offset,
@@ -296,12 +301,14 @@
 gboolean _mbim_message_read_string        (const MbimMessage  *self,
                                            guint32             struct_start_offset,
                                            guint32             relative_offset,
+                                           MbimStringEncoding  encoding,
                                            gchar             **str,
                                            GError            **error);
 gboolean _mbim_message_read_string_array  (const MbimMessage   *self,
                                            guint32              array_size,
                                            guint32              struct_start_offset,
                                            guint32              relative_offset_array_start,
+                                           MbimStringEncoding   encoding,
                                            gchar             ***array,
                                            GError             **error);
 gboolean _mbim_message_read_ipv4          (const MbimMessage  *self,
diff --git a/src/libmbim-glib/mbim-message.c b/src/libmbim-glib/mbim-message.c
index 9274d35..69de3a1 100644
--- a/src/libmbim-glib/mbim-message.c
+++ b/src/libmbim-glib/mbim-message.c
@@ -308,18 +308,17 @@
 }
 
 gboolean
-_mbim_message_read_string (const MbimMessage  *self,
-                           guint32             struct_start_offset,
-                           guint32             relative_offset,
-                           gchar             **str,
-                           GError            **error)
+_mbim_message_read_string (const MbimMessage   *self,
+                           guint32              struct_start_offset,
+                           guint32              relative_offset,
+                           MbimStringEncoding   encoding,
+                           gchar              **str,
+                           GError             **error)
 {
     guint64               required_size;
     guint32               offset;
     guint32               size;
     guint32               information_buffer_offset;
-    g_autofree gunichar2 *utf16d = NULL;
-    const gunichar2      *utf16 = NULL;
 
     information_buffer_offset = _mbim_message_get_information_buffer_offset (self);
 
@@ -352,27 +351,48 @@
         return FALSE;
     }
 
-    utf16 = (const gunichar2 *) G_STRUCT_MEMBER_P (self->data, (information_buffer_offset + struct_start_offset + offset));
+    if (encoding == MBIM_STRING_ENCODING_UTF16) {
+        g_autofree gunichar2 *utf16d = NULL;
+        const gunichar2      *utf16 = NULL;
 
-    /* For BE systems, convert from LE to BE */
-    if (G_BYTE_ORDER == G_BIG_ENDIAN) {
-        guint i;
+        utf16 = (const gunichar2 *) G_STRUCT_MEMBER_P (self->data, (information_buffer_offset + struct_start_offset + offset));
 
-        utf16d = (gunichar2 *) g_malloc (size);
-        for (i = 0; i < (size / 2); i++)
-            utf16d[i] = GUINT16_FROM_LE (utf16[i]);
-    }
+        /* For BE systems, convert from LE to BE */
+        if (G_BYTE_ORDER == G_BIG_ENDIAN) {
+            guint i;
 
-    *str = g_utf16_to_utf8 (utf16d ? utf16d : utf16,
-                            size / 2,
-                            NULL,
-                            NULL,
-                            error);
+            utf16d = (gunichar2 *) g_malloc (size);
+            for (i = 0; i < (size / 2); i++)
+                utf16d[i] = GUINT16_FROM_LE (utf16[i]);
+        }
 
-    if (!(*str)) {
-        g_prefix_error (error, "Error converting string to UTF-8: ");
-        return FALSE;
-    }
+        *str = g_utf16_to_utf8 (utf16d ? utf16d : utf16,
+                                size / 2,
+                                NULL,
+                                NULL,
+                                error);
+
+        if (!(*str)) {
+            g_prefix_error (error, "Error converting string to UTF-8: ");
+            return FALSE;
+        }
+    } else if (encoding == MBIM_STRING_ENCODING_UTF8) {
+        const gchar *utf8;
+
+        utf8 = (const gchar *) G_STRUCT_MEMBER_P (self->data, (information_buffer_offset + struct_start_offset + offset));
+
+        /* size may include the trailing NUL byte, skip it from the check */
+        while (size > 0 && utf8[size - 1] == '\0')
+            size--;
+
+        if (!g_utf8_validate (utf8, size, NULL)) {
+            g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Error validating UTF-8 string");
+            return FALSE;
+        }
+
+        *str = g_strndup (utf8, size);
+    } else
+        g_assert_not_reached ();
 
     return TRUE;
 }
@@ -382,6 +402,7 @@
                                  guint32              array_size,
                                  guint32              struct_start_offset,
                                  guint32              relative_offset_array_start,
+                                 MbimStringEncoding   encoding,
                                  gchar             ***array,
                                  GError             **error)
 {
@@ -401,7 +422,7 @@
          i < array_size;
          offset += 8, i++) {
         /* Read next string in the OL pair list */
-        if (!_mbim_message_read_string (self, struct_start_offset, offset, &((*array)[i]), &inner_error))
+        if (!_mbim_message_read_string (self, struct_start_offset, offset, encoding, &((*array)[i]), &inner_error))
             break;
     }
 
diff --git a/src/libmbim-glib/mbim-proxy.c b/src/libmbim-glib/mbim-proxy.c
index dcbed96..50b15c3 100644
--- a/src/libmbim-glib/mbim-proxy.c
+++ b/src/libmbim-glib/mbim-proxy.c
@@ -771,7 +771,7 @@
     }
 
     /* Retrieve path from request */
-    if (!_mbim_message_read_string (message, 0, 0, &incoming_path, &error)) {
+    if (!_mbim_message_read_string (message, 0, 0, MBIM_STRING_ENCODING_UTF16, &incoming_path, &error)) {
         g_warning ("[client %lu,0x%08x] cannot configure proxy: couldn't read device path from request: %s",
                    request->client->id, request->original_transaction_id, error->message);
         request->response = build_proxy_control_command_done (message, MBIM_STATUS_ERROR_INVALID_PARAMETERS);
diff --git a/src/libmbim-glib/test/test-message-parser.c b/src/libmbim-glib/test/test-message-parser.c
index 7d1b00b..585f6a7 100644
--- a/src/libmbim-glib/test/test-message-parser.c
+++ b/src/libmbim-glib/test/test-message-parser.c
@@ -14,6 +14,7 @@
 #include "mbim-stk.h"
 #include "mbim-ms-firmware-id.h"
 #include "mbim-ms-basic-connect-extensions.h"
+#include "mbim-ms-uicc-low-level-access.h"
 #include "mbim-message.h"
 #include "mbim-tlv.h"
 #include "mbim-cid.h"
@@ -3119,6 +3120,93 @@
     g_assert (memcmp (packet, expected_packet, sizeof (expected_packet)) == 0);
 }
 
+static void
+test_ms_uicc_low_level_access_application_list (void)
+{
+    g_autoptr(GError)                   error = NULL;
+    g_autoptr(MbimMessage)              response = NULL;
+    gboolean                            result;
+    guint32                             version;
+    guint32                             application_count;
+    guint32                             active_application_index;
+    guint32                             application_list_size_bytes;
+    g_autoptr(MbimUiccApplicationArray) applications = NULL;
+
+    const guint8  expected_application_id[] = { 0xA0, 0x00, 0x00, 0x00,
+                                                0x87, 0x10, 0x02, 0xFF,
+                                                0x34, 0xFF, 0x07, 0x89,
+                                                0x31, 0x2E, 0x30, 0xFF };
+    const gchar  *expected_application_name = "Movistar";
+    const guint8  expected_pin_key_references[] = { 0x01, 0x81 };
+
+    const guint8 buffer [] =  {
+        /* header */
+        0x03, 0x00, 0x00, 0x80, /* type */
+        0x84, 0x00, 0x00, 0x00, /* length */
+        0x03, 0x00, 0x00, 0x00, /* transaction id */
+        /* fragment header */
+        0x01, 0x00, 0x00, 0x00, /* total */
+        0x00, 0x00, 0x00, 0x00, /* current */
+        /* command_done message */
+        0xC2, 0xF6, 0x58, 0x8E, /* service id */
+        0xF0, 0x37, 0x4B, 0xC9,
+        0x86, 0x65, 0xF4, 0xD4,
+        0x4B, 0xD0, 0x93, 0x67,
+        0x07, 0x00, 0x00, 0x00, /* command id */
+        0x00, 0x00, 0x00, 0x00, /* status code */
+        0x54, 0x00, 0x00, 0x00, /* buffer_length */
+        /* information buffer */
+        0x01, 0x00, 0x00, 0x00, /* version: 1 */
+        0x01, 0x00, 0x00, 0x00, /* app count: 1 */
+        0x00, 0x00, 0x00, 0x00, /* active app index: 0 */
+        0x3C, 0x00, 0x00, 0x00, /* app list size bytes: 60 */
+        0x18, 0x00, 0x00, 0x00, /* application 0 offset: 24 bytes */
+        0x3C, 0x00, 0x00, 0x00, /* application 0 length: 60 bytes */
+        /* application 0 */
+        0x04, 0x00, 0x00, 0x00, /* application type: usim */
+        0x20, 0x00, 0x00, 0x00, /* application id offset: 32 bytes */
+        0x10, 0x00, 0x00, 0x00, /* application id length: 16 bytes */
+        0x30, 0x00, 0x00, 0x00, /* application name offset: 48 bytes */
+        0x08, 0x00, 0x00, 0x00, /* application name length: 8 bytes */
+        0x02, 0x00, 0x00, 0x00, /* num pin key refs: 2 */
+        0x38, 0x00, 0x00, 0x00, /* pin key refs offset: 56 bytes */
+        0x02, 0x00, 0x00, 0x00, /* pin key refs length: 2 bytes */
+        /* application 0 databuffer */
+        0xA0, 0x00, 0x00, 0x00, /* application id */
+        0x87, 0x10, 0x02, 0xFF,
+        0x34, 0xFF, 0x07, 0x89,
+        0x31, 0x2E, 0x30, 0xFF,
+        0x4D, 0x6F, 0x76, 0x69, /* application name */
+        0x73, 0x74, 0x61, 0x72,
+        0x01, 0x81, 0x00, 0x00, /* pin key refs plus 2 padding bytes */
+    };
+
+    response = mbim_message_new (buffer, sizeof (buffer));
+    test_message_printable (response, 1, 0);
+
+    result = (mbim_message_ms_uicc_low_level_access_application_list_response_parse (
+                  response,
+                  &version,
+                  &application_count,
+                  &active_application_index,
+                  &application_list_size_bytes,
+                  &applications,
+                  &error));
+    g_assert_no_error (error);
+    g_assert (result);
+
+    g_assert_cmpuint (version, ==, 1);
+    g_assert_cmpuint (application_count, ==, 1);
+    g_assert_cmpuint (active_application_index, ==, 0);
+    g_assert_cmpuint (application_list_size_bytes, ==, 60);
+    g_assert_cmpuint (applications[0]->application_id_size, ==, sizeof (expected_application_id));
+    g_assert (memcmp (applications[0]->application_id, expected_application_id, sizeof (expected_application_id)) == 0);
+    g_assert (g_strcmp0 (applications[0]->application_name, expected_application_name) == 0);
+    g_assert_cmpuint (applications[0]->pin_key_reference_count, ==, 2);
+    g_assert_cmpuint (applications[0]->pin_key_references_size, ==, sizeof (expected_pin_key_references));
+    g_assert (memcmp (applications[0]->pin_key_references, expected_pin_key_references, sizeof (expected_pin_key_references)) == 0);
+}
+
 int main (int argc, char **argv)
 {
     g_test_init (&argc, &argv, NULL);
@@ -3159,6 +3247,7 @@
     g_test_add_func (PREFIX "/basic-connect-extensions/wake-reason/command", test_ms_basic_connect_extensions_wake_reason_command);
     g_test_add_func (PREFIX "/basic-connect-extensions/wake-reason/command/payload", test_ms_basic_connect_extensions_wake_reason_command_payload);
     g_test_add_func (PREFIX "/basic-connect-extensions/wake-reason/packet", test_ms_basic_connect_extensions_wake_reason_packet);
+    g_test_add_func (PREFIX "/ms-uicc-low-level-access/application-list", test_ms_uicc_low_level_access_application_list);
 
 #undef PREFIX
 
diff --git a/src/mbimcli/mbimcli-basic-connect.c b/src/mbimcli/mbimcli-basic-connect.c
index 64f78a5..ce22146 100644
--- a/src/mbimcli/mbimcli-basic-connect.c
+++ b/src/mbimcli/mbimcli-basic-connect.c
@@ -60,6 +60,13 @@
 static gchar    *query_ip_packet_filters_str;
 static gchar    *set_ip_packet_filters_str;
 static gboolean  query_provisioned_contexts_flag;
+static gchar    *set_provisioned_contexts_str;
+static gchar    *set_signal_state_str;
+static gchar    *set_network_idle_hint_str;
+static gboolean  query_network_idle_hint_flag;
+static gchar    *set_emergency_mode_str;
+static gboolean  query_emergency_mode_flag;
+static gchar    *set_service_activation_str;
 
 static gboolean query_connection_state_arg_parse (const char *option_name,
                                                   const char *value,
@@ -200,6 +207,34 @@
       "Query provisioned contexts",
       NULL
     },
+    { "set-provisioned-contexts", 0, 0, G_OPTION_ARG_STRING, &set_provisioned_contexts_str,
+      "Set provisioned contexts (allowed keys: context-id, context-type, auth, compression, username, password, access-string, provider-id)",
+      "[\"key=value,...\"]"
+    },
+    { "set-signal-state", 0, 0, G_OPTION_ARG_STRING, &set_signal_state_str,
+      "Set signal state (allowed keys: signal-strength-interval, rssi-threshold, error-rate-threshold)",
+      "[\"key=value,...\"]"
+    },
+    { "set-network-idle-hint", 0, 0, G_OPTION_ARG_STRING, &set_network_idle_hint_str,
+      "Set network idle hint",
+      "[(enabled|disabled)]"
+    },
+    { "query-network-idle-hint", 0, 0, G_OPTION_ARG_NONE, &query_network_idle_hint_flag,
+      "Query network idle hint",
+      NULL
+    },
+    { "set-emergency-mode", 0, 0, G_OPTION_ARG_STRING, &set_emergency_mode_str,
+      "Set emergency mode",
+      "[(on|off)]"
+    },
+    { "query-emergency-mode", 0, 0, G_OPTION_ARG_NONE, &query_emergency_mode_flag,
+      "Query emergency mode",
+      NULL
+    },
+    { "set-service-activation", 0, 0, G_OPTION_ARG_STRING, &set_service_activation_str,
+      "Set service activation",
+      "[Data]"
+    },
     { NULL }
 };
 
@@ -295,7 +330,14 @@
                  query_packet_statistics_flag +
                  !!query_ip_packet_filters_str +
                  !!set_ip_packet_filters_str +
-                 query_provisioned_contexts_flag);
+                 query_provisioned_contexts_flag +
+                 !!set_provisioned_contexts_str +
+                 !!set_signal_state_str +
+                 !!set_network_idle_hint_str +
+                 query_network_idle_hint_flag +
+                 !!set_emergency_mode_str +
+                 query_emergency_mode_flag +
+                 !!set_service_activation_str);
 
     if (n_actions > 1) {
         g_printerr ("error: too many Basic Connect actions requested\n");
@@ -2098,6 +2140,223 @@
     shutdown (TRUE);
 }
 
+typedef struct {
+    guint             context_id;
+    MbimCompression   compression;
+    MbimAuthProtocol  auth_protocol;
+    MbimContextType   context_type;
+    gchar            *access_string;
+    gchar            *username;
+    gchar            *password;
+    gchar            *provider_id;
+} ProvisionedContextProperties;
+
+static void
+provisioned_context_properties_clear (ProvisionedContextProperties *props)
+{
+    g_free (props->access_string);
+    g_free (props->username);
+    g_free (props->password);
+    g_free (props->provider_id);
+}
+
+G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(ProvisionedContextProperties, provisioned_context_properties_clear)
+
+static gboolean
+set_provisioned_contexts_foreach_cb (const gchar                   *key,
+                                     const gchar                   *value,
+                                     GError                       **error,
+                                     ProvisionedContextProperties  *props)
+{
+    if (g_ascii_strcasecmp (key, "context-id") == 0) {
+        if (!mbimcli_read_uint_from_string (value, &props->context_id)) {
+            g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS,
+                         "Couldn't parse context-id as integer : '%s'", value);
+            return FALSE;
+        }
+    } else if (g_ascii_strcasecmp (key, "context-type") == 0) {
+        if (!mbimcli_read_context_type_from_string (value, &props->context_type)) {
+            g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS,
+                         "unknown context-type: '%s'", value);
+            return FALSE;
+        }
+    } else if (g_ascii_strcasecmp (key, "auth") == 0) {
+        if (!mbimcli_read_auth_protocol_from_string (value, &props->auth_protocol)) {
+            g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS,
+                         "unknown auth: '%s'", value);
+            return FALSE;
+        }
+    } else if (g_ascii_strcasecmp (key, "compression") == 0) {
+        if (!mbimcli_read_compression_from_string (value, &props->compression)) {
+            g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS,
+                         "unknown compression: '%s'", value);
+            return FALSE;
+        }
+    } else if (g_ascii_strcasecmp (key, "username") == 0) {
+        g_free (props->username);
+        props->username = g_strdup (value);
+    } else if (g_ascii_strcasecmp (key, "password") == 0) {
+        g_free (props->password);
+        props->password = g_strdup (value);
+    } else if (g_ascii_strcasecmp (key, "access-string") == 0) {
+        g_free (props->access_string);
+        props->access_string = g_strdup (value);
+    } else if (g_ascii_strcasecmp (key, "provider-id") == 0) {
+        g_free (props->provider_id);
+        props->provider_id = g_strdup (value);
+    } else {
+        g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                     "unrecognized option '%s'", key);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+typedef struct {
+    guint32  signal_strength;
+    guint32  rssi;
+    guint32  error_rate;
+} SignalStateProperties;
+
+static gboolean
+set_signal_state_foreach_cb (const gchar            *key,
+                             const gchar            *value,
+                             GError                **error,
+                             SignalStateProperties  *props)
+{
+    if (g_ascii_strcasecmp (key, "signal-strength-interval") == 0) {
+        if (!mbimcli_read_uint_from_string (value, &props->signal_strength)) {
+            g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS,
+                         "Couldn't parse signal-strength as integer : '%s'", value);
+            return FALSE;
+        }
+    } else if (g_ascii_strcasecmp (key, "rssi-threshold") == 0) {
+        if (!mbimcli_read_uint_from_string (value, &props->rssi)) {
+            g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS,
+                         "Couldn't parse rssi as integer : '%s'", value);
+            return FALSE;
+        }
+    } else if (g_ascii_strcasecmp (key, "error-rate-threshold") == 0) {
+        if (!mbimcli_read_uint_from_string (value, &props->error_rate)) {
+            g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS,
+                         "Couldn't parse error-rate as integer : '%s'", value);
+            return FALSE;
+        }
+    } else {
+        g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                     "unrecognized option '%s'", key);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static void
+network_idle_hint_ready (MbimDevice   *device,
+                         GAsyncResult *res)
+{
+    g_autoptr(MbimMessage)    response = NULL;
+    g_autoptr(GError)         error = NULL;
+    MbimNetworkIdleHintState  network_state;
+    const gchar              *network_state_str = NULL;
+
+    response = mbim_device_command_finish (device, res, &error);
+    if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) {
+        g_printerr ("error: operation failed: %s\n", error->message);
+        shutdown (FALSE);
+        return;
+    }
+
+    if (!mbim_message_network_idle_hint_response_parse (
+            response,
+            &network_state,
+            &error)) {
+        g_printerr ("error: couldn't parse response message: %s\n", error->message);
+        shutdown (FALSE);
+        return;
+    }
+
+    network_state_str = mbim_network_idle_hint_state_get_string (network_state);
+    g_print ("[%s] Network idle hint state: '%s'\n",
+             mbim_device_get_path_display (device),
+             VALIDATE_UNKNOWN (network_state_str));
+
+    shutdown (TRUE);
+}
+
+static void
+emergency_mode_ready (MbimDevice   *device,
+                      GAsyncResult *res)
+{
+    g_autoptr(MbimMessage)  response = NULL;
+    g_autoptr(GError)       error = NULL;
+    MbimEmergencyModeState  emergency_state;
+    const gchar            *emergency_state_str = NULL;
+
+    response = mbim_device_command_finish (device, res, &error);
+    if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) {
+        g_printerr ("error: operation failed: %s\n", error->message);
+        shutdown (FALSE);
+        return;
+    }
+
+    if (!mbim_message_emergency_mode_response_parse (
+            response,
+            &emergency_state,
+            &error)) {
+        g_printerr ("error: couldn't parse response message: %s\n", error->message);
+        shutdown (FALSE);
+        return;
+    }
+
+    emergency_state_str = mbim_emergency_mode_state_get_string (emergency_state);
+    g_print ("[%s] Emergency mode: '%s'\n",
+             mbim_device_get_path_display (device),
+             VALIDATE_UNKNOWN (emergency_state_str));
+
+    shutdown (TRUE);
+}
+
+static void
+set_service_activation_ready (MbimDevice   *device,
+                              GAsyncResult *res)
+{
+    g_autoptr(MbimMessage)  response = NULL;
+    g_autoptr(GError)       error = NULL;
+    MbimNwError             nw_error;
+    guint32                 result_data_size;
+    const guint8           *result_data = NULL;
+    g_autofree gchar       *result_data_str = NULL;
+
+    response = mbim_device_command_finish (device, res, &error);
+    if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) {
+        g_printerr ("error: operation failed: %s\n", error->message);
+        shutdown (FALSE);
+        return;
+    }
+
+    if (!mbim_message_service_activation_response_parse (response,
+                                                         &nw_error,
+                                                         &result_data_size,
+                                                         &result_data,
+                                                         &error)) {
+        g_printerr ("error: couldn't parse response message: %s\n", error->message);
+        shutdown (FALSE);
+        return;
+    }
+
+    result_data_str = mbim_common_str_hex (result_data, result_data_size, ':');
+    g_print ("[%s] Service activation response received successfully:\n"
+             "\t         Network error: '%s'\n"
+             "\t                  Data: '%s'\n",
+             mbim_device_get_path_display (device),
+             VALIDATE_UNKNOWN (mbim_nw_error_get_string (nw_error)),
+             result_data_str);
+
+    shutdown (TRUE);
+}
+
 void
 mbimcli_basic_connect_run (MbimDevice   *device,
                            GCancellable *cancellable)
@@ -2664,5 +2923,191 @@
         return;
     }
 
+    /* Set provisioned context */
+    if (set_provisioned_contexts_str) {
+        g_auto(ProvisionedContextProperties) props = {
+            .access_string   = NULL,
+            .context_id      = 0,
+            .auth_protocol   = MBIM_AUTH_PROTOCOL_NONE,
+            .username        = NULL,
+            .password        = NULL,
+            .compression     = MBIM_COMPRESSION_NONE,
+            .context_type    = MBIM_CONTEXT_TYPE_INVALID,
+            .provider_id     = NULL
+        };
+
+        if (!mbimcli_parse_key_value_string (set_provisioned_contexts_str,
+                                             &error,
+                                             (MbimParseKeyValueForeachFn)set_provisioned_contexts_foreach_cb,
+                                             &props)) {
+            g_printerr ("error: couldn't parse input string: %s\n", error->message);
+            shutdown (FALSE);
+            return;
+        }
+
+        request = mbim_message_provisioned_contexts_set_new ((guint32)props.context_id,
+                                                             mbim_uuid_from_context_type (props.context_type),
+                                                             props.access_string,
+                                                             props.username,
+                                                             props.password,
+                                                             props.compression,
+                                                             props.auth_protocol,
+                                                             props.provider_id,
+                                                             &error);
+        if (!request) {
+            g_printerr ("error: couldn't create request: %s\n", error->message);
+            shutdown (FALSE);
+            return;
+        }
+
+        mbim_device_command (ctx->device,
+                             request,
+                             60,
+                             ctx->cancellable,
+                             (GAsyncReadyCallback)provisioned_contexts_ready,
+                             NULL);
+        return;
+    }
+
+    /* Set signal state */
+    if (set_signal_state_str) {
+        SignalStateProperties props = {
+            .signal_strength = 0,
+            .rssi            = 0,
+            .error_rate      = 0
+        };
+
+        if (!mbimcli_parse_key_value_string (set_signal_state_str,
+                                             &error,
+                                             (MbimParseKeyValueForeachFn)set_signal_state_foreach_cb,
+                                             &props)) {
+            g_printerr ("error: couldn't parse input string: %s\n", error->message);
+            shutdown (FALSE);
+            return;
+        }
+
+        request = mbim_message_signal_state_set_new (props.signal_strength,
+                                                     props.rssi,
+                                                     props.error_rate,
+                                                     &error);
+        if (!request) {
+            g_printerr ("error: couldn't create request: %s\n", error->message);
+            shutdown (FALSE);
+            return;
+        }
+
+        mbim_device_command (ctx->device,
+                             request,
+                             60,
+                             ctx->cancellable,
+                             (GAsyncReadyCallback)signal_state_ready,
+                             NULL);
+        return;
+    }
+
+    /* Set network idle hint state */
+    if (set_network_idle_hint_str) {
+        MbimNetworkIdleHintState  network_state;
+
+        if (!mbimcli_read_network_idle_hint_state_from_string (set_network_idle_hint_str, &network_state)) {
+            shutdown (FALSE);
+            return;
+        }
+
+        request = mbim_message_network_idle_hint_set_new (network_state, &error);
+        if (!request) {
+            g_printerr ("error: couldn't create request: %s\n", error->message);
+            shutdown (FALSE);
+            return;
+        }
+
+        mbim_device_command (ctx->device,
+                             request,
+                             10,
+                             ctx->cancellable,
+                             (GAsyncReadyCallback)network_idle_hint_ready,
+                             NULL);
+        return;
+    }
+
+    /* Get network idle hint state */
+    if (query_network_idle_hint_flag) {
+        request = mbim_message_network_idle_hint_query_new (NULL);
+        mbim_device_command (ctx->device,
+                             request,
+                             10,
+                             ctx->cancellable,
+                             (GAsyncReadyCallback)network_idle_hint_ready,
+                             NULL);
+        return;
+    }
+
+    /* Set emergency mode state */
+    if (set_emergency_mode_str) {
+        MbimEmergencyModeState  emergency_state;
+
+        if (!mbimcli_read_emergency_mode_state_from_string (set_emergency_mode_str, &emergency_state)) {
+            shutdown (FALSE);
+            return;
+        }
+
+        request = mbim_message_emergency_mode_set_new (emergency_state, &error);
+        if (!request) {
+            g_printerr ("error: couldn't create request: %s\n", error->message);
+            shutdown (FALSE);
+            return;
+        }
+
+        mbim_device_command (ctx->device,
+                             request,
+                             10,
+                             ctx->cancellable,
+                             (GAsyncReadyCallback)emergency_mode_ready,
+                             NULL);
+        return;
+    }
+
+    /* Query emergency mode state */
+    if (query_emergency_mode_flag) {
+        request = mbim_message_emergency_mode_query_new (NULL);
+        mbim_device_command (ctx->device,
+                             request,
+                             10,
+                             ctx->cancellable,
+                             (GAsyncReadyCallback)emergency_mode_ready,
+                             NULL);
+        return;
+    }
+
+    /* Request to set service activation */
+    if (set_service_activation_str) {
+        guint8 *data = NULL;
+        gsize   data_size = 0;
+
+        data = mbimcli_read_buffer_from_string (set_service_activation_str, -1, &data_size, &error);
+        if (!data) {
+            g_printerr ("error: couldn't parse the input: %s\n", error->message);
+            shutdown (FALSE);
+            return;
+        }
+
+        request = mbim_message_service_activation_set_new (data_size,
+                                                           data,
+                                                           &error);
+        if (!request) {
+            g_printerr ("error: couldn't create request: %s\n", error->message);
+            shutdown (FALSE);
+            return;
+        }
+
+        mbim_device_command (ctx->device,
+                             request,
+                             10,
+                             ctx->cancellable,
+                             (GAsyncReadyCallback)set_service_activation_ready,
+                             NULL);
+        return;
+    }
+
     g_warn_if_reached ();
 }
diff --git a/src/mbimcli/mbimcli-helpers.h b/src/mbimcli/mbimcli-helpers.h
index b512005..247624c 100644
--- a/src/mbimcli/mbimcli-helpers.h
+++ b/src/mbimcli/mbimcli-helpers.h
@@ -65,6 +65,8 @@
     MBIMCLI_ENUM_LIST_ITEM (MbimLadnInfo,                 ladn_info,                   "ladn info")                   \
     MBIMCLI_ENUM_LIST_ITEM (MbimDefaultPduActivationHint, default_pdu_activation_hint, "default pdu activation hint") \
     MBIMCLI_ENUM_LIST_ITEM (MbimAccessMediaType,          access_media_type,           "access media type")           \
+    MBIMCLI_ENUM_LIST_ITEM (MbimNetworkIdleHintState,     network_idle_hint_state,     "network idle hint state")     \
+    MBIMCLI_ENUM_LIST_ITEM (MbimEmergencyModeState,       emergency_mode_state,        "emergency mode state")        \
     MBIMCLI_ENUM_LIST_ITEM (MbimIntelBootMode,            intel_boot_mode,             "intel boot mode")
 
 #define MBIMCLI_ENUM_LIST_ITEM(TYPE,TYPE_UNDERSCORE,DESCR)        \
diff --git a/src/mbimcli/mbimcli-ms-uicc-low-level-access.c b/src/mbimcli/mbimcli-ms-uicc-low-level-access.c
new file mode 100644
index 0000000..9f0ea05
--- /dev/null
+++ b/src/mbimcli/mbimcli-ms-uicc-low-level-access.c
@@ -0,0 +1,746 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * mbimcli -- Command line interface to control MBIM devices
+ *
+ * Copyright (C) 2022 Google, Inc.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <libmbim-glib.h>
+
+#include "mbim-common.h"
+#include "mbimcli.h"
+#include "mbimcli-helpers.h"
+
+/* Context */
+typedef struct {
+    MbimDevice   *device;
+    GCancellable *cancellable;
+} Context;
+static Context *ctx;
+
+/* Options */
+static gboolean  query_uicc_application_list_flag;
+static gchar    *query_uicc_file_status_str;
+static gchar    *query_uicc_read_binary_str;
+static gchar    *query_uicc_read_record_str;
+
+static GOptionEntry entries[] = {
+    { "ms-query-uicc-application-list", 0, 0, G_OPTION_ARG_NONE, &query_uicc_application_list_flag,
+      "Query UICC application list",
+      NULL
+    },
+    { "ms-query-uicc-file-status", 0, 0, G_OPTION_ARG_STRING, &query_uicc_file_status_str,
+      "Query UICC file status (allowed keys: application-id, file-path)",
+      "[\"key=value,...\"]"
+    },
+    { "ms-query-uicc-read-binary", 0, 0, G_OPTION_ARG_STRING, &query_uicc_read_binary_str,
+      "Read UICC binary file (allowed keys: application-id, file-path, read-offset, read-size, local-pin and data)",
+      "[\"key=value,...\"]"
+    },
+    { "ms-query-uicc-read-record", 0, 0, G_OPTION_ARG_STRING, &query_uicc_read_record_str,
+      "Read UICC record file (allowed keys: application-id, file-path, record-number, local-pin and data)",
+      "[\"key=value,...\"]"
+    },
+    { NULL }
+};
+
+GOptionGroup *
+mbimcli_ms_uicc_low_level_access_get_option_group (void)
+{
+   GOptionGroup *group;
+
+   group = g_option_group_new ("ms-uicc-low-level-access",
+                               "Microsoft UICC Low Level Access Service options:",
+                               "Show Microsoft UICC Low Level Access Service options",
+                               NULL,
+                               NULL);
+   g_option_group_add_entries (group, entries);
+
+   return group;
+}
+
+gboolean
+mbimcli_ms_uicc_low_level_access_options_enabled (void)
+{
+    static guint n_actions = 0;
+    static gboolean checked = FALSE;
+
+    if (checked)
+        return !!n_actions;
+
+    n_actions = query_uicc_application_list_flag +
+                !!query_uicc_file_status_str +
+                !!query_uicc_read_binary_str +
+                !!query_uicc_read_record_str;
+
+    if (n_actions > 1) {
+        g_printerr ("error: too many Microsoft UICC Low Level Access Service actions requested\n");
+        exit (EXIT_FAILURE);
+    }
+
+    checked = TRUE;
+    return !!n_actions;
+}
+
+static void
+context_free (Context *context)
+{
+    if (!context)
+        return;
+
+    if (context->cancellable)
+        g_object_unref (context->cancellable);
+    if (context->device)
+        g_object_unref (context->device);
+    g_slice_free (Context, context);
+}
+
+static void
+shutdown (gboolean operation_status)
+{
+    /* Cleanup context and finish async operation */
+    context_free (ctx);
+    mbimcli_async_operation_done (operation_status);
+}
+
+static void
+read_record_query_ready (MbimDevice   *device,
+                         GAsyncResult *res)
+{
+    g_autoptr(MbimMessage)    response = NULL;
+    g_autoptr(GError)         error = NULL;
+    guint32                   status_word_1;
+    guint32                   status_word_2;
+    const guint8             *data;
+    guint32                   data_size;
+    g_autofree gchar         *data_str = NULL;
+
+    response = mbim_device_command_finish (device, res, &error);
+    if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) {
+        g_printerr ("error: operation failed: %s\n", error->message);
+        shutdown (FALSE);
+        return;
+    }
+
+    if (!mbim_message_ms_uicc_low_level_access_read_record_response_parse (
+            response,
+            NULL, /* version */
+            &status_word_1,
+            &status_word_2,
+            &data_size,
+            &data,
+            &error)) {
+        g_printerr ("error: couldn't parse response message: %s\n", error->message);
+        shutdown (FALSE);
+        return;
+    }
+
+    data_str = mbim_common_str_hex (data, data_size, ':');
+
+    g_print ("[%s] UICC file record read:\n"
+             "\tStatus word 1: %u\n"
+             "\tStatus word 2: %u\n"
+             "\t         Data: %s\n",
+             mbim_device_get_path_display (device),
+             status_word_1,
+             status_word_2,
+             data_str);
+
+    shutdown (TRUE);
+}
+
+typedef struct {
+    gsize    application_id_size;
+    guint8  *application_id;
+    gsize    file_path_size;
+    guint8  *file_path;
+    guint32  record_number;
+    gchar   *local_pin;
+    gsize    data_size;
+    guint8  *data;
+} ReadRecordQueryProperties;
+
+static void
+read_record_query_properties_clear (ReadRecordQueryProperties *props)
+{
+    g_clear_pointer (&props->application_id, g_free);
+    g_clear_pointer (&props->file_path, g_free);
+    g_clear_pointer (&props->local_pin, g_free);
+    g_clear_pointer (&props->data, g_free);
+}
+
+G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(ReadRecordQueryProperties, read_record_query_properties_clear);
+
+static gboolean
+read_record_query_properties_handle (const gchar  *key,
+                                     const gchar  *value,
+                                     GError      **error,
+                                     gpointer      user_data)
+{
+    ReadRecordQueryProperties *props = user_data;
+
+    if (g_ascii_strcasecmp (key, "application-id") == 0) {
+        g_clear_pointer (&props->application_id, g_free);
+        props->application_id_size = 0;
+        props->application_id = mbimcli_read_buffer_from_string (value, -1, &props->application_id_size, error);
+        if (!props->application_id)
+            return FALSE;
+    } else if (g_ascii_strcasecmp (key, "file-path") == 0) {
+        g_clear_pointer (&props->file_path, g_free);
+        props->file_path_size = 0;
+        props->file_path = mbimcli_read_buffer_from_string (value, -1, &props->file_path_size, error);
+        if (!props->file_path)
+            return FALSE;
+    } else if (g_ascii_strcasecmp (key, "record-number") == 0) {
+        if (!mbimcli_read_uint_from_string (value, &props->record_number)) {
+            g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                         "Failed to parse field as an integer");
+            return FALSE;
+        }
+    } else if (g_ascii_strcasecmp (key, "local-pin") == 0) {
+        g_clear_pointer (&props->local_pin, g_free);
+        props->local_pin = g_strdup (value);
+    } else if (g_ascii_strcasecmp (key, "data") == 0) {
+        g_clear_pointer (&props->data, g_free);
+        props->data_size = 0;
+        props->data = mbimcli_read_buffer_from_string (value, -1, &props->data_size, error);
+        if (!props->data)
+            return FALSE;
+    } else {
+        g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                     "unrecognized option '%s'", key);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean
+read_record_query_input_parse (const gchar                *str,
+                               ReadRecordQueryProperties  *props,
+                               GError                    **error)
+{
+
+    if (!mbimcli_parse_key_value_string (str,
+                                         error,
+                                         read_record_query_properties_handle,
+                                         props))
+        return FALSE;
+
+    if (!props->application_id_size || !props->application_id) {
+        g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                     "Option 'application-id' is missing");
+        return FALSE;
+    }
+
+    if (!props->file_path_size || !props->file_path) {
+        g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                     "Option 'file-path' is missing");
+        return FALSE;
+    }
+
+    /* all the other fields are optional */
+
+    return TRUE;
+}
+
+static void
+read_binary_query_ready (MbimDevice   *device,
+                         GAsyncResult *res)
+{
+    g_autoptr(MbimMessage)    response = NULL;
+    g_autoptr(GError)         error = NULL;
+    guint32                   status_word_1;
+    guint32                   status_word_2;
+    const guint8             *data;
+    guint32                   data_size;
+    g_autofree gchar         *data_str = NULL;
+
+    response = mbim_device_command_finish (device, res, &error);
+    if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) {
+        g_printerr ("error: operation failed: %s\n", error->message);
+        shutdown (FALSE);
+        return;
+    }
+
+    if (!mbim_message_ms_uicc_low_level_access_read_binary_response_parse (
+            response,
+            NULL, /* version */
+            &status_word_1,
+            &status_word_2,
+            &data_size,
+            &data,
+            &error)) {
+        g_printerr ("error: couldn't parse response message: %s\n", error->message);
+        shutdown (FALSE);
+        return;
+    }
+
+    data_str = mbim_common_str_hex (data, data_size, ':');
+
+    g_print ("[%s] UICC file binary read:\n"
+             "\tStatus word 1: %u\n"
+             "\tStatus word 2: %u\n"
+             "\t         Data: %s\n",
+             mbim_device_get_path_display (device),
+             status_word_1,
+             status_word_2,
+             data_str);
+
+    shutdown (TRUE);
+}
+
+typedef struct {
+    gsize    application_id_size;
+    guint8  *application_id;
+    gsize    file_path_size;
+    guint8  *file_path;
+    guint32  read_offset;
+    guint32  read_size;
+    gchar   *local_pin;
+    gsize    data_size;
+    guint8  *data;
+} ReadBinaryQueryProperties;
+
+static void
+read_binary_query_properties_clear (ReadBinaryQueryProperties *props)
+{
+    g_clear_pointer (&props->application_id, g_free);
+    g_clear_pointer (&props->file_path, g_free);
+    g_clear_pointer (&props->local_pin, g_free);
+    g_clear_pointer (&props->data, g_free);
+}
+
+G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(ReadBinaryQueryProperties, read_binary_query_properties_clear);
+
+static gboolean
+read_binary_query_properties_handle (const gchar  *key,
+                                     const gchar  *value,
+                                     GError      **error,
+                                     gpointer      user_data)
+{
+    ReadBinaryQueryProperties *props = user_data;
+
+    if (g_ascii_strcasecmp (key, "application-id") == 0) {
+        g_clear_pointer (&props->application_id, g_free);
+        props->application_id_size = 0;
+        props->application_id = mbimcli_read_buffer_from_string (value, -1, &props->application_id_size, error);
+        if (!props->application_id)
+            return FALSE;
+    } else if (g_ascii_strcasecmp (key, "file-path") == 0) {
+        g_clear_pointer (&props->file_path, g_free);
+        props->file_path_size = 0;
+        props->file_path = mbimcli_read_buffer_from_string (value, -1, &props->file_path_size, error);
+        if (!props->file_path)
+            return FALSE;
+    } else if (g_ascii_strcasecmp (key, "read-offset") == 0) {
+        if (!mbimcli_read_uint_from_string (value, &props->read_offset)) {
+            g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                         "Failed to parse field as an integer");
+            return FALSE;
+        }
+    } else if (g_ascii_strcasecmp (key, "read-size") == 0) {
+        if (!mbimcli_read_uint_from_string (value, &props->read_size)) {
+            g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                         "Failed to parse field as an integer");
+            return FALSE;
+        }
+    } else if (g_ascii_strcasecmp (key, "local-pin") == 0) {
+        g_clear_pointer (&props->local_pin, g_free);
+        props->local_pin = g_strdup (value);
+    } else if (g_ascii_strcasecmp (key, "data") == 0) {
+        g_clear_pointer (&props->data, g_free);
+        props->data_size = 0;
+        props->data = mbimcli_read_buffer_from_string (value, -1, &props->data_size, error);
+        if (!props->data)
+            return FALSE;
+    } else {
+        g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                     "unrecognized option '%s'", key);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean
+read_binary_query_input_parse (const gchar                *str,
+                               ReadBinaryQueryProperties  *props,
+                               GError                    **error)
+{
+
+    if (!mbimcli_parse_key_value_string (str,
+                                         error,
+                                         read_binary_query_properties_handle,
+                                         props))
+        return FALSE;
+
+    if (!props->application_id_size || !props->application_id) {
+        g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                     "Option 'application-id' is missing");
+        return FALSE;
+    }
+
+    if (!props->file_path_size || !props->file_path) {
+        g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                     "Option 'file-path' is missing");
+        return FALSE;
+    }
+
+    /* all the other fields are optional */
+
+    return TRUE;
+}
+
+static void
+file_status_query_ready (MbimDevice   *device,
+                         GAsyncResult *res)
+{
+    g_autoptr(MbimMessage)    response = NULL;
+    g_autoptr(GError)         error = NULL;
+    guint32                   status_word_1;
+    guint32                   status_word_2;
+    MbimUiccFileAccessibility file_accessibility;
+    MbimUiccFileType          file_type;
+    MbimUiccFileStructure     file_structure;
+    guint32                   file_item_count;
+    guint32                   file_item_size;
+    MbimPinType               access_condition_read;
+    MbimPinType               access_condition_update;
+    MbimPinType               access_condition_activate;
+    MbimPinType               access_condition_deactivate;
+
+    response = mbim_device_command_finish (device, res, &error);
+    if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) {
+        g_printerr ("error: operation failed: %s\n", error->message);
+        shutdown (FALSE);
+        return;
+    }
+
+    if (!mbim_message_ms_uicc_low_level_access_file_status_response_parse (
+            response,
+            NULL, /* version */
+            &status_word_1,
+            &status_word_2,
+            &file_accessibility,
+            &file_type,
+            &file_structure,
+            &file_item_count,
+            &file_item_size,
+            &access_condition_read,
+            &access_condition_update,
+            &access_condition_activate,
+            &access_condition_deactivate,
+            &error)) {
+        g_printerr ("error: couldn't parse response message: %s\n", error->message);
+        shutdown (FALSE);
+        return;
+    }
+
+    g_print ("[%s] UICC file status retrieved:\n"
+             "\t    Status word 1: %u\n"
+             "\t    Status word 2: %u\n"
+             "\t    Accessibility: %s\n"
+             "\t             Type: %s\n"
+             "\t        Structure: %s\n"
+             "\t       Item count: %u\n"
+             "\t        Item size: %u\n"
+             "\tAccess conditions:\n"
+             "\t                 Read: %s\n"
+             "\t               Update: %s\n"
+             "\t             Activate: %s\n"
+             "\t           Deactivate: %s\n",
+             mbim_device_get_path_display (device),
+             status_word_1,
+             status_word_2,
+             mbim_uicc_file_accessibility_get_string (file_accessibility),
+             mbim_uicc_file_type_get_string (file_type),
+             mbim_uicc_file_structure_get_string (file_structure),
+             file_item_count,
+             file_item_size,
+             mbim_pin_type_get_string (access_condition_read),
+             mbim_pin_type_get_string (access_condition_update),
+             mbim_pin_type_get_string (access_condition_activate),
+             mbim_pin_type_get_string (access_condition_deactivate));
+
+    shutdown (TRUE);
+}
+
+typedef struct {
+    gsize   application_id_size;
+    guint8 *application_id;
+    gsize   file_path_size;
+    guint8 *file_path;
+} FileStatusQueryProperties;
+
+static void
+file_status_query_properties_clear (FileStatusQueryProperties *props)
+{
+    g_clear_pointer (&props->application_id, g_free);
+    g_clear_pointer (&props->file_path, g_free);
+}
+
+G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(FileStatusQueryProperties, file_status_query_properties_clear);
+
+static gboolean
+file_status_query_properties_handle (const gchar  *key,
+                                     const gchar  *value,
+                                     GError      **error,
+                                     gpointer      user_data)
+{
+    FileStatusQueryProperties *props = user_data;
+
+    if (g_ascii_strcasecmp (key, "application-id") == 0) {
+        g_clear_pointer (&props->application_id, g_free);
+        props->application_id_size = 0;
+        props->application_id = mbimcli_read_buffer_from_string (value, -1, &props->application_id_size, error);
+        if (!props->application_id)
+            return FALSE;
+    } else if (g_ascii_strcasecmp (key, "file-path") == 0) {
+        g_clear_pointer (&props->file_path, g_free);
+        props->file_path_size = 0;
+        props->file_path = mbimcli_read_buffer_from_string (value, -1, &props->file_path_size, error);
+        if (!props->file_path)
+            return FALSE;
+    } else {
+        g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                     "unrecognized option '%s'", key);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean
+file_status_query_input_parse (const gchar                *str,
+                               FileStatusQueryProperties  *props,
+                               GError                    **error)
+{
+
+    if (!mbimcli_parse_key_value_string (str,
+                                         error,
+                                         file_status_query_properties_handle,
+                                         props))
+        return FALSE;
+
+    if (!props->application_id_size || !props->application_id) {
+        g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                     "Option 'application-id' is missing");
+        return FALSE;
+    }
+
+    if (!props->file_path_size || !props->file_path) {
+        g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                     "Option 'file-path' is missing");
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static void
+application_list_query_ready (MbimDevice   *device,
+                              GAsyncResult *res)
+{
+    g_autoptr(MbimMessage)              response = NULL;
+    g_autoptr(GError)                   error = NULL;
+    guint32                             application_count;
+    guint32                             active_application_index;
+    g_autoptr(MbimUiccApplicationArray) applications = NULL;
+    guint32                             i;
+
+    response = mbim_device_command_finish (device, res, &error);
+    if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) {
+        g_printerr ("error: operation failed: %s\n", error->message);
+        shutdown (FALSE);
+        return;
+    }
+
+    if (!mbim_message_ms_uicc_low_level_access_application_list_response_parse (
+            response,
+            NULL, /* version */
+            &application_count,
+            &active_application_index,
+            NULL, /* application_list_size_bytes */
+            &applications,
+            &error)) {
+        g_printerr ("error: couldn't parse response message: %s\n", error->message);
+        shutdown (FALSE);
+        return;
+    }
+
+    g_print ("[%s] UICC applications: (%u)\n",
+             mbim_device_get_path_display (device),
+             application_count);
+
+    for (i = 0; i < application_count; i++) {
+        g_autofree gchar *application_id_str = NULL;
+        g_autofree gchar *pin_key_references_str = NULL;
+
+        application_id_str = mbim_common_str_hex (applications[i]->application_id, applications[i]->application_id_size, ':');
+        pin_key_references_str = mbim_common_str_hex (applications[i]->pin_key_references, applications[i]->pin_key_references_size, ':');
+
+        g_print ("Application %u:%s\n",             i, (i == active_application_index) ? " (active)" : "");
+        g_print ("\tApplication type:        %s\n", mbim_uicc_application_type_get_string (applications[i]->application_type));
+        g_print ("\tApplication ID:          %s\n", application_id_str);
+        g_print ("\tApplication name:        %s\n", applications[i]->application_name);
+        g_print ("\tPIN key reference count: %u\n", applications[i]->pin_key_reference_count);
+        g_print ("\tPIN key references:      %s\n", pin_key_references_str);
+    }
+
+    shutdown (TRUE);
+}
+
+void
+mbimcli_ms_uicc_low_level_access_run (MbimDevice   *device,
+                                      GCancellable *cancellable)
+{
+    g_autoptr(MbimMessage) request = NULL;
+    g_autoptr(GError)      error = NULL;
+
+    /* Initialize context */
+    ctx = g_slice_new (Context);
+    ctx->device = g_object_ref (device);
+    ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+
+    /* Request to query UICC application list? */
+    if (query_uicc_application_list_flag) {
+        g_debug ("Asynchronously querying UICC application list...");
+        request = mbim_message_ms_uicc_low_level_access_application_list_query_new (NULL);
+        mbim_device_command (ctx->device,
+                             request,
+                             10,
+                             ctx->cancellable,
+                             (GAsyncReadyCallback)application_list_query_ready,
+                             NULL);
+        return;
+    }
+
+    /* Request to query UICC file status? */
+    if (query_uicc_file_status_str) {
+        g_auto(FileStatusQueryProperties) props = {
+            .application_id_size = 0,
+            .application_id      = NULL,
+            .file_path_size      = 0,
+            .file_path           = NULL,
+        };
+
+        g_debug ("Asynchronously querying UICC file status...");
+
+        if (!file_status_query_input_parse (query_uicc_file_status_str, &props, &error)) {
+            g_printerr ("error: couldn't parse input arguments: %s\n", error->message);
+            shutdown (FALSE);
+            return;
+        }
+
+        request = mbim_message_ms_uicc_low_level_access_file_status_query_new (1, /* version fixed */
+                                                                               props.application_id_size,
+                                                                               props.application_id,
+                                                                               props.file_path_size,
+                                                                               props.file_path,
+                                                                               NULL);
+        mbim_device_command (ctx->device,
+                             request,
+                             10,
+                             ctx->cancellable,
+                             (GAsyncReadyCallback)file_status_query_ready,
+                             NULL);
+        return;
+    }
+
+    /* Request to UICC read binary? */
+    if (query_uicc_read_binary_str) {
+        g_auto(ReadBinaryQueryProperties) props = {
+            .application_id_size = 0,
+            .application_id      = NULL,
+            .file_path_size      = 0,
+            .file_path           = NULL,
+            .read_offset         = 0,
+            .read_size           = 0,
+            .local_pin           = NULL,
+            .data_size           = 0,
+            .data                = NULL,
+        };
+
+        g_debug ("Asynchronously reading from UICC in binary...");
+
+        if (!read_binary_query_input_parse (query_uicc_read_binary_str, &props, &error)) {
+            g_printerr ("error: couldn't parse input arguments: %s\n", error->message);
+            shutdown (FALSE);
+            return;
+        }
+
+        request = mbim_message_ms_uicc_low_level_access_read_binary_query_new (1, /* version fixed */
+                                                                               props.application_id_size,
+                                                                               props.application_id,
+                                                                               props.file_path_size,
+                                                                               props.file_path,
+                                                                               props.read_offset,
+                                                                               props.read_size,
+                                                                               props.local_pin,
+                                                                               props.data_size,
+                                                                               props.data,
+                                                                               NULL);
+        mbim_device_command (ctx->device,
+                             request,
+                             10,
+                             ctx->cancellable,
+                             (GAsyncReadyCallback)read_binary_query_ready,
+                             NULL);
+        return;
+    }
+
+    /* Request to UICC read record? */
+    if (query_uicc_read_record_str) {
+        g_auto(ReadRecordQueryProperties) props = {
+            .application_id_size = 0,
+            .application_id      = NULL,
+            .file_path_size      = 0,
+            .file_path           = NULL,
+            .record_number       = 0,
+            .local_pin           = NULL,
+            .data_size           = 0,
+            .data                = NULL,
+        };
+
+        g_debug ("Asynchronously reading from UICC record...");
+
+        if (!read_record_query_input_parse (query_uicc_read_record_str, &props, &error)) {
+            g_printerr ("error: couldn't parse input arguments: %s\n", error->message);
+            shutdown (FALSE);
+            return;
+        }
+
+        request = mbim_message_ms_uicc_low_level_access_read_record_query_new (1, /* version fixed */
+                                                                               props.application_id_size,
+                                                                               props.application_id,
+                                                                               props.file_path_size,
+                                                                               props.file_path,
+                                                                               props.record_number,
+                                                                               props.local_pin,
+                                                                               props.data_size,
+                                                                               props.data,
+                                                                               NULL);
+        mbim_device_command (ctx->device,
+                             request,
+                             10,
+                             ctx->cancellable,
+                             (GAsyncReadyCallback)read_record_query_ready,
+                             NULL);
+        return;
+    }
+
+    g_warn_if_reached ();
+}
diff --git a/src/mbimcli/mbimcli.c b/src/mbimcli/mbimcli.c
index 65cf268..3c12ac6 100644
--- a/src/mbimcli/mbimcli.c
+++ b/src/mbimcli/mbimcli.c
@@ -308,6 +308,9 @@
     case MBIM_SERVICE_MS_VOICE_EXTENSIONS:
         mbimcli_ms_voice_extensions_run (dev, cancellable);
         return;
+    case MBIM_SERVICE_MS_UICC_LOW_LEVEL_ACCESS:
+        mbimcli_ms_uicc_low_level_access_run (dev, cancellable);
+        return;
     case MBIM_SERVICE_SMS:
     case MBIM_SERVICE_USSD:
     case MBIM_SERVICE_STK:
@@ -315,7 +318,6 @@
     case MBIM_SERVICE_PROXY_CONTROL:
     case MBIM_SERVICE_QMI:
     case MBIM_SERVICE_QDU:
-    case MBIM_SERVICE_MS_UICC_LOW_LEVEL_ACCESS:
         /* unsupported actions in the CLI */
     case MBIM_SERVICE_INVALID:
     default:
@@ -440,6 +442,11 @@
         actions_enabled++;
     }
 
+    if (mbimcli_ms_uicc_low_level_access_options_enabled ()) {
+        service = MBIM_SERVICE_MS_UICC_LOW_LEVEL_ACCESS;
+        actions_enabled++;
+    }
+
     /* Noop */
     if (noop_flag)
         actions_enabled++;
@@ -487,6 +494,7 @@
     g_option_context_add_group (context, mbimcli_link_management_get_option_group ());
     g_option_context_add_group (context, mbimcli_intel_thermal_rf_get_option_group ());
     g_option_context_add_group (context, mbimcli_ms_voice_extensions_get_option_group ());
+    g_option_context_add_group (context, mbimcli_ms_uicc_low_level_access_get_option_group ());
     g_option_context_add_main_entries (context, main_entries, NULL);
     if (!g_option_context_parse (context, &argc, &argv, &error)) {
         g_printerr ("error: %s\n", error->message);
diff --git a/src/mbimcli/mbimcli.h b/src/mbimcli/mbimcli.h
index 255e3f8..e7188e3 100644
--- a/src/mbimcli/mbimcli.h
+++ b/src/mbimcli/mbimcli.h
@@ -29,6 +29,7 @@
 GOptionGroup *mbimcli_quectel_get_option_group                     (void);
 GOptionGroup *mbimcli_intel_thermal_rf_get_option_group            (void);
 GOptionGroup *mbimcli_ms_voice_extensions_get_option_group         (void);
+GOptionGroup *mbimcli_ms_uicc_low_level_access_get_option_group    (void);
 
 gboolean      mbimcli_basic_connect_options_enabled               (void);
 gboolean      mbimcli_phonebook_options_enabled                   (void);
@@ -42,6 +43,7 @@
 gboolean      mbimcli_quectel_options_enabled                     (void);
 gboolean      mbimcli_intel_thermal_rf_options_enabled            (void);
 gboolean      mbimcli_ms_voice_extensions_options_enabled         (void);
+gboolean      mbimcli_ms_uicc_low_level_access_options_enabled    (void);
 
 void          mbimcli_basic_connect_run                 (MbimDevice   *device,
                                                          GCancellable *cancellable);
@@ -67,6 +69,8 @@
                                                          GCancellable *cancellable);
 void          mbimcli_ms_voice_extensions_run           (MbimDevice   *device,
                                                          GCancellable *cancellable);
+void          mbimcli_ms_uicc_low_level_access_run      (MbimDevice   *device,
+                                                         GCancellable *cancellable);
 
 
 /* link management */
diff --git a/src/mbimcli/meson.build b/src/mbimcli/meson.build
index 79c52da..2f50b6d 100644
--- a/src/mbimcli/meson.build
+++ b/src/mbimcli/meson.build
@@ -12,6 +12,7 @@
   'mbimcli-ms-firmware-id.c',
   'mbimcli-ms-host-shutdown.c',
   'mbimcli-ms-sar.c',
+  'mbimcli-ms-uicc-low-level-access.c',
   'mbimcli-ms-voice-extensions.c',
   'mbimcli-phonebook.c',
   'mbimcli-quectel.c',