shared-qmi: acquisition order preference TLV always same items

The acquisition order preference TLV must always have the same number
of elements, just the order of the elements should be different.

Also, always prefer the acquisition order preference TLV to the
GSM+WCDMA specific one, which is the same logic the modem applies.

Fixes https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/340
This commit is contained in:
Aleksander Morgado
2021-03-15 17:46:49 +01:00
parent bb5bc9c8c5
commit fdfd4b270a
3 changed files with 99 additions and 80 deletions
+58 -50
View File
@@ -1106,66 +1106,74 @@ mm_modem_capability_to_qmi_acquisition_order_preference (MMModemCapability caps)
return array;
}
static gboolean
radio_interface_array_contains (GArray *array,
QmiNasRadioInterface act)
{
guint i;
for (i = 0; i < array->len; i++) {
QmiNasRadioInterface value;
value = g_array_index (array, QmiNasRadioInterface, i);
if (value == act)
return TRUE;
}
return FALSE;
}
static void
radio_interface_array_add_missing (GArray *array,
GArray *all)
{
guint i;
for (i = 0; i < all->len; i++) {
QmiNasRadioInterface value;
value = g_array_index (all, QmiNasRadioInterface, i);
if (!radio_interface_array_contains (array, value))
g_array_append_val (array, value);
}
}
GArray *
mm_modem_mode_to_qmi_acquisition_order_preference (MMModemMode allowed,
MMModemMode preferred,
gboolean is_cdma,
gboolean is_3gpp)
mm_modem_mode_to_qmi_acquisition_order_preference (MMModemMode allowed,
MMModemMode preferred,
GArray *all)
{
GArray *array;
QmiNasRadioInterface preferred_radio = QMI_NAS_RADIO_INTERFACE_UNKNOWN;
QmiNasRadioInterface value;
array = g_array_new (FALSE, FALSE, sizeof (QmiNasRadioInterface));
array = g_array_sized_new (FALSE, FALSE, sizeof (QmiNasRadioInterface), all->len);
if (allowed & MM_MODEM_MODE_5G) {
value = QMI_NAS_RADIO_INTERFACE_5GNR;
if (preferred == MM_MODEM_MODE_5G)
g_array_prepend_val (array, value);
else
g_array_append_val (array, value);
#define PROCESS_ALLOWED_PREFERRED_MODE(MODE,RADIO) \
if ((allowed & MODE) && (radio_interface_array_contains (all, RADIO))) { \
if ((preferred == MODE) && (preferred_radio == QMI_NAS_RADIO_INTERFACE_UNKNOWN)) \
preferred_radio = RADIO; \
else { \
value = RADIO; \
g_array_append_val (array, value); \
} \
}
if (allowed & MM_MODEM_MODE_4G) {
value = QMI_NAS_RADIO_INTERFACE_LTE;
if (preferred == MM_MODEM_MODE_4G)
g_array_prepend_val (array, value);
else
g_array_append_val (array, value);
}
PROCESS_ALLOWED_PREFERRED_MODE (MM_MODEM_MODE_5G, QMI_NAS_RADIO_INTERFACE_5GNR);
PROCESS_ALLOWED_PREFERRED_MODE (MM_MODEM_MODE_4G, QMI_NAS_RADIO_INTERFACE_LTE);
PROCESS_ALLOWED_PREFERRED_MODE (MM_MODEM_MODE_3G, QMI_NAS_RADIO_INTERFACE_UMTS);
PROCESS_ALLOWED_PREFERRED_MODE (MM_MODEM_MODE_3G, QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO);
PROCESS_ALLOWED_PREFERRED_MODE (MM_MODEM_MODE_2G, QMI_NAS_RADIO_INTERFACE_GSM);
PROCESS_ALLOWED_PREFERRED_MODE (MM_MODEM_MODE_2G, QMI_NAS_RADIO_INTERFACE_CDMA_1X);
if (allowed & MM_MODEM_MODE_3G) {
if (is_cdma) {
value = QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO;
if (preferred == MM_MODEM_MODE_3G)
g_array_prepend_val (array, value);
else
g_array_append_val (array, value);
}
if (is_3gpp) {
value = QMI_NAS_RADIO_INTERFACE_UMTS;
if (preferred == MM_MODEM_MODE_3G)
g_array_prepend_val (array, value);
else
g_array_append_val (array, value);
}
}
#undef PROCESS_ALLOWED_PREFERRED_MODE
if (allowed & MM_MODEM_MODE_2G) {
if (is_cdma) {
value = QMI_NAS_RADIO_INTERFACE_CDMA_1X;
if (preferred == MM_MODEM_MODE_2G)
g_array_prepend_val (array, value);
else
g_array_append_val (array, value);
}
if (is_3gpp) {
value = QMI_NAS_RADIO_INTERFACE_GSM;
if (preferred == MM_MODEM_MODE_2G)
g_array_prepend_val (array, value);
else
g_array_append_val (array, value);
}
}
if (preferred_radio != QMI_NAS_RADIO_INTERFACE_UNKNOWN)
g_array_prepend_val (array, preferred_radio);
/* the acquisition order preference is a TLV that must ALWAYS contain the
* same list of QmiNasRadioInterface values, just with a different order. */
radio_interface_array_add_missing (array, all);
g_assert_cmpuint (array->len, ==, all->len);
return array;
}
+4 -5
View File
@@ -66,11 +66,10 @@ QmiNasRatModePreference mm_modem_mode_to_qmi_rat_mode_preference (MMModemMode mo
MMModemCapability mm_modem_capability_from_qmi_rat_mode_preference (QmiNasRatModePreference qmi);
QmiNasRatModePreference mm_modem_capability_to_qmi_rat_mode_preference (MMModemCapability caps);
GArray *mm_modem_capability_to_qmi_acquisition_order_preference (MMModemCapability caps);
GArray *mm_modem_mode_to_qmi_acquisition_order_preference (MMModemMode allowed,
MMModemMode preferred,
gboolean is_cdma,
gboolean is_3gpp);
GArray *mm_modem_capability_to_qmi_acquisition_order_preference (MMModemCapability caps);
GArray *mm_modem_mode_to_qmi_acquisition_order_preference (MMModemMode allowed,
MMModemMode preferred,
GArray *all);
MMModemCapability mm_modem_capability_from_qmi_radio_technology_preference (QmiNasRadioTechnologyPreference qmi);
QmiNasRadioTechnologyPreference mm_modem_capability_to_qmi_radio_technology_preference (MMModemCapability caps);
+37 -25
View File
@@ -74,6 +74,8 @@ typedef struct {
Feature feature_nas_tp;
Feature feature_nas_ssp;
Feature feature_nas_ssp_extended_lte_band_preference;
Feature feature_nas_ssp_acquisition_order_preference;
GArray *feature_nas_ssp_acquisition_order_preference_array;
gboolean disable_4g_only_mode;
GArray *supported_bands;
@@ -125,6 +127,8 @@ private_free (Private *priv)
g_object_unref (priv->uim_client);
if (priv->uim_refresh_start_timeout_id)
g_source_remove (priv->uim_refresh_start_timeout_id);
if (priv->feature_nas_ssp_acquisition_order_preference_array)
g_array_unref (priv->feature_nas_ssp_acquisition_order_preference_array);
g_strfreev (priv->loc_assistance_data_servers);
g_slice_free (Private, priv);
}
@@ -144,6 +148,7 @@ get_private (MMSharedQmi *self)
priv->feature_nas_tp = FEATURE_UNKNOWN;
priv->feature_nas_ssp = FEATURE_UNKNOWN;
priv->feature_nas_ssp_extended_lte_band_preference = FEATURE_UNKNOWN;
priv->feature_nas_ssp_acquisition_order_preference = FEATURE_UNKNOWN;
priv->config_active_i = -1;
/* Setup parent class' MMIfaceModemLocation */
@@ -923,6 +928,7 @@ load_current_capabilities_get_system_selection_preference_ready (QmiClientNas *c
priv->feature_nas_ssp = FEATURE_UNSUPPORTED;
priv->feature_nas_ssp_extended_lte_band_preference = FEATURE_UNSUPPORTED;
priv->feature_nas_ssp_acquisition_order_preference = FEATURE_UNSUPPORTED;
output = qmi_client_nas_get_system_selection_preference_finish (client, res, &error);
if (!output) {
@@ -938,6 +944,12 @@ load_current_capabilities_get_system_selection_preference_ready (QmiClientNas *c
priv->feature_nas_ssp = FEATURE_SUPPORTED;
if (qmi_message_nas_get_system_selection_preference_output_get_extended_lte_band_preference (output, NULL, NULL, NULL, NULL, NULL))
priv->feature_nas_ssp_extended_lte_band_preference = FEATURE_SUPPORTED;
if (qmi_message_nas_get_system_selection_preference_output_get_acquisition_order_preference (output, &acquisition_order_preference_array, NULL) &&
acquisition_order_preference_array &&
acquisition_order_preference_array->len) {
priv->feature_nas_ssp_acquisition_order_preference = FEATURE_SUPPORTED;
priv->feature_nas_ssp_acquisition_order_preference_array = g_array_ref (acquisition_order_preference_array);
}
qmi_message_nas_get_system_selection_preference_output_get_mode_preference (
output,
@@ -1259,11 +1271,13 @@ static void
set_current_modes_system_selection_preference (GTask *task)
{
MMIfaceModem *self;
Private *priv;
SetCurrentModesContext *ctx;
QmiMessageNasSetSystemSelectionPreferenceInput *input;
QmiNasRatModePreference pref;
self = g_task_get_source_object (task);
priv = get_private (MM_SHARED_QMI (self));
ctx = g_task_get_task_data (task);
input = qmi_message_nas_set_system_selection_preference_input_new ();
@@ -1272,16 +1286,17 @@ set_current_modes_system_selection_preference (GTask *task)
/* Preferred modes */
if (ctx->preferred != MM_MODEM_MODE_NONE) {
GArray *array;
if (priv->feature_nas_ssp_acquisition_order_preference == FEATURE_SUPPORTED) {
GArray *array;
/* Acquisition order array */
array = mm_modem_mode_to_qmi_acquisition_order_preference (ctx->allowed,
ctx->preferred,
mm_iface_modem_is_cdma (self),
mm_iface_modem_is_3gpp (self));
g_assert (array);
qmi_message_nas_set_system_selection_preference_input_set_acquisition_order_preference (input, array, NULL);
g_array_unref (array);
/* Acquisition order array */
array = mm_modem_mode_to_qmi_acquisition_order_preference (ctx->allowed,
ctx->preferred,
priv->feature_nas_ssp_acquisition_order_preference_array);
g_assert (array);
qmi_message_nas_set_system_selection_preference_input_set_acquisition_order_preference (input, array, NULL);
g_array_unref (array);
}
/* Only set GSM/WCDMA acquisition order preference if both 2G and 3G given as allowed */
if (mm_iface_modem_is_3gpp (self) && ((ctx->allowed & (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G)) == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G))) {
@@ -1508,24 +1523,11 @@ load_current_modes_system_selection_preference_ready (QmiClientNas *client,
result->allowed = allowed;
result->preferred = MM_MODEM_MODE_NONE;
/* For 2G+3G only rely on the GSM/WCDMA acquisition order preference TLV */
if (mode_preference_mask == (QMI_NAS_RAT_MODE_PREFERENCE_GSM | QMI_NAS_RAT_MODE_PREFERENCE_UMTS)) {
QmiNasGsmWcdmaAcquisitionOrderPreference gsm_or_wcdma;
if (qmi_message_nas_get_system_selection_preference_output_get_gsm_wcdma_acquisition_order_preference (
output,
&gsm_or_wcdma,
NULL))
result->preferred = mm_modem_mode_from_qmi_gsm_wcdma_acquisition_order_preference (gsm_or_wcdma, self);
}
/* Otherwise, rely on the acquisition order array TLV */
else {
/* If acquisition order preference is available, always use that first */
if (priv->feature_nas_ssp_acquisition_order_preference == FEATURE_SUPPORTED) {
GArray *array;
if (qmi_message_nas_get_system_selection_preference_output_get_acquisition_order_preference (
output,
&array,
NULL) &&
if (qmi_message_nas_get_system_selection_preference_output_get_acquisition_order_preference (output, &array, NULL) &&
array->len > 0) {
guint i;
@@ -1546,6 +1548,16 @@ load_current_modes_system_selection_preference_ready (QmiClientNas *client,
}
}
}
/* For 2G+3G only rely on the GSM/WCDMA acquisition order preference TLV */
else if (mode_preference_mask == (QMI_NAS_RAT_MODE_PREFERENCE_GSM | QMI_NAS_RAT_MODE_PREFERENCE_UMTS)) {
QmiNasGsmWcdmaAcquisitionOrderPreference gsm_or_wcdma;
if (qmi_message_nas_get_system_selection_preference_output_get_gsm_wcdma_acquisition_order_preference (
output,
&gsm_or_wcdma,
NULL))
result->preferred = mm_modem_mode_from_qmi_gsm_wcdma_acquisition_order_preference (gsm_or_wcdma, self);
}
g_task_return_pointer (task, result, g_free);