summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2014-06-10 17:10:45 +0200
committerAleksander Morgado <aleksander@aleksander.es>2014-06-10 17:36:24 +0200
commit6f2a64292e16bd8a8e6c6b79d898a693eb372b45 (patch)
treec17c7824e7d4050833c1d675884223a43db099b5
parentb8860570bcd212db2628639e2045645ca00f7c24 (diff)
libmbim-glib,device: match transaction also by type
There's this Huawei EM820W which replies several OPEN DONE messages, even using a transaction ID which doesn't belong to the original OPEN message. Hardware | manufacturer: 'Huawei' | model: 'MBIM [12D1:1571]' | revision: '11.810.10.02.00' E.g. Send OPEN message (transaction 1) <<<<<< RAW: <<<<<< length = 16 <<<<<< data = 01:00:00:00:10:00:00:00:01:00:00:00:00:06:00:00 Get OPEN DONE message (transaction 1) >>>>>> RAW: >>>>>> length = 16 >>>>>> data = 01:00:00:80:10:00:00:00:01:00:00:00:00:00:00:00 Send COMMAND message (transaction 2) <<<<<< RAW: <<<<<< length = 48 <<<<<< data = 03:00:00:00:30:00:00:00:02:00:00:00:01:00:... Receive OPEN DONE message (transaction 2) <---------- ERROR >>>>>> RAW: >>>>>> length = 16 >>>>>> data = 01:00:00:80:10:00:00:00:02:00:00:00:00:00:00:00 Then, get the COMMAND DONE message (transaction 2) as we expected >>>>>> RAW: >>>>>> length = 208 >>>>>> data = 03:00:00:80:D0:00:00:00:02:00:00:00:01:00:00:00:... So, in order to handle this, match responses not only by transaction ID, but also by expected message type. The expected message type is the that of the message which was originally used to create the transaction, i.e. not the type of the message expected to complete it.
-rw-r--r--src/libmbim-glib/mbim-device.c46
1 files changed, 30 insertions, 16 deletions
diff --git a/src/libmbim-glib/mbim-device.c b/src/libmbim-glib/mbim-device.c
index 6f965e9..4ac6464 100644
--- a/src/libmbim-glib/mbim-device.c
+++ b/src/libmbim-glib/mbim-device.c
@@ -123,6 +123,7 @@ typedef struct {
typedef struct {
MbimMessage *fragments;
+ MbimMessageType type;
guint32 transaction_id;
GSimpleAsyncResult *result;
guint timeout_id;
@@ -133,6 +134,7 @@ typedef struct {
static Transaction *
transaction_new (MbimDevice *self,
+ MbimMessageType type,
guint32 transaction_id,
GCancellable *cancellable,
GAsyncReadyCallback callback,
@@ -141,6 +143,7 @@ transaction_new (MbimDevice *self,
Transaction *tr;
tr = g_slice_new0 (Transaction);
+ tr->type = type;
tr->transaction_id = transaction_id;
tr->result = g_simple_async_result_new (G_OBJECT (self),
callback,
@@ -187,13 +190,14 @@ transaction_complete_and_free (Transaction *tr,
static Transaction *
device_release_transaction (MbimDevice *self,
TransactionType type,
+ MbimMessageType expected_type,
guint32 transaction_id)
{
Transaction *tr = NULL;
if (self->priv->transactions[type]) {
tr = g_hash_table_lookup (self->priv->transactions[type], GUINT_TO_POINTER (transaction_id));
- if (tr)
+ if (tr && ((tr->type == expected_type) || (expected_type == MBIM_MESSAGE_TYPE_INVALID)))
/* If found, remove it from the HT */
g_hash_table_remove (self->priv->transactions[type], GUINT_TO_POINTER (transaction_id));
}
@@ -207,7 +211,10 @@ transaction_timed_out (TransactionWaitContext *ctx)
Transaction *tr;
GError *error = NULL;
- tr = device_release_transaction (ctx->self, ctx->type, ctx->transaction_id);
+ tr = device_release_transaction (ctx->self,
+ ctx->type,
+ MBIM_MESSAGE_TYPE_INVALID,
+ ctx->transaction_id);
tr->timeout_id = 0;
/* If no fragment was received, complete transaction with a timeout error */
@@ -240,7 +247,10 @@ transaction_cancelled (GCancellable *cancellable,
Transaction *tr;
GError *error = NULL;
- tr = device_release_transaction (ctx->self, ctx->type, ctx->transaction_id);
+ tr = device_release_transaction (ctx->self,
+ ctx->type,
+ MBIM_MESSAGE_TYPE_INVALID,
+ ctx->transaction_id);
tr->cancellable_id = 0;
/* Complete transaction with an abort error */
@@ -294,15 +304,6 @@ device_store_transaction (MbimDevice *self,
return TRUE;
}
-static Transaction *
-device_match_transaction (MbimDevice *self,
- TransactionType type,
- const MbimMessage *message)
-{
- /* msg can be either the original message or the response */
- return device_release_transaction (self, type, mbim_message_get_transaction_id (message));
-}
-
/*****************************************************************************/
/**
@@ -456,17 +457,26 @@ process_message (MbimDevice *self,
if (MBIM_MESSAGE_GET_MESSAGE_TYPE (message) == MBIM_MESSAGE_TYPE_INDICATE_STATUS) {
/* Grab transaction */
- tr = device_match_transaction (self, TRANSACTION_TYPE_MODEM, message);
+ tr = device_release_transaction (self,
+ TRANSACTION_TYPE_MODEM,
+ MBIM_MESSAGE_TYPE_INDICATE_STATUS,
+ mbim_message_get_transaction_id (message));
+
if (!tr)
/* Create new transaction for the indication */
tr = transaction_new (self,
+ MBIM_MESSAGE_TYPE_INDICATE_STATUS,
mbim_message_get_transaction_id (message),
NULL, /* no cancellable */
(GAsyncReadyCallback)indication_ready,
NULL);
} else {
- /* Grab transaction */
- tr = device_match_transaction (self, TRANSACTION_TYPE_HOST, message);
+ /* Grab transaction. This is a _DONE message, so look for the request
+ * that generated the _DONE */
+ tr = device_release_transaction (self,
+ TRANSACTION_TYPE_HOST,
+ (MBIM_MESSAGE_GET_MESSAGE_TYPE (message) - 0x80000000),
+ mbim_message_get_transaction_id (message));
if (!tr) {
g_debug ("[%s] No transaction matched in received message",
self->priv->path_display);
@@ -1466,6 +1476,7 @@ mbim_device_command (MbimDevice *self,
}
tr = transaction_new (self,
+ MBIM_MESSAGE_GET_MESSAGE_TYPE (message),
transaction_id,
cancellable,
callback,
@@ -1491,7 +1502,10 @@ mbim_device_command (MbimDevice *self,
if (!device_send (self, message, &error)) {
/* Match transaction so that we remove it from our tracking table */
- tr = device_match_transaction (self, TRANSACTION_TYPE_HOST, message);
+ tr = device_release_transaction (self,
+ TRANSACTION_TYPE_HOST,
+ MBIM_MESSAGE_GET_MESSAGE_TYPE (message),
+ mbim_message_get_transaction_id (message));
transaction_complete_and_free (tr, error);
g_error_free (error);
return;