[RFC PATCH] port-qmi: automatically try to set 802.3 link layer protocol when opening

Dan Williams dcbw at redhat.com
Wed Jun 10 12:57:41 PDT 2015


On Mon, 2015-06-08 at 11:00 +0200, Aleksander Morgado wrote:
> We do this as early as possible, because it looks like the WDA operation
> isn't allowed if the modem is in use.
> 
> Also, this operation is only needed when the CTL Set Data Format command
> is ignored by the modem, like the Netgear Aircard 341U.
> 
> Last thing, we setup retries because the modem may ignore the requests for
> some time.
> ---
> 
> Comments, anyone?

Looks OK to me.  I haven't tested it though, but I assume you have with
both WDA-supporting and non-WDA-supporting devices?

Dan

> With this change I can reliably use the Netgear Aircard 341U in QMI mode, even
> if it takes quite a long time to do the switch to 802.3 and get it exposed in
> DBus (more than one minute).
> 
> ---
>  src/mm-port-qmi.c | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  src/mm-port-qmi.h |   8 ++
>  2 files changed, 242 insertions(+), 2 deletions(-)
> 
> diff --git a/src/mm-port-qmi.c b/src/mm-port-qmi.c
> index bc5c738..589af78 100644
> --- a/src/mm-port-qmi.c
> +++ b/src/mm-port-qmi.c
> @@ -162,6 +162,214 @@ mm_port_qmi_allocate_client (MMPortQmi *self,
>  }
> 
>  /*****************************************************************************/
> +/* Data format setting
> + *
> + * Up to 5 mins...
> + * the modem will not be exported until this operation finishes
> + */
> +
> +#define DATA_FORMAT_RETRY_TIMEOUT_SECS 5
> +#define DATA_FORMAT_RETRY_NUMBER       60
> +
> +typedef struct {
> +    MMPortQmi *self;
> +    QmiClient *wda;
> +    guint n_retries;
> +    GSimpleAsyncResult *result;
> +    GCancellable *cancellable;
> +} PortDataFormatContext;
> +
> +static void
> +port_data_format_context_complete_and_free (PortDataFormatContext *ctx)
> +{
> +    g_simple_async_result_complete_in_idle (ctx->result);
> +    if (ctx->cancellable)
> +        g_object_unref (ctx->cancellable);
> +    if (ctx->wda) {
> +        qmi_device_release_client (ctx->self->priv->qmi_device,
> +                                   ctx->wda,
> +                                   QMI_DEVICE_RELEASE_CLIENT_FLAGS_RELEASE_CID,
> +                                   3, NULL, NULL, NULL);
> +        g_object_unref (ctx->wda);
> +    }
> +    g_object_unref (ctx->result);
> +    g_object_unref (ctx->self);
> +    g_slice_free (PortDataFormatContext, ctx);
> +}
> +
> +static gboolean
> +port_qmi_data_format_finish (MMPortQmi *self,
> +                             GAsyncResult *res,
> +                             GError **error)
> +{
> +    return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
> +}
> +
> +static void data_format_context_retry (PortDataFormatContext *ctx);
> +
> +static gboolean
> +schedule_data_format_retry (PortDataFormatContext *ctx)
> +{
> +    data_format_context_retry (ctx);
> +    return FALSE;
> +}
> +
> +static void
> +set_data_format_ready (QmiClientWda *client,
> +                       GAsyncResult *res,
> +                       PortDataFormatContext *ctx)
> +{
> +    QmiMessageWdaSetDataFormatOutput *output;
> +    GError *error = NULL;
> +    QmiWdaLinkLayerProtocol link_layer_protocol;
> +
> +    output = qmi_client_wda_set_data_format_finish (client, res, &error);
> +    if (output &&
> +        qmi_message_wda_set_data_format_output_get_result (output, &error) &&
> +        qmi_message_wda_set_data_format_output_get_link_layer_protocol (output, &link_layer_protocol, &error)) {
> +        if (link_layer_protocol == QMI_WDA_LINK_LAYER_PROTOCOL_802_3) {
> +            mm_dbg ("net interface is updated with 802.3 link layer protocol");
> +            g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
> +            port_data_format_context_complete_and_free (ctx);
> +            return;
> +        }
> +        mm_dbg ("couldn't setup net interface with 802.3 link layer protocol: request ignored");
> +    } else {
> +        mm_dbg ("couldn't setup net interface with 802.3 link layer protocol: %s", error->message);
> +        g_error_free (error);
> +    }
> +
> +    /* Retry? */
> +    ctx->n_retries--;
> +    if (ctx->n_retries == 0) {
> +        g_simple_async_result_set_error (ctx->result,
> +                                         MM_CORE_ERROR, MM_CORE_ERROR_ABORTED,
> +                                         "Couldn't update net interface with 802.3 link layer protocol after %u retries",
> +                                         DATA_FORMAT_RETRY_NUMBER);
> +        port_data_format_context_complete_and_free (ctx);
> +        return;
> +    }
> +
> +    if (output)
> +        qmi_message_wda_set_data_format_output_unref (output);
> +
> +    /* Schedule retry */
> +    mm_dbg ("scheduling net interface link layer protocol check... (%u retries left)", ctx->n_retries);
> +    g_timeout_add_seconds (DATA_FORMAT_RETRY_TIMEOUT_SECS, (GSourceFunc) schedule_data_format_retry, ctx);
> +}
> +
> +static void
> +get_data_format_ready (QmiClientWda *client,
> +                       GAsyncResult *res,
> +                       PortDataFormatContext *ctx)
> +{
> +    QmiMessageWdaGetDataFormatOutput *output;
> +    GError *error = NULL;
> +    QmiWdaLinkLayerProtocol link_layer_protocol;
> +    QmiMessageWdaSetDataFormatInput *input;
> +
> +    output = qmi_client_wda_get_data_format_finish (client, res, &error);
> +    if (output &&
> +        qmi_message_wda_get_data_format_output_get_result (output, &error) &&
> +        qmi_message_wda_get_data_format_output_get_link_layer_protocol (output, &link_layer_protocol, &error)) {
> +        /* If we already have 802.3 setup, we're done */
> +        if (link_layer_protocol == QMI_WDA_LINK_LAYER_PROTOCOL_802_3) {
> +            mm_dbg ("net interface is already setup with 802.3 link layer protocol");
> +            qmi_message_wda_get_data_format_output_unref (output);
> +            g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
> +            port_data_format_context_complete_and_free (ctx);
> +            return;
> +        }
> +        mm_dbg ("need to setup interface with 802.3 link layer protocol");
> +    } else {
> +        mm_dbg ("couldn't check whether link layer protocol was correctly set in the net interface: %s",
> +                error->message);
> +        g_error_free (error);
> +    }
> +
> +    if (output)
> +        qmi_message_wda_get_data_format_output_unref (output);
> +
> +    /* Try to setup 802.3 link layer protocol */
> +    mm_dbg ("setting net interface link layer protocol...");
> +    input = qmi_message_wda_set_data_format_input_new ();
> +    qmi_message_wda_set_data_format_input_set_link_layer_protocol (input, QMI_WDA_LINK_LAYER_PROTOCOL_802_3, NULL);
> +    qmi_client_wda_set_data_format (QMI_CLIENT_WDA (ctx->wda),
> +                                    input,
> +                                    10,
> +                                    ctx->cancellable,
> +                                    (GAsyncReadyCallback)set_data_format_ready,
> +                                    ctx);
> +    qmi_message_wda_set_data_format_input_unref (input);
> +}
> +
> +static void
> +data_format_context_retry (PortDataFormatContext *ctx)
> +{
> +    g_assert (ctx->n_retries > 0);
> +
> +    /* Query current data format */
> +    mm_dbg ("checking net interface link layer protocol...");
> +    qmi_client_wda_get_data_format (QMI_CLIENT_WDA (ctx->wda),
> +                                    NULL,
> +                                    10,
> +                                    ctx->cancellable,
> +                                    (GAsyncReadyCallback)get_data_format_ready,
> +                                    ctx);
> +}
> +
> +static void
> +data_format_allocate_wda_client_ready (QmiDevice *qmi_device,
> +                                       GAsyncResult *res,
> +                                       PortDataFormatContext *ctx)
> +{
> +    GError *error = NULL;
> +
> +    ctx->wda = qmi_device_allocate_client_finish (qmi_device, res, &error);
> +    if (!ctx->wda) {
> +        /* Ignore error and finish operation */
> +        mm_dbg ("couldn't allocate WDA client to check whether link layer protocol "
> +                "was correctly set in the net interface: %s",
> +                error->message);
> +        g_error_free (error);
> +        g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
> +        port_data_format_context_complete_and_free (ctx);
> +        return;
> +    }
> +
> +    data_format_context_retry (ctx);
> +}
> +
> +static void
> +port_qmi_data_format (MMPortQmi *self,
> +                      GCancellable *cancellable,
> +                      GAsyncReadyCallback callback,
> +                      gpointer user_data)
> +{
> +    PortDataFormatContext *ctx;
> +
> +    g_return_if_fail (MM_IS_PORT_QMI (self));
> +
> +    ctx = g_slice_new0 (PortDataFormatContext);
> +    ctx->self = g_object_ref (self);
> +    ctx->result = g_simple_async_result_new (G_OBJECT (self),
> +                                             callback,
> +                                             user_data,
> +                                             port_qmi_data_format);
> +    ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
> +    ctx->n_retries = DATA_FORMAT_RETRY_NUMBER;
> +
> +    /* Try to get a WDA client, in order to check the network data format set */
> +    qmi_device_allocate_client (self->priv->qmi_device,
> +                                QMI_SERVICE_WDA,
> +                                QMI_CID_NONE,
> +                                10,
> +                                ctx->cancellable,
> +                                (GAsyncReadyCallback)data_format_allocate_wda_client_ready,
> +                                ctx);
> +}
> +
> +/*****************************************************************************/
> 
>  typedef struct {
>      MMPortQmi *self;
> @@ -190,6 +398,20 @@ mm_port_qmi_open_finish (MMPortQmi *self,
>  }
> 
>  static void
> +data_format_ready (MMPortQmi *self,
> +                   GAsyncResult *res,
> +                   PortOpenContext *ctx)
> +{
> +    GError *error = NULL;
> +
> +    if (!port_qmi_data_format_finish (self, res, &error))
> +        g_simple_async_result_take_error (ctx->result, error);
> +    else
> +        g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
> +    port_open_context_complete_and_free (ctx);
> +}
> +
> +static void
>  qmi_device_open_ready (QmiDevice *qmi_device,
>                         GAsyncResult *res,
>                         PortOpenContext *ctx)
> @@ -202,10 +424,20 @@ qmi_device_open_ready (QmiDevice *qmi_device,
>      if (!qmi_device_open_finish (qmi_device, res, &error)) {
>          g_clear_object (&ctx->self->priv->qmi_device);
>          g_simple_async_result_take_error (ctx->result, error);
> -    } else
> +        port_open_context_complete_and_free (ctx);
> +        return;
> +    }
> +
> +    if (!ctx->set_data_format) {
>          g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
> +        port_open_context_complete_and_free (ctx);
> +        return;
> +    }
> 
> -    port_open_context_complete_and_free (ctx);
> +    port_qmi_data_format (ctx->self,
> +                          ctx->cancellable,
> +                          (GAsyncReadyCallback) data_format_ready,
> +                          ctx);
>  }
> 
>  static void
> diff --git a/src/mm-port-qmi.h b/src/mm-port-qmi.h
> index 9c38b0c..b693ce9 100644
> --- a/src/mm-port-qmi.h
> +++ b/src/mm-port-qmi.h
> @@ -82,4 +82,12 @@ QmiClient *mm_port_qmi_get_client  (MMPortQmi *self,
>                                      QmiService service,
>                                      MMPortQmiFlag flag);
> 
> +void     mm_port_qmi_data_format        (MMPortQmi *self,
> +                                         GCancellable *cancellable,
> +                                         GAsyncReadyCallback callback,
> +                                         gpointer user_data);
> +gboolean mm_port_qmi_data_format_finish (MMPortQmi *self,
> +                                         GAsyncResult *res,
> +                                         GError **error);
> +
>  #endif /* MM_PORT_QMI_H */
> --
> 2.4.2
> _______________________________________________
> ModemManager-devel mailing list
> ModemManager-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/modemmanager-devel




More information about the ModemManager-devel mailing list