[PATCH] nas: add support for Set System Selection Preference radio interface acquisition order
Aleksander Morgado
aleksander at aleksander.es
Thu Feb 16 20:49:13 UTC 2017
On 16/02/17 21:01, Dan Williams wrote:
> 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?
>
Tested here. For anyone else interested, this patch applies on top of
82d9bd7499973ee75e78108f10cbafabc3ce62f7.
Using a MC7455, doing QMI over MBIM, I switched between
--nas-set-system-selection-preference="lte|umts"
and
--nas-set-system-selection-preference="umts|lte"
When LTE preferred I got:
Mode preference: 'umts'
Radio Interface Acquisition Order: 'lte|umts|gsm|cdma-1x|cdma-1xevdo'
When UMTS preferred I got:
Mode preference: 'umts'
Radio Interface Acquisition Order: 'umts|lte|gsm|cdma-1x|cdma-1xevdo'
The modem was originally set to prefer umts, and that didn't change with
the commands above (i.e. Mode preference didn't change even if I
selected LTE in the command line). Running --nas-get-signal-info showed
that the modem stayed in WCDMA as well, no real change to LTE. I do see
the acquisition order changing, not sure why I see all technologies
there though, anyway, that's just for the order.
I think that we shouldn't "fallback" to updating Mode preference only if
setting the acquisition order fails; I believe we need the SSP command
with both TLVs: mode preference selects which techs you want,
acquisition order selects the order of those techs. Would that make sense?
> 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;
> }
>
--
Aleksander
https://aleksander.es
More information about the libqmi-devel
mailing list