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

Hook up to the WDS Packet Service Status indication, listen for
disconnection events, and disconnect the bearer when we get one.
This commit is contained in:
Dan Williams
2016-04-13 12:16:57 -05:00
parent 650f4a2e91
commit 80ce59385f

View File

@@ -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);
@@ -744,6 +771,75 @@ set_ip_family_ready (QmiClientWds *client,
connect_context_step (ctx);
}
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,
@@ -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);