[PATCH] nas: add support for Set System Selection Preference radio interface acquisition order

Dan Williams dcbw at redhat.com
Thu Feb 16 20:01:52 UTC 2017


Supported by NAS >= 1.21 at least, not sure how much earlier the TLV goes.
---
Tested on a Sierra MC7700 and MC7750, but not with a live network to verify
that the device actually does pick the right RAT in-order. Could somebody
else maybe do that?

 data/qmi-service-nas.json       |  38 ++++++++++++-
 src/libqmi-glib/qmi-enums-nas.h |  12 ++--
 src/qmicli/qmicli-helpers.c     |  53 ++++++++++++++++-
 src/qmicli/qmicli-helpers.h     |   3 +-
 src/qmicli/qmicli-nas.c         | 122 ++++++++++++++++++++++++++++------------
 5 files changed, 181 insertions(+), 47 deletions(-)

diff --git a/data/qmi-service-nas.json b/data/qmi-service-nas.json
index 7f6b809..9bc674e 100644
--- a/data/qmi-service-nas.json
+++ b/data/qmi-service-nas.json
@@ -1391,13 +1391,37 @@
                       "since"         : "1.0",
                       "format"        : "guint8",
                       "public-format" : "gboolean" },
+                    { "name"          : "Domain Preference",
+                      "id"            : "0x1B",
+                      "mandatory"     : "no",
+                      "type"          : "TLV",
+                      "since"         : "1.18",
+                      "format"        : "guint32",
+                      "public-format" : "QmiNasServiceDomainPreference" },
+                    { "name"          : "Acquisition Order Preference",
+                      "id"            : "0x1C",
+                      "mandatory"     : "no",
+                      "type"          : "TLV",
+                      "since"         : "1.18",
+                      "format"        : "guint32",
+                      "public-format" : "QmiNasGsmWcdmaAcquisitionOrderPreference" },
                     { "name"          : "TD SCDMA Band Preference",
                       "id"            : "0x1D",
                       "mandatory"     : "no",
                       "type"          : "TLV",
                       "since"         : "1.0",
                       "format"        : "guint64",
-                      "public-format" : "QmiNasTdScdmaBandPreference" } ],
+                      "public-format" : "QmiNasTdScdmaBandPreference" },
+                    { "name"               : "Acquisition Order",
+                      "id"                 : "0x1E",
+                      "mandatory"          : "no",
+                      "type"               : "TLV",
+                      "since"              : "1.18",
+                      "size-prefix-format" : "guint8",
+                      "format"             : "array",
+                      "array-element"      : { "name"          : "Radio Interface",
+                                               "format"        : "guint8",
+                                               "public-format" : "QmiNasRadioInterface" } } ],
      "output"  : [  { "common-ref" : "Operation Result" } ] },
 
   // *********************************************************************************
@@ -1490,7 +1514,17 @@
                                         "format" : "guint16" },
                                       { "name"          : "Includes PCS Digit",
                                         "format"        : "guint8",
-                                        "public-format" : "gboolean" } ] } ] },
+                                        "public-format" : "gboolean" } ] },
+                    { "name"               : "Acquisition Order",
+                      "id"                 : "0x1C",
+                      "mandatory"          : "no",
+                      "type"               : "TLV",
+                      "since"              : "1.18",
+                      "size-prefix-format" : "guint8",
+                      "format"             : "array",
+                      "array-element"      : { "name"          : "Radio Interface",
+                                               "format"        : "guint8",
+                                               "public-format" : "QmiNasRadioInterface" } } ] },
 
   // *********************************************************************************
   {  "name"    : "Get Operator Name",
diff --git a/src/libqmi-glib/qmi-enums-nas.h b/src/libqmi-glib/qmi-enums-nas.h
index c728547..81d552f 100644
--- a/src/libqmi-glib/qmi-enums-nas.h
+++ b/src/libqmi-glib/qmi-enums-nas.h
@@ -873,17 +873,19 @@ typedef enum {
  * @QMI_NAS_SERVICE_DOMAIN_PREFERENCE_CS_PS: Circuit-switched and packet-switched.
  * @QMI_NAS_SERVICE_DOMAIN_PREFERENCE_PS_ATTACH: Packet-switched attach.
  * @QMI_NAS_SERVICE_DOMAIN_PREFERENCE_PS_DETACH:Packet-switched dettach.
+ * @QMI_NAS_SERVICE_DOMAIN_PREFERENCE_PS_DETACH_WITH_NO_CHANGE:Packet-switched dettach with no change.
  *
  * Service domain preference.
  *
  * Since: 1.0
  */
 typedef enum {
-    QMI_NAS_SERVICE_DOMAIN_PREFERENCE_CS_ONLY   = 0x00,
-    QMI_NAS_SERVICE_DOMAIN_PREFERENCE_PS_ONLY   = 0x01,
-    QMI_NAS_SERVICE_DOMAIN_PREFERENCE_CS_PS     = 0x02,
-    QMI_NAS_SERVICE_DOMAIN_PREFERENCE_PS_ATTACH = 0x03,
-    QMI_NAS_SERVICE_DOMAIN_PREFERENCE_PS_DETACH = 0x04,
+    QMI_NAS_SERVICE_DOMAIN_PREFERENCE_CS_ONLY                  = 0x00,
+    QMI_NAS_SERVICE_DOMAIN_PREFERENCE_PS_ONLY                  = 0x01,
+    QMI_NAS_SERVICE_DOMAIN_PREFERENCE_CS_PS                    = 0x02,
+    QMI_NAS_SERVICE_DOMAIN_PREFERENCE_PS_ATTACH                = 0x03,
+    QMI_NAS_SERVICE_DOMAIN_PREFERENCE_PS_DETACH                = 0x04,
+    QMI_NAS_SERVICE_DOMAIN_PREFERENCE_PS_DETACH_WITH_NO_CHANGE = 0x05,
 } QmiNasServiceDomainPreference;
 
 /**
diff --git a/src/qmicli/qmicli-helpers.c b/src/qmicli/qmicli-helpers.c
index 2a2dad2..4470fa2 100644
--- a/src/qmicli/qmicli-helpers.c
+++ b/src/qmicli/qmicli-helpers.c
@@ -224,27 +224,71 @@ qmicli_read_operating_mode_from_string (const gchar *str,
     return !!enum_value;
 }
 
+static QmiNasRadioInterface
+nas_rat_mode_to_radio_interface (QmiNasRatModePreference mode)
+{
+    switch (mode) {
+    case QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1X:
+        return QMI_NAS_RADIO_INTERFACE_CDMA_1X;
+    case QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1XEVDO:
+        return QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO;
+    case QMI_NAS_RAT_MODE_PREFERENCE_GSM:
+        return QMI_NAS_RADIO_INTERFACE_GSM;
+    case QMI_NAS_RAT_MODE_PREFERENCE_UMTS:
+        return QMI_NAS_RADIO_INTERFACE_UMTS;
+    case QMI_NAS_RAT_MODE_PREFERENCE_LTE:
+        return QMI_NAS_RADIO_INTERFACE_LTE;
+    case QMI_NAS_RAT_MODE_PREFERENCE_TD_SCDMA:
+        return QMI_NAS_RADIO_INTERFACE_TD_SCDMA;
+    default:
+        break;
+    }
+    return QMI_NAS_RADIO_INTERFACE_UNKNOWN;
+}
+
+/**
+ * qmicli_read_rat_mode_pref_from_string:
+ * @str: a '|' separated string of #QmiNasRatModePreference
+ * @out: a bitfield translation of @str
+ * @out_radio_interface_array: (transfer full): an ordered #GArray of @str
+ * translated to #QmiNasRadioInterface, free with #g_array_unref when done
+ *
+ * Returns: %TRUE on success, %FALSE on malformed input @str
+ */
 gboolean
 qmicli_read_rat_mode_pref_from_string (const gchar *str,
-                                       QmiNasRatModePreference *out)
+                                       QmiNasRatModePreference *out,
+                                       GArray **out_radio_interface_array)
 {
     GType type;
     GFlagsClass *flags_class;
     GFlagsValue *flags_value;
     gboolean success = TRUE, set = FALSE;
     char **items, **iter;
+    GArray *array;
 
     type = qmi_nas_rat_mode_preference_get_type ();
     flags_class = G_FLAGS_CLASS (g_type_class_ref (type));
 
     items = g_strsplit_set (str, "|", 0);
+
+    array = g_array_sized_new (FALSE,
+                               TRUE,
+                               sizeof (QmiNasRadioInterface),
+                               g_strv_length (items));
+
     for (iter = items; iter && *iter && success; iter++) {
         if (!*iter[0])
             continue;
 
         flags_value = g_flags_get_value_by_nick (flags_class, *iter);
         if (flags_value) {
-            *out |= (QmiNasRatModePreference)flags_value->value;
+            QmiNasRatModePreference mode_pref = flags_value->value;
+            QmiNasRadioInterface radio_interface = nas_rat_mode_to_radio_interface (mode_pref);
+
+            *out |= mode_pref;
+            if (radio_interface >= QMI_NAS_RADIO_INTERFACE_NONE)
+                g_array_append_val (array, radio_interface);
             set = TRUE;
         } else {
             g_printerr ("error: invalid rat mode pref value given: '%s'\n", *iter);
@@ -252,9 +296,14 @@ qmicli_read_rat_mode_pref_from_string (const gchar *str,
         }
     }
 
+
     if (!set)
         g_printerr ("error: invalid rat mode pref input given: '%s'\n", str);
 
+    if (set && success)
+        *out_radio_interface_array = g_array_ref (array);
+    g_array_unref (array);
+
     if (items)
         g_strfreev (items);
     g_type_class_unref (flags_class);
diff --git a/src/qmicli/qmicli-helpers.h b/src/qmicli/qmicli-helpers.h
index 4a1e087..b477a9f 100644
--- a/src/qmicli/qmicli-helpers.h
+++ b/src/qmicli/qmicli-helpers.h
@@ -39,7 +39,8 @@ gboolean qmicli_read_uim_pin_id_from_string                  (const gchar *str,
 gboolean qmicli_read_operating_mode_from_string              (const gchar *str,
                                                               QmiDmsOperatingMode *out);
 gboolean qmicli_read_rat_mode_pref_from_string               (const gchar *str,
-                                                              QmiNasRatModePreference *out);
+                                                              QmiNasRatModePreference *out,
+                                                              GArray **out_radio_interface_array);
 gboolean qmicli_read_facility_from_string                    (const gchar *str,
                                                               QmiDmsUimFacility *out);
 gboolean qmicli_read_enable_disable_from_string              (const gchar *str,
diff --git a/src/qmicli/qmicli-nas.c b/src/qmicli/qmicli-nas.c
index 3ee9653..41f7c4a 100644
--- a/src/qmicli/qmicli-nas.c
+++ b/src/qmicli/qmicli-nas.c
@@ -96,7 +96,7 @@ static GOptionEntry entries[] = {
       NULL
     },
     { "nas-set-system-selection-preference", 0, 0, G_OPTION_ARG_STRING, &set_system_selection_preference_str,
-      "Set system selection preference",
+      "Set system selection preference (in preference order)",
       "[cdma-1x|cdma-1xevdo|gsm|umts|lte|td-scdma]"
     },
     { "nas-network-scan", 0, 0, G_OPTION_ARG_NONE, &network_scan_flag,
@@ -1967,6 +1967,7 @@ get_system_selection_preference_ready (QmiClientNas *client,
     QmiNasNetworkSelectionPreference network_selection_preference;
     QmiNasServiceDomainPreference service_domain_preference;
     QmiNasGsmWcdmaAcquisitionOrderPreference gsm_wcdma_acquisition_order_preference;
+    GArray *radio_interfaces;
     guint16 mcc;
     guint16 mnc;
     gboolean has_pcs_digit;
@@ -2083,6 +2084,25 @@ get_system_selection_preference_ready (QmiClientNas *client,
                  qmi_nas_gsm_wcdma_acquisition_order_preference_get_string (gsm_wcdma_acquisition_order_preference));
     }
 
+    if (qmi_message_nas_get_system_selection_preference_output_get_acquisition_order (
+            output,
+            &radio_interfaces,
+            NULL)) {
+        guint i;
+        GString *str = g_string_sized_new (25);
+
+        for (i = 0; i < radio_interfaces->len; i++) {
+            QmiNasRadioInterface radio_interface = g_array_index (radio_interfaces, QmiNasRadioInterface, i);
+
+            if (i > 0)
+                g_string_append_c (str, '|');
+            g_string_append (str, qmi_nas_radio_interface_get_string (radio_interface));
+
+        }
+        g_print ("\tRadio Interface Acquisition Order: '%s'\n", str->str);
+        g_string_free (str, TRUE);
+    }
+
     if (qmi_message_nas_get_system_selection_preference_output_get_manual_network_selection (
             output,
             &mcc,
@@ -2103,63 +2123,69 @@ get_system_selection_preference_ready (QmiClientNas *client,
 }
 
 static QmiMessageNasSetSystemSelectionPreferenceInput *
-set_system_selection_preference_input_create (const gchar *str)
+set_system_selection_preference_input_create (const gchar *str, gboolean build_array)
 {
     QmiMessageNasSetSystemSelectionPreferenceInput *input = NULL;
     QmiNasRatModePreference pref;
+    GArray *pref_array = NULL;
     GError *error = NULL;
 
-    if (!qmicli_read_rat_mode_pref_from_string (str, &pref)) {
+    if (!qmicli_read_rat_mode_pref_from_string (str, &pref, &pref_array)) {
         g_printerr ("error: failed to parse mode pref\n");
         return NULL;
     }
 
     input = qmi_message_nas_set_system_selection_preference_input_new ();
-    if (!qmi_message_nas_set_system_selection_preference_input_set_mode_preference (
-            input,
-            pref,
-            &error)) {
-        g_printerr ("error: couldn't create input data bundle: '%s'\n",
-                    error->message);
-        g_error_free (error);
-        qmi_message_nas_set_system_selection_preference_input_unref (input);
-        return NULL;
+
+    if (build_array) {
+        if (!qmi_message_nas_set_system_selection_preference_input_set_acquisition_order (
+                input,
+                pref_array,
+                &error))
+            goto error;
+    } else {
+        if (!qmi_message_nas_set_system_selection_preference_input_set_mode_preference (
+                input,
+                pref,
+                &error))
+            goto error;
+
+        if (pref & (QMI_NAS_RAT_MODE_PREFERENCE_GSM |
+                    QMI_NAS_RAT_MODE_PREFERENCE_UMTS |
+                    QMI_NAS_RAT_MODE_PREFERENCE_LTE)) {
+            if (!qmi_message_nas_set_system_selection_preference_input_set_gsm_wcdma_acquisition_order_preference (
+                    input,
+                    QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_AUTOMATIC,
+                    &error))
+                goto error;
+        }
     }
 
+
     if (!qmi_message_nas_set_system_selection_preference_input_set_change_duration (
             input,
             QMI_NAS_CHANGE_DURATION_PERMANENT,
-            &error)) {
-        g_printerr ("error: couldn't create input data bundle: '%s'\n",
-                    error->message);
-        g_error_free (error);
-        qmi_message_nas_set_system_selection_preference_input_unref (input);
-        return NULL;
-    }
-
-    if (pref & (QMI_NAS_RAT_MODE_PREFERENCE_GSM |
-                QMI_NAS_RAT_MODE_PREFERENCE_UMTS |
-                QMI_NAS_RAT_MODE_PREFERENCE_LTE)) {
-        if (!qmi_message_nas_set_system_selection_preference_input_set_gsm_wcdma_acquisition_order_preference (
-                input,
-                QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_AUTOMATIC,
-                &error)) {
-            g_printerr ("error: couldn't create input data bundle: '%s'\n",
-                        error->message);
-            g_error_free (error);
-            qmi_message_nas_set_system_selection_preference_input_unref (input);
-            return NULL;
-        }
-    }
+            &error))
+        goto error;
 
+    g_array_unref (pref_array);
     return input;
+
+error:
+    g_printerr ("error: couldn't create input data bundle: '%s'\n", error->message);
+    g_error_free (error);
+    g_array_unref (pref_array);
+    qmi_message_nas_set_system_selection_preference_input_unref (input);
+    return NULL;
 }
 
 static void
 set_system_selection_preference_ready (QmiClientNas *client,
-                                       GAsyncResult *res)
+                                       GAsyncResult *res,
+                                       gpointer user_data)
 {
     QmiMessageNasSetSystemSelectionPreferenceOutput *output = NULL;
+    const char *pref_str = user_data;
     GError *error = NULL;
 
     output = qmi_client_nas_set_system_selection_preference_finish (client, res, &error);
@@ -2171,6 +2197,28 @@ set_system_selection_preference_ready (QmiClientNas *client,
     }
 
     if (!qmi_message_nas_set_system_selection_preference_output_get_result (output, &error)) {
+        if (pref_str != NULL) {
+            QmiMessageNasSetSystemSelectionPreferenceInput *input;
+
+            g_print ("[%s] Ordered system selection preference failed; retrying as mode preference.\n",
+                     qmi_device_get_path_display (ctx->device));
+
+            input = set_system_selection_preference_input_create (pref_str, FALSE);
+            if (!input) {
+                operation_shutdown (FALSE);
+                return;
+            }
+
+            qmi_client_nas_set_system_selection_preference (ctx->client,
+                                                            input,
+                                                            10,
+                                                            ctx->cancellable,
+                                                            (GAsyncReadyCallback)set_system_selection_preference_ready,
+                                                            NULL);
+            qmi_message_nas_set_system_selection_preference_input_unref (input);
+            return;
+        }
+
         g_printerr ("error: couldn't set operating mode: %s\n", error->message);
         g_error_free (error);
         qmi_message_nas_set_system_selection_preference_output_unref (output);
@@ -3327,7 +3375,7 @@ qmicli_nas_run (QmiDevice *device,
         QmiMessageNasSetSystemSelectionPreferenceInput *input;
         g_debug ("Asynchronously setting system selection preference...");
 
-        input = set_system_selection_preference_input_create (set_system_selection_preference_str);
+        input = set_system_selection_preference_input_create (set_system_selection_preference_str, TRUE);
         if (!input) {
             operation_shutdown (FALSE);
             return;
@@ -3338,7 +3386,7 @@ qmicli_nas_run (QmiDevice *device,
                                                         10,
                                                         ctx->cancellable,
                                                         (GAsyncReadyCallback)set_system_selection_preference_ready,
-                                                        NULL);
+                                                        set_system_selection_preference_str);
         qmi_message_nas_set_system_selection_preference_input_unref (input);
         return;
     }
-- 
2.9.3


More information about the libqmi-devel mailing list