[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