/**
 * qmi_client_ctl_release_cid:
 * @self: a #QmiClientCtl.
 * @service: a #QmiService.
 * @cid: the client ID to release.
 * @timeout: maximum time to wait to get the operation completed.
 * @cancellable: optional #GCancellable object, #NULL to ignore.
 * @callback: a #GAsyncReadyCallback to call when the operation is finished.
 * @user_data: the data to pass to callback function.
 *
 * Release a previously allocated client ID for the given @service.
 * When the query is finished, @callback will be called. You can then call
 * qmi_client_ctl_release_cid_finish() to get the the result of the operation.
 */
void
qmi_client_ctl_release_cid (QmiClientCtl *self,
                            QmiService service,
                            guint8 cid,
                            guint timeout,
                            GCancellable *cancellable,
                            GAsyncReadyCallback callback,
                            gpointer user_data)
{
    ReleaseCidContext *ctx;
    QmiMessage *request;

    ctx = g_slice_new (ReleaseCidContext);
    ctx->self = g_object_ref (self);
    ctx->service = service;
    ctx->cid = cid;
    ctx->result = g_simple_async_result_new (G_OBJECT (self),
                                             callback,
                                             user_data,
                                             qmi_client_ctl_release_cid);

    request = qmi_message_ctl_release_cid_new (qmi_client_get_next_transaction_id (QMI_CLIENT (self)),
                                               service,
                                               cid);
    qmi_device_command (QMI_DEVICE (qmi_client_peek_device (QMI_CLIENT (self))),
                        request,
                        timeout,
                        cancellable,
                        (GAsyncReadyCallback)release_cid_ready,
                        ctx);
    qmi_message_unref (request);
}
/**
 * qmi_client_ctl_sync:
 * @self: a #QmiClientCtl.
 * @timeout: maximum time to wait to get the operation completed.
 * @cancellable: optional #GCancellable object, #NULL to ignore.
 * @callback: a #GAsyncReadyCallback to call when the operation is finished.
 * @user_data: the data to pass to callback function.
 *
 * Request to sync with the device.
 * When the operation is finished, @callback will be called. You can then call
 * qmi_client_ctl_sync_finish() to get the the result of the operation.
 */
void
qmi_client_ctl_sync (QmiClientCtl *self,
                     guint timeout,
                     GCancellable *cancellable,
                     GAsyncReadyCallback callback,
                     gpointer user_data)
{
    GSimpleAsyncResult *result;
    QmiMessage *request;

    result = g_simple_async_result_new (G_OBJECT (self),
                                        callback,
                                        user_data,
                                        qmi_client_ctl_sync);

    request = qmi_message_ctl_sync_new (qmi_client_get_next_transaction_id (QMI_CLIENT (self)));
    qmi_device_command (QMI_DEVICE (qmi_client_peek_device (QMI_CLIENT (self))),
                        request,
                        timeout,
                        cancellable,
                        (GAsyncReadyCallback)sync_command_ready,
                        result);
    qmi_message_unref (request);
}
Esempio n. 3
0
static void
connect_context_step (ConnectContext *ctx)
{
    /* If cancelled, complete */
    if (g_cancellable_is_cancelled (ctx->cancellable)) {
        g_simple_async_result_set_error (ctx->result,
                                         MM_CORE_ERROR,
                                         MM_CORE_ERROR_CANCELLED,
                                         "Connection setup operation has been cancelled");
        connect_context_complete_and_free (ctx);
        return;
    }

    switch (ctx->step) {
    case CONNECT_STEP_FIRST:

        g_assert (ctx->ipv4 || ctx->ipv6);

        /* Fall down */
        ctx->step++;

    case CONNECT_STEP_OPEN_QMI_PORT:
        if (!mm_qmi_port_is_open (ctx->qmi)) {
            mm_qmi_port_open (ctx->qmi,
                              TRUE,
                              ctx->cancellable,
                              (GAsyncReadyCallback)qmi_port_open_ready,
                              ctx);
            return;
        }

        /* If already open, just fall down */
        ctx->step++;

    case CONNECT_STEP_IPV4:
        /* If no IPv4 setup needed, jump to IPv6 */
        if (!ctx->ipv4) {
            ctx->step = CONNECT_STEP_IPV6;
            connect_context_step (ctx);
            return;
        }

        /* Start IPv4 setup */
        mm_dbg ("Running IPv4 connection setup");
        ctx->running_ipv4 = TRUE;
        ctx->running_ipv6 = FALSE;
        /* Just fall down */
        ctx->step++;

    case CONNECT_STEP_WDS_CLIENT_IPV4: {
        QmiClient *client;

        client = mm_qmi_port_get_client (ctx->qmi,
                                         QMI_SERVICE_WDS,
                                         MM_QMI_PORT_FLAG_WDS_IPV4);
        if (!client) {
            mm_dbg ("Allocating IPv4-specific WDS client");
            mm_qmi_port_allocate_client (ctx->qmi,
                                         QMI_SERVICE_WDS,
                                         MM_QMI_PORT_FLAG_WDS_IPV4,
                                         ctx->cancellable,
                                         (GAsyncReadyCallback)qmi_port_allocate_client_ready,
                                         ctx);
            return;
        }

        ctx->client_ipv4 = QMI_CLIENT_WDS (client);
        /* Just fall down */
        ctx->step++;
    }

    case CONNECT_STEP_IP_FAMILY_IPV4:
        /* If client is new enough, select IP family */
        if (!ctx->no_ip_family_preference &&
            qmi_client_check_version (QMI_CLIENT (ctx->client_ipv4), 1, 9)) {
            QmiMessageWdsSetIpFamilyInput *input;

            mm_dbg ("Setting default IP family to: IPv4");
            input = qmi_message_wds_set_ip_family_input_new ();
            qmi_message_wds_set_ip_family_input_set_preference (input, QMI_WDS_IP_FAMILY_IPV4, NULL);
            qmi_client_wds_set_ip_family (ctx->client_ipv4,
                                          input,
                                          10,
                                          ctx->cancellable,
                                          (GAsyncReadyCallback)set_ip_family_ready,
                                          ctx);
            qmi_message_wds_set_ip_family_input_unref (input);
            return;
        }

        ctx->default_ip_family_set = FALSE;

        /* Just fall down */
        ctx->step++;

    case CONNECT_STEP_START_NETWORK_IPV4: {
        QmiMessageWdsStartNetworkInput *input;

        mm_dbg ("Starting IPv4 connection...");
        input = build_start_network_input (ctx);
        qmi_client_wds_start_network (ctx->client_ipv4,
                                      input,
                                      45,
                                      ctx->cancellable,
                                      (GAsyncReadyCallback)start_network_ready,
                                      ctx);
        qmi_message_wds_start_network_input_unref (input);
        return;
    }

    case CONNECT_STEP_IPV6:
        /* If no IPv6 setup needed, jump to last */
        if (!ctx->ipv6) {
            ctx->step = CONNECT_STEP_GET_CURRENT_SETTINGS;
            connect_context_step (ctx);
            return;
        }

        /* Start IPv6 setup */
        mm_dbg ("Running IPv6 connection setup");
        ctx->running_ipv4 = FALSE;
        ctx->running_ipv6 = TRUE;
        /* Just fall down */
        ctx->step++;

    case CONNECT_STEP_WDS_CLIENT_IPV6: {
        QmiClient *client;

        client = mm_qmi_port_get_client (ctx->qmi,
                                         QMI_SERVICE_WDS,
                                         MM_QMI_PORT_FLAG_WDS_IPV6);
        if (!client) {
            mm_dbg ("Allocating IPv6-specific WDS client");
            mm_qmi_port_allocate_client (ctx->qmi,
                                         QMI_SERVICE_WDS,
                                         MM_QMI_PORT_FLAG_WDS_IPV6,
                                         ctx->cancellable,
                                         (GAsyncReadyCallback)qmi_port_allocate_client_ready,
                                         ctx);
            return;
        }

        ctx->client_ipv6 = QMI_CLIENT_WDS (client);
        /* Just fall down */
        ctx->step++;
    }

    case CONNECT_STEP_IP_FAMILY_IPV6:

        g_assert (ctx->no_ip_family_preference == FALSE);

        /* If client is new enough, select IP family */
        if (qmi_client_check_version (QMI_CLIENT (ctx->client_ipv6), 1, 9)) {
            QmiMessageWdsSetIpFamilyInput *input;

            mm_dbg ("Setting default IP family to: IPv6");
            input = qmi_message_wds_set_ip_family_input_new ();
            qmi_message_wds_set_ip_family_input_set_preference (input, QMI_WDS_IP_FAMILY_IPV6, NULL);
            qmi_client_wds_set_ip_family (ctx->client_ipv6,
                                          input,
                                          10,
                                          ctx->cancellable,
                                          (GAsyncReadyCallback)set_ip_family_ready,
                                          ctx);
            qmi_message_wds_set_ip_family_input_unref (input);
            return;
        }

        ctx->default_ip_family_set = FALSE;

        /* Just fall down */
        ctx->step++;

    case CONNECT_STEP_START_NETWORK_IPV6: {
        QmiMessageWdsStartNetworkInput *input;

        mm_dbg ("Starting IPv6 connection...");
        input = build_start_network_input (ctx);
        qmi_client_wds_start_network (ctx->client_ipv6,
                                      input,
                                      45,
                                      ctx->cancellable,
                                      (GAsyncReadyCallback)start_network_ready,
                                      ctx);
        qmi_message_wds_start_network_input_unref (input);
        return;
    }

    case CONNECT_STEP_GET_CURRENT_SETTINGS: {
        QmiMessageWdsGetCurrentSettingsInput *input;
        QmiClientWds *client;

        if (ctx->running_ipv4)
            client = ctx->client_ipv4;
        else if (ctx->running_ipv6)
            client = ctx->client_ipv6;
        else
            g_assert_not_reached ();

        mm_dbg ("Getting IP configuration...");
        input = build_get_current_settings_input (ctx);
        qmi_client_wds_get_current_settings (client,
                                             input,
                                             45,
                                             ctx->cancellable,
                                             (GAsyncReadyCallback)get_current_settings_ready,
                                             ctx);
        qmi_message_wds_get_current_settings_input_unref (input);
        return;
    }

    case CONNECT_STEP_LAST:
        /* If one of IPv4 or IPv6 succeeds, we're connected */
        if (ctx->packet_data_handle_ipv4 || ctx->packet_data_handle_ipv6) {
            MMBearerIpConfig *config;
            ConnectResult *result;

            /* Port is connected; update the state */
            mm_port_set_connected (MM_PORT (ctx->data), TRUE);

            /* Keep connection related data */
            g_assert (ctx->self->priv->data == NULL);
            ctx->self->priv->data = g_object_ref (ctx->data);

            g_assert (ctx->self->priv->packet_data_handle_ipv4 == 0);
            g_assert (ctx->self->priv->client_ipv4 == NULL);
            if (ctx->packet_data_handle_ipv4) {
                ctx->self->priv->packet_data_handle_ipv4 = ctx->packet_data_handle_ipv4;
                ctx->self->priv->client_ipv4 = g_object_ref (ctx->client_ipv4);
            }

            g_assert (ctx->self->priv->packet_data_handle_ipv6 == 0);
            g_assert (ctx->self->priv->client_ipv6 == NULL);
            if (ctx->packet_data_handle_ipv6) {
                ctx->self->priv->packet_data_handle_ipv6 = ctx->packet_data_handle_ipv6;
                ctx->self->priv->client_ipv6 = g_object_ref (ctx->client_ipv6);
            }

            /* Build IP config; always DHCP based */
            config = mm_bearer_ip_config_new ();
            mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_DHCP);

            /* Build result */
            result = g_slice_new0 (ConnectResult);
            result->data = g_object_ref (ctx->data);
            if (ctx->packet_data_handle_ipv4)
                result->ipv4_config = g_object_ref (config);
            if (ctx->packet_data_handle_ipv6)
                result->ipv6_config = g_object_ref (config);

            g_object_unref (config);

            /* Set operation result */
            g_simple_async_result_set_op_res_gpointer (ctx->result,
                                                       result,
                                                       (GDestroyNotify)connect_result_free);
        } else {
            GError *error;

            /* No connection, set error. If both set, IPv4 error preferred */
            if (ctx->error_ipv4) {
                error = ctx->error_ipv4;
                ctx->error_ipv4 = NULL;
            } else {
                error = ctx->error_ipv6;
                ctx->error_ipv6 = NULL;
            }

            g_simple_async_result_take_error (ctx->result, error);
        }

        connect_context_complete_and_free (ctx);
        return;
    }
}