[PATCH] qmi-message: add functions to operate on QMI part of QmiMessage

Eric Caruso ejcaruso at chromium.org
Tue Jan 8 19:10:56 UTC 2019


QRTR-based transports will not have QMUX headers, and will instead
encode that information in a different way. However, that data will
still need to be passed around as part of the message by the library
consumer, so reusing the QMUX header structure to pass it around
should be fine and we will need to be able to create fake QMUX
headers.

Also add a unit test for the new functions.
---
 src/libqmi-glib/qmi-message.c       | 63 +++++++++++++++++++++++++++++
 src/libqmi-glib/qmi-message.h       | 37 +++++++++++++++++
 src/libqmi-glib/test/test-message.c | 58 ++++++++++++++++++++++++--
 3 files changed, 155 insertions(+), 3 deletions(-)

diff --git a/src/libqmi-glib/qmi-message.c b/src/libqmi-glib/qmi-message.c
index 7ba1dd5..b2fe177 100644
--- a/src/libqmi-glib/qmi-message.c
+++ b/src/libqmi-glib/qmi-message.c
@@ -449,6 +449,53 @@ qmi_message_new (QmiService service,
     return (QmiMessage *)self;
 }
 
+QmiMessage *
+qmi_message_new_from_qmi (QmiService   service,
+                          guint8       client_id,
+                          GByteArray  *raw,
+                          GError     **error)
+{
+    GByteArray *self;
+    struct full_message *buffer;
+    gsize buffer_len;
+    gsize message_len;
+
+    /* Create array with enough size for the QMUX marker and QMUX header, and
+     * with enough room to copy the rest of the message into */
+    if (service == QMI_SERVICE_CTL) {
+        message_len = sizeof (struct control_header) +
+            ((struct control_message *)(raw->data))->header.tlv_length;
+    } else {
+        message_len = sizeof (struct service_header) +
+            ((struct service_message *)(raw->data))->header.tlv_length;
+    }
+    buffer_len = (1 + sizeof (struct qmux) + message_len);
+    /* Create the GByteArray with buffer_len bytes preallocated */
+    self = g_byte_array_sized_new (buffer_len);
+    g_byte_array_set_size (self, buffer_len);
+
+    /* Set up fake QMUX header */
+    buffer = (struct full_message *)(self->data);
+    buffer->marker = QMI_MESSAGE_QMUX_MARKER;
+    buffer->qmux.length = buffer_len - 1;
+    buffer->qmux.flags = 0;
+    buffer->qmux.service = service;
+    buffer->qmux.client = client_id;
+
+    /* Move bytes from the raw array to the newly created message */
+    memcpy (&buffer->qmi, raw->data, message_len);
+    g_byte_array_remove_range (raw, 0, message_len);
+
+    /* Check input message validity as soon as we create the QmiMessage */
+    if (!message_check (self, error)) {
+        /* Yes, we lose the whole message here */
+        qmi_message_unref (self);
+        return NULL;
+    }
+
+    return (QmiMessage *)self;
+}
+
 QmiMessage *
 qmi_message_response_new (QmiMessage       *request,
                           QmiProtocolError  error)
@@ -510,6 +557,22 @@ qmi_message_get_raw (QmiMessage *self,
     return self->data;
 }
 
+const guint8 *
+qmi_message_get_qmi (QmiMessage *self,
+                     gsize *length,
+                     GError **error)
+{
+    g_return_val_if_fail (self != NULL, NULL);
+    g_return_val_if_fail (length != NULL, NULL);
+
+    if (message_is_control (self))
+        *length = sizeof (struct control_header);
+    else
+        *length = sizeof (struct service_header);
+    *length += get_all_tlvs_length (self);
+    return (guint8 *)(&((struct full_message *)(self->data))->qmi);
+}
+
 /*****************************************************************************/
 /* TLV builder & writer */
 
diff --git a/src/libqmi-glib/qmi-message.h b/src/libqmi-glib/qmi-message.h
index 714adae..ddc637c 100644
--- a/src/libqmi-glib/qmi-message.h
+++ b/src/libqmi-glib/qmi-message.h
@@ -122,6 +122,26 @@ QmiMessage *qmi_message_new (QmiService service,
 QmiMessage *qmi_message_new_from_raw (GByteArray  *raw,
                                       GError     **error);
 
+/**
+ * qmi_message_new_from_qmi:
+ * @service: a #QmiService
+ * @client_id: client ID of the originating control point.
+ * @raw: (inout): raw data buffer containing only the QMI part of the message.
+ * @error: return location for error or %NULL.
+ *
+ * Create a new #QmiMessage from the given raw data buffer.
+ *
+ * Whenever a complete QMI message is read, its raw data gets removed from the @raw buffer.
+ *
+ * Returns: (transfer full): a newly created #QmiMessage, which should be freed with qmi_message_unref(). If @raw doesn't contain a complete QMI message #NULL is returned. If there is a complete QMI message but it appears not to be valid, #NULL is returned and @error is set.
+ *
+ * Since: 1.24
+ */
+QmiMessage *qmi_message_new_from_qmi (QmiService   service,
+                                      guint8       client_id,
+                                      GByteArray  *raw,
+                                      GError     **error);
+
 /**
  * qmi_message_response_new:
  * @request: a request #QmiMessage.
@@ -274,6 +294,23 @@ const guint8 *qmi_message_get_raw (QmiMessage  *self,
                                    gsize       *length,
                                    GError     **error);
 
+
+/**
+ * qmi_message_get_raw:
+ * @self: a #QmiMessage.
+ * @length: (out): return location for the size of the output buffer.
+ * @error: return location for error or %NULL.
+ *
+ * Gets the raw data buffer of the #QmiMessage.
+ *
+ * Returns: (transfer none): The raw QMI buffer, or #NULL if @error is set.
+ *
+ * Since: 1.24
+ */
+const guint8 *qmi_message_get_qmi (QmiMessage  *self,
+                                   gsize       *length,
+                                   GError     **error);
+
 /*****************************************************************************/
 /* Version support from the database */
 /**
diff --git a/src/libqmi-glib/test/test-message.c b/src/libqmi-glib/test/test-message.c
index 7a4b11d..a53a1d0 100644
--- a/src/libqmi-glib/test/test-message.c
+++ b/src/libqmi-glib/test/test-message.c
@@ -272,6 +272,57 @@ test_message_new_request (void)
     qmi_message_unref (self);
 }
 
+static void
+test_message_new_request_from_qmi (void)
+{
+    static const guint8 expected_buffer [] = {
+        0x00,       /* service flags */
+        0x02, 0x00, /* transaction */
+        0xFF, 0xFF, /* message id */
+        0x00, 0x00, /* all tlvs length */
+    };
+
+    GByteArray *qmi;
+    QmiMessage *self;
+    GError *error = NULL;
+    const guint8 *buffer;
+    gsize buffer_length = 0;
+
+    /* set up service header */
+    qmi = g_byte_array_new ();
+    g_byte_array_append (qmi, expected_buffer, sizeof (expected_buffer));
+
+    self = qmi_message_new_from_qmi (QMI_SERVICE_DMS, 0x01, qmi, NULL);
+    g_assert (self);
+
+    /* check that the QMUX header contains the right values*/
+    g_assert_cmpuint (qmi_message_get_service (self), ==, QMI_SERVICE_DMS);
+    g_assert_cmpuint (qmi_message_get_client_id (self), ==, 0x01);
+
+    /* length (13) = qmux marker (1) + qmux header length (5) + qmi header length (7) */
+    g_assert_cmpuint (qmi_message_get_length (self), ==, 13);
+
+    /* check that transaction and message IDs line up */
+    g_assert_cmpuint (qmi_message_get_transaction_id (self), ==, 0x02);
+    g_assert_cmpuint (qmi_message_get_message_id (self), ==, 0xFFFF);
+
+    buffer = qmi_message_get_raw (self, &buffer_length, &error);
+    g_assert_no_error (error);
+    g_assert (buffer != NULL);
+    g_assert_cmpuint (buffer_length, >, 0);
+    /* check that we have a qmux marker so we don't break framing */
+    g_assert_cmpuint (buffer[0], ==, 0x01);
+
+    /* make sure the qmi portion of the message is what we expect */
+    buffer = qmi_message_get_qmi (self, &buffer_length, &error);
+    g_assert_no_error (error);
+    g_assert (buffer != NULL);
+    g_assert_cmpuint (buffer_length, >, 0);
+    _g_assert_cmpmem (buffer, buffer_length, expected_buffer, sizeof (expected_buffer));
+
+    qmi_message_unref (self);
+}
+
 static void
 test_message_new_response_ok (void)
 {
@@ -1514,9 +1565,10 @@ int main (int argc, char **argv)
     g_test_add_func ("/libqmi-glib/message/parse/wrong-tlv",             test_message_parse_wrong_tlv);
     g_test_add_func ("/libqmi-glib/message/parse/missing-size",          test_message_parse_missing_size);
 
-    g_test_add_func ("/libqmi-glib/message/new/request",        test_message_new_request);
-    g_test_add_func ("/libqmi-glib/message/new/response/ok",    test_message_new_response_ok);
-    g_test_add_func ("/libqmi-glib/message/new/response/error", test_message_new_response_error);
+    g_test_add_func ("/libqmi-glib/message/new/request",          test_message_new_request);
+    g_test_add_func ("/libqmi-glib/message/new/request-from-qmi", test_message_new_request_from_qmi);
+    g_test_add_func ("/libqmi-glib/message/new/response/ok",      test_message_new_response_ok);
+    g_test_add_func ("/libqmi-glib/message/new/response/error",   test_message_new_response_error);
 
     g_test_add_func ("/libqmi-glib/message/tlv-write/empty",           test_message_tlv_write_empty);
     g_test_add_func ("/libqmi-glib/message/tlv-write/reset",           test_message_tlv_write_reset);
-- 
2.20.1.97.g81188d93c3-goog



More information about the libqmi-devel mailing list