[PATCH] bearer-qmi: print verbose PDN throttle info on call failure

Dan Williams dcbw at redhat.com
Mon Jan 11 11:17:48 PST 2016


When a call fails due to throttling, request additional information
and log how long the APN is throttled for.
---
 src/mm-bearer-qmi.c | 150 +++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 120 insertions(+), 30 deletions(-)

diff --git a/src/mm-bearer-qmi.c b/src/mm-bearer-qmi.c
index 30fa2f9..a31452f 100644
--- a/src/mm-bearer-qmi.c
+++ b/src/mm-bearer-qmi.c
@@ -221,12 +221,12 @@ typedef enum {
     CONNECT_STEP_WDS_CLIENT_IPV4,
     CONNECT_STEP_IP_FAMILY_IPV4,
     CONNECT_STEP_START_NETWORK_IPV4,
-    CONNECT_STEP_GET_CURRENT_SETTINGS_IPV4,
+    CONNECT_STEP_NETWORK_RESULT_IPV4,
     CONNECT_STEP_IPV6,
     CONNECT_STEP_WDS_CLIENT_IPV6,
     CONNECT_STEP_IP_FAMILY_IPV6,
     CONNECT_STEP_START_NETWORK_IPV6,
-    CONNECT_STEP_GET_CURRENT_SETTINGS_IPV6,
+    CONNECT_STEP_NETWORK_RESULT_IPV6,
     CONNECT_STEP_LAST
 } ConnectStep;
 
@@ -244,6 +244,10 @@ typedef struct {
     gboolean no_ip_family_preference;
     gboolean default_ip_family_set;
 
+    QmiWdsCallEndReason call_end_reason;
+    QmiWdsVerboseCallEndReasonType verbose_call_end_reason_type;
+    gint16 verbose_call_end_reason_reason;
+
     gboolean ipv4;
     gboolean running_ipv4;
     QmiClientWds *client_ipv4;
@@ -328,28 +332,15 @@ start_network_ready (QmiClientWds *client,
             if (g_error_matches (error,
                                  QMI_PROTOCOL_ERROR,
                                  QMI_PROTOCOL_ERROR_CALL_FAILED)) {
-                QmiWdsCallEndReason cer;
-                QmiWdsVerboseCallEndReasonType verbose_cer_type;
-                gint16 verbose_cer_reason;
-
-                if (qmi_message_wds_start_network_output_get_call_end_reason (
+                qmi_message_wds_start_network_output_get_call_end_reason (
                         output,
-                        &cer,
-                        NULL))
-                    mm_info ("call end reason (%u): '%s'",
-                             cer,
-                             qmi_wds_call_end_reason_get_string (cer));
-
-                if (qmi_message_wds_start_network_output_get_verbose_call_end_reason (
+                        &ctx->call_end_reason,
+                        NULL);
+                qmi_message_wds_start_network_output_get_verbose_call_end_reason (
                         output,
-                        &verbose_cer_type,
-                        &verbose_cer_reason,
-                        NULL))
-                    mm_info ("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));
+                        &ctx->verbose_call_end_reason_type,
+                        &ctx->verbose_call_end_reason_reason,
+                        NULL);
             }
         }
     }
@@ -713,6 +704,99 @@ get_current_settings (ConnectContext *ctx, QmiClientWds *client)
 }
 
 static void
+get_throttle_info_ready (QmiClientWds *client,
+                         GAsyncResult *res,
+                         ConnectContext *ctx)
+{
+    GError *error = NULL;
+    QmiMessageWdsGetPdnThrottleInfoOutput *output;
+
+    g_assert (ctx->running_ipv4 || ctx->running_ipv6);
+
+    output = qmi_client_wds_get_pdn_throttle_info_finish (client, res, &error);
+    if (!output ||
+        !qmi_message_wds_get_pdn_throttle_info_output_get_result (output, &error)) {
+        /* Never treat this as a hard connection error; not all devices support
+         * "WDS Get PDN Throttle Info" */
+        mm_info ("error: couldn't get PDN throttle info: %s", error->message);
+        g_error_free (error);
+    } else {
+        GArray *array;
+        guint i;
+
+        if (qmi_message_wds_get_pdn_throttle_info_output_get_info (output, &array, &error)) {
+            mm_info ("PDN Throttle Info:");
+            for (i = 0; array && (i < array->len); i++) {
+                const QmiMessageWdsGetPdnThrottleInfoOutputInfoElement *item = &g_array_index (array, QmiMessageWdsGetPdnThrottleInfoOutputInfoElement, i);
+
+                mm_info ("  APN: %s (IPv4: %ums, IPv6: %ums)",
+                         item->apn,
+                         item->ipv4_throttled ? item->ipv4_throttle_time_left_ms : 0,
+                         item->ipv6_throttled ? item->ipv6_throttle_time_left_ms : 0);
+            }
+        } else {
+            mm_info ("error: failed to read PDN throttle info: %s", error ? error->message : "unknown");
+            g_clear_error (&error);
+        }
+    }
+
+    if (output)
+        qmi_message_wds_get_pdn_throttle_info_output_unref (output);
+
+    /* Keep on */
+    ctx->step++;
+    connect_context_step (ctx);
+}
+
+static void
+get_start_network_failure_info (ConnectContext *ctx, QmiClientWds *client)
+{
+    g_assert (ctx->running_ipv4 || ctx->running_ipv6);
+
+    if (ctx->call_end_reason != 0) {
+        mm_info ("%s call end reason (%u): '%s'",
+                 ctx->running_ipv4 ? "IPv4" : "IPv6",
+                 ctx->call_end_reason,
+                 qmi_wds_call_end_reason_get_string (ctx->call_end_reason));
+    }
+
+    if (ctx->verbose_call_end_reason_type != 0) {
+        mm_info ("%s verbose call end reason (%u,%d): [%s] %s",
+                 ctx->running_ipv4 ? "IPv4" : "IPv6",
+                 ctx->verbose_call_end_reason_type,
+                 ctx->verbose_call_end_reason_reason,
+                 qmi_wds_verbose_call_end_reason_type_get_string (ctx->verbose_call_end_reason_type),
+                 qmi_wds_verbose_call_end_reason_get_string (
+                        ctx->verbose_call_end_reason_type,
+                        ctx->verbose_call_end_reason_reason));
+    }
+
+    if (ctx->verbose_call_end_reason_type == QMI_WDS_VERBOSE_CALL_END_REASON_TYPE_INTERNAL &&
+        (ctx->verbose_call_end_reason_reason == QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_PDN_IPV4_CALL_THROTTLED ||
+         ctx->verbose_call_end_reason_reason == QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_PDN_IPV6_CALL_THROTTLED)) {
+        QmiMessageWdsGetPdnThrottleInfoInput *input;
+
+        input = qmi_message_wds_get_pdn_throttle_info_input_new ();
+        qmi_message_wds_get_pdn_throttle_info_input_set_network_type (
+                input,
+                ctx->apn ? QMI_WDS_DATA_SYSTEM_NETWORK_TYPE_3GPP : QMI_WDS_DATA_SYSTEM_NETWORK_TYPE_3GPP2,
+                NULL);
+        qmi_client_wds_get_pdn_throttle_info (client,
+                                              input,
+                                              10,
+                                              ctx->cancellable,
+                                              (GAsyncReadyCallback)get_throttle_info_ready,
+                                              ctx);
+        qmi_message_wds_get_pdn_throttle_info_input_unref (input);
+        return;
+    }
+
+    /* Keep on */
+    ctx->step++;
+    connect_context_step (ctx);
+}
+
+static void
 set_ip_family_ready (QmiClientWds *client,
                      GAsyncResult *res,
                      ConnectContext *ctx)
@@ -902,15 +986,18 @@ connect_context_step (ConnectContext *ctx)
         return;
     }
 
-    case CONNECT_STEP_GET_CURRENT_SETTINGS_IPV4: {
+    case CONNECT_STEP_NETWORK_RESULT_IPV4: {
         /* Retrieve and print IP configuration */
         if (ctx->packet_data_handle_ipv4) {
             mm_dbg ("Getting IPv4 configuration...");
             get_current_settings (ctx, ctx->client_ipv4);
-            return;
+        } else if (ctx->call_end_reason) {
+            mm_dbg ("Getting IPv4 failure information...");
+            get_start_network_failure_info (ctx, ctx->client_ipv4);
+        } else {
+            /* Fall through */
+            ctx->step++;
         }
-        /* Fall through */
-        ctx->step++;
     }
 
     case CONNECT_STEP_IPV6:
@@ -991,15 +1078,18 @@ connect_context_step (ConnectContext *ctx)
         return;
     }
 
-    case CONNECT_STEP_GET_CURRENT_SETTINGS_IPV6: {
+    case CONNECT_STEP_NETWORK_RESULT_IPV6: {
         /* Retrieve and print IP configuration */
         if (ctx->packet_data_handle_ipv6) {
             mm_dbg ("Getting IPv6 configuration...");
             get_current_settings (ctx, ctx->client_ipv6);
-            return;
+        } else if (ctx->call_end_reason) {
+            mm_dbg ("Getting IPv6 failure information...");
+            get_start_network_failure_info (ctx, ctx->client_ipv6);
+        } else {
+            /* Fall through */
+            ctx->step++;
         }
-        /* Fall through */
-        ctx->step++;
     }
 
     case CONNECT_STEP_LAST:
-- 
2.4.3


More information about the ModemManager-devel mailing list