[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