[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