<div dir="ltr">lgtm</div><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Aug 6, 2017 at 8:08 AM, Aleksander Morgado <span dir="ltr"><<a href="mailto:aleksander@aleksander.es" target="_blank">aleksander@aleksander.es</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">If we try to 'MBIM open' the channel with a Sierra Wireless EM7345<br>
(FIH7160_V1.1_MODEM_01.1349.<wbr>12) and the channel is already open in the<br>
device (e.g. mbim-proxy crashed and we try to reopen, or just running<br>
consecutive mbimcli commands with --no-close), the device returns a<br>
'MBIM close done' message for every 'MBIM open' request we send.<br>
<br>
We update the logic to try to detect this case, and if we do, we<br>
launch an explicit 'MBIM close' operation before retrying the 'MBIM<br>
open' again.<br>
<br>
E.g. this is the flow when trying to run mbimcli command while the<br>
MBIM channel is already open in the device side:<br>
<br>
$ mbimcli -d /dev/cdc-wdm1 --query-device-caps --no-close --verbose<br>
[06 ago 2017, 16:58:21] [Debug] opening device...<br>
[06 ago 2017, 16:58:21] [Debug] [/dev/cdc-wdm1] Queried max control message size: 512<br>
[06 ago 2017, 16:58:21] [Debug] [/dev/cdc-wdm1] Sent message...<br>
<<<<<< RAW:<br>
<<<<<< length = 16<br>
<<<<<< data = 01:00:00:00:10:00:00:00:01:00:<wbr>00:00:00:02:00:00<br>
<br>
[06 ago 2017, 16:58:21] [Debug] [/dev/cdc-wdm1] Sent message (translated)...<br>
<<<<<< Header:<br>
<<<<<< length = 16<br>
<<<<<< type = open (0x00000001)<br>
<<<<<< transaction = 1<br>
<<<<<< Contents:<br>
<<<<<< max_control_transfer = 512<br>
<br>
[06 ago 2017, 16:58:21] [Debug] [/dev/cdc-wdm1] Received message...<br>
>>>>>> RAW:<br>
>>>>>> length = 16<br>
>>>>>> data = 02:00:00:80:10:00:00:00:02:00:<wbr>00:00:00:00:00:00<br>
<br>
[06 ago 2017, 16:58:21] [Debug] [/dev/cdc-wdm1] No transaction matched in received message<br>
[06 ago 2017, 16:58:21] [Debug] [/dev/cdc-wdm1] Received unexpected message (translated)...<br>
>>>>>> Header:<br>
>>>>>> length = 16<br>
>>>>>> type = close-done (0x80000002)<br>
>>>>>> transaction = 2<br>
>>>>>> Contents:<br>
>>>>>> status error = 'None' (0x00000000)<br>
<br>
[06 ago 2017, 16:58:21] [Debug] [/dev/cdc-wdm1] Sent message...<br>
<<<<<< RAW:<br>
<<<<<< length = 12<br>
<<<<<< data = 02:00:00:00:0C:00:00:00:02:00:<wbr>00:00<br>
<br>
[06 ago 2017, 16:58:21] [Debug] [/dev/cdc-wdm1] Sent message (translated)...<br>
<<<<<< Header:<br>
<<<<<< length = 12<br>
<<<<<< type = close (0x00000002)<br>
<<<<<< transaction = 2<br>
<br>
[06 ago 2017, 16:58:21] [Debug] [/dev/cdc-wdm1] Received message...<br>
>>>>>> RAW:<br>
>>>>>> length = 16<br>
>>>>>> data = 02:00:00:80:10:00:00:00:02:00:<wbr>00:00:00:00:00:00<br>
<br>
[06 ago 2017, 16:58:21] [Debug] [/dev/cdc-wdm1] Sent message...<br>
<<<<<< RAW:<br>
<<<<<< length = 16<br>
<<<<<< data = 01:00:00:00:10:00:00:00:03:00:<wbr>00:00:00:02:00:00<br>
<br>
[06 ago 2017, 16:58:21] [Debug] [/dev/cdc-wdm1] Sent message (translated)...<br>
<<<<<< Header:<br>
<<<<<< length = 16<br>
<<<<<< type = open (0x00000001)<br>
<<<<<< transaction = 3<br>
<<<<<< Contents:<br>
<<<<<< max_control_transfer = 512<br>
<br>
[06 ago 2017, 16:58:21] [Debug] [/dev/cdc-wdm1] Received message...<br>
>>>>>> RAW:<br>
>>>>>> length = 16<br>
>>>>>> data = 01:00:00:80:10:00:00:00:03:00:<wbr>00:00:00:00:00:00<br>
<br>
[06 ago 2017, 16:58:21] [Debug] MBIM Device at '/dev/cdc-wdm1' ready<br>
---<br>
src/libmbim-glib/mbim-device.c | 114 ++++++++++++++++++++++++++++++<wbr>+++++++++--<br>
src/libmbim-glib/mbim-errors.h | 6 ++-<br>
2 files changed, 115 insertions(+), 5 deletions(-)<br>
<br>
diff --git a/src/libmbim-glib/mbim-<wbr>device.c b/src/libmbim-glib/mbim-<wbr>device.c<br>
index 775c2fd..3c20bd8 100644<br>
--- a/src/libmbim-glib/mbim-<wbr>device.c<br>
+++ b/src/libmbim-glib/mbim-<wbr>device.c<br>
@@ -37,7 +37,9 @@<br>
#include <gio/gunixsocketaddress.h><br>
#include <sys/ioctl.h><br>
#define IOCTL_WDM_MAX_COMMAND _IOR('H', 0xA0, guint16)<br>
-#define RETRY_TIMEOUT_SECS 5<br>
+<br>
+#define OPEN_RETRY_TIMEOUT_SECS 5<br>
+#define OPEN_CLOSE_TIMEOUT_SECS 2<br>
<br>
#if defined WITH_UDEV<br>
# include <gudev/gudev.h><br>
@@ -111,6 +113,7 @@ struct _MbimDevicePrivate {<br>
GSource *iochannel_source;<br>
GByteArray *response;<br>
OpenStatus open_status;<br>
+ guint32 open_transaction_id;<br>
<br>
/* Support for mbim-proxy */<br>
GSocketClient *socket_client;<br>
@@ -485,6 +488,33 @@ indication_ready (MbimDevice *self,<br>
}<br>
<br>
static void<br>
+finalize_pending_open_request (MbimDevice *self)<br>
+{<br>
+ Transaction *tr;<br>
+ GError *error = NULL;<br>
+<br>
+ if (!self->priv->open_<wbr>transaction_id)<br>
+ return;<br>
+<br>
+ /* Grab transaction. This is a _DONE message, so look for the request<br>
+ * that generated the _DONE */<br>
+ tr = device_release_transaction (self,<br>
+ TRANSACTION_TYPE_HOST,<br>
+ MBIM_MESSAGE_TYPE_OPEN,<br>
+ self->priv->open_transaction_<wbr>id);<br>
+<br>
+ /* If there is a valid open_transaction_id, there must be a valid transaction */<br>
+ g_assert (tr);<br>
+<br>
+ /* Clear right away before completing the transaction */<br>
+ self->priv->open_transaction_<wbr>id = 0;<br>
+<br>
+ error = g_error_new (MBIM_CORE_ERROR, MBIM_CORE_ERROR_UNKNOWN_STATE, "device state is unknown");<br>
+ transaction_complete_and_free (tr, error);<br>
+ g_error_free (error);<br>
+}<br>
+<br>
+static void<br>
process_message (MbimDevice *self,<br>
const MbimMessage *message)<br>
{<br>
@@ -561,6 +591,14 @@ process_message (MbimDevice *self,<br>
printable);<br>
g_free (printable);<br>
}<br>
+<br>
+ /* If we're opening and we get a CLOSE_DONE message without any<br>
+ * matched transaction, finalize the open request right away to<br>
+ * trigger a close before open */<br>
+ if (self->priv->open_status == OPEN_STATUS_OPENING &&<br>
+ MBIM_MESSAGE_GET_MESSAGE_TYPE (message) == MBIM_MESSAGE_TYPE_CLOSE_DONE)<br>
+ finalize_pending_open_request (self);<br>
+<br>
return;<br>
}<br>
<br>
@@ -1209,6 +1247,7 @@ typedef enum {<br>
DEVICE_OPEN_CONTEXT_STEP_FIRST = 0,<br>
DEVICE_OPEN_CONTEXT_STEP_<wbr>CREATE_IOCHANNEL,<br>
DEVICE_OPEN_CONTEXT_STEP_<wbr>FLAGS_PROXY,<br>
+ DEVICE_OPEN_CONTEXT_STEP_<wbr>CLOSE_MESSAGE,<br>
DEVICE_OPEN_CONTEXT_STEP_OPEN_<wbr>MESSAGE,<br>
DEVICE_OPEN_CONTEXT_STEP_LAST<br>
} DeviceOpenContextStep;<br>
@@ -1218,6 +1257,7 @@ typedef struct {<br>
MbimDeviceOpenFlags flags;<br>
guint timeout;<br>
GTimer *timer;<br>
+ gboolean close_before_open;<br>
} DeviceOpenContext;<br>
<br>
static void<br>
@@ -1278,8 +1318,19 @@ open_message_ready (MbimDevice *self,<br>
<br>
ctx = g_task_get_task_data (task);<br>
<br>
+ /* Cleanup, as no longer needed */<br>
+ self->priv->open_transaction_<wbr>id = 0;<br>
+<br>
response = mbim_device_command_finish (self, res, &error);<br>
if (!response) {<br>
+ /* If we get reported that the state is unknown, try to close before open */<br>
+ if (g_error_matches (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_UNKNOWN_STATE)<wbr>) {<br>
+ ctx->close_before_open = TRUE;<br>
+ ctx->step = DEVICE_OPEN_CONTEXT_STEP_<wbr>CLOSE_MESSAGE;<br>
+ device_open_context_step (task);<br>
+ return;<br>
+ }<br>
+<br>
/* Check if we should be retrying after a timeout */<br>
if (g_error_matches (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_TIMEOUT)) {<br>
/* Retry same step */<br>
@@ -1319,11 +1370,12 @@ open_message (GTask *task)<br>
self = g_task_get_source_object (task);<br>
<br>
/* Launch 'Open' command */<br>
- request = mbim_message_open_new (mbim_device_get_next_<wbr>transaction_id (self),<br>
+ self->priv->open_transaction_<wbr>id = mbim_device_get_next_<wbr>transaction_id (self);<br>
+ request = mbim_message_open_new (self->priv->open_transaction_<wbr>id,<br>
self->priv->max_control_<wbr>transfer);<br>
mbim_device_command (self,<br>
request,<br>
- RETRY_TIMEOUT_SECS,<br>
+ OPEN_RETRY_TIMEOUT_SECS,<br>
g_task_get_cancellable (task),<br>
(GAsyncReadyCallback)open_<wbr>message_ready,<br>
task);<br>
@@ -1331,6 +1383,51 @@ open_message (GTask *task)<br>
}<br>
<br>
static void<br>
+close_message_before_open_<wbr>ready (MbimDevice *self,<br>
+ GAsyncResult *res,<br>
+ GTask *task)<br>
+{<br>
+ DeviceOpenContext *ctx;<br>
+ MbimMessage *response;<br>
+ GError *error = NULL;<br>
+<br>
+ ctx = g_task_get_task_data (task);<br>
+<br>
+ response = mbim_device_command_finish (self, res, &error);<br>
+ if (!response)<br>
+ g_debug ("error reported in close before open: %s (ignored)", error->message);<br>
+ else if (!mbim_message_response_get_<wbr>result (response, MBIM_MESSAGE_TYPE_CLOSE_DONE, &error))<br>
+ g_debug ("getting close done result failed: %s (ignored)", error->message);<br>
+<br>
+ g_clear_error (&error);<br>
+ if (response)<br>
+ mbim_message_unref (response);<br>
+<br>
+ /* go on */<br>
+ ctx->step++;<br>
+ device_open_context_step (task);<br>
+}<br>
+<br>
+static void<br>
+close_message_before_open (GTask *task)<br>
+{<br>
+ MbimDevice *self;<br>
+ MbimMessage *request;<br>
+<br>
+ self = g_task_get_source_object (task);<br>
+<br>
+ /* Launch 'Close' command */<br>
+ request = mbim_message_close_new (mbim_device_get_next_<wbr>transaction_id (self));<br>
+ mbim_device_command (self,<br>
+ request,<br>
+ OPEN_CLOSE_TIMEOUT_SECS,<br>
+ g_task_get_cancellable (task),<br>
+ (GAsyncReadyCallback)close_<wbr>message_before_open_ready,<br>
+ task);<br>
+ mbim_message_unref (request);<br>
+}<br>
+<br>
+static void<br>
proxy_cfg_message_ready (MbimDevice *self,<br>
GAsyncResult *res,<br>
GTask *task)<br>
@@ -1466,6 +1563,16 @@ device_open_context_step (GTask *task)<br>
ctx->step++;<br>
/* Fall down */<br>
<br>
+ case DEVICE_OPEN_CONTEXT_STEP_<wbr>CLOSE_MESSAGE:<br>
+ /* Only send an explicit close during open if needed */<br>
+ if (ctx->close_before_open) {<br>
+ ctx->close_before_open = FALSE;<br>
+ close_message_before_open (task);<br>
+ return;<br>
+ }<br>
+ ctx->step++;<br>
+ /* Fall down */<br>
+<br>
case DEVICE_OPEN_CONTEXT_STEP_OPEN_<wbr>MESSAGE:<br>
/* If the device is already in-session, avoid the open message */<br>
if (!self->priv->in_session) {<br>
@@ -1525,6 +1632,7 @@ mbim_device_open_full (MbimDevice *self,<br>
ctx->flags = flags;<br>
ctx->timeout = timeout;<br>
ctx->timer = g_timer_new ();<br>
+ ctx->close_before_open = FALSE;<br>
<br>
task = g_task_new (self, cancellable, callback, user_data);<br>
g_task_set_task_data (task, ctx, (GDestroyNotify)device_open_<wbr>context_free);<br>
diff --git a/src/libmbim-glib/mbim-<wbr>errors.h b/src/libmbim-glib/mbim-<wbr>errors.h<br>
index 2c7d177..064660b 100644<br>
--- a/src/libmbim-glib/mbim-<wbr>errors.h<br>
+++ b/src/libmbim-glib/mbim-<wbr>errors.h<br>
@@ -49,7 +49,8 @@<br>
* @MBIM_CORE_ERROR_INVALID_ARGS: Invalid arguments given.<br>
* @MBIM_CORE_ERROR_INVALID_<wbr>MESSAGE: MBIM message is invalid.<br>
* @MBIM_CORE_ERROR_UNSUPPORTED: Not supported.<br>
- * @MBIM_CORE_ERROR_ABORTED: Operation aborted..<br>
+ * @MBIM_CORE_ERROR_ABORTED: Operation aborted.<br>
+ * @MBIM_CORE_ERROR_UNKNOWN_<wbr>STATE: State is unknown.<br>
*<br>
* Common errors that may be reported by libmbim-glib.<br>
*/<br>
@@ -60,7 +61,8 @@ typedef enum { /*< underscore_name=mbim_core_<wbr>error >*/<br>
MBIM_CORE_ERROR_INVALID_ARGS = 3, /*< nick=InvalidArgs >*/<br>
MBIM_CORE_ERROR_INVALID_<wbr>MESSAGE = 4, /*< nick=InvalidMessage >*/<br>
MBIM_CORE_ERROR_UNSUPPORTED = 5, /*< nick=Unsupported >*/<br>
- MBIM_CORE_ERROR_ABORTED = 6 /*< nick=Aborted >*/<br>
+ MBIM_CORE_ERROR_ABORTED = 6, /*< nick=Aborted >*/<br>
+ MBIM_CORE_ERROR_UNKNOWN_STATE = 7 /*< nick=UnknownState >*/<br>
} MbimCoreError;<br>
<br>
/**<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.13.3<br>
<br>
</font></span></blockquote></div><br></div>