<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>