diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2014-06-10 17:10:45 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2014-06-10 17:36:24 +0200 |
commit | 6f2a64292e16bd8a8e6c6b79d898a693eb372b45 (patch) | |
tree | c17c7824e7d4050833c1d675884223a43db099b5 | |
parent | b8860570bcd212db2628639e2045645ca00f7c24 (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.c | 46 |
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; |