diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2020-04-11 09:44:59 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2020-04-11 09:59:17 +0200 |
commit | 1d470316fc3641359ae3f4fed708984e76a1ae35 (patch) | |
tree | 64c741f831fe32afdb59b2c3ffd12fffacdab099 | |
parent | 0abd522198674c18e6f72173968adc90084b14ef (diff) |
libqmi-glib,message: fixed sized strings may be suffixed with 0xFF
If the contents of a fixed sized string are shorter than the field
size (e.g. a 2-digit MNC in a 3-digit string), a 0xFF filled suffix
will be included.
Since the 0xFF suffix makes the full string not UTF-8 valid, the
method that reads the fixed sized strings is updated to allow
returning all the valid UTF-8 characters found at the beginning of the
string, if any, instead of returning an error.
Fixes https://gitlab.freedesktop.org/mobile-broadband/libqmi/-/issues/33
(cherry picked from commit 86ca463762e74660491562dc1ffbe1bd4f1106c1)
-rw-r--r-- | src/libqmi-glib/qmi-message.c | 33 | ||||
-rw-r--r-- | src/libqmi-glib/qmi-message.h | 5 | ||||
-rw-r--r-- | src/libqmi-glib/test/test-generated.c | 156 |
3 files changed, 183 insertions, 11 deletions
diff --git a/src/libqmi-glib/qmi-message.c b/src/libqmi-glib/qmi-message.c index 695ec7a..5152a90 100644 --- a/src/libqmi-glib/qmi-message.c +++ b/src/libqmi-glib/qmi-message.c @@ -1355,26 +1355,37 @@ qmi_message_tlv_read_fixed_size_string (QmiMessage *self, gchar *out, GError **error) { + const guint8 *ptr; + const gchar *end = NULL; + g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (offset != NULL, FALSE); g_return_val_if_fail (out != NULL, FALSE); - if (string_length > 0) { - const guint8 *ptr; - - if (!(ptr = tlv_error_if_read_overflow (self, tlv_offset, *offset, string_length, error))) - return FALSE; + if (string_length == 0) + return TRUE; - if (!g_utf8_validate ((const gchar *)ptr, string_length, NULL)) { - g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_INVALID_DATA, "invalid string"); - return FALSE; - } + if (!(ptr = tlv_error_if_read_overflow (self, tlv_offset, *offset, string_length, error))) + return FALSE; + /* full string valid? */ + if (g_utf8_validate ((const gchar *)ptr, string_length, &end)) { memcpy (out, ptr, string_length); + *offset = (*offset + string_length); + return TRUE; } - *offset = (*offset + string_length); - return TRUE; + /* partial string valid? */ + if (end && end > (const gchar *)ptr) { + /* copy only the valid bytes */ + memcpy (out, ptr, end - (const gchar *)ptr); + /* but update offset with the full expected length */ + *offset = (*offset + string_length); + return TRUE; + } + + g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_INVALID_DATA, "invalid string"); + return FALSE; } guint16 diff --git a/src/libqmi-glib/qmi-message.h b/src/libqmi-glib/qmi-message.h index 8f876f9..769e73d 100644 --- a/src/libqmi-glib/qmi-message.h +++ b/src/libqmi-glib/qmi-message.h @@ -952,6 +952,11 @@ gboolean qmi_message_tlv_read_string (QmiMessage *self, * * Since 1.24.6 the read string is guaranteed to be valid UTF-8. * + * The fixed sized field may be suffixed with e.g. 0xFF if the contents are + * shorter than @string_length. Since 1.26, this method will return the valid + * UTF-8 characters in the start of the string, instead of returning an error + * when doing the full UTF-8 string validation. + * * Returns: %TRUE if the variable is successfully read, otherwise %FALSE is returned and @error is set. * * Since: 1.12 diff --git a/src/libqmi-glib/test/test-generated.c b/src/libqmi-glib/test/test-generated.c index 36b357c..e542b3f 100644 --- a/src/libqmi-glib/test/test-generated.c +++ b/src/libqmi-glib/test/test-generated.c @@ -731,6 +731,161 @@ test_generated_nas_get_serving_system (TestFixture *fixture) } /*****************************************************************************/ +/* NAS Get System Info */ + +static void +nas_get_system_info_ready (QmiClientNas *client, + GAsyncResult *res, + TestFixture *fixture) +{ + QmiMessageNasGetSystemInfoOutput *output; + GError *error = NULL; + gboolean st; + + output = qmi_client_nas_get_system_info_finish (client, res, &error); + g_assert_no_error (error); + g_assert (output); + + st = qmi_message_nas_get_system_info_output_get_result (output, &error); + g_assert_no_error (error); + g_assert (st); + + { + gboolean domain_valid = FALSE; + QmiNasNetworkServiceDomain domain; + gboolean service_capability_valid = FALSE; + QmiNasNetworkServiceDomain service_capability; + gboolean roaming_status_valid = FALSE; + QmiNasRoamingStatus roaming_status; + gboolean forbidden_valid = FALSE; + gboolean forbidden; + gboolean lac_valid = FALSE; + guint16 lac; + gboolean cid_valid = FALSE; + guint32 cid; + gboolean registration_reject_info_valid = FALSE; + QmiNasNetworkServiceDomain registration_reject_domain; + guint8 registration_reject_cause; + gboolean network_id_valid = FALSE; + const gchar *mcc = NULL; + const gchar *mnc = NULL; + gboolean tac_valid = FALSE; + guint16 tac; + + /* + * LTE service: + * Status: 'available' + * True Status: 'available' + * Preferred data path: 'no' + * Domain: 'cs-ps' + * Service capability: 'cs-ps' + * Roaming status: 'off' + * Forbidden: 'no' + * Cell ID: '1609474' + * MCC: '530' + * MNC: '24' -- Given as 2 digits, suffixed with 0xFF! + * Tracking Area Code: '63001' + * Voice support: 'yes' + * IMS voice support: 'no' + * eMBMS coverage info support: 'no' + * eMBMS coverage info trace ID: '65535' + * Cell access: 'all-calls' + * Registration restriction: 'unrestricted' + * Registration domain: 'not-applicable' + */ + + g_assert (qmi_message_nas_get_system_info_output_get_lte_system_info (output, + &domain_valid, + &domain, + &service_capability_valid, + &service_capability, + &roaming_status_valid, + &roaming_status, + &forbidden_valid, + &forbidden, + &lac_valid, + &lac, + &cid_valid, + &cid, + ®istration_reject_info_valid, + ®istration_reject_domain, + ®istration_reject_cause, + &network_id_valid, + &mcc, + &mnc, + &tac_valid, + &tac, + &error)); + g_assert_no_error (error); + g_assert (domain_valid); + g_assert_cmpuint (domain, ==, QMI_NAS_NETWORK_SERVICE_DOMAIN_CS_PS); + g_assert (service_capability_valid); + g_assert_cmpuint (service_capability, ==, QMI_NAS_NETWORK_SERVICE_DOMAIN_CS_PS); + g_assert (roaming_status_valid); + g_assert_cmpuint (roaming_status, ==, QMI_NAS_ROAMING_STATUS_OFF); + g_assert (forbidden_valid); + g_assert (!forbidden); + g_assert (!lac_valid); + g_assert (cid_valid); + g_assert_cmpuint (cid, ==, 1616133); + g_assert (!registration_reject_info_valid); + g_assert (network_id_valid); + g_assert_cmpstr (mcc, ==, "530"); + g_assert_cmpstr (mnc, ==, "24"); + g_assert (tac_valid); + g_assert_cmpuint (tac, ==, 63001); + } + + qmi_message_nas_get_system_info_output_unref (output); + + test_fixture_loop_stop (fixture); +} + +static void +test_generated_nas_get_system_info (TestFixture *fixture) +{ + guint8 expected[] = { + 0x01, + 0x0C, 0x00, 0x00, 0x03, 0x01, + 0x00, 0x01, 0x00, 0x4D, 0x00, 0x00, 0x00 + }; + guint8 response[] = { + 0x01, + 0x9A, 0x00, 0x80, 0x03, 0x01, + 0x02, 0x01, 0x00, 0x4D, 0x00, 0x8E, 0x00, 0x02, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x14, 0x03, 0x00, 0x02, 0x02, 0x00, + 0x19, 0x1D, 0x00, 0x01, 0x03, 0x01, 0x03, 0x01, + 0x00, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x05, + 0xA9, 0x18, 0x00, 0x00, 0x00, 0x00, 0x01, 0x35, + 0x33, 0x30, 0x32, 0x34, 0xFF, 0x01, 0x19, 0xF6, + 0x1E, 0x02, 0x00, 0xFF, 0xFF, 0x21, 0x01, 0x00, + 0x01, 0x26, 0x01, 0x00, 0x00, 0x27, 0x04, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x29, 0x01, 0x00, 0x00, + 0x2A, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2F, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x02, 0x00, + 0xFF, 0xFF, 0x38, 0x04, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x39, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x3E, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, + 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x46, 0x04, + 0x00, 0x04, 0x00, 0x00, 0x00 + }; + + test_port_context_set_command (fixture->ctx, + expected, G_N_ELEMENTS (expected), + response, G_N_ELEMENTS (response), + fixture->service_info[QMI_SERVICE_NAS].transaction_id++); + + qmi_client_nas_get_system_info (QMI_CLIENT_NAS (fixture->service_info[QMI_SERVICE_NAS].client), NULL, 3, NULL, + (GAsyncReadyCallback) nas_get_system_info_ready, + fixture); + + test_fixture_loop_run (fixture); +} + +/*****************************************************************************/ static void nas_get_cell_location_info_invalid_response_ready (QmiClientNas *client, @@ -800,6 +955,7 @@ int main (int argc, char **argv) TEST_ADD ("/libqmi-glib/generated/nas/network-scan", test_generated_nas_network_scan); TEST_ADD ("/libqmi-glib/generated/nas/get-cell-location-info", test_generated_nas_get_cell_location_info); TEST_ADD ("/libqmi-glib/generated/nas/get-serving-system", test_generated_nas_get_serving_system); + TEST_ADD ("/libqmi-glib/generated/nas/get-system-info", test_generated_nas_get_system_info); /* Invalid responses */ TEST_ADD ("/libqmi-glib/generated/nas/invalid/get-cell-location-info", test_generated_nas_get_cell_location_info_invalid_response); |