[PATCH] bearer-qmi: listen for Packet Service Status indication and handle disconnection

Diego López Montes dlopezm at teltronic.es
Thu Apr 14 08:17:40 UTC 2016


Great job! I'm going to try it. I will report the results the tests as 
soon as possible.
> Hook up to the WDS Packet Service Status indication, listen for
> disconnection events, and disconnect the bearer when we get one.
> ---
>   src/mm-bearer-qmi.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 139 insertions(+)
>
> *** testing with dual-stack (IPV4V6) appreciated!
>
> diff --git a/src/mm-bearer-qmi.c b/src/mm-bearer-qmi.c
> index 74e74f7..e750bf2 100644
> --- a/src/mm-bearer-qmi.c
> +++ b/src/mm-bearer-qmi.c
> @@ -49,7 +49,11 @@ static GParamSpec *properties[PROP_LAST];
>   struct _MMBearerQmiPrivate {
>       /* State kept while connected */
>       QmiClientWds *client_ipv4;
> +    guint packet_service_status_ipv4_indication_id;
> +
>       QmiClientWds *client_ipv6;
> +    guint packet_service_status_ipv6_indication_id;
> +
>       MMPort *data;
>       guint32 packet_data_handle_ipv4;
>       guint32 packet_data_handle_ipv6;
> @@ -214,17 +218,24 @@ reload_stats (MMBaseBearer *self,
>   /*****************************************************************************/
>   /* Connect */
>   
> +static void common_setup_cleanup_unsolicited_events (MMBearerQmi *self,
> +                                                     QmiClientWds *client,
> +                                                     gboolean enable,
> +                                                     guint *indication_id);
> +
>   typedef enum {
>       CONNECT_STEP_FIRST,
>       CONNECT_STEP_OPEN_QMI_PORT,
>       CONNECT_STEP_IPV4,
>       CONNECT_STEP_WDS_CLIENT_IPV4,
>       CONNECT_STEP_IP_FAMILY_IPV4,
> +    CONNECT_STEP_ENABLE_INDICATIONS_IPV4,
>       CONNECT_STEP_START_NETWORK_IPV4,
>       CONNECT_STEP_GET_CURRENT_SETTINGS_IPV4,
>       CONNECT_STEP_IPV6,
>       CONNECT_STEP_WDS_CLIENT_IPV6,
>       CONNECT_STEP_IP_FAMILY_IPV6,
> +    CONNECT_STEP_ENABLE_INDICATIONS_IPV6,
>       CONNECT_STEP_START_NETWORK_IPV6,
>       CONNECT_STEP_GET_CURRENT_SETTINGS_IPV6,
>       CONNECT_STEP_LAST
> @@ -247,6 +258,7 @@ typedef struct {
>       gboolean ipv4;
>       gboolean running_ipv4;
>       QmiClientWds *client_ipv4;
> +    guint packet_service_status_ipv4_indication_id;
>       guint32 packet_data_handle_ipv4;
>       MMBearerIpConfig *ipv4_config;
>       GError *error_ipv4;
> @@ -254,6 +266,7 @@ typedef struct {
>       gboolean ipv6;
>       gboolean running_ipv6;
>       QmiClientWds *client_ipv6;
> +    guint packet_service_status_ipv6_indication_id;
>       guint32 packet_data_handle_ipv6;
>       MMBearerIpConfig *ipv6_config;
>       GError *error_ipv6;
> @@ -267,6 +280,20 @@ connect_context_complete_and_free (ConnectContext *ctx)
>       g_free (ctx->apn);
>       g_free (ctx->user);
>       g_free (ctx->password);
> +
> +    if (ctx->packet_service_status_ipv4_indication_id) {
> +        common_setup_cleanup_unsolicited_events (ctx->self,
> +                                                 ctx->client_ipv4,
> +                                                 FALSE,
> +                                                 &ctx->packet_service_status_ipv4_indication_id);
> +    }
> +    if (ctx->packet_service_status_ipv6_indication_id) {
> +        common_setup_cleanup_unsolicited_events (ctx->self,
> +                                                 ctx->client_ipv6,
> +                                                 FALSE,
> +                                                 &ctx->packet_service_status_ipv6_indication_id);
> +    }
> +
>       g_clear_error (&ctx->error_ipv4);
>       g_clear_error (&ctx->error_ipv6);
>       g_clear_object (&ctx->client_ipv4);
> @@ -745,6 +772,75 @@ set_ip_family_ready (QmiClientWds *client,
>   }
>   
>   static void
> +packet_service_status_indication_cb (QmiClientWds *client,
> +                                     QmiIndicationWdsPacketServiceStatusOutput *output,
> +                                     MMBearerQmi *self)
> +{
> +    QmiWdsConnectionStatus connection_status;
> +
> +    if (qmi_indication_wds_packet_service_status_output_get_connection_status (
> +            output,
> +            &connection_status,
> +            NULL,
> +            NULL)) {
> +        MMBearerConnectionStatus bearer_status = mm_base_bearer_get_status (MM_BASE_BEARER (self));
> +
> +        if (connection_status == QMI_WDS_CONNECTION_STATUS_DISCONNECTED &&
> +            bearer_status != MM_BEARER_CONNECTION_STATUS_DISCONNECTED &&
> +            bearer_status != MM_BEARER_CONNECTION_STATUS_DISCONNECTING) {
> +            QmiWdsCallEndReason cer;
> +            QmiWdsVerboseCallEndReasonType verbose_cer_type;
> +            gint16 verbose_cer_reason;
> +
> +            if (qmi_indication_wds_packet_service_status_output_get_call_end_reason (
> +                    output,
> +                    &cer,
> +                    NULL))
> +                mm_info ("bearer call end reason (%u): '%s'",
> +                         cer,
> +                         qmi_wds_call_end_reason_get_string (cer));
> +
> +            if (qmi_indication_wds_packet_service_status_output_get_verbose_call_end_reason (
> +                    output,
> +                    &verbose_cer_type,
> +                    &verbose_cer_reason,
> +                    NULL))
> +                mm_info ("bearer verbose call end reason (%u,%d): [%s] %s",
> +                         verbose_cer_type,
> +                         verbose_cer_reason,
> +                         qmi_wds_verbose_call_end_reason_type_get_string (verbose_cer_type),
> +                         qmi_wds_verbose_call_end_reason_get_string (verbose_cer_type, verbose_cer_reason));
> +
> +            mm_base_bearer_report_connection_status (MM_BASE_BEARER (self), MM_BEARER_CONNECTION_STATUS_DISCONNECTED);
> +        }
> +    }
> +}
> +
> +static void
> +common_setup_cleanup_unsolicited_events (MMBearerQmi *self,
> +                                         QmiClientWds *client,
> +                                         gboolean enable,
> +                                         guint *indication_id)
> +{
> +    if (!client)
> +        return;
> +
> +    /* Connect/Disconnect "Packet Service Status" indications */
> +    if (enable) {
> +        g_assert (*indication_id == 0);
> +        *indication_id =
> +            g_signal_connect (client,
> +                              "packet-service-status",
> +                              G_CALLBACK (packet_service_status_indication_cb),
> +                              self);
> +    } else {
> +        g_assert (*indication_id != 0);
> +        g_signal_handler_disconnect (client, *indication_id);
> +        *indication_id = 0;
> +    }
> +}
> +
> +static void
>   qmi_port_allocate_client_ready (MMPortQmi *qmi,
>                                   GAsyncResult *res,
>                                   ConnectContext *ctx)
> @@ -887,6 +983,14 @@ connect_context_step (ConnectContext *ctx)
>           /* Just fall down */
>           ctx->step++;
>   
> +    case CONNECT_STEP_ENABLE_INDICATIONS_IPV4:
> +        common_setup_cleanup_unsolicited_events (ctx->self,
> +                                                 ctx->client_ipv4,
> +                                                 TRUE,
> +                                                 &ctx->packet_service_status_ipv4_indication_id);
> +        /* Just fall down */
> +        ctx->step++;
> +
>       case CONNECT_STEP_START_NETWORK_IPV4: {
>           QmiMessageWdsStartNetworkInput *input;
>   
> @@ -976,6 +1080,14 @@ connect_context_step (ConnectContext *ctx)
>           /* Just fall down */
>           ctx->step++;
>   
> +    case CONNECT_STEP_ENABLE_INDICATIONS_IPV6:
> +        common_setup_cleanup_unsolicited_events (ctx->self,
> +                                                 ctx->client_ipv6,
> +                                                 TRUE,
> +                                                 &ctx->packet_service_status_ipv6_indication_id);
> +        /* Just fall down */
> +        ctx->step++;
> +
>       case CONNECT_STEP_START_NETWORK_IPV6: {
>           QmiMessageWdsStartNetworkInput *input;
>   
> @@ -1016,6 +1128,8 @@ connect_context_step (ConnectContext *ctx)
>               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->packet_service_status_ipv4_indication_id = ctx->packet_service_status_ipv4_indication_id;
> +                ctx->packet_service_status_ipv4_indication_id = 0;
>                   ctx->self->priv->client_ipv4 = g_object_ref (ctx->client_ipv4);
>               }
>   
> @@ -1023,6 +1137,8 @@ connect_context_step (ConnectContext *ctx)
>               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->packet_service_status_ipv6_indication_id = ctx->packet_service_status_ipv6_indication_id;
> +                ctx->packet_service_status_ipv6_indication_id = 0;
>                   ctx->self->priv->client_ipv6 = g_object_ref (ctx->client_ipv6);
>               }
>   
> @@ -1357,6 +1473,11 @@ disconnect_context_step (DisconnectContext *ctx)
>           if (ctx->packet_data_handle_ipv4) {
>               QmiMessageWdsStopNetworkInput *input;
>   
> +            common_setup_cleanup_unsolicited_events (ctx->self,
> +                                                     ctx->client_ipv4,
> +                                                     FALSE,
> +                                                     &ctx->self->priv->packet_service_status_ipv4_indication_id);
> +
>               input = qmi_message_wds_stop_network_input_new ();
>               qmi_message_wds_stop_network_input_set_packet_data_handle (input, ctx->packet_data_handle_ipv4, NULL);
>   
> @@ -1378,6 +1499,11 @@ disconnect_context_step (DisconnectContext *ctx)
>           if (ctx->packet_data_handle_ipv6) {
>               QmiMessageWdsStopNetworkInput *input;
>   
> +            common_setup_cleanup_unsolicited_events (ctx->self,
> +                                                     ctx->client_ipv6,
> +                                                     FALSE,
> +                                                     &ctx->self->priv->packet_service_status_ipv6_indication_id);
> +
>               input = qmi_message_wds_stop_network_input_new ();
>               qmi_message_wds_stop_network_input_set_packet_data_handle (input, ctx->packet_data_handle_ipv6, NULL);
>   
> @@ -1544,6 +1670,19 @@ dispose (GObject *object)
>   {
>       MMBearerQmi *self = MM_BEARER_QMI (object);
>   
> +    if (self->priv->packet_service_status_ipv4_indication_id) {
> +        common_setup_cleanup_unsolicited_events (self,
> +                                                 self->priv->client_ipv4,
> +                                                 FALSE,
> +                                                 &self->priv->packet_service_status_ipv4_indication_id);
> +    }
> +    if (self->priv->packet_service_status_ipv6_indication_id) {
> +        common_setup_cleanup_unsolicited_events (self,
> +                                                 self->priv->client_ipv6,
> +                                                 FALSE,
> +                                                 &self->priv->packet_service_status_ipv6_indication_id);
> +    }
> +
>       g_clear_object (&self->priv->data);
>       g_clear_object (&self->priv->client_ipv4);
>       g_clear_object (&self->priv->client_ipv6);
> -- 
> 2.5.5



More information about the ModemManager-devel mailing list