/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details: * * Copyright (C) 2012-2018 Google, Inc. * Copyright (C) 2018 Aleksander Morgado * Copyright (c) 2021 Qualcomm Innovation Center, Inc. */ #include #include #include #include "mm-modem-helpers-qmi.h" #include "mm-modem-helpers.h" #include "mm-error-helpers.h" #include "mm-enums-types.h" #include "mm-flags-types.h" #include "mm-log-object.h" /*****************************************************************************/ MMModemCapability mm_modem_capability_from_qmi_radio_interface (QmiDmsRadioInterface network, gpointer log_object) { switch (network) { case QMI_DMS_RADIO_INTERFACE_CDMA20001X: return MM_MODEM_CAPABILITY_CDMA_EVDO; case QMI_DMS_RADIO_INTERFACE_EVDO: return MM_MODEM_CAPABILITY_CDMA_EVDO; case QMI_DMS_RADIO_INTERFACE_GSM: return MM_MODEM_CAPABILITY_GSM_UMTS; case QMI_DMS_RADIO_INTERFACE_UMTS: return MM_MODEM_CAPABILITY_GSM_UMTS; case QMI_DMS_RADIO_INTERFACE_LTE: return MM_MODEM_CAPABILITY_LTE; case QMI_DMS_RADIO_INTERFACE_TDS: return MM_MODEM_CAPABILITY_TDS; case QMI_DMS_RADIO_INTERFACE_5GNR: return MM_MODEM_CAPABILITY_5GNR; default: mm_obj_warn (log_object, "unhandled QMI radio interface '%u'", (guint)network); return MM_MODEM_CAPABILITY_NONE; } } /*****************************************************************************/ MMModemMode mm_modem_mode_from_qmi_radio_interface (QmiDmsRadioInterface network, gpointer log_object) { switch (network) { case QMI_DMS_RADIO_INTERFACE_CDMA20001X: return MM_MODEM_MODE_2G; case QMI_DMS_RADIO_INTERFACE_EVDO: return MM_MODEM_MODE_3G; case QMI_DMS_RADIO_INTERFACE_GSM: return MM_MODEM_MODE_2G; case QMI_DMS_RADIO_INTERFACE_UMTS: return MM_MODEM_MODE_3G; case QMI_DMS_RADIO_INTERFACE_LTE: return MM_MODEM_MODE_4G; case QMI_DMS_RADIO_INTERFACE_5GNR: return MM_MODEM_MODE_5G; case QMI_DMS_RADIO_INTERFACE_TDS: default: mm_obj_warn (log_object, "unhandled QMI radio interface '%u'", (guint)network); return MM_MODEM_MODE_NONE; } } /*****************************************************************************/ /* pin1 TRUE for PIN1, FALSE for PIN2 */ MMModemLock mm_modem_lock_from_qmi_uim_pin_status (QmiDmsUimPinStatus status, gboolean pin1) { switch (status) { case QMI_DMS_UIM_PIN_STATUS_NOT_INITIALIZED: return MM_MODEM_LOCK_UNKNOWN; case QMI_DMS_UIM_PIN_STATUS_ENABLED_NOT_VERIFIED: return pin1 ? MM_MODEM_LOCK_SIM_PIN : MM_MODEM_LOCK_SIM_PIN2; case QMI_DMS_UIM_PIN_STATUS_ENABLED_VERIFIED: return MM_MODEM_LOCK_NONE; case QMI_DMS_UIM_PIN_STATUS_DISABLED: return MM_MODEM_LOCK_NONE; case QMI_DMS_UIM_PIN_STATUS_BLOCKED: return pin1 ? MM_MODEM_LOCK_SIM_PUK : MM_MODEM_LOCK_SIM_PUK2; case QMI_DMS_UIM_PIN_STATUS_PERMANENTLY_BLOCKED: return MM_MODEM_LOCK_UNKNOWN; case QMI_DMS_UIM_PIN_STATUS_UNBLOCKED: /* This state is possibly given when after an Unblock() operation has been performed. * We'll assume the PIN is verified after this. */ return MM_MODEM_LOCK_NONE; case QMI_DMS_UIM_PIN_STATUS_CHANGED: /* This state is possibly given when after an ChangePin() operation has been performed. * We'll assume the PIN is verified after this. */ return MM_MODEM_LOCK_NONE; default: return MM_MODEM_LOCK_UNKNOWN; } } /*****************************************************************************/ gboolean mm_pin_enabled_from_qmi_uim_pin_status (QmiDmsUimPinStatus status) { switch (status) { case QMI_DMS_UIM_PIN_STATUS_ENABLED_NOT_VERIFIED: case QMI_DMS_UIM_PIN_STATUS_ENABLED_VERIFIED: case QMI_DMS_UIM_PIN_STATUS_BLOCKED: case QMI_DMS_UIM_PIN_STATUS_PERMANENTLY_BLOCKED: case QMI_DMS_UIM_PIN_STATUS_UNBLOCKED: case QMI_DMS_UIM_PIN_STATUS_CHANGED: /* assume the PIN to be enabled then */ return TRUE; case QMI_DMS_UIM_PIN_STATUS_DISABLED: case QMI_DMS_UIM_PIN_STATUS_NOT_INITIALIZED: /* assume the PIN to be disabled then */ return FALSE; default: /* by default assume disabled */ return FALSE; } } /*****************************************************************************/ QmiDmsUimFacility mm_3gpp_facility_to_qmi_uim_facility (MMModem3gppFacility mm) { switch (mm) { case MM_MODEM_3GPP_FACILITY_PH_SIM: /* Not really sure about this one; it may be PH_FSIM? */ return QMI_DMS_UIM_FACILITY_PF; case MM_MODEM_3GPP_FACILITY_NET_PERS: return QMI_DMS_UIM_FACILITY_PN; case MM_MODEM_3GPP_FACILITY_NET_SUB_PERS: return QMI_DMS_UIM_FACILITY_PU; case MM_MODEM_3GPP_FACILITY_PROVIDER_PERS: return QMI_DMS_UIM_FACILITY_PP; case MM_MODEM_3GPP_FACILITY_CORP_PERS: return QMI_DMS_UIM_FACILITY_PC; case MM_MODEM_3GPP_FACILITY_NONE: case MM_MODEM_3GPP_FACILITY_SIM: case MM_MODEM_3GPP_FACILITY_FIXED_DIALING: case MM_MODEM_3GPP_FACILITY_PH_FSIM: default: /* Never try to ask for a facility we cannot translate */ g_assert_not_reached (); } } /*****************************************************************************/ typedef struct { QmiDmsBandCapability qmi_band; MMModemBand mm_band; } DmsBandsMap; static const DmsBandsMap dms_bands_map [] = { /* CDMA bands */ { (QMI_DMS_BAND_CAPABILITY_BC_0_A_SYSTEM | QMI_DMS_BAND_CAPABILITY_BC_0_B_SYSTEM), MM_MODEM_BAND_CDMA_BC0 }, { QMI_DMS_BAND_CAPABILITY_BC_1_ALL_BLOCKS, MM_MODEM_BAND_CDMA_BC1 }, { QMI_DMS_BAND_CAPABILITY_BC_2, MM_MODEM_BAND_CDMA_BC2 }, { QMI_DMS_BAND_CAPABILITY_BC_3_A_SYSTEM, MM_MODEM_BAND_CDMA_BC3 }, { QMI_DMS_BAND_CAPABILITY_BC_4_ALL_BLOCKS, MM_MODEM_BAND_CDMA_BC4 }, { QMI_DMS_BAND_CAPABILITY_BC_5_ALL_BLOCKS, MM_MODEM_BAND_CDMA_BC5 }, { QMI_DMS_BAND_CAPABILITY_BC_6, MM_MODEM_BAND_CDMA_BC6 }, { QMI_DMS_BAND_CAPABILITY_BC_7, MM_MODEM_BAND_CDMA_BC7 }, { QMI_DMS_BAND_CAPABILITY_BC_8, MM_MODEM_BAND_CDMA_BC8 }, { QMI_DMS_BAND_CAPABILITY_BC_9, MM_MODEM_BAND_CDMA_BC9 }, { QMI_DMS_BAND_CAPABILITY_BC_10, MM_MODEM_BAND_CDMA_BC10 }, { QMI_DMS_BAND_CAPABILITY_BC_11, MM_MODEM_BAND_CDMA_BC11 }, { QMI_DMS_BAND_CAPABILITY_BC_12, MM_MODEM_BAND_CDMA_BC12 }, { QMI_DMS_BAND_CAPABILITY_BC_14, MM_MODEM_BAND_CDMA_BC14 }, { QMI_DMS_BAND_CAPABILITY_BC_15, MM_MODEM_BAND_CDMA_BC15 }, { QMI_DMS_BAND_CAPABILITY_BC_16, MM_MODEM_BAND_CDMA_BC16 }, { QMI_DMS_BAND_CAPABILITY_BC_17, MM_MODEM_BAND_CDMA_BC17 }, { QMI_DMS_BAND_CAPABILITY_BC_18, MM_MODEM_BAND_CDMA_BC18 }, { QMI_DMS_BAND_CAPABILITY_BC_19, MM_MODEM_BAND_CDMA_BC19 }, /* GSM bands */ { QMI_DMS_BAND_CAPABILITY_GSM_DCS_1800, MM_MODEM_BAND_DCS }, { (QMI_DMS_BAND_CAPABILITY_GSM_900_PRIMARY | QMI_DMS_BAND_CAPABILITY_GSM_900_EXTENDED), MM_MODEM_BAND_EGSM }, { QMI_DMS_BAND_CAPABILITY_GSM_PCS_1900, MM_MODEM_BAND_PCS }, { QMI_DMS_BAND_CAPABILITY_GSM_850, MM_MODEM_BAND_G850 }, { QMI_DMS_BAND_CAPABILITY_GSM_450, MM_MODEM_BAND_G450 }, { QMI_DMS_BAND_CAPABILITY_GSM_480, MM_MODEM_BAND_G480 }, { QMI_DMS_BAND_CAPABILITY_GSM_750, MM_MODEM_BAND_G750 }, /* UMTS/WCDMA bands */ { QMI_DMS_BAND_CAPABILITY_WCDMA_2100, MM_MODEM_BAND_UTRAN_1 }, { QMI_DMS_BAND_CAPABILITY_WCDMA_DCS_1800, MM_MODEM_BAND_UTRAN_3 }, { QMI_DMS_BAND_CAPABILITY_WCDMA_PCS_1900, MM_MODEM_BAND_UTRAN_2 }, { QMI_DMS_BAND_CAPABILITY_WCDMA_1700_US, MM_MODEM_BAND_UTRAN_4 }, { QMI_DMS_BAND_CAPABILITY_WCDMA_800, MM_MODEM_BAND_UTRAN_6 }, { QMI_DMS_BAND_CAPABILITY_WCDMA_850_US, MM_MODEM_BAND_UTRAN_5 }, { QMI_DMS_BAND_CAPABILITY_WCDMA_900, MM_MODEM_BAND_UTRAN_8 }, { QMI_DMS_BAND_CAPABILITY_WCDMA_1700_JAPAN, MM_MODEM_BAND_UTRAN_9 }, { QMI_DMS_BAND_CAPABILITY_WCDMA_2600, MM_MODEM_BAND_UTRAN_7 }, { QMI_DMS_BAND_CAPABILITY_WCDMA_1500, MM_MODEM_BAND_UTRAN_11 }, { QMI_DMS_BAND_CAPABILITY_WCDMA_850_JAPAN, MM_MODEM_BAND_UTRAN_19 }, }; static void dms_add_qmi_bands (GArray *mm_bands, QmiDmsBandCapability qmi_bands, gpointer log_object) { static QmiDmsBandCapability qmi_bands_expected = 0; QmiDmsBandCapability not_expected; guint i; g_assert (mm_bands != NULL); /* Build mask of expected bands only once */ if (G_UNLIKELY (qmi_bands_expected == 0)) { for (i = 0; i < G_N_ELEMENTS (dms_bands_map); i++) { qmi_bands_expected |= dms_bands_map[i].qmi_band; } } /* Log about the bands that cannot be represented in ModemManager */ not_expected = ((qmi_bands_expected ^ qmi_bands) & qmi_bands); if (not_expected) { g_autofree gchar *aux = NULL; aux = qmi_dms_band_capability_build_string_from_mask (not_expected); mm_obj_dbg (log_object, "cannot add the following bands: '%s'", aux); } /* And add the expected ones */ for (i = 0; i < G_N_ELEMENTS (dms_bands_map); i++) { if (qmi_bands & dms_bands_map[i].qmi_band) g_array_append_val (mm_bands, dms_bands_map[i].mm_band); } } typedef struct { QmiDmsLteBandCapability qmi_band; MMModemBand mm_band; } DmsLteBandsMap; static const DmsLteBandsMap dms_lte_bands_map [] = { { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_1, MM_MODEM_BAND_EUTRAN_1 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_2, MM_MODEM_BAND_EUTRAN_2 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_3, MM_MODEM_BAND_EUTRAN_3 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_4, MM_MODEM_BAND_EUTRAN_4 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_5, MM_MODEM_BAND_EUTRAN_5 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_6, MM_MODEM_BAND_EUTRAN_6 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_7, MM_MODEM_BAND_EUTRAN_7 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_8, MM_MODEM_BAND_EUTRAN_8 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_9, MM_MODEM_BAND_EUTRAN_9 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_10, MM_MODEM_BAND_EUTRAN_10 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_11, MM_MODEM_BAND_EUTRAN_11 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_12, MM_MODEM_BAND_EUTRAN_12 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_13, MM_MODEM_BAND_EUTRAN_13 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_14, MM_MODEM_BAND_EUTRAN_14 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_17, MM_MODEM_BAND_EUTRAN_17 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_18, MM_MODEM_BAND_EUTRAN_18 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_19, MM_MODEM_BAND_EUTRAN_19 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_20, MM_MODEM_BAND_EUTRAN_20 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_21, MM_MODEM_BAND_EUTRAN_21 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_24, MM_MODEM_BAND_EUTRAN_24 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_25, MM_MODEM_BAND_EUTRAN_25 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_26, MM_MODEM_BAND_EUTRAN_26 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_27, MM_MODEM_BAND_EUTRAN_27 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_28, MM_MODEM_BAND_EUTRAN_28 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_29, MM_MODEM_BAND_EUTRAN_29 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_30, MM_MODEM_BAND_EUTRAN_30 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_31, MM_MODEM_BAND_EUTRAN_31 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_32, MM_MODEM_BAND_EUTRAN_32 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_33, MM_MODEM_BAND_EUTRAN_33 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_34, MM_MODEM_BAND_EUTRAN_34 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_35, MM_MODEM_BAND_EUTRAN_35 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_36, MM_MODEM_BAND_EUTRAN_36 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_37, MM_MODEM_BAND_EUTRAN_37 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_38, MM_MODEM_BAND_EUTRAN_38 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_39, MM_MODEM_BAND_EUTRAN_39 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_40, MM_MODEM_BAND_EUTRAN_40 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_41, MM_MODEM_BAND_EUTRAN_41 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_42, MM_MODEM_BAND_EUTRAN_42 }, { QMI_DMS_LTE_BAND_CAPABILITY_EUTRAN_43, MM_MODEM_BAND_EUTRAN_43 } }; static void dms_add_qmi_lte_bands (GArray *mm_bands, QmiDmsLteBandCapability qmi_bands) { /* All QMI LTE bands have a counterpart in ModemManager, no need to check * for unexpected ones */ guint i; g_assert (mm_bands != NULL); for (i = 0; i < G_N_ELEMENTS (dms_lte_bands_map); i++) { if (qmi_bands & dms_lte_bands_map[i].qmi_band) g_array_append_val (mm_bands, dms_lte_bands_map[i].mm_band); } } static void dms_add_extended_qmi_lte_bands (GArray *mm_bands, GArray *extended_qmi_bands, gpointer log_object) { guint i; g_assert (mm_bands != NULL); if (!extended_qmi_bands) return; for (i = 0; i < extended_qmi_bands->len; i++) { guint16 val; val = g_array_index (extended_qmi_bands, guint16, i); /* MM_MODEM_BAND_EUTRAN_1 = 31, * ... * MM_MODEM_BAND_EUTRAN_71 = 101 */ if (val < 1 || val > 71) mm_obj_dbg (log_object, "unexpected LTE band supported by module: EUTRAN %u", val); else { MMModemBand band; band = (MMModemBand)(val + MM_MODEM_BAND_EUTRAN_1 - 1); g_array_append_val (mm_bands, band); } } } static void dms_add_qmi_nr5g_bands (GArray *mm_bands, GArray *qmi_bands, gpointer log_object) { guint i; g_assert (mm_bands != NULL); if (!qmi_bands) return; for (i = 0; i < qmi_bands->len; i++) { guint16 val; val = g_array_index (qmi_bands, guint16, i); /* MM_MODEM_BAND_NGRAN_1 = 301, * ... * MM_MODEM_BAND_NGRAN_261 = 561 */ if (val < 1 || val > 261) mm_obj_dbg (log_object, "unexpected NR5G band supported by module: NGRAN %u", val); else { MMModemBand band; band = (MMModemBand)(val + MM_MODEM_BAND_NGRAN_1 - 1); g_array_append_val (mm_bands, band); } } } GArray * mm_modem_bands_from_qmi_band_capabilities (QmiDmsBandCapability qmi_bands, QmiDmsLteBandCapability qmi_lte_bands, GArray *extended_qmi_lte_bands, GArray *qmi_nr5g_bands, gpointer log_object) { GArray *mm_bands; mm_bands = g_array_new (FALSE, FALSE, sizeof (MMModemBand)); dms_add_qmi_bands (mm_bands, qmi_bands, log_object); if (extended_qmi_lte_bands) dms_add_extended_qmi_lte_bands (mm_bands, extended_qmi_lte_bands, log_object); else dms_add_qmi_lte_bands (mm_bands, qmi_lte_bands); if (qmi_nr5g_bands) dms_add_qmi_nr5g_bands (mm_bands, qmi_nr5g_bands, log_object); return mm_bands; } /*****************************************************************************/ typedef struct { QmiNasBandPreference qmi_band; MMModemBand mm_band; } NasBandsMap; static const NasBandsMap nas_bands_map [] = { /* CDMA bands */ { (QMI_NAS_BAND_PREFERENCE_BC_0_A_SYSTEM | QMI_NAS_BAND_PREFERENCE_BC_0_B_SYSTEM), MM_MODEM_BAND_CDMA_BC0 }, { QMI_NAS_BAND_PREFERENCE_BC_1_ALL_BLOCKS, MM_MODEM_BAND_CDMA_BC1 }, { QMI_NAS_BAND_PREFERENCE_BC_2, MM_MODEM_BAND_CDMA_BC2 }, { QMI_NAS_BAND_PREFERENCE_BC_3_A_SYSTEM, MM_MODEM_BAND_CDMA_BC3 }, { QMI_NAS_BAND_PREFERENCE_BC_4_ALL_BLOCKS, MM_MODEM_BAND_CDMA_BC4 }, { QMI_NAS_BAND_PREFERENCE_BC_5_ALL_BLOCKS, MM_MODEM_BAND_CDMA_BC5 }, { QMI_NAS_BAND_PREFERENCE_BC_6, MM_MODEM_BAND_CDMA_BC6 }, { QMI_NAS_BAND_PREFERENCE_BC_7, MM_MODEM_BAND_CDMA_BC7 }, { QMI_NAS_BAND_PREFERENCE_BC_8, MM_MODEM_BAND_CDMA_BC8 }, { QMI_NAS_BAND_PREFERENCE_BC_9, MM_MODEM_BAND_CDMA_BC9 }, { QMI_NAS_BAND_PREFERENCE_BC_10, MM_MODEM_BAND_CDMA_BC10 }, { QMI_NAS_BAND_PREFERENCE_BC_11, MM_MODEM_BAND_CDMA_BC11 }, { QMI_NAS_BAND_PREFERENCE_BC_12, MM_MODEM_BAND_CDMA_BC12 }, { QMI_NAS_BAND_PREFERENCE_BC_14, MM_MODEM_BAND_CDMA_BC14 }, { QMI_NAS_BAND_PREFERENCE_BC_15, MM_MODEM_BAND_CDMA_BC15 }, { QMI_NAS_BAND_PREFERENCE_BC_16, MM_MODEM_BAND_CDMA_BC16 }, { QMI_NAS_BAND_PREFERENCE_BC_17, MM_MODEM_BAND_CDMA_BC17 }, { QMI_NAS_BAND_PREFERENCE_BC_18, MM_MODEM_BAND_CDMA_BC18 }, { QMI_NAS_BAND_PREFERENCE_BC_19, MM_MODEM_BAND_CDMA_BC19 }, /* GSM bands */ { QMI_NAS_BAND_PREFERENCE_GSM_DCS_1800, MM_MODEM_BAND_DCS }, { (QMI_NAS_BAND_PREFERENCE_GSM_900_PRIMARY | QMI_NAS_BAND_PREFERENCE_GSM_900_EXTENDED), MM_MODEM_BAND_EGSM }, { QMI_NAS_BAND_PREFERENCE_GSM_PCS_1900, MM_MODEM_BAND_PCS }, { QMI_NAS_BAND_PREFERENCE_GSM_850, MM_MODEM_BAND_G850 }, { QMI_NAS_BAND_PREFERENCE_GSM_450, MM_MODEM_BAND_G450 }, { QMI_NAS_BAND_PREFERENCE_GSM_480, MM_MODEM_BAND_G480 }, { QMI_NAS_BAND_PREFERENCE_GSM_750, MM_MODEM_BAND_G750 }, /* UMTS/WCDMA bands */ { QMI_NAS_BAND_PREFERENCE_WCDMA_2100, MM_MODEM_BAND_UTRAN_1 }, { QMI_NAS_BAND_PREFERENCE_WCDMA_DCS_1800, MM_MODEM_BAND_UTRAN_3 }, { QMI_NAS_BAND_PREFERENCE_WCDMA_PCS_1900, MM_MODEM_BAND_UTRAN_2 }, { QMI_NAS_BAND_PREFERENCE_WCDMA_1700_US, MM_MODEM_BAND_UTRAN_4 }, { QMI_NAS_BAND_PREFERENCE_WCDMA_800, MM_MODEM_BAND_UTRAN_6 }, { QMI_NAS_BAND_PREFERENCE_WCDMA_850_US, MM_MODEM_BAND_UTRAN_5 }, { QMI_NAS_BAND_PREFERENCE_WCDMA_900, MM_MODEM_BAND_UTRAN_8 }, { QMI_NAS_BAND_PREFERENCE_WCDMA_1700_JAPAN, MM_MODEM_BAND_UTRAN_9 }, { QMI_NAS_BAND_PREFERENCE_WCDMA_2600, MM_MODEM_BAND_UTRAN_7 }, { QMI_NAS_BAND_PREFERENCE_WCDMA_1500, MM_MODEM_BAND_UTRAN_11 }, { QMI_NAS_BAND_PREFERENCE_WCDMA_850_JAPAN, MM_MODEM_BAND_UTRAN_19 }, }; static void nas_add_qmi_bands (GArray *mm_bands, QmiNasBandPreference qmi_bands, gpointer log_object) { static QmiNasBandPreference qmi_bands_expected = 0; QmiNasBandPreference not_expected; guint i; g_assert (mm_bands != NULL); /* Build mask of expected bands only once */ if (G_UNLIKELY (qmi_bands_expected == 0)) { for (i = 0; i < G_N_ELEMENTS (nas_bands_map); i++) { qmi_bands_expected |= nas_bands_map[i].qmi_band; } } /* Log about the bands that cannot be represented in ModemManager */ not_expected = ((qmi_bands_expected ^ qmi_bands) & qmi_bands); if (not_expected) { g_autofree gchar *aux = NULL; aux = qmi_nas_band_preference_build_string_from_mask (not_expected); mm_obj_dbg (log_object, "cannot add the following bands: '%s'", aux); } /* And add the expected ones */ for (i = 0; i < G_N_ELEMENTS (nas_bands_map); i++) { if (qmi_bands & nas_bands_map[i].qmi_band) g_array_append_val (mm_bands, nas_bands_map[i].mm_band); } } typedef struct { QmiNasLteBandPreference qmi_band; MMModemBand mm_band; } NasLteBandsMap; static const NasLteBandsMap nas_lte_bands_map [] = { { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_1, MM_MODEM_BAND_EUTRAN_1 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_2, MM_MODEM_BAND_EUTRAN_2 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_3, MM_MODEM_BAND_EUTRAN_3 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_4, MM_MODEM_BAND_EUTRAN_4 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_5, MM_MODEM_BAND_EUTRAN_5 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_6, MM_MODEM_BAND_EUTRAN_6 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_7, MM_MODEM_BAND_EUTRAN_7 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_8, MM_MODEM_BAND_EUTRAN_8 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_9, MM_MODEM_BAND_EUTRAN_9 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_10, MM_MODEM_BAND_EUTRAN_10 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_11, MM_MODEM_BAND_EUTRAN_11 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_12, MM_MODEM_BAND_EUTRAN_12 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_13, MM_MODEM_BAND_EUTRAN_13 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_14, MM_MODEM_BAND_EUTRAN_14 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_17, MM_MODEM_BAND_EUTRAN_17 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_18, MM_MODEM_BAND_EUTRAN_18 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_19, MM_MODEM_BAND_EUTRAN_19 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_20, MM_MODEM_BAND_EUTRAN_20 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_21, MM_MODEM_BAND_EUTRAN_21 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_24, MM_MODEM_BAND_EUTRAN_24 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_25, MM_MODEM_BAND_EUTRAN_25 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_26, MM_MODEM_BAND_EUTRAN_26 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_27, MM_MODEM_BAND_EUTRAN_27 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_28, MM_MODEM_BAND_EUTRAN_28 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_29, MM_MODEM_BAND_EUTRAN_29 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_30, MM_MODEM_BAND_EUTRAN_30 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_31, MM_MODEM_BAND_EUTRAN_31 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_32, MM_MODEM_BAND_EUTRAN_32 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_33, MM_MODEM_BAND_EUTRAN_33 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_34, MM_MODEM_BAND_EUTRAN_34 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_35, MM_MODEM_BAND_EUTRAN_35 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_36, MM_MODEM_BAND_EUTRAN_36 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_37, MM_MODEM_BAND_EUTRAN_37 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_38, MM_MODEM_BAND_EUTRAN_38 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_39, MM_MODEM_BAND_EUTRAN_39 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_40, MM_MODEM_BAND_EUTRAN_40 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_41, MM_MODEM_BAND_EUTRAN_41 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_42, MM_MODEM_BAND_EUTRAN_42 }, { QMI_NAS_LTE_BAND_PREFERENCE_EUTRAN_43, MM_MODEM_BAND_EUTRAN_43 } }; static void nas_add_qmi_lte_bands (GArray *mm_bands, QmiNasLteBandPreference qmi_bands) { /* All QMI LTE bands have a counterpart in ModemManager, no need to check * for unexpected ones */ guint i; g_assert (mm_bands != NULL); for (i = 0; i < G_N_ELEMENTS (nas_lte_bands_map); i++) { if (qmi_bands & nas_lte_bands_map[i].qmi_band) g_array_append_val (mm_bands, nas_lte_bands_map[i].mm_band); } } static void nas_add_extended_qmi_lte_bands (GArray *mm_bands, const guint64 *extended_qmi_lte_bands, guint extended_qmi_lte_bands_size, gpointer log_object) { guint i; g_assert (mm_bands != NULL); for (i = 0; i < extended_qmi_lte_bands_size; i++) { guint j; for (j = 0; j < 64; j++) { guint val; if (!(extended_qmi_lte_bands[i] & (((guint64) 1) << j))) continue; val = 1 + j + (i * 64); /* MM_MODEM_BAND_EUTRAN_1 = 31, * ... * MM_MODEM_BAND_EUTRAN_71 = 101 */ if (val < 1 || val > 71) mm_obj_dbg (log_object, "unexpected LTE band supported by module: EUTRAN %u", val); else { MMModemBand band; band = (val + MM_MODEM_BAND_EUTRAN_1 - 1); g_array_append_val (mm_bands, band); } } } } static void nas_add_qmi_nr5g_bands (GArray *mm_bands, const guint64 *qmi_nr5g_bands, guint qmi_nr5g_bands_size, gpointer log_object) { guint i; g_assert (mm_bands != NULL); for (i = 0; i < qmi_nr5g_bands_size; i++) { guint j; for (j = 0; j < 64; j++) { guint val; if (!(qmi_nr5g_bands[i] & (((guint64) 1) << j))) continue; val = 1 + j + (i * 64); /* MM_MODEM_BAND_NGRAN_1 = 301, * ... * MM_MODEM_BAND_NGRAN_261 = 561 */ if (val < 1 || val > 261) mm_obj_dbg (log_object, "unexpected NR5G band supported by module: NGRAN %u", val); else { MMModemBand band; band = (val + MM_MODEM_BAND_NGRAN_1 - 1); g_array_append_val (mm_bands, band); } } } } GArray * mm_modem_bands_from_qmi_band_preference (QmiNasBandPreference qmi_bands, QmiNasLteBandPreference qmi_lte_bands, const guint64 *extended_qmi_lte_bands, guint extended_qmi_lte_bands_size, const guint64 *qmi_nr5g_bands, guint qmi_nr5g_bands_size, gpointer log_object) { GArray *mm_bands; mm_bands = g_array_new (FALSE, FALSE, sizeof (MMModemBand)); nas_add_qmi_bands (mm_bands, qmi_bands, log_object); if (extended_qmi_lte_bands && extended_qmi_lte_bands_size) nas_add_extended_qmi_lte_bands (mm_bands, extended_qmi_lte_bands, extended_qmi_lte_bands_size, log_object); else nas_add_qmi_lte_bands (mm_bands, qmi_lte_bands); if (qmi_nr5g_bands && qmi_nr5g_bands_size) nas_add_qmi_nr5g_bands (mm_bands, qmi_nr5g_bands, qmi_nr5g_bands_size, log_object); return mm_bands; } void mm_modem_bands_to_qmi_band_preference (GArray *mm_bands, QmiNasBandPreference *qmi_bands, QmiNasLteBandPreference *qmi_lte_bands, guint64 *extended_qmi_lte_bands, guint extended_qmi_lte_bands_size, guint64 *qmi_nr5g_bands, guint qmi_nr5g_bands_size, gpointer log_object) { guint i; *qmi_bands = 0; *qmi_lte_bands = 0; if (extended_qmi_lte_bands) memset (extended_qmi_lte_bands, 0, extended_qmi_lte_bands_size * sizeof (guint64)); if (qmi_nr5g_bands) memset (qmi_nr5g_bands, 0, qmi_nr5g_bands_size * sizeof (guint64)); for (i = 0; i < mm_bands->len; i++) { MMModemBand band; band = g_array_index (mm_bands, MMModemBand, i); if (band >= MM_MODEM_BAND_EUTRAN_1 && band <= MM_MODEM_BAND_EUTRAN_71) { if (extended_qmi_lte_bands && extended_qmi_lte_bands_size) { /* Add extended LTE band preference */ guint val; guint j; guint k; /* it's really (band - MM_MODEM_BAND_EUTRAN_1 +1 -1), because * we want EUTRAN1 in index 0 */ val = band - MM_MODEM_BAND_EUTRAN_1; j = val / 64; g_assert (j < extended_qmi_lte_bands_size); k = val % 64; extended_qmi_lte_bands[j] |= ((guint64)1 << k); } else { /* Add LTE band preference */ guint j; for (j = 0; j < G_N_ELEMENTS (nas_lte_bands_map); j++) { if (nas_lte_bands_map[j].mm_band == band) { *qmi_lte_bands |= nas_lte_bands_map[j].qmi_band; break; } } if (j == G_N_ELEMENTS (nas_lte_bands_map)) mm_obj_dbg (log_object, "cannot add the following LTE band: '%s'", mm_modem_band_get_string (band)); } } else if (band >= MM_MODEM_BAND_NGRAN_1 && band <= MM_MODEM_BAND_NGRAN_261) { if (qmi_nr5g_bands && qmi_nr5g_bands_size) { /* Add NR5G band preference */ guint val; guint j; guint k; /* it's really (band - MM_MODEM_BAND_NGRAN_1 +1 -1), because * we want NGRAN1 in index 0 */ val = band - MM_MODEM_BAND_NGRAN_1; j = val / 64; g_assert (j < qmi_nr5g_bands_size); k = val % 64; qmi_nr5g_bands[j] |= ((guint64)1 << k); } } else { /* Add non-LTE band preference */ guint j; for (j = 0; j < G_N_ELEMENTS (nas_bands_map); j++) { if (nas_bands_map[j].mm_band == band) { *qmi_bands |= nas_bands_map[j].qmi_band; break; } } if (j == G_N_ELEMENTS (nas_bands_map)) mm_obj_dbg (log_object, "cannot add the following band: '%s'", mm_modem_band_get_string (band)); } } } /*****************************************************************************/ typedef struct { QmiNasActiveBand qmi_band; MMModemBand mm_band; } ActiveBandsMap; static const ActiveBandsMap active_bands_map [] = { /* CDMA bands */ { QMI_NAS_ACTIVE_BAND_BC_0, MM_MODEM_BAND_CDMA_BC0 }, { QMI_NAS_ACTIVE_BAND_BC_1, MM_MODEM_BAND_CDMA_BC1 }, { QMI_NAS_ACTIVE_BAND_BC_2, MM_MODEM_BAND_CDMA_BC2 }, { QMI_NAS_ACTIVE_BAND_BC_3, MM_MODEM_BAND_CDMA_BC3 }, { QMI_NAS_ACTIVE_BAND_BC_4, MM_MODEM_BAND_CDMA_BC4 }, { QMI_NAS_ACTIVE_BAND_BC_5, MM_MODEM_BAND_CDMA_BC5 }, { QMI_NAS_ACTIVE_BAND_BC_6, MM_MODEM_BAND_CDMA_BC6 }, { QMI_NAS_ACTIVE_BAND_BC_7, MM_MODEM_BAND_CDMA_BC7 }, { QMI_NAS_ACTIVE_BAND_BC_8, MM_MODEM_BAND_CDMA_BC8 }, { QMI_NAS_ACTIVE_BAND_BC_9, MM_MODEM_BAND_CDMA_BC9 }, { QMI_NAS_ACTIVE_BAND_BC_10, MM_MODEM_BAND_CDMA_BC10 }, { QMI_NAS_ACTIVE_BAND_BC_11, MM_MODEM_BAND_CDMA_BC11 }, { QMI_NAS_ACTIVE_BAND_BC_12, MM_MODEM_BAND_CDMA_BC12 }, { QMI_NAS_ACTIVE_BAND_BC_13, MM_MODEM_BAND_CDMA_BC13 }, { QMI_NAS_ACTIVE_BAND_BC_14, MM_MODEM_BAND_CDMA_BC14 }, { QMI_NAS_ACTIVE_BAND_BC_15, MM_MODEM_BAND_CDMA_BC15 }, { QMI_NAS_ACTIVE_BAND_BC_16, MM_MODEM_BAND_CDMA_BC16 }, { QMI_NAS_ACTIVE_BAND_BC_17, MM_MODEM_BAND_CDMA_BC17 }, { QMI_NAS_ACTIVE_BAND_BC_18, MM_MODEM_BAND_CDMA_BC18 }, { QMI_NAS_ACTIVE_BAND_BC_19, MM_MODEM_BAND_CDMA_BC19 }, /* GSM bands */ { QMI_NAS_ACTIVE_BAND_GSM_850, MM_MODEM_BAND_G850 }, { QMI_NAS_ACTIVE_BAND_GSM_900_EXTENDED, MM_MODEM_BAND_EGSM }, { QMI_NAS_ACTIVE_BAND_GSM_DCS_1800, MM_MODEM_BAND_DCS }, { QMI_NAS_ACTIVE_BAND_GSM_PCS_1900, MM_MODEM_BAND_PCS }, { QMI_NAS_ACTIVE_BAND_GSM_450, MM_MODEM_BAND_G450 }, { QMI_NAS_ACTIVE_BAND_GSM_480, MM_MODEM_BAND_G480 }, { QMI_NAS_ACTIVE_BAND_GSM_750, MM_MODEM_BAND_G750 }, /* WCDMA bands */ { QMI_NAS_ACTIVE_BAND_WCDMA_2100, MM_MODEM_BAND_UTRAN_1 }, { QMI_NAS_ACTIVE_BAND_WCDMA_PCS_1900, MM_MODEM_BAND_UTRAN_2 }, { QMI_NAS_ACTIVE_BAND_WCDMA_DCS_1800, MM_MODEM_BAND_UTRAN_3 }, { QMI_NAS_ACTIVE_BAND_WCDMA_1700_US, MM_MODEM_BAND_UTRAN_4 }, { QMI_NAS_ACTIVE_BAND_WCDMA_850, MM_MODEM_BAND_UTRAN_5 }, { QMI_NAS_ACTIVE_BAND_WCDMA_800, MM_MODEM_BAND_UTRAN_6 }, { QMI_NAS_ACTIVE_BAND_WCDMA_2600, MM_MODEM_BAND_UTRAN_7 }, { QMI_NAS_ACTIVE_BAND_WCDMA_900, MM_MODEM_BAND_UTRAN_8 }, { QMI_NAS_ACTIVE_BAND_WCDMA_1700_JAPAN, MM_MODEM_BAND_UTRAN_9 }, { QMI_NAS_ACTIVE_BAND_WCDMA_1500_JAPAN, MM_MODEM_BAND_UTRAN_11 }, { QMI_NAS_ACTIVE_BAND_WCDMA_850_JAPAN, MM_MODEM_BAND_UTRAN_19 }, /* LTE bands */ { QMI_NAS_ACTIVE_BAND_EUTRAN_1, MM_MODEM_BAND_EUTRAN_1 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_2 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_3, MM_MODEM_BAND_EUTRAN_3 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_4 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_5, MM_MODEM_BAND_EUTRAN_5 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_6, MM_MODEM_BAND_EUTRAN_6 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_7, MM_MODEM_BAND_EUTRAN_7 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_8, MM_MODEM_BAND_EUTRAN_8 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_9, MM_MODEM_BAND_EUTRAN_9 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_10, MM_MODEM_BAND_EUTRAN_10 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_11, MM_MODEM_BAND_EUTRAN_11 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_12, MM_MODEM_BAND_EUTRAN_12 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_13, MM_MODEM_BAND_EUTRAN_13 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_14, MM_MODEM_BAND_EUTRAN_14 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_17, MM_MODEM_BAND_EUTRAN_17 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_18, MM_MODEM_BAND_EUTRAN_18 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_19, MM_MODEM_BAND_EUTRAN_19 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_20, MM_MODEM_BAND_EUTRAN_20 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_21, MM_MODEM_BAND_EUTRAN_21 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_24, MM_MODEM_BAND_EUTRAN_24 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_25, MM_MODEM_BAND_EUTRAN_25 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_33, MM_MODEM_BAND_EUTRAN_33 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_34, MM_MODEM_BAND_EUTRAN_34 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_35, MM_MODEM_BAND_EUTRAN_35 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_36, MM_MODEM_BAND_EUTRAN_36 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_37, MM_MODEM_BAND_EUTRAN_37 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_38, MM_MODEM_BAND_EUTRAN_38 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_39, MM_MODEM_BAND_EUTRAN_39 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_40, MM_MODEM_BAND_EUTRAN_40 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_41, MM_MODEM_BAND_EUTRAN_41 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_42, MM_MODEM_BAND_EUTRAN_42 }, { QMI_NAS_ACTIVE_BAND_EUTRAN_43, MM_MODEM_BAND_EUTRAN_43 } }; static void add_active_bands (GArray *mm_bands, QmiNasActiveBand qmi_bands) { guint i; g_assert (mm_bands != NULL); for (i = 0; i < G_N_ELEMENTS (active_bands_map); i++) { if (qmi_bands == active_bands_map[i].qmi_band) { guint j; /* Avoid adding duplicate band entries */ for (j = 0; j < mm_bands->len; j++) { if (g_array_index (mm_bands, MMModemBand, j) == active_bands_map[i].mm_band) return; } g_array_append_val (mm_bands, active_bands_map[i].mm_band); return; } } } GArray * mm_modem_bands_from_qmi_rf_band_information_array (GArray *info_array) { GArray *mm_bands; mm_bands = g_array_new (FALSE, FALSE, sizeof (MMModemBand)); if (info_array) { guint i; for (i = 0; i < info_array->len; i++) { QmiMessageNasGetRfBandInformationOutputListElement *item; item = &g_array_index (info_array, QmiMessageNasGetRfBandInformationOutputListElement, i); add_active_bands (mm_bands, item->active_band_class); } } return mm_bands; } /*****************************************************************************/ MMModemAccessTechnology mm_modem_access_technology_from_qmi_radio_interface (QmiNasRadioInterface interface) { switch (interface) { case QMI_NAS_RADIO_INTERFACE_CDMA_1X: return MM_MODEM_ACCESS_TECHNOLOGY_1XRTT; case QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO: return MM_MODEM_ACCESS_TECHNOLOGY_EVDO0; case QMI_NAS_RADIO_INTERFACE_GSM: return MM_MODEM_ACCESS_TECHNOLOGY_GSM; case QMI_NAS_RADIO_INTERFACE_UMTS: return MM_MODEM_ACCESS_TECHNOLOGY_UMTS; case QMI_NAS_RADIO_INTERFACE_LTE: return MM_MODEM_ACCESS_TECHNOLOGY_LTE; case QMI_NAS_RADIO_INTERFACE_5GNR: return MM_MODEM_ACCESS_TECHNOLOGY_5GNR; case QMI_NAS_RADIO_INTERFACE_UNKNOWN: case QMI_NAS_RADIO_INTERFACE_TD_SCDMA: case QMI_NAS_RADIO_INTERFACE_AMPS: case QMI_NAS_RADIO_INTERFACE_NONE: default: return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; } } /*****************************************************************************/ MMModemAccessTechnology mm_modem_access_technologies_from_qmi_radio_interface_array (GArray *radio_interfaces) { MMModemAccessTechnology access_technology = 0; guint i; for (i = 0; i < radio_interfaces->len; i++) { QmiNasRadioInterface iface; iface = g_array_index (radio_interfaces, QmiNasRadioInterface, i); access_technology |= mm_modem_access_technology_from_qmi_radio_interface (iface); } return access_technology; } /*****************************************************************************/ MMModemAccessTechnology mm_modem_access_technology_from_qmi_data_capability (QmiNasDataCapability cap) { switch (cap) { case QMI_NAS_DATA_CAPABILITY_GPRS: return MM_MODEM_ACCESS_TECHNOLOGY_GPRS; case QMI_NAS_DATA_CAPABILITY_EDGE: return MM_MODEM_ACCESS_TECHNOLOGY_EDGE; case QMI_NAS_DATA_CAPABILITY_HSDPA: return MM_MODEM_ACCESS_TECHNOLOGY_HSDPA; case QMI_NAS_DATA_CAPABILITY_HSUPA: return MM_MODEM_ACCESS_TECHNOLOGY_HSUPA; case QMI_NAS_DATA_CAPABILITY_WCDMA: return MM_MODEM_ACCESS_TECHNOLOGY_UMTS; case QMI_NAS_DATA_CAPABILITY_CDMA: return MM_MODEM_ACCESS_TECHNOLOGY_1XRTT; case QMI_NAS_DATA_CAPABILITY_EVDO_REV_0: return MM_MODEM_ACCESS_TECHNOLOGY_EVDO0; case QMI_NAS_DATA_CAPABILITY_EVDO_REV_A: return MM_MODEM_ACCESS_TECHNOLOGY_EVDOA; case QMI_NAS_DATA_CAPABILITY_GSM: return MM_MODEM_ACCESS_TECHNOLOGY_GSM; case QMI_NAS_DATA_CAPABILITY_EVDO_REV_B: return MM_MODEM_ACCESS_TECHNOLOGY_EVDOB; case QMI_NAS_DATA_CAPABILITY_LTE: return MM_MODEM_ACCESS_TECHNOLOGY_LTE; case QMI_NAS_DATA_CAPABILITY_HSDPA_PLUS: case QMI_NAS_DATA_CAPABILITY_DC_HSDPA_PLUS: return MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS; case QMI_NAS_DATA_CAPABILITY_NONE: default: return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; } } /*****************************************************************************/ MMModemAccessTechnology mm_modem_access_technologies_from_qmi_data_capability_array (GArray *data_capabilities) { MMModemAccessTechnology access_technology = 0; guint i; for (i = 0; i < data_capabilities->len; i++) { QmiNasDataCapability cap; cap = g_array_index (data_capabilities, QmiNasDataCapability, i); access_technology |= mm_modem_access_technology_from_qmi_data_capability (cap); } return access_technology; } /*****************************************************************************/ MMModemMode mm_modem_mode_from_qmi_nas_radio_interface (QmiNasRadioInterface iface) { switch (iface) { case QMI_NAS_RADIO_INTERFACE_CDMA_1X: case QMI_NAS_RADIO_INTERFACE_GSM: return MM_MODEM_MODE_2G; case QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO: case QMI_NAS_RADIO_INTERFACE_UMTS: return MM_MODEM_MODE_3G; case QMI_NAS_RADIO_INTERFACE_LTE: return MM_MODEM_MODE_4G; case QMI_NAS_RADIO_INTERFACE_5GNR: return MM_MODEM_MODE_5G; case QMI_NAS_RADIO_INTERFACE_NONE: case QMI_NAS_RADIO_INTERFACE_AMPS: case QMI_NAS_RADIO_INTERFACE_TD_SCDMA: case QMI_NAS_RADIO_INTERFACE_UNKNOWN: default: return MM_MODEM_MODE_NONE; } } /*****************************************************************************/ MMModemMode mm_modem_mode_from_qmi_radio_technology_preference (QmiNasRadioTechnologyPreference qmi) { MMModemMode mode = MM_MODEM_MODE_NONE; if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_3GPP2) { /* Ignore AMPS, we really don't report CS mode in QMI modems */ if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_CDMA_OR_WCDMA) mode |= MM_MODEM_MODE_2G; /* CDMA */ if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_HDR) mode |= MM_MODEM_MODE_3G; /* EV-DO */ } if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_3GPP) { if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_AMPS_OR_GSM) mode |= MM_MODEM_MODE_2G; /* GSM */ if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_CDMA_OR_WCDMA) mode |= MM_MODEM_MODE_3G; /* WCDMA */ } if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_LTE) mode |= MM_MODEM_MODE_4G; return mode; } QmiNasRadioTechnologyPreference mm_modem_mode_to_qmi_radio_technology_preference (MMModemMode mode, gboolean is_cdma) { QmiNasRadioTechnologyPreference pref = 0; if (is_cdma) { pref |= QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_3GPP2; if (mode & MM_MODEM_MODE_2G) pref |= QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_CDMA_OR_WCDMA; /* CDMA */ if (mode & MM_MODEM_MODE_3G) pref |= QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_HDR; /* EV-DO */ } else { pref |= QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_3GPP; if (mode & MM_MODEM_MODE_2G) pref |= QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_AMPS_OR_GSM; /* GSM */ if (mode & MM_MODEM_MODE_3G) pref |= QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_CDMA_OR_WCDMA; /* WCDMA */ } if (mode & MM_MODEM_MODE_4G) pref |= QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_LTE; return pref; } /*****************************************************************************/ MMModemMode mm_modem_mode_from_qmi_rat_mode_preference (QmiNasRatModePreference qmi) { MMModemMode mode = MM_MODEM_MODE_NONE; if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1X) mode |= MM_MODEM_MODE_2G; if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1XEVDO) mode |= MM_MODEM_MODE_3G; if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_GSM) mode |= MM_MODEM_MODE_2G; if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_UMTS) mode |= MM_MODEM_MODE_3G; if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_LTE) mode |= MM_MODEM_MODE_4G; if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_5GNR) mode |= MM_MODEM_MODE_5G; return mode; } QmiNasRatModePreference mm_modem_mode_to_qmi_rat_mode_preference (MMModemMode mode, gboolean is_cdma, gboolean is_3gpp) { QmiNasRatModePreference pref = 0; if (is_cdma) { if (mode & MM_MODEM_MODE_2G) pref |= QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1X; if (mode & MM_MODEM_MODE_3G) pref |= QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1XEVDO; } if (is_3gpp) { if (mode & MM_MODEM_MODE_2G) pref |= QMI_NAS_RAT_MODE_PREFERENCE_GSM; if (mode & MM_MODEM_MODE_3G) pref |= QMI_NAS_RAT_MODE_PREFERENCE_UMTS; if (mode & MM_MODEM_MODE_4G) pref |= QMI_NAS_RAT_MODE_PREFERENCE_LTE; if (mode & MM_MODEM_MODE_5G) pref |= QMI_NAS_RAT_MODE_PREFERENCE_5GNR; } return pref; } /*****************************************************************************/ MMModemCapability mm_modem_capability_from_qmi_rat_mode_preference (QmiNasRatModePreference qmi) { MMModemCapability caps = MM_MODEM_CAPABILITY_NONE; if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1X) caps |= MM_MODEM_CAPABILITY_CDMA_EVDO; if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1XEVDO) caps |= MM_MODEM_CAPABILITY_CDMA_EVDO; if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_GSM) caps |= MM_MODEM_CAPABILITY_GSM_UMTS; if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_UMTS) caps |= MM_MODEM_CAPABILITY_GSM_UMTS; if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_LTE) caps |= MM_MODEM_CAPABILITY_LTE; if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_5GNR) caps |= MM_MODEM_CAPABILITY_5GNR; return caps; } QmiNasRatModePreference mm_modem_capability_to_qmi_rat_mode_preference (MMModemCapability caps) { QmiNasRatModePreference qmi = 0; if (caps & MM_MODEM_CAPABILITY_CDMA_EVDO) { qmi |= QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1X; qmi |= QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1XEVDO; } if (caps & MM_MODEM_CAPABILITY_GSM_UMTS) { qmi |= QMI_NAS_RAT_MODE_PREFERENCE_GSM; qmi |= QMI_NAS_RAT_MODE_PREFERENCE_UMTS; } if (caps & MM_MODEM_CAPABILITY_LTE) qmi |= QMI_NAS_RAT_MODE_PREFERENCE_LTE; if (caps & MM_MODEM_CAPABILITY_5GNR) qmi |= QMI_NAS_RAT_MODE_PREFERENCE_5GNR; return qmi; } /*****************************************************************************/ GArray * mm_modem_capability_to_qmi_acquisition_order_preference (MMModemCapability caps) { GArray *array; QmiNasRadioInterface value; array = g_array_new (FALSE, FALSE, sizeof (QmiNasRadioInterface)); if (caps & MM_MODEM_CAPABILITY_5GNR) { value = QMI_NAS_RADIO_INTERFACE_5GNR; g_array_append_val (array, value); } if (caps & MM_MODEM_CAPABILITY_LTE) { value = QMI_NAS_RADIO_INTERFACE_LTE; g_array_append_val (array, value); } if (caps & MM_MODEM_CAPABILITY_GSM_UMTS) { value = QMI_NAS_RADIO_INTERFACE_UMTS; g_array_append_val (array, value); value = QMI_NAS_RADIO_INTERFACE_GSM; g_array_append_val (array, value); } if (caps & MM_MODEM_CAPABILITY_CDMA_EVDO) { value = QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO; g_array_append_val (array, value); value = QMI_NAS_RADIO_INTERFACE_CDMA_1X; g_array_append_val (array, value); } 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, GArray *all) { GArray *array; QmiNasRadioInterface preferred_radio = QMI_NAS_RADIO_INTERFACE_UNKNOWN; QmiNasRadioInterface value; array = g_array_sized_new (FALSE, FALSE, sizeof (QmiNasRadioInterface), all->len); #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); \ } \ } 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); #undef PROCESS_ALLOWED_PREFERRED_MODE 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; } /*****************************************************************************/ MMModemCapability mm_modem_capability_from_qmi_radio_technology_preference (QmiNasRadioTechnologyPreference qmi) { MMModemCapability caps = MM_MODEM_CAPABILITY_NONE; if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_3GPP2) { /* Skip AMPS */ if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_CDMA_OR_WCDMA) caps |= MM_MODEM_CAPABILITY_CDMA_EVDO; /* CDMA */ if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_HDR) caps |= MM_MODEM_CAPABILITY_CDMA_EVDO; /* EV-DO */ } if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_3GPP) { if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_AMPS_OR_GSM) caps |= MM_MODEM_CAPABILITY_GSM_UMTS; /* GSM */ if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_CDMA_OR_WCDMA) caps |= MM_MODEM_CAPABILITY_GSM_UMTS; /* WCDMA */ } if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_LTE) caps |= MM_MODEM_CAPABILITY_LTE; /* NOTE: no 5GNR defined in Technology Preference */ return caps; } QmiNasRadioTechnologyPreference mm_modem_capability_to_qmi_radio_technology_preference (MMModemCapability caps) { QmiNasRadioTechnologyPreference qmi = 0; if (caps & MM_MODEM_CAPABILITY_GSM_UMTS) { qmi |= QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_3GPP; qmi |= QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_AMPS_OR_GSM; qmi |= QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_CDMA_OR_WCDMA; } if (caps & MM_MODEM_CAPABILITY_CDMA_EVDO) { qmi |= QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_3GPP2; qmi |= QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_CDMA_OR_WCDMA; qmi |= QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_HDR; } if (caps & MM_MODEM_CAPABILITY_LTE) qmi |= QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_LTE; return qmi; } /*****************************************************************************/ #define ALL_3GPP2_BANDS \ (QMI_NAS_BAND_PREFERENCE_BC_0_A_SYSTEM | \ QMI_NAS_BAND_PREFERENCE_BC_0_B_SYSTEM | \ QMI_NAS_BAND_PREFERENCE_BC_1_ALL_BLOCKS | \ QMI_NAS_BAND_PREFERENCE_BC_2 | \ QMI_NAS_BAND_PREFERENCE_BC_3_A_SYSTEM | \ QMI_NAS_BAND_PREFERENCE_BC_4_ALL_BLOCKS | \ QMI_NAS_BAND_PREFERENCE_BC_5_ALL_BLOCKS | \ QMI_NAS_BAND_PREFERENCE_BC_6 | \ QMI_NAS_BAND_PREFERENCE_BC_7 | \ QMI_NAS_BAND_PREFERENCE_BC_8 | \ QMI_NAS_BAND_PREFERENCE_BC_9 | \ QMI_NAS_BAND_PREFERENCE_BC_10 | \ QMI_NAS_BAND_PREFERENCE_BC_11 | \ QMI_NAS_BAND_PREFERENCE_BC_12 | \ QMI_NAS_BAND_PREFERENCE_BC_14 | \ QMI_NAS_BAND_PREFERENCE_BC_15 | \ QMI_NAS_BAND_PREFERENCE_BC_16 | \ QMI_NAS_BAND_PREFERENCE_BC_17 | \ QMI_NAS_BAND_PREFERENCE_BC_18 | \ QMI_NAS_BAND_PREFERENCE_BC_19) #define ALL_3GPP_BANDS \ (QMI_NAS_BAND_PREFERENCE_GSM_DCS_1800 | \ QMI_NAS_BAND_PREFERENCE_GSM_900_EXTENDED | \ QMI_NAS_BAND_PREFERENCE_GSM_900_PRIMARY | \ QMI_NAS_BAND_PREFERENCE_GSM_450 | \ QMI_NAS_BAND_PREFERENCE_GSM_480 | \ QMI_NAS_BAND_PREFERENCE_GSM_750 | \ QMI_NAS_BAND_PREFERENCE_GSM_850 | \ QMI_NAS_BAND_PREFERENCE_GSM_900_RAILWAYS | \ QMI_NAS_BAND_PREFERENCE_GSM_PCS_1900 | \ QMI_NAS_BAND_PREFERENCE_WCDMA_2100 | \ QMI_NAS_BAND_PREFERENCE_WCDMA_PCS_1900 | \ QMI_NAS_BAND_PREFERENCE_WCDMA_DCS_1800 | \ QMI_NAS_BAND_PREFERENCE_WCDMA_1700_US | \ QMI_NAS_BAND_PREFERENCE_WCDMA_850_US | \ QMI_NAS_BAND_PREFERENCE_WCDMA_800 | \ QMI_NAS_BAND_PREFERENCE_WCDMA_2600 | \ QMI_NAS_BAND_PREFERENCE_WCDMA_900 | \ QMI_NAS_BAND_PREFERENCE_WCDMA_1700_JAPAN) MMModemCapability mm_modem_capability_from_qmi_band_preference (QmiNasBandPreference qmi) { MMModemCapability caps = MM_MODEM_CAPABILITY_NONE; if (qmi & ALL_3GPP_BANDS) caps |= MM_MODEM_CAPABILITY_GSM_UMTS; if (qmi & ALL_3GPP2_BANDS) caps |= MM_MODEM_CAPABILITY_CDMA_EVDO; return caps; } /*****************************************************************************/ MMModemMode mm_modem_mode_from_qmi_gsm_wcdma_acquisition_order_preference (QmiNasGsmWcdmaAcquisitionOrderPreference qmi, gpointer log_object) { switch (qmi) { case QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_AUTOMATIC: return MM_MODEM_MODE_NONE; case QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_GSM: return MM_MODEM_MODE_2G; case QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_WCDMA: return MM_MODEM_MODE_3G; default: mm_obj_dbg (log_object, "unknown acquisition order preference: '%s'", qmi_nas_gsm_wcdma_acquisition_order_preference_get_string (qmi)); return MM_MODEM_MODE_NONE; } } QmiNasGsmWcdmaAcquisitionOrderPreference mm_modem_mode_to_qmi_gsm_wcdma_acquisition_order_preference (MMModemMode mode, gpointer log_object) { g_autofree gchar *str = NULL; /* mode is not a mask in this case, only a value */ switch (mode) { case MM_MODEM_MODE_3G: return QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_WCDMA; case MM_MODEM_MODE_2G: return QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_GSM; case MM_MODEM_MODE_NONE: return QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_AUTOMATIC; case MM_MODEM_MODE_CS: case MM_MODEM_MODE_4G: case MM_MODEM_MODE_5G: case MM_MODEM_MODE_ANY: default: break; } str = mm_modem_mode_build_string_from_mask (mode); mm_obj_dbg (log_object, "unhandled modem mode: '%s'", str); return QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_AUTOMATIC; } /*****************************************************************************/ MMModem3gppRegistrationState mm_modem_3gpp_registration_state_from_qmi_registration_state (QmiNasAttachState attach_state, QmiNasRegistrationState registration_state, gboolean roaming) { if (attach_state == QMI_NAS_ATTACH_STATE_UNKNOWN) return MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; if (attach_state == QMI_NAS_ATTACH_STATE_DETACHED) return MM_MODEM_3GPP_REGISTRATION_STATE_IDLE; /* attached */ switch (registration_state) { case QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED: return MM_MODEM_3GPP_REGISTRATION_STATE_IDLE; case QMI_NAS_REGISTRATION_STATE_REGISTERED: return (roaming ? MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING : MM_MODEM_3GPP_REGISTRATION_STATE_HOME); case QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED_SEARCHING: return MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING; case QMI_NAS_REGISTRATION_STATE_REGISTRATION_DENIED: return MM_MODEM_3GPP_REGISTRATION_STATE_DENIED; case QMI_NAS_REGISTRATION_STATE_UNKNOWN: default: return MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; } } /*****************************************************************************/ MMModemCdmaRegistrationState mm_modem_cdma_registration_state_from_qmi_registration_state (QmiNasRegistrationState registration_state) { switch (registration_state) { case QMI_NAS_REGISTRATION_STATE_REGISTERED: return MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; case QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED: case QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED_SEARCHING: case QMI_NAS_REGISTRATION_STATE_REGISTRATION_DENIED: case QMI_NAS_REGISTRATION_STATE_UNKNOWN: default: return MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; } } /*****************************************************************************/ MMModemCdmaActivationState mm_modem_cdma_activation_state_from_qmi_activation_state (QmiDmsActivationState state) { switch (state) { case QMI_DMS_ACTIVATION_STATE_NOT_ACTIVATED: return MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED; case QMI_DMS_ACTIVATION_STATE_ACTIVATED: return MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED; case QMI_DMS_ACTIVATION_STATE_CONNECTING: case QMI_DMS_ACTIVATION_STATE_CONNECTED: case QMI_DMS_ACTIVATION_STATE_OTASP_AUTHENTICATED: case QMI_DMS_ACTIVATION_STATE_OTASP_NAM: case QMI_DMS_ACTIVATION_STATE_OTASP_MDN: case QMI_DMS_ACTIVATION_STATE_OTASP_IMSI: case QMI_DMS_ACTIVATION_STATE_OTASP_PRL: case QMI_DMS_ACTIVATION_STATE_OTASP_SPC: return MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING; case QMI_DMS_ACTIVATION_STATE_OTASP_COMMITED: return MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED; default: return MM_MODEM_CDMA_ACTIVATION_STATE_UNKNOWN; } } /*****************************************************************************/ static void process_common_info (const gchar *info_name, QmiNasServiceStatus service_status, gboolean domain_valid, QmiNasNetworkServiceDomain domain, gboolean roaming_status_valid, QmiNasRoamingStatus roaming_status, gboolean forbidden_valid, gboolean forbidden, gboolean lac_valid, guint16 lac, gboolean tac_valid, guint16 tac, gboolean cid_valid, guint32 cid, gboolean network_id_valid, const gchar *mcc, const gchar *mnc, MMModem3gppRegistrationState *out_cs_registration_state, MMModem3gppRegistrationState *out_ps_registration_state, guint16 *out_lac, guint16 *out_tac, guint32 *out_cid, gchar **out_operator_id, gpointer log_object) { #define SET_OUTPUT(OUT, VAL) do { \ if (OUT) \ *(OUT) = (VAL); \ } while (0) /* If power save service status reported the modem is not actively searching * for a network, therefore "idle". */ if (service_status == QMI_NAS_SERVICE_STATUS_POWER_SAVE) { SET_OUTPUT (out_cs_registration_state, MM_MODEM_3GPP_REGISTRATION_STATE_IDLE); SET_OUTPUT (out_ps_registration_state, MM_MODEM_3GPP_REGISTRATION_STATE_IDLE); return; } /* If no service status reported, the modem is actively searching for a * network, therefore "searching". */ if (service_status == QMI_NAS_SERVICE_STATUS_NONE) { SET_OUTPUT (out_cs_registration_state, MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING); SET_OUTPUT (out_ps_registration_state, MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING); return; } /* When forbidden, the service status is usually reported as 'limited' or * 'limited-regional', e.g. allowing only emergency calls. If the * forbidden flag is explicitly reported, we report 'denied', otherwise * 'emergency-services-only' */ if (forbidden_valid && forbidden) { SET_OUTPUT (out_cs_registration_state, MM_MODEM_3GPP_REGISTRATION_STATE_DENIED); SET_OUTPUT (out_ps_registration_state, MM_MODEM_3GPP_REGISTRATION_STATE_DENIED); } else if (service_status == QMI_NAS_SERVICE_STATUS_LIMITED || service_status == QMI_NAS_SERVICE_STATUS_LIMITED_REGIONAL) { SET_OUTPUT (out_cs_registration_state, MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY); SET_OUTPUT (out_ps_registration_state, MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY); } /* On a successful registration (either home or roaming) we require a valid * domain and "available" service status */ else if (domain_valid && domain != QMI_NAS_NETWORK_SERVICE_DOMAIN_UNKNOWN && domain != QMI_NAS_NETWORK_SERVICE_DOMAIN_NONE && service_status == QMI_NAS_SERVICE_STATUS_AVAILABLE) { MMModem3gppRegistrationState tmp_registration_state; if (roaming_status_valid && roaming_status == QMI_NAS_ROAMING_STATUS_ON) tmp_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING; else tmp_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_HOME; if (domain == QMI_NAS_NETWORK_SERVICE_DOMAIN_CS) { SET_OUTPUT (out_cs_registration_state, tmp_registration_state); SET_OUTPUT (out_ps_registration_state, MM_MODEM_3GPP_REGISTRATION_STATE_IDLE); } else if (domain == QMI_NAS_NETWORK_SERVICE_DOMAIN_PS) { SET_OUTPUT (out_cs_registration_state, MM_MODEM_3GPP_REGISTRATION_STATE_IDLE); SET_OUTPUT (out_ps_registration_state, tmp_registration_state); } else if (domain == QMI_NAS_NETWORK_SERVICE_DOMAIN_CS_PS) { SET_OUTPUT (out_cs_registration_state, tmp_registration_state); SET_OUTPUT (out_ps_registration_state, tmp_registration_state); } /* If we're registered either at home or roaming, try to get LAC/CID */ if (lac_valid) SET_OUTPUT (out_lac, lac); if (tac_valid) SET_OUTPUT (out_tac, tac); if (cid_valid) SET_OUTPUT (out_cid, cid); } else { /* Issue a warning in case this ever happens and this logic needs to be updated */ mm_obj_warn (log_object, "unexpected %s system info: domain valid %s, domain %s, service status %s", info_name, domain_valid ? "yes" : "no", qmi_nas_network_service_domain_get_string (domain), qmi_nas_service_status_get_string (service_status)); return; } /* Network ID report also in the case of registration denial */ if (network_id_valid) { *out_operator_id = g_malloc0 (7); memcpy (*out_operator_id, mcc, 3); if ((guint8)mnc[2] == 0xFF) memcpy (&((*out_operator_id)[3]), mnc, 2); else memcpy (&((*out_operator_id)[3]), mnc, 3); } } static void process_gsm_info (QmiMessageNasGetSystemInfoOutput *response_output, QmiIndicationNasSystemInfoOutput *indication_output, MMModem3gppRegistrationState *out_cs_registration_state, MMModem3gppRegistrationState *out_ps_registration_state, guint16 *out_lac, guint32 *out_cid, gchar **out_operator_id, gpointer log_object) { QmiNasServiceStatus service_status = QMI_NAS_SERVICE_STATUS_NONE; gboolean domain_valid = FALSE; QmiNasNetworkServiceDomain domain = QMI_NAS_NETWORK_SERVICE_DOMAIN_UNKNOWN; gboolean roaming_status_valid = FALSE; QmiNasRoamingStatus roaming_status = QMI_NAS_ROAMING_STATUS_OFF; gboolean forbidden_valid = FALSE; gboolean forbidden = FALSE; gboolean lac_valid = FALSE; guint16 lac = 0; gboolean cid_valid = FALSE; guint32 cid = 0; gboolean network_id_valid = FALSE; const gchar *mcc = NULL; const gchar *mnc = NULL; if (response_output) { /* if service status info not given, ACT is unsupported */ if (!qmi_message_nas_get_system_info_output_get_gsm_service_status ( response_output, &service_status, NULL, /* true_service_status */ NULL, /* preferred_data_path */ NULL)) return; qmi_message_nas_get_system_info_output_get_gsm_system_info_v2 ( response_output, &domain_valid, &domain, NULL, NULL, /* service_capability */ &roaming_status_valid, &roaming_status, &forbidden_valid, &forbidden, &lac_valid, &lac, &cid_valid, &cid, NULL, NULL, NULL, /* registration_reject_info */ &network_id_valid, &mcc, &mnc, NULL, NULL, /* egprs support */ NULL, NULL, /* dtm_support */ NULL); } else if (indication_output) { /* if service status info not given, ACT is unsupported */ if (!qmi_indication_nas_system_info_output_get_gsm_service_status ( indication_output, &service_status, NULL, /* true_service_status */ NULL, /* preferred_data_path */ NULL)) return; qmi_indication_nas_system_info_output_get_gsm_system_info_v2 ( indication_output, &domain_valid, &domain, NULL, NULL, /* service_capability */ &roaming_status_valid, &roaming_status, &forbidden_valid, &forbidden, &lac_valid, &lac, &cid_valid, &cid, NULL, NULL, NULL, /* registration_reject_info */ &network_id_valid, &mcc, &mnc, NULL, NULL, /* egprs support */ NULL, NULL, /* dtm_support */ NULL); } else g_assert_not_reached (); process_common_info ("GSM", service_status, domain_valid, domain, roaming_status_valid, roaming_status, forbidden_valid, forbidden, lac_valid, lac, FALSE, 0, cid_valid, cid, network_id_valid, mcc, mnc, out_cs_registration_state, out_ps_registration_state, out_lac, NULL, /* out_tac */ out_cid, out_operator_id, log_object); } static void process_wcdma_info (QmiMessageNasGetSystemInfoOutput *response_output, QmiIndicationNasSystemInfoOutput *indication_output, MMModem3gppRegistrationState *out_cs_registration_state, MMModem3gppRegistrationState *out_ps_registration_state, guint16 *out_lac, guint32 *out_cid, gchar **out_operator_id, gpointer log_object) { QmiNasServiceStatus service_status = QMI_NAS_SERVICE_STATUS_NONE; gboolean domain_valid = FALSE; QmiNasNetworkServiceDomain domain = QMI_NAS_NETWORK_SERVICE_DOMAIN_UNKNOWN; gboolean roaming_status_valid = FALSE; QmiNasRoamingStatus roaming_status = QMI_NAS_ROAMING_STATUS_OFF; gboolean forbidden_valid = FALSE; gboolean forbidden = FALSE; gboolean lac_valid = FALSE; guint16 lac = 0; gboolean cid_valid = FALSE; guint32 cid = 0; gboolean network_id_valid = FALSE; const gchar *mcc = NULL; const gchar *mnc = NULL; if (response_output) { /* if service status info not given, ACT is unsupported */ if (!qmi_message_nas_get_system_info_output_get_wcdma_service_status ( response_output, &service_status, NULL, /* true_service_status */ NULL, /* preferred_data_path */ NULL)) return; qmi_message_nas_get_system_info_output_get_wcdma_system_info_v2 ( response_output, &domain_valid, &domain, NULL, NULL, /* service_capability */ &roaming_status_valid, &roaming_status, &forbidden_valid, &forbidden, &lac_valid, &lac, &cid_valid, &cid, NULL, NULL, NULL, /* registration_reject_info */ &network_id_valid, &mcc, &mnc, NULL, NULL, /* hs_call_status */ NULL, NULL, /* hs_service */ NULL, NULL, /* primary_scrambling_code */ NULL); } else if (indication_output) { /* if service status info not given, ACT is unsupported */ if (!qmi_indication_nas_system_info_output_get_wcdma_service_status ( indication_output, &service_status, NULL, /* true_service_status */ NULL, /* preferred_data_path */ NULL)) return; qmi_indication_nas_system_info_output_get_wcdma_system_info_v2 ( indication_output, &domain_valid, &domain, NULL, NULL, /* service_capability */ &roaming_status_valid, &roaming_status, &forbidden_valid, &forbidden, &lac_valid, &lac, &cid_valid, &cid, NULL, NULL, NULL, /* registration_reject_info */ &network_id_valid, &mcc, &mnc, NULL, NULL, /* hs_call_status */ NULL, NULL, /* hs_service */ NULL, NULL, /* primary_scrambling_code */ NULL); } else g_assert_not_reached (); process_common_info ("WCDMA", service_status, domain_valid, domain, roaming_status_valid, roaming_status, forbidden_valid, forbidden, lac_valid, lac, FALSE, 0, cid_valid, cid, network_id_valid, mcc, mnc, out_cs_registration_state, out_ps_registration_state, out_lac, NULL, /* out_tac */ out_cid, out_operator_id, log_object); } static void process_lte_info (QmiMessageNasGetSystemInfoOutput *response_output, QmiIndicationNasSystemInfoOutput *indication_output, MMModem3gppRegistrationState *out_eps_registration_state, guint16 *out_tac, guint32 *out_cid, gchar **out_operator_id, gboolean *out_endc_available, gpointer log_object) { QmiNasServiceStatus service_status = QMI_NAS_SERVICE_STATUS_NONE; gboolean domain_valid = FALSE; QmiNasNetworkServiceDomain domain = QMI_NAS_NETWORK_SERVICE_DOMAIN_UNKNOWN; gboolean roaming_status_valid = FALSE; QmiNasRoamingStatus roaming_status = QMI_NAS_ROAMING_STATUS_OFF; gboolean forbidden_valid = FALSE; gboolean forbidden = FALSE; gboolean tac_valid = FALSE; guint16 tac = 0; gboolean cid_valid = FALSE; guint32 cid = 0; gboolean network_id_valid = FALSE; const gchar *mcc = NULL; const gchar *mnc = NULL; if (response_output) { /* if service status info not given, ACT is unsupported */ if (!qmi_message_nas_get_system_info_output_get_lte_service_status ( response_output, &service_status, NULL, /* true_service_status */ NULL, /* preferred_data_path */ NULL)) return; qmi_message_nas_get_system_info_output_get_lte_system_info_v2 ( response_output, &domain_valid, &domain, NULL, NULL, /* service_capability */ &roaming_status_valid, &roaming_status, &forbidden_valid, &forbidden, NULL, NULL, /* lac */ &cid_valid, &cid, NULL, NULL, NULL, /* registration_reject_info */ &network_id_valid, &mcc, &mnc, &tac_valid, &tac, NULL); qmi_message_nas_get_system_info_output_get_eutra_with_nr5g_availability ( response_output, out_endc_available, NULL); } else if (indication_output) { /* if service status info not given, ACT is unsupported */ if (!qmi_indication_nas_system_info_output_get_lte_service_status ( indication_output, &service_status, NULL, /* true_service_status */ NULL, /* preferred_data_path */ NULL)) return; qmi_indication_nas_system_info_output_get_lte_system_info_v2 ( indication_output, &domain_valid, &domain, NULL, NULL, /* service_capability */ &roaming_status_valid, &roaming_status, &forbidden_valid, &forbidden, NULL, NULL, /* lac */ &cid_valid, &cid, NULL, NULL, NULL, /* registration_reject_info */ &network_id_valid, &mcc, &mnc, &tac_valid, &tac, NULL); qmi_indication_nas_system_info_output_get_eutra_with_nr5g_availability ( indication_output, out_endc_available, NULL); } else g_assert_not_reached (); process_common_info ("LTE", service_status, domain_valid, domain, roaming_status_valid, roaming_status, forbidden_valid, forbidden, FALSE, 0, tac_valid, tac, cid_valid, cid, network_id_valid, mcc, mnc, NULL, /* out_cs_registration_state */ out_eps_registration_state, NULL, /* out_lac */ out_tac, out_cid, out_operator_id, log_object); } static void process_nr5g_info (QmiMessageNasGetSystemInfoOutput *response_output, QmiIndicationNasSystemInfoOutput *indication_output, MMModem3gppRegistrationState *out_5gs_registration_state, guint16 *out_tac, guint32 *out_cid, gchar **out_operator_id, gpointer log_object) { QmiNasServiceStatus service_status = QMI_NAS_SERVICE_STATUS_NONE; gboolean domain_valid = FALSE; QmiNasNetworkServiceDomain domain = QMI_NAS_NETWORK_SERVICE_DOMAIN_UNKNOWN; gboolean roaming_status_valid = FALSE; QmiNasRoamingStatus roaming_status = QMI_NAS_ROAMING_STATUS_OFF; gboolean forbidden_valid = FALSE; gboolean forbidden = FALSE; gboolean tac_valid = FALSE; guint16 tac = 0; gboolean cid_valid = FALSE; guint32 cid = 0; gboolean network_id_valid = FALSE; const gchar *mcc = NULL; const gchar *mnc = NULL; if (response_output) { /* if service status info not given, ACT is unsupported */ if (!qmi_message_nas_get_system_info_output_get_nr5g_service_status_info ( response_output, &service_status, NULL, /* true_service_status */ NULL, /* preferred_data_path */ NULL)) return; qmi_message_nas_get_system_info_output_get_nr5g_system_info ( response_output, &domain_valid, &domain, NULL, NULL, /* service_capability */ &roaming_status_valid, &roaming_status, &forbidden_valid, &forbidden, NULL, NULL, /* lac */ &cid_valid, &cid, NULL, NULL, NULL, /* registration_reject_info */ &network_id_valid, &mcc, &mnc, &tac_valid, &tac, NULL); } else if (indication_output) { /* if service status info not given, ACT is unsupported */ if (!qmi_indication_nas_system_info_output_get_nr5g_service_status_info ( indication_output, &service_status, NULL, /* true_service_status */ NULL, /* preferred_data_path */ NULL)) return; qmi_indication_nas_system_info_output_get_nr5g_system_info ( indication_output, &domain_valid, &domain, NULL, NULL, /* service_capability */ &roaming_status_valid, &roaming_status, &forbidden_valid, &forbidden, NULL, NULL, /* lac */ &cid_valid, &cid, NULL, NULL, NULL, /* registration_reject_info */ &network_id_valid, &mcc, &mnc, &tac_valid, &tac, NULL); } else g_assert_not_reached (); process_common_info ("NR5G", service_status, domain_valid, domain, roaming_status_valid, roaming_status, forbidden_valid, forbidden, FALSE, 0, tac_valid, tac, cid_valid, cid, network_id_valid, mcc, mnc, NULL, /* cs_registration_state */ out_5gs_registration_state, NULL, /* out_lac */ out_tac, out_cid, out_operator_id, log_object); } static MMModem3gppRegistrationState unregistered_state_fallback (MMModem3gppRegistrationState umts_state, MMModem3gppRegistrationState gsm_state) { /* For 3G and 2G unregistered states, we will select SEARCHING if one of them * reports it, otherwise DENIED if one of the reports it, and otherwise * the 3G one if not unknown and finally the 2G one otherwise. */ if (umts_state == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING || gsm_state == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING) return MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING; if (umts_state == MM_MODEM_3GPP_REGISTRATION_STATE_DENIED || gsm_state == MM_MODEM_3GPP_REGISTRATION_STATE_DENIED) return MM_MODEM_3GPP_REGISTRATION_STATE_DENIED; if (umts_state != MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN) return umts_state; return gsm_state; } void mm_modem_registration_state_from_qmi_system_info (QmiMessageNasGetSystemInfoOutput *response_output, QmiIndicationNasSystemInfoOutput *indication_output, MMModem3gppRegistrationState *out_cs_registration_state, MMModem3gppRegistrationState *out_ps_registration_state, MMModem3gppRegistrationState *out_eps_registration_state, MMModem3gppRegistrationState *out_5gs_registration_state, guint16 *out_lac, guint16 *out_tac, guint32 *out_cid, gchar **out_operator_id, MMModemAccessTechnology *out_act, gpointer log_object) { MMModem3gppRegistrationState gsm_cs_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; MMModem3gppRegistrationState gsm_ps_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; MMModem3gppRegistrationState wcdma_cs_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; MMModem3gppRegistrationState wcdma_ps_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; MMModem3gppRegistrationState lte_eps_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; MMModem3gppRegistrationState nr5g_5gs_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; g_autofree gchar *gsm_operator_id = NULL; g_autofree gchar *wcdma_operator_id = NULL; g_autofree gchar *lte_operator_id = NULL; g_autofree gchar *nr5g_operator_id = NULL; guint16 gsm_lac = 0; guint32 gsm_cid = 0; guint16 wcdma_lac = 0; guint32 wcdma_cid = 0; guint16 lte_tac = 0; guint32 lte_cid = 0; guint16 nr5g_tac = 0; guint32 nr5g_cid = 0; gboolean endc_available = FALSE; gboolean reg_info_set = FALSE; /* Reset outputs */ *out_cs_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; *out_ps_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; *out_eps_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; *out_5gs_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; *out_lac = 0; *out_tac = 0; *out_cid = 0; *out_operator_id = NULL; *out_act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; process_nr5g_info (response_output, indication_output, &nr5g_5gs_registration_state, &nr5g_tac, &nr5g_cid, &nr5g_operator_id, log_object); process_lte_info (response_output, indication_output, <e_eps_registration_state, <e_tac, <e_cid, <e_operator_id, &endc_available, log_object); process_wcdma_info (response_output, indication_output, &wcdma_cs_registration_state, &wcdma_ps_registration_state, &wcdma_lac, &wcdma_cid, &wcdma_operator_id, log_object); process_gsm_info (response_output, indication_output, &gsm_cs_registration_state, &gsm_ps_registration_state, &gsm_lac, &gsm_cid, &gsm_operator_id, log_object); #define REG_INFO_SET(TAC,LAC,CID,OPERATOR_ID) \ if (!reg_info_set) { \ reg_info_set = TRUE; \ *out_tac = (TAC); \ *out_lac = (LAC); \ *out_cid = (CID); \ *out_operator_id = g_steal_pointer (&(OPERATOR_ID)); \ } /* Process 5G data */ *out_5gs_registration_state = nr5g_5gs_registration_state; if (mm_modem_3gpp_registration_state_is_registered (nr5g_5gs_registration_state)) { REG_INFO_SET (nr5g_tac, 0, nr5g_cid, nr5g_operator_id) *out_act |= MM_MODEM_ACCESS_TECHNOLOGY_5GNR; } /* Process 4G data */ *out_eps_registration_state = lte_eps_registration_state; if (mm_modem_3gpp_registration_state_is_registered (lte_eps_registration_state)) { REG_INFO_SET (lte_tac, 0, lte_cid, lte_operator_id) *out_act |= MM_MODEM_ACCESS_TECHNOLOGY_LTE; if (endc_available) *out_act |= MM_MODEM_ACCESS_TECHNOLOGY_5GNR; } /* Process 2G/3G data */ if (mm_modem_3gpp_registration_state_is_registered (wcdma_ps_registration_state)) { *out_ps_registration_state = wcdma_ps_registration_state; *out_act |= MM_MODEM_ACCESS_TECHNOLOGY_UMTS; REG_INFO_SET (0, wcdma_lac, wcdma_cid, wcdma_operator_id) } else if (mm_modem_3gpp_registration_state_is_registered (gsm_ps_registration_state)) { *out_ps_registration_state = gsm_ps_registration_state; *out_act |= MM_MODEM_ACCESS_TECHNOLOGY_GPRS; REG_INFO_SET (0, gsm_lac, gsm_cid, gsm_operator_id) } else { *out_ps_registration_state = unregistered_state_fallback (wcdma_ps_registration_state, gsm_ps_registration_state); } if (mm_modem_3gpp_registration_state_is_registered (wcdma_cs_registration_state)) { *out_cs_registration_state = wcdma_cs_registration_state; *out_act |= MM_MODEM_ACCESS_TECHNOLOGY_UMTS; REG_INFO_SET (0, wcdma_lac, wcdma_cid, wcdma_operator_id) } else if (mm_modem_3gpp_registration_state_is_registered (gsm_cs_registration_state)) { *out_cs_registration_state = gsm_cs_registration_state; *out_act |= MM_MODEM_ACCESS_TECHNOLOGY_GSM; REG_INFO_SET (0, gsm_lac, gsm_cid, gsm_operator_id) } else { *out_cs_registration_state = unregistered_state_fallback (wcdma_cs_registration_state, gsm_cs_registration_state); } #undef REG_INFO_SET } /*****************************************************************************/ QmiWmsStorageType mm_sms_storage_to_qmi_storage_type (MMSmsStorage storage) { switch (storage) { case MM_SMS_STORAGE_SM: return QMI_WMS_STORAGE_TYPE_UIM; case MM_SMS_STORAGE_ME: return QMI_WMS_STORAGE_TYPE_NV; case MM_SMS_STORAGE_UNKNOWN: case MM_SMS_STORAGE_MT: case MM_SMS_STORAGE_SR: case MM_SMS_STORAGE_BM: case MM_SMS_STORAGE_TA: default: return QMI_WMS_STORAGE_TYPE_NONE; } } MMSmsStorage mm_sms_storage_from_qmi_storage_type (QmiWmsStorageType qmi_storage) { switch (qmi_storage) { case QMI_WMS_STORAGE_TYPE_UIM: return MM_SMS_STORAGE_SM; case QMI_WMS_STORAGE_TYPE_NV: return MM_SMS_STORAGE_ME; case QMI_WMS_STORAGE_TYPE_NONE: default: return MM_SMS_STORAGE_UNKNOWN; } } /*****************************************************************************/ MMSmsState mm_sms_state_from_qmi_message_tag (QmiWmsMessageTagType tag) { switch (tag) { case QMI_WMS_MESSAGE_TAG_TYPE_MT_READ: case QMI_WMS_MESSAGE_TAG_TYPE_MT_NOT_READ: return MM_SMS_STATE_RECEIVED; case QMI_WMS_MESSAGE_TAG_TYPE_MO_SENT: return MM_SMS_STATE_SENT; case QMI_WMS_MESSAGE_TAG_TYPE_MO_NOT_SENT: return MM_SMS_STATE_STORED; default: return MM_SMS_STATE_UNKNOWN; } } /*****************************************************************************/ QmiWdsAuthentication mm_bearer_allowed_auth_to_qmi_authentication (MMBearerAllowedAuth auth, gpointer log_object, GError **error) { QmiWdsAuthentication out; if (auth == MM_BEARER_ALLOWED_AUTH_UNKNOWN) { mm_obj_dbg (log_object, "using default (CHAP) authentication method"); return QMI_WDS_AUTHENTICATION_CHAP; } if (auth == MM_BEARER_ALLOWED_AUTH_NONE) return QMI_WDS_AUTHENTICATION_NONE; /* otherwise find a bitmask that matches the input bitmask */ out = QMI_WDS_AUTHENTICATION_NONE; if (auth & MM_BEARER_ALLOWED_AUTH_PAP) out |= QMI_WDS_AUTHENTICATION_PAP; if (auth & MM_BEARER_ALLOWED_AUTH_CHAP) out |= QMI_WDS_AUTHENTICATION_CHAP; /* and if the bitmask cannot be built, error out */ if (out == QMI_WDS_AUTHENTICATION_NONE) { g_autofree gchar *str = NULL; str = mm_bearer_allowed_auth_build_string_from_mask (auth); g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Unsupported authentication methods (%s)", str); } return out; } MMBearerAllowedAuth mm_bearer_allowed_auth_from_qmi_authentication (QmiWdsAuthentication auth) { MMBearerAllowedAuth out = 0; /* Exact match for NONE */ if (auth == QMI_WDS_AUTHENTICATION_NONE) return MM_BEARER_ALLOWED_AUTH_NONE; if (auth & QMI_WDS_AUTHENTICATION_PAP) out |= MM_BEARER_ALLOWED_AUTH_PAP; if (auth & QMI_WDS_AUTHENTICATION_CHAP) out |= MM_BEARER_ALLOWED_AUTH_CHAP; return out; } MMBearerIpFamily mm_bearer_ip_family_from_qmi_ip_support_type (QmiWdsIpSupportType ip_support_type) { switch (ip_support_type) { case QMI_WDS_IP_SUPPORT_TYPE_IPV4: return MM_BEARER_IP_FAMILY_IPV4; case QMI_WDS_IP_SUPPORT_TYPE_IPV6: return MM_BEARER_IP_FAMILY_IPV6; case QMI_WDS_IP_SUPPORT_TYPE_IPV4V6: return MM_BEARER_IP_FAMILY_IPV4V6; default: return MM_BEARER_IP_FAMILY_NONE; } } MMBearerIpFamily mm_bearer_ip_family_from_qmi_pdp_type (QmiWdsPdpType pdp_type) { switch (pdp_type) { case QMI_WDS_PDP_TYPE_IPV4: return MM_BEARER_IP_FAMILY_IPV4; case QMI_WDS_PDP_TYPE_IPV6: return MM_BEARER_IP_FAMILY_IPV6; case QMI_WDS_PDP_TYPE_IPV4_OR_IPV6: return MM_BEARER_IP_FAMILY_IPV4V6; case QMI_WDS_PDP_TYPE_PPP: default: return MM_BEARER_IP_FAMILY_NONE; } } gboolean mm_bearer_ip_family_to_qmi_pdp_type (MMBearerIpFamily ip_family, QmiWdsPdpType *out_pdp_type) { switch (ip_family) { case MM_BEARER_IP_FAMILY_IPV4: *out_pdp_type = QMI_WDS_PDP_TYPE_IPV4; return TRUE; case MM_BEARER_IP_FAMILY_IPV6: *out_pdp_type = QMI_WDS_PDP_TYPE_IPV6; return TRUE; case MM_BEARER_IP_FAMILY_IPV4V6: *out_pdp_type = QMI_WDS_PDP_TYPE_IPV4_OR_IPV6; return TRUE; case MM_BEARER_IP_FAMILY_NON_IP: case MM_BEARER_IP_FAMILY_NONE: case MM_BEARER_IP_FAMILY_ANY: default: /* there is no valid conversion, so just return FALSE to indicate it */ return FALSE; } } QmiWdsApnTypeMask mm_bearer_apn_type_to_qmi_apn_type (MMBearerApnType apn_type, gpointer log_object) { guint64 value = 0; if (apn_type == MM_BEARER_APN_TYPE_NONE) { mm_obj_dbg (log_object, "using default (internet) APN type"); return QMI_WDS_APN_TYPE_MASK_DEFAULT; } if (apn_type & MM_BEARER_APN_TYPE_DEFAULT) value |= QMI_WDS_APN_TYPE_MASK_DEFAULT; if (apn_type & MM_BEARER_APN_TYPE_IMS) value |= QMI_WDS_APN_TYPE_MASK_IMS; if (apn_type & MM_BEARER_APN_TYPE_MMS) value |= QMI_WDS_APN_TYPE_MASK_MMS; if (apn_type & MM_BEARER_APN_TYPE_MANAGEMENT) value |= QMI_WDS_APN_TYPE_MASK_FOTA; if (apn_type & MM_BEARER_APN_TYPE_INITIAL) value |= QMI_WDS_APN_TYPE_MASK_IA; if (apn_type & MM_BEARER_APN_TYPE_EMERGENCY) value |= QMI_WDS_APN_TYPE_MASK_EMERGENCY; return value; } MMBearerApnType mm_bearer_apn_type_from_qmi_apn_type (QmiWdsApnTypeMask apn_type) { MMBearerApnType value = MM_BEARER_APN_TYPE_NONE; if (apn_type & QMI_WDS_APN_TYPE_MASK_DEFAULT) value |= MM_BEARER_APN_TYPE_DEFAULT; if (apn_type & QMI_WDS_APN_TYPE_MASK_IMS) value |= MM_BEARER_APN_TYPE_IMS; if (apn_type & QMI_WDS_APN_TYPE_MASK_MMS) value |= MM_BEARER_APN_TYPE_MMS; if (apn_type & QMI_WDS_APN_TYPE_MASK_FOTA) value |= MM_BEARER_APN_TYPE_MANAGEMENT; if (apn_type & QMI_WDS_APN_TYPE_MASK_IA) value |= MM_BEARER_APN_TYPE_INITIAL; if (apn_type & QMI_WDS_APN_TYPE_MASK_EMERGENCY) value |= MM_BEARER_APN_TYPE_EMERGENCY; return value; } /*****************************************************************************/ /* QMI/WDA to MM translations */ QmiDataEndpointType mm_port_net_driver_to_qmi_endpoint_type (const gchar *net_driver) { if (!g_strcmp0 (net_driver, "qmi_wwan")) return QMI_DATA_ENDPOINT_TYPE_HSUSB; if (!g_strcmp0 (net_driver, "mhi_net")) return QMI_DATA_ENDPOINT_TYPE_PCIE; if (!g_strcmp0 (net_driver, "ipa")) return QMI_DATA_ENDPOINT_TYPE_EMBEDDED; if (!g_strcmp0 (net_driver, "bam-dmux")) return QMI_DATA_ENDPOINT_TYPE_BAM_DMUX; return QMI_DATA_ENDPOINT_TYPE_UNKNOWN; } /*****************************************************************************/ /** * The only case where we need to apply some logic to decide what the current * capabilities are is when we have a multimode CDMA/EVDO+GSM/UMTS device, in * which case we'll check the SSP and TP current values to decide which * capabilities are present and which have been disabled. * * For all the other cases, the DMS capabilities are exactly the current ones, * as there would be no capability switching support. */ MMModemCapability mm_current_capability_from_qmi_current_capabilities_context (MMQmiCurrentCapabilitiesContext *ctx, gpointer log_object) { MMModemCapability tmp = MM_MODEM_CAPABILITY_NONE; g_autofree gchar *nas_ssp_mode_preference_str = NULL; g_autofree gchar *nas_tp_str = NULL; g_autofree gchar *dms_capabilities_str = NULL; g_autofree gchar *tmp_str = NULL; /* If not a multimode device, we're done */ if (!ctx->multimode) { if (ctx->dms_capabilities != MM_MODEM_CAPABILITY_NONE) tmp = ctx->dms_capabilities; /* SSP logic to gather capabilities uses the Mode Preference TLV if available */ else if (ctx->nas_ssp_mode_preference_mask) tmp = mm_modem_capability_from_qmi_rat_mode_preference (ctx->nas_ssp_mode_preference_mask); /* If no value retrieved from SSP, check TP. We only process TP * values if not 'auto' (0). */ else if (ctx->nas_tp_mask != QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_AUTO) tmp = mm_modem_capability_from_qmi_radio_technology_preference (ctx->nas_tp_mask); } else { /* We have a multimode CDMA/EVDO+GSM/UMTS device, check SSP and TP */ /* SSP logic to gather capabilities uses the Mode Preference TLV if available */ if (ctx->nas_ssp_mode_preference_mask) tmp = mm_modem_capability_from_qmi_rat_mode_preference (ctx->nas_ssp_mode_preference_mask); /* If no value retrieved from SSP, check TP. We only process TP * values if not 'auto' (0). */ else if (ctx->nas_tp_mask != QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_AUTO) tmp = mm_modem_capability_from_qmi_radio_technology_preference (ctx->nas_tp_mask); /* Final capabilities are the union of the active multimode capability * (GSM/UMTS or CDMA/EVDO or both or none) in TP or SSP and other supported device's capabilities. * If the Technology Preference was "auto" or unknown we just fall back * to the Get Capabilities response. */ if (tmp == MM_MODEM_CAPABILITY_NONE) tmp = ctx->dms_capabilities; else tmp = (tmp & MM_MODEM_CAPABILITY_MULTIMODE) | (MM_MODEM_CAPABILITY_MULTIMODE ^ ctx->dms_capabilities); } /* Log about the logic applied */ nas_ssp_mode_preference_str = qmi_nas_rat_mode_preference_build_string_from_mask (ctx->nas_ssp_mode_preference_mask); nas_tp_str = qmi_nas_radio_technology_preference_build_string_from_mask (ctx->nas_tp_mask); dms_capabilities_str = mm_modem_capability_build_string_from_mask (ctx->dms_capabilities); tmp_str = mm_modem_capability_build_string_from_mask (tmp); mm_obj_dbg (log_object, "Current capabilities built: '%s'\n" " SSP mode preference: '%s'\n" " TP: '%s'\n" " DMS Capabilities: '%s'", tmp_str, nas_ssp_mode_preference_str ? nas_ssp_mode_preference_str : "unknown", nas_tp_str ? nas_tp_str : "unknown", dms_capabilities_str); return tmp; } /*****************************************************************************/ /* Utility to build list of supported capabilities */ GArray * mm_supported_capabilities_from_qmi_supported_capabilities_context (MMQmiSupportedCapabilitiesContext *ctx, gpointer log_object) { GArray *supported_combinations; supported_combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), 4); /* Add all possible supported capability combinations. * In order to avoid unnecessary modem reboots, we will only implement capabilities * switching only when switching GSM/UMTS+CDMA/EVDO multimode devices, and only if * we have support for the commands doing it. */ if ((ctx->nas_tp_supported || ctx->nas_ssp_supported) && ctx->multimode) { MMModemCapability single; /* Multimode GSM/UMTS+CDMA/EVDO+(LTE/5GNR) device switched to GSM/UMTS+(LTE/5GNR) device */ single = MM_MODEM_CAPABILITY_GSM_UMTS | (MM_MODEM_CAPABILITY_MULTIMODE ^ ctx->dms_capabilities); g_array_append_val (supported_combinations, single); /* Multimode GSM/UMTS+CDMA/EVDO+(LTE/5GNR) device switched to CDMA/EVDO+(LTE/5GNR) device */ single = MM_MODEM_CAPABILITY_CDMA_EVDO | (MM_MODEM_CAPABILITY_MULTIMODE ^ ctx->dms_capabilities); g_array_append_val (supported_combinations, single); /* * Multimode GSM/UMTS+CDMA/EVDO+(LTE/5GNR) device switched to (LTE/5GNR) device * * This case is required because we use the same methods and operations to * switch capabilities and modes. */ if ((single = (MM_MODEM_CAPABILITY_MULTIMODE ^ ctx->dms_capabilities))) g_array_append_val (supported_combinations, single); } /* Add the full mask itself */ g_array_append_val (supported_combinations, ctx->dms_capabilities); return supported_combinations; } /*****************************************************************************/ /* Utility to build list of supported modes */ GArray * mm_supported_modes_from_qmi_supported_modes_context (MMQmiSupportedModesContext *ctx, gpointer log_object) { g_autoptr(GArray) combinations = NULL; g_autoptr(GArray) all = NULL; MMModemModeCombination mode; /* Start with a mode including ALL */ mode.allowed = ctx->all; mode.preferred = MM_MODEM_MODE_NONE; all = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1); g_array_append_val (all, mode); /* If SSP and TP are not supported, ignore supported mode management */ if (!ctx->nas_ssp_supported && !ctx->nas_tp_supported) return g_steal_pointer (&all); combinations = g_array_new (FALSE, FALSE, sizeof (MMModemModeCombination)); #define ADD_MODE_PREFERENCE(MODE1, MODE2, MODE3, MODE4) do { \ mode.allowed = MODE1; \ if (MODE2 != MM_MODEM_MODE_NONE) { \ mode.allowed |= MODE2; \ if (MODE3 != MM_MODEM_MODE_NONE) { \ mode.allowed |= MODE3; \ if (MODE4 != MM_MODEM_MODE_NONE) \ mode.allowed |= MODE4; \ } \ if (ctx->nas_ssp_supported) { \ if (MODE3 != MM_MODEM_MODE_NONE) { \ if (MODE4 != MM_MODEM_MODE_NONE) { \ mode.preferred = MODE4; \ g_array_append_val (combinations, mode); \ } \ mode.preferred = MODE3; \ g_array_append_val (combinations, mode); \ } \ mode.preferred = MODE2; \ g_array_append_val (combinations, mode); \ mode.preferred = MODE1; \ g_array_append_val (combinations, mode); \ } else { \ mode.preferred = MM_MODEM_MODE_NONE; \ g_array_append_val (combinations, mode); \ } \ } else { \ mode.allowed = MODE1; \ mode.preferred = MM_MODEM_MODE_NONE; \ g_array_append_val (combinations, mode); \ } \ } while (0) /* 2G-only, 3G-only */ ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); ADD_MODE_PREFERENCE (MM_MODEM_MODE_3G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); /* * This case is required because we use the same methods and operations to * switch capabilities and modes. For the LTE capability there is a direct * related 4G mode, and so we cannot select a '4G only' mode in this device * because we wouldn't be able to know the full list of current capabilities * if the device was rebooted, as we would only see LTE capability. So, * handle this special case so that the LTE/4G-only mode can exclusively be * selected as capability switching in this kind of devices. */ if (!ctx->multimode || !(ctx->current_capabilities & MM_MODEM_CAPABILITY_MULTIMODE)) { /* 4G-only */ ADD_MODE_PREFERENCE (MM_MODEM_MODE_4G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); } /* 2G, 3G, 4G combinations */ ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_3G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_4G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); ADD_MODE_PREFERENCE (MM_MODEM_MODE_3G, MM_MODEM_MODE_4G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_3G, MM_MODEM_MODE_4G, MM_MODEM_MODE_NONE); /* 5G related mode combinations are only supported when NAS SSP is supported, * as there is no 5G support in NAS TP. */ if (ctx->nas_ssp_supported) { /* Same reasoning as for the special 4G-only case above */ if (!ctx->multimode || !(ctx->current_capabilities & MM_MODEM_CAPABILITY_MULTIMODE)) { ADD_MODE_PREFERENCE (MM_MODEM_MODE_5G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); ADD_MODE_PREFERENCE (MM_MODEM_MODE_4G, MM_MODEM_MODE_5G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); } ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_5G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); ADD_MODE_PREFERENCE (MM_MODEM_MODE_3G, MM_MODEM_MODE_5G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_3G, MM_MODEM_MODE_5G, MM_MODEM_MODE_NONE); ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_4G, MM_MODEM_MODE_5G, MM_MODEM_MODE_NONE); ADD_MODE_PREFERENCE (MM_MODEM_MODE_3G, MM_MODEM_MODE_4G, MM_MODEM_MODE_5G, MM_MODEM_MODE_NONE); ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_3G, MM_MODEM_MODE_4G, MM_MODEM_MODE_5G); } /* Filter out unsupported modes */ return mm_filter_supported_modes (all, combinations, log_object); } /*****************************************************************************/ MMOmaSessionType mm_oma_session_type_from_qmi_oma_session_type (QmiOmaSessionType qmi_session_type) { switch (qmi_session_type) { case QMI_OMA_SESSION_TYPE_CLIENT_INITIATED_DEVICE_CONFIGURE: return MM_OMA_SESSION_TYPE_CLIENT_INITIATED_DEVICE_CONFIGURE; case QMI_OMA_SESSION_TYPE_CLIENT_INITIATED_PRL_UPDATE: return MM_OMA_SESSION_TYPE_CLIENT_INITIATED_PRL_UPDATE; case QMI_OMA_SESSION_TYPE_CLIENT_INITIATED_HANDS_FREE_ACTIVATION: return MM_OMA_SESSION_TYPE_CLIENT_INITIATED_HANDS_FREE_ACTIVATION; case QMI_OMA_SESSION_TYPE_DEVICE_INITIATED_HANDS_FREE_ACTIVATION: return MM_OMA_SESSION_TYPE_DEVICE_INITIATED_HANDS_FREE_ACTIVATION; case QMI_OMA_SESSION_TYPE_NETWORK_INITIATED_PRL_UPDATE: return MM_OMA_SESSION_TYPE_NETWORK_INITIATED_PRL_UPDATE; case QMI_OMA_SESSION_TYPE_NETWORK_INITIATED_DEVICE_CONFIGURE: return MM_OMA_SESSION_TYPE_NETWORK_INITIATED_DEVICE_CONFIGURE; case QMI_OMA_SESSION_TYPE_DEVICE_INITIATED_PRL_UPDATE: return MM_OMA_SESSION_TYPE_DEVICE_INITIATED_PRL_UPDATE; default: return MM_OMA_SESSION_TYPE_UNKNOWN; } } QmiOmaSessionType mm_oma_session_type_to_qmi_oma_session_type (MMOmaSessionType mm_session_type) { switch (mm_session_type) { case MM_OMA_SESSION_TYPE_CLIENT_INITIATED_DEVICE_CONFIGURE: return QMI_OMA_SESSION_TYPE_CLIENT_INITIATED_DEVICE_CONFIGURE; case MM_OMA_SESSION_TYPE_CLIENT_INITIATED_PRL_UPDATE: return QMI_OMA_SESSION_TYPE_CLIENT_INITIATED_PRL_UPDATE; case MM_OMA_SESSION_TYPE_CLIENT_INITIATED_HANDS_FREE_ACTIVATION: return QMI_OMA_SESSION_TYPE_CLIENT_INITIATED_HANDS_FREE_ACTIVATION; case MM_OMA_SESSION_TYPE_DEVICE_INITIATED_HANDS_FREE_ACTIVATION: return QMI_OMA_SESSION_TYPE_DEVICE_INITIATED_HANDS_FREE_ACTIVATION; case MM_OMA_SESSION_TYPE_NETWORK_INITIATED_PRL_UPDATE: return QMI_OMA_SESSION_TYPE_NETWORK_INITIATED_PRL_UPDATE; case MM_OMA_SESSION_TYPE_NETWORK_INITIATED_DEVICE_CONFIGURE: return QMI_OMA_SESSION_TYPE_NETWORK_INITIATED_DEVICE_CONFIGURE; case MM_OMA_SESSION_TYPE_DEVICE_INITIATED_PRL_UPDATE: return QMI_OMA_SESSION_TYPE_DEVICE_INITIATED_PRL_UPDATE; case MM_OMA_SESSION_TYPE_UNKNOWN: default: g_assert_not_reached (); } } MMOmaSessionState mm_oma_session_state_from_qmi_oma_session_state (QmiOmaSessionState qmi_session_state) { /* Note: MM_OMA_SESSION_STATE_STARTED is not a state received from the modem */ switch (qmi_session_state) { case QMI_OMA_SESSION_STATE_COMPLETE_INFORMATION_UPDATED: case QMI_OMA_SESSION_STATE_COMPLETE_UPDATED_INFORMATION_UNAVAILABLE: return MM_OMA_SESSION_STATE_COMPLETED; case QMI_OMA_SESSION_STATE_FAILED: return MM_OMA_SESSION_STATE_FAILED; case QMI_OMA_SESSION_STATE_RETRYING: return MM_OMA_SESSION_STATE_RETRYING; case QMI_OMA_SESSION_STATE_CONNECTING: return MM_OMA_SESSION_STATE_CONNECTING; case QMI_OMA_SESSION_STATE_CONNECTED: return MM_OMA_SESSION_STATE_CONNECTED; case QMI_OMA_SESSION_STATE_AUTHENTICATED: return MM_OMA_SESSION_STATE_AUTHENTICATED; case QMI_OMA_SESSION_STATE_MDN_DOWNLOADED: return MM_OMA_SESSION_STATE_MDN_DOWNLOADED; case QMI_OMA_SESSION_STATE_MSID_DOWNLOADED: return MM_OMA_SESSION_STATE_MSID_DOWNLOADED; case QMI_OMA_SESSION_STATE_PRL_DOWNLOADED: return MM_OMA_SESSION_STATE_PRL_DOWNLOADED; case QMI_OMA_SESSION_STATE_MIP_PROFILE_DOWNLOADED: return MM_OMA_SESSION_STATE_MIP_PROFILE_DOWNLOADED; default: return MM_OMA_SESSION_STATE_UNKNOWN; } } /*****************************************************************************/ MMOmaSessionStateFailedReason mm_oma_session_state_failed_reason_from_qmi_oma_session_failed_reason (QmiOmaSessionFailedReason qmi_session_failed_reason) { switch (qmi_session_failed_reason) { case QMI_OMA_SESSION_FAILED_REASON_UNKNOWN: return MM_OMA_SESSION_STATE_FAILED_REASON_UNKNOWN; case QMI_OMA_SESSION_FAILED_REASON_NETWORK_UNAVAILABLE: return MM_OMA_SESSION_STATE_FAILED_REASON_NETWORK_UNAVAILABLE; case QMI_OMA_SESSION_FAILED_REASON_SERVER_UNAVAILABLE: return MM_OMA_SESSION_STATE_FAILED_REASON_SERVER_UNAVAILABLE; case QMI_OMA_SESSION_FAILED_REASON_AUTHENTICATION_FAILED: return MM_OMA_SESSION_STATE_FAILED_REASON_AUTHENTICATION_FAILED; case QMI_OMA_SESSION_FAILED_REASON_MAX_RETRY_EXCEEDED: return MM_OMA_SESSION_STATE_FAILED_REASON_MAX_RETRY_EXCEEDED; case QMI_OMA_SESSION_FAILED_REASON_SESSION_CANCELLED: return MM_OMA_SESSION_STATE_FAILED_REASON_SESSION_CANCELLED; default: return MM_OMA_SESSION_STATE_FAILED_REASON_UNKNOWN; } } /*****************************************************************************/ /* Convert between firmware unique ID (string) and QMI unique ID (16 bytes) * * The unique ID coming in the QMI message is a fixed-size 16 byte array, and its * format really depends on the manufacturer. But, if the manufacturer is nice enough * to use ASCII for this field, just use it ourselves as well, no need to obfuscate * the information we expose in our interfaces. * * We also need to do the conversion in the other way around, because when * selecting a new image to run we need to provide the QMI unique ID. */ #define EXPECTED_QMI_UNIQUE_ID_LENGTH 16 gchar * mm_qmi_unique_id_to_firmware_unique_id (GArray *qmi_unique_id, GError **error) { guint i; gboolean expect_nul_byte = FALSE; if (qmi_unique_id->len != EXPECTED_QMI_UNIQUE_ID_LENGTH) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "unexpected QMI unique ID length: %u (expected: %u)", qmi_unique_id->len, EXPECTED_QMI_UNIQUE_ID_LENGTH); return NULL; } for (i = 0; i < qmi_unique_id->len; i++) { guint8 val; val = g_array_index (qmi_unique_id, guint8, i); /* Check for ASCII chars */ if (g_ascii_isprint ((gchar) val)) { /* Halt iteration if we found an ASCII char after a NUL byte */ if (expect_nul_byte) break; /* good char */ continue; } /* Allow NUL bytes at the end of the array */ if (val == '\0' && i > 0) { if (!expect_nul_byte) expect_nul_byte = TRUE; continue; } /* Halt iteration, not something we can build as ASCII */ break; } if (i != qmi_unique_id->len) return mm_utils_bin2hexstr ((const guint8 *)qmi_unique_id->data, qmi_unique_id->len); return g_strndup ((const gchar *)qmi_unique_id->data, qmi_unique_id->len); } GArray * mm_firmware_unique_id_to_qmi_unique_id (const gchar *unique_id, GError **error) { guint len; GArray *qmi_unique_id; len = strlen (unique_id); /* The length will be exactly EXPECTED_QMI_UNIQUE_ID_LENGTH*2 if given in HEX */ if (len == (2 * EXPECTED_QMI_UNIQUE_ID_LENGTH)) { g_autofree guint8 *tmp = NULL; gsize tmp_len; tmp_len = 0; tmp = mm_utils_hexstr2bin (unique_id, -1, &tmp_len, error); if (!tmp) { g_prefix_error (error, "Unexpected character found in unique id: "); return NULL; } g_assert (tmp_len == EXPECTED_QMI_UNIQUE_ID_LENGTH); qmi_unique_id = g_array_sized_new (FALSE, FALSE, sizeof (guint8), tmp_len); g_array_insert_vals (qmi_unique_id, 0, tmp, tmp_len); return qmi_unique_id; } /* The length will be EXPECTED_QMI_UNIQUE_ID_LENGTH or less if given in ASCII */ if (len > 0 && len <= EXPECTED_QMI_UNIQUE_ID_LENGTH) { guint i; for (i = 0; i < len; i++) { if (!g_ascii_isprint (unique_id[i])) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unexpected character found in unique id (not ASCII): %c", unique_id[i]); return NULL; } } qmi_unique_id = g_array_sized_new (FALSE, FALSE, sizeof (guint8), EXPECTED_QMI_UNIQUE_ID_LENGTH); g_array_set_size (qmi_unique_id, EXPECTED_QMI_UNIQUE_ID_LENGTH); memcpy (&qmi_unique_id->data[0], unique_id, len); if (len < EXPECTED_QMI_UNIQUE_ID_LENGTH) memset (&qmi_unique_id->data[len], 0, EXPECTED_QMI_UNIQUE_ID_LENGTH - len); return qmi_unique_id; } g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unexpected unique id length: %u", len); return NULL; } /*****************************************************************************/ gboolean mm_qmi_uim_get_card_status_output_parse (gpointer log_object, QmiMessageUimGetCardStatusOutput *output, MMModemLock *o_lock, QmiUimPinState *o_pin1_state, guint *o_pin1_retries, guint *o_puk1_retries, QmiUimPinState *o_pin2_state, guint *o_pin2_retries, guint *o_puk2_retries, guint *o_pers_retries, GError **error) { QmiMessageUimGetCardStatusOutputCardStatusCardsElement *card; QmiMessageUimGetCardStatusOutputCardStatusCardsElementApplicationsElementV2 *app; GArray *cards; guint16 index_gw_primary = 0xFFFF; guint8 gw_primary_slot_i = 0; guint8 gw_primary_application_i = 0; MMModemLock lock = MM_MODEM_LOCK_UNKNOWN; /* This command supports MULTIPLE cards with MULTIPLE applications each. For our * purposes, we're going to consider as the SIM to use the one identified as * 'primary GW' exclusively. We don't really support Dual Sim Dual Standby yet. */ qmi_message_uim_get_card_status_output_get_card_status ( output, &index_gw_primary, NULL, /* index_1x_primary */ NULL, /* index_gw_secondary */ NULL, /* index_1x_secondary */ &cards, NULL); if (cards->len == 0) { g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED, "No cards reported"); return FALSE; } /* Look for the primary GW slot and application. * If we don't have valid GW primary slot index and application index, assume * we're missing the SIM altogether */ gw_primary_slot_i = ((index_gw_primary & 0xFF00) >> 8); gw_primary_application_i = ((index_gw_primary & 0x00FF)); if (gw_primary_slot_i == 0xFF) { g_set_error (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED, "GW primary session index unknown"); return FALSE; } mm_obj_dbg (log_object, "GW primary session index: %u", gw_primary_slot_i); if (gw_primary_application_i == 0xFF) { g_set_error (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED, "GW primary application index unknown"); return FALSE; } mm_obj_dbg (log_object, "GW primary application index: %u", gw_primary_application_i); /* Validate slot index */ if (gw_primary_slot_i >= cards->len) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Invalid GW primary session index: %u", gw_primary_slot_i); return FALSE; } /* Get card at slot */ card = &g_array_index (cards, QmiMessageUimGetCardStatusOutputCardStatusCardsElement, gw_primary_slot_i); if (card->card_state == QMI_UIM_CARD_STATE_ABSENT) { g_set_error (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED, "No card found"); return FALSE; } if (card->card_state == QMI_UIM_CARD_STATE_ERROR) { const gchar *card_error; card_error = qmi_uim_card_error_get_string (card->error_code); g_set_error (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, "Card error: %s", card_error ? card_error : "unknown error"); return FALSE; } if (card->card_state != QMI_UIM_CARD_STATE_PRESENT) { g_set_error (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, "Card error: unexpected card state: 0x%x", card->card_state); return FALSE; } /* Card is present */ if (card->applications->len == 0) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "No applications reported in card"); return FALSE; } /* Validate application index */ if (gw_primary_application_i >= card->applications->len) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Invalid GW primary application index: %u", gw_primary_application_i); return FALSE; } app = &g_array_index (card->applications, QmiMessageUimGetCardStatusOutputCardStatusCardsElementApplicationsElementV2, gw_primary_application_i); if ((app->type != QMI_UIM_CARD_APPLICATION_TYPE_SIM) && (app->type != QMI_UIM_CARD_APPLICATION_TYPE_USIM)) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unsupported application type found in GW primary application index: %s", qmi_uim_card_application_type_get_string (app->type)); return FALSE; } /* Illegal application state is fatal, consider it as a failed SIM right * away and don't even attempt to retry */ if (app->state == QMI_UIM_CARD_APPLICATION_STATE_ILLEGAL) { g_set_error (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, "Illegal SIM/USIM application state"); return FALSE; } /* If card not ready yet, return RETRY error. * If the application state reports needing PIN/PUk, consider that ready as * well, and let the logic fall down to check PIN1/PIN2. */ if (app->state != QMI_UIM_CARD_APPLICATION_STATE_READY && app->state != QMI_UIM_CARD_APPLICATION_STATE_PIN1_OR_UPIN_PIN_REQUIRED && app->state != QMI_UIM_CARD_APPLICATION_STATE_PUK1_OR_UPIN_PUK_REQUIRED && app->state != QMI_UIM_CARD_APPLICATION_STATE_CHECK_PERSONALIZATION_STATE && app->state != QMI_UIM_CARD_APPLICATION_STATE_PIN1_BLOCKED) { mm_obj_dbg (log_object, "neither SIM nor USIM are ready"); g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY, "SIM not ready yet (retry)"); return FALSE; } /* Report state and retries if requested to do so */ if (o_pin1_state) *o_pin1_state = app->pin1_state; if (o_pin1_retries) *o_pin1_retries = app->pin1_retries; if (o_puk1_retries) *o_puk1_retries = app->puk1_retries; if (o_pin2_state) *o_pin2_state = app->pin2_state; if (o_pin2_retries) *o_pin2_retries = app->pin2_retries; if (o_puk2_retries) *o_puk2_retries = app->puk2_retries; /* Early bail out if lock status isn't wanted at this point, so that we * don't fail with an error the unlock retries check */ if (!o_lock) return TRUE; /* Card is ready, what's the lock status? */ /* PIN1 */ switch (app->pin1_state) { case QMI_UIM_PIN_STATE_NOT_INITIALIZED: g_set_error (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, "SIM PIN/PUK status not known yet"); return FALSE; case QMI_UIM_PIN_STATE_PERMANENTLY_BLOCKED: g_set_error (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, "SIM PIN/PUK permanently blocked"); return FALSE; case QMI_UIM_PIN_STATE_ENABLED_NOT_VERIFIED: lock = MM_MODEM_LOCK_SIM_PIN; break; case QMI_UIM_PIN_STATE_BLOCKED: lock = MM_MODEM_LOCK_SIM_PUK; break; case QMI_UIM_PIN_STATE_DISABLED: case QMI_UIM_PIN_STATE_ENABLED_VERIFIED: lock = MM_MODEM_LOCK_NONE; break; default: g_set_error (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, "Unknown SIM PIN/PUK status"); return FALSE; } /* Personalization */ if (lock == MM_MODEM_LOCK_NONE && app->state == QMI_UIM_CARD_APPLICATION_STATE_CHECK_PERSONALIZATION_STATE) { if (app->personalization_state == QMI_UIM_CARD_APPLICATION_PERSONALIZATION_STATE_IN_PROGRESS || app->personalization_state == QMI_UIM_CARD_APPLICATION_PERSONALIZATION_STATE_UNKNOWN) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY, "Personalization check in progress"); return FALSE; } if (app->personalization_state == QMI_UIM_CARD_APPLICATION_PERSONALIZATION_STATE_CODE_REQUIRED || app->personalization_state == QMI_UIM_CARD_APPLICATION_PERSONALIZATION_STATE_PUK_CODE_REQUIRED) { gboolean pin; pin = app->personalization_state == QMI_UIM_CARD_APPLICATION_PERSONALIZATION_STATE_CODE_REQUIRED; switch (app->personalization_feature) { case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_GW_NETWORK: lock = (pin ? MM_MODEM_LOCK_PH_NET_PIN : MM_MODEM_LOCK_PH_NET_PUK); break; case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_GW_NETWORK_SUBSET: lock = (pin ? MM_MODEM_LOCK_PH_NETSUB_PIN : MM_MODEM_LOCK_PH_NETSUB_PUK); break; case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_GW_SERVICE_PROVIDER: lock = (pin ? MM_MODEM_LOCK_PH_SP_PIN : MM_MODEM_LOCK_PH_SP_PUK); break; case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_GW_CORPORATE: lock = (pin ? MM_MODEM_LOCK_PH_CORP_PIN : MM_MODEM_LOCK_PH_CORP_PUK); break; case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_GW_UIM: if (pin) { lock = MM_MODEM_LOCK_PH_SIM_PIN; break; } /* fall through */ case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_1X_NETWORK_TYPE_1: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_1X_NETWORK_TYPE_2: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_1X_HRPD: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_1X_SERVICE_PROVIDER: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_1X_CORPORATE: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_1X_RUIM: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_UNKNOWN: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_GW_SERVICE_PROVIDER_NAME: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_GW_SP_EHPLMN: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_GW_ICCID: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_GW_IMPI: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_GW_NETWORK_SUBSET_SERVICE_PROVIDER: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_STATUS_GW_CARRIER: default: g_set_error (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, "Unsupported personalization feature"); return FALSE; } if (o_pers_retries) *o_pers_retries = app->personalization_retries; } } /* PIN2 */ if (lock == MM_MODEM_LOCK_NONE) { switch (app->pin2_state) { case QMI_UIM_PIN_STATE_NOT_INITIALIZED: mm_obj_warn (log_object, "SIM PIN2/PUK2 status not known yet"); break; case QMI_UIM_PIN_STATE_ENABLED_NOT_VERIFIED: lock = MM_MODEM_LOCK_SIM_PIN2; break; case QMI_UIM_PIN_STATE_PERMANENTLY_BLOCKED: mm_obj_warn (log_object, "PUK2 permanently blocked"); /* Fall through */ case QMI_UIM_PIN_STATE_BLOCKED: lock = MM_MODEM_LOCK_SIM_PUK2; break; case QMI_UIM_PIN_STATE_DISABLED: case QMI_UIM_PIN_STATE_ENABLED_VERIFIED: break; default: mm_obj_warn (log_object, "unknown SIM PIN2/PUK2 status"); break; } } *o_lock = lock; return TRUE; } /*****************************************************************************/ gboolean mm_qmi_uim_get_configuration_output_parse (gpointer log_object, QmiMessageUimGetConfigurationOutput *output, MMModem3gppFacility *o_lock, GError **error) { QmiMessageUimGetConfigurationOutputPersonalizationStatusElement *element; GArray *elements; guint idx; *o_lock = MM_MODEM_3GPP_FACILITY_NONE; if (!qmi_message_uim_get_configuration_output_get_personalization_status (output, &elements, error)) { g_prefix_error (error, "UIM Get Personalization Status failed: "); return FALSE; } for (idx = 0; idx < elements->len; idx++) { element = &g_array_index (elements, QmiMessageUimGetConfigurationOutputPersonalizationStatusElement, idx); switch (element->feature) { case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_NETWORK: *o_lock |= MM_MODEM_3GPP_FACILITY_NET_PERS; break; case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_NETWORK_SUBSET: *o_lock |= MM_MODEM_3GPP_FACILITY_NET_SUB_PERS; break; case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_SERVICE_PROVIDER: *o_lock |= MM_MODEM_3GPP_FACILITY_PROVIDER_PERS; break; case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_CORPORATE: *o_lock |= MM_MODEM_3GPP_FACILITY_CORP_PERS; break; case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_UIM: *o_lock |= MM_MODEM_3GPP_FACILITY_PH_SIM; break; case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_1X_NETWORK_TYPE_1: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_1X_NETWORK_TYPE_2: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_1X_HRPD: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_1X_SERVICE_PROVIDER: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_1X_CORPORATE: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_1X_RUIM: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_SERVICE_PROVIDER_NAME: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_SP_EHPLMN: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_ICCID: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_IMPI: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_NETWORK_SUBSET_SERVICE_PROVIDER: case QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_CARRIER: mm_obj_dbg (log_object, "ignoring lock in UIM feature: %s", qmi_uim_card_application_personalization_feature_get_string (element->feature)); break; default: mm_obj_dbg (log_object, "ignoring lock in unhandled UIM feature: 0x%x", (guint)element->feature); } } return TRUE; } /*****************************************************************************/ gboolean qmi_personalization_feature_from_mm_modem_3gpp_facility (MMModem3gppFacility facility, QmiUimCardApplicationPersonalizationFeature *o_feature) { switch (facility) { case MM_MODEM_3GPP_FACILITY_NET_PERS: *o_feature = QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_NETWORK; return TRUE; case MM_MODEM_3GPP_FACILITY_NET_SUB_PERS: *o_feature = QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_NETWORK_SUBSET; return TRUE; case MM_MODEM_3GPP_FACILITY_PROVIDER_PERS: *o_feature = QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_SERVICE_PROVIDER; return TRUE; case MM_MODEM_3GPP_FACILITY_CORP_PERS: *o_feature = QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_CORPORATE; return TRUE; case MM_MODEM_3GPP_FACILITY_PH_SIM: *o_feature = QMI_UIM_CARD_APPLICATION_PERSONALIZATION_FEATURE_GW_UIM; return TRUE; case MM_MODEM_3GPP_FACILITY_NONE: case MM_MODEM_3GPP_FACILITY_SIM: case MM_MODEM_3GPP_FACILITY_FIXED_DIALING: case MM_MODEM_3GPP_FACILITY_PH_FSIM: default: return FALSE; } } /*****************************************************************************/ typedef struct { QmiWdsVerboseCallEndReasonInternal vcer; gboolean is_core_error; /* TRUE if MM_CORE_ERROR, FALSE if MM_MOBILE_EQUIPMENT_ERROR */ guint error_code; } InternalErrorMap; static const InternalErrorMap internal_error_map[] = { /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_ERROR */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_CALL_ENDED */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_UNKNOWN_INTERNAL_CAUSE */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_UNKNOWN_CAUSE */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_CLOSE_IN_PROGRESS */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_NETWORK_INITIATED_TERMINATION */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_APP_PREEMPTED */ { QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_PDN_IPV4_CALL_DISALLOWED, FALSE, MM_MOBILE_EQUIPMENT_ERROR_IPV6_ONLY_ALLOWED }, { QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_PDN_IPV4_CALL_THROTTLED, TRUE, MM_CORE_ERROR_THROTTLED }, { QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_PDN_IPV6_CALL_DISALLOWED, FALSE, MM_MOBILE_EQUIPMENT_ERROR_IPV4_ONLY_ALLOWED }, { QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_PDN_IPV6_CALL_THROTTLED, TRUE, MM_CORE_ERROR_THROTTLED }, /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_MODEM_RESTART */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_PDP_PPP_NOT_SUPPORTED */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_UNPREFERRED_RAT */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_PHYSICAL_LINK_CLOSE_IN_PROGRESS */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_APN_PENDING_HANDOVER */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_PROFILE_BEARER_INCOMPATIBLE */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_MMGDSI_CARD_EVENT */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_LPM_OR_POWER_DOWN */ { QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_APN_DISABLED, FALSE, MM_MOBILE_EQUIPMENT_ERROR_MISSING_OR_UNKNOWN_APN }, /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_MPIT_EXPIRED */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_IPV6_ADDRESS_TRANSFER_FAILED */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_TRAT_SWAP_FAILED */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_EHRPD_TO_HRPD_FALLBACK */ { QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_MANDATORY_APN_DISABLED, FALSE, MM_MOBILE_EQUIPMENT_ERROR_MISSING_OR_UNKNOWN_APN }, /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_MIP_CONFIG_FAILURE */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_PDN_INACTIVITY_TIMER_EXPIRED */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_MAX_V4_CONNECTIONS */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_MAX_V6_CONNECTIONS */ { QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_APN_MISMATCH, FALSE, MM_MOBILE_EQUIPMENT_ERROR_MISSING_OR_UNKNOWN_APN }, /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_IP_VERSION_MISMATCH: NOTE: this one is treated in a special way */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_DUN_CALL_DISALLOWED */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_INVALID_PROFILE */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_EPC_NONEPC_TRANSITION */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_INVALID_PROFILE_ID */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_CALL_ALREADY_PRESENT */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_INTERFACE_IN_USE */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_IP_PDP_MISMATCH */ { QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_APN_DISALLOWED_ON_ROAMING, FALSE, MM_MOBILE_EQUIPMENT_ERROR_MISSING_OR_UNKNOWN_APN }, /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_APN_PARAMETER_CHANGE */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_INTERFACE_IN_USE_CONFIG_MATCH */ { QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_NULL_APN_DISALLOWED, FALSE, MM_MOBILE_EQUIPMENT_ERROR_MISSING_OR_UNKNOWN_APN }, /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_THERMAL_MITIGATION */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_SUBS_ID_MISMATCH */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_DATA_SETTINGS_DISABLED */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_DATA_ROAMING_SETTINGS_DISABLED */ { QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_APN_FORMAT_INVALID, FALSE, MM_MOBILE_EQUIPMENT_ERROR_MISSING_OR_UNKNOWN_APN }, /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_DDS_CALL_ABORT */ /* QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_VALIDATION_FAILURE */ }; static GError * error_from_wds_verbose_call_end_reason_internal (QmiWdsVerboseCallEndReasonInternal vcer_reason, const gchar *vcer_reason_str, MMBearerIpFamily ip_type, gpointer log_object) { guint i; /* Try to normalize the "IP version mismatch" error based on the IP type being connected. But * leave the original reason string to clearly show that we did this translation. */ if (vcer_reason == QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_IP_VERSION_MISMATCH) { if (ip_type == MM_BEARER_IP_FAMILY_IPV4) vcer_reason = QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_PDN_IPV4_CALL_DISALLOWED; else if (ip_type == MM_BEARER_IP_FAMILY_IPV6) vcer_reason = QMI_WDS_VERBOSE_CALL_END_REASON_INTERNAL_PDN_IPV6_CALL_DISALLOWED; } for (i = 0; i < G_N_ELEMENTS (internal_error_map); i++) { if (internal_error_map[i].vcer == vcer_reason) { GError *error; g_assert (vcer_reason_str); if (internal_error_map[i].is_core_error) error = g_error_new_literal (MM_CORE_ERROR, internal_error_map[i].error_code, vcer_reason_str); else { error = mm_mobile_equipment_error_for_code (internal_error_map[i].error_code, log_object); g_prefix_error (&error, "%s: ", vcer_reason_str); } return error; } } return NULL; } /*****************************************************************************/ static const MMMobileEquipmentError qmi_vcer_3gpp_errors[] = { [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_OPERATOR_DETERMINED_BARRING] = MM_MOBILE_EQUIPMENT_ERROR_OPERATOR_DETERMINED_BARRING, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_INSUFFICIENT_RESOURCES] = MM_MOBILE_EQUIPMENT_ERROR_INSUFFICIENT_RESOURCES, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_UNKNOWN_APN] = MM_MOBILE_EQUIPMENT_ERROR_MISSING_OR_UNKNOWN_APN, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_UNKNOWN_PDP] = MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN_PDP_ADDRESS_OR_TYPE, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_AUTHENTICATION_FAILED] = MM_MOBILE_EQUIPMENT_ERROR_USER_AUTHENTICATION_FAILED, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_GGSN_REJECT] = MM_MOBILE_EQUIPMENT_ERROR_ACTIVATION_REJECTED_BY_GGSN_OR_GW, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_ACTIVATION_REJECT] = MM_MOBILE_EQUIPMENT_ERROR_ACTIVATION_REJECTED_UNSPECIFIED, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_OPTION_NOT_SUPPORTED] = MM_MOBILE_EQUIPMENT_ERROR_SERVICE_OPTION_NOT_SUPPORTED, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_OPTION_UNSUBSCRIBED] = MM_MOBILE_EQUIPMENT_ERROR_SERVICE_OPTION_NOT_SUBSCRIBED, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_OPTION_TEMPORARILY_OUT_OF_ORDER] = MM_MOBILE_EQUIPMENT_ERROR_SERVICE_OPTION_OUT_OF_ORDER, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_NSAPI_ALREADY_USED] = MM_MOBILE_EQUIPMENT_ERROR_NSAPI_OR_PTI_ALREADY_IN_USE, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_REGULAR_DEACTIVATION] = MM_MOBILE_EQUIPMENT_ERROR_REGULAR_DEACTIVATION, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_QOS_NOT_ACCEPTED] = MM_MOBILE_EQUIPMENT_ERROR_QOS_NOT_ACCEPTED, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_NETWORK_FAILURE] = MM_MOBILE_EQUIPMENT_ERROR_NETWORK_FAILURE_ATTACH, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_REATTACH_REQUIRED] = MM_MOBILE_EQUIPMENT_ERROR_NETWORK_FAILURE_ATTACH, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_FEATURE_NOT_SUPPORTED] = MM_MOBILE_EQUIPMENT_ERROR_FEATURE_NOT_SUPPORTED, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_TFT_SEMANTIC_ERROR] = MM_MOBILE_EQUIPMENT_ERROR_SEMANTIC_ERROR_IN_TFT_OPERATION, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_TFT_SYNTAX_ERROR] = MM_MOBILE_EQUIPMENT_ERROR_SYNTACTICAL_ERROR_IN_TFT_OPERATION, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_UNKNOWN_PDP_CONTEXT] = MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN_PDP_CONTEXT, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_FILTER_SEMANTIC_ERROR] = MM_MOBILE_EQUIPMENT_ERROR_SEMANTIC_ERRORS_IN_PACKET_FILTER, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_FILTER_SYNTAX_ERROR] = MM_MOBILE_EQUIPMENT_ERROR_SYNTACTICAL_ERROR_IN_PACKET_FILTER, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_PDP_WITHOUT_ACTIVE_TFT] = MM_MOBILE_EQUIPMENT_ERROR_PDP_CONTEXT_WITHOUT_TFT_ALREADY_ACTIVATED, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_IPV4_ONLY_ALLOWED] = MM_MOBILE_EQUIPMENT_ERROR_IPV4_ONLY_ALLOWED, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_IPV6_ONLY_ALLOWED] = MM_MOBILE_EQUIPMENT_ERROR_IPV6_ONLY_ALLOWED, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_SINGLE_ADDRESS_BEARER_ONLY] = MM_MOBILE_EQUIPMENT_ERROR_SINGLE_ADDRESS_BEARERS_ONLY_ALLOWED, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_ESM_INFO_NOT_RECEIVED] = MM_MOBILE_EQUIPMENT_ERROR_ESM_INFORMATION_NOT_RECEIVED, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_PDN_CONNECTION_DOES_NOT_EXIST] = MM_MOBILE_EQUIPMENT_ERROR_PDN_CONNECTION_NONEXISTENT, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_MULTIPLE_CONNECTION_TO_SAME_PDN_NOT_ALLOWED] = MM_MOBILE_EQUIPMENT_ERROR_MULTIPLE_PDN_CONNECTION_SAME_APN_NOT_ALLOWED, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_INVALID_TRANSACTION_ID] = MM_MOBILE_EQUIPMENT_ERROR_INVALID_TRANSACTION_ID_VALUE, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_MESSAGE_INCORRECT_SEMANTIC] = MM_MOBILE_EQUIPMENT_ERROR_SEMANTICALLY_INCORRECT_MESSAGE, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_INVALID_MANDATORY_INFO] = MM_MOBILE_EQUIPMENT_ERROR_INVALID_MANDATORY_INFORMATION, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_MESSAGE_TYPE_UNSUPPORTED] = MM_MOBILE_EQUIPMENT_ERROR_MESSAGE_TYPE_NOT_IMPLEMENTED, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_MESSAGE_TYPE_NONCOMPATIBLE_STATE] = MM_MOBILE_EQUIPMENT_ERROR_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_UNKNOWN_INFO_ELEMENT] = MM_MOBILE_EQUIPMENT_ERROR_IE_NOT_IMPLEMENTED, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_CONDITIONAL_IE_ERROR] = MM_MOBILE_EQUIPMENT_ERROR_CONDITIONAL_IE_ERROR, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_MESSAGE_AND_PROTOCOL_STATE_UNCOMPATIBLE] = MM_MOBILE_EQUIPMENT_ERROR_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, [QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_PROTOCOL_ERROR] = MM_MOBILE_EQUIPMENT_ERROR_UNSPECIFIED_PROTOCOL_ERROR, /* unmapped errors */ /* QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_LLC_SNDCP_FAILURE */ /* QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_APN_TYPE_CONFLICT */ /* QMI_WDS_VERBOSE_CALL_END_REASON_3GPP_INVALID_PROXY_CALL_SESSION_CONTROL_FUNCTION_ADDRESS */ }; static GError * error_from_wds_verbose_call_end_reason_3gpp (QmiWdsVerboseCallEndReason3gpp vcer_reason, const gchar *vcer_reason_str, gpointer log_object) { MMMobileEquipmentError error_code; GError *error; error_code = (vcer_reason < G_N_ELEMENTS (qmi_vcer_3gpp_errors)) ? qmi_vcer_3gpp_errors[vcer_reason] : 0; if (!error_code) return NULL; g_assert (vcer_reason_str); error = mm_mobile_equipment_error_for_code (error_code, log_object); g_prefix_error (&error, "%s: ", vcer_reason_str); return error; } GError * mm_error_from_wds_verbose_call_end_reason (QmiWdsVerboseCallEndReasonType vcer_type, guint vcer_reason, MMBearerIpFamily ip_type, gpointer log_object) { GError *error = NULL; const gchar *vcer_type_str; const gchar *vcer_reason_str; vcer_type_str = qmi_wds_verbose_call_end_reason_type_get_string (vcer_type); vcer_reason_str = qmi_wds_verbose_call_end_reason_get_string (vcer_type, vcer_reason); mm_obj_msg (log_object, "verbose call end reason (%u,%d): [%s] %s", vcer_type, vcer_reason, vcer_type_str, vcer_reason_str); switch (vcer_type) { case QMI_WDS_VERBOSE_CALL_END_REASON_TYPE_INTERNAL: error = error_from_wds_verbose_call_end_reason_internal (vcer_reason, vcer_reason_str, ip_type, log_object); break; case QMI_WDS_VERBOSE_CALL_END_REASON_TYPE_3GPP: error = error_from_wds_verbose_call_end_reason_3gpp (vcer_reason, vcer_reason_str, log_object); break; case QMI_WDS_VERBOSE_CALL_END_REASON_TYPE_MIP: case QMI_WDS_VERBOSE_CALL_END_REASON_TYPE_CM: case QMI_WDS_VERBOSE_CALL_END_REASON_TYPE_PPP: case QMI_WDS_VERBOSE_CALL_END_REASON_TYPE_EHRPD: case QMI_WDS_VERBOSE_CALL_END_REASON_TYPE_IPV6: default: break; } if (error) return error; return g_error_new (MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN, "Call failed: %s error: %s", vcer_type_str ? vcer_type_str : "unknown", vcer_reason_str ? vcer_reason_str : "unknown"); } /*****************************************************************************/ gboolean mm_error_from_qmi_loc_indication_status (QmiLocIndicationStatus status, GError **error) { switch (status) { case QMI_LOC_INDICATION_STATUS_SUCCESS: return TRUE; case QMI_LOC_INDICATION_STATUS_GENERAL_FAILURE: g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "LOC service: general failure"); return FALSE; case QMI_LOC_INDICATION_STATUS_UNSUPPORTED: g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "LOC service: unsupported"); return FALSE; case QMI_LOC_INDICATION_STATUS_INVALID_PARAMETER: g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "LOC service: invalid parameter"); return FALSE; case QMI_LOC_INDICATION_STATUS_ENGINE_BUSY: g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS, "LOC service: engine busy"); return FALSE; case QMI_LOC_INDICATION_STATUS_PHONE_OFFLINE: g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE, "LOC service: phone offline"); return FALSE; case QMI_LOC_INDICATION_STATUS_TIMEOUT: g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED, "LOC service: timeout"); return FALSE; default: g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "LOC service: unknown failure"); return FALSE; } } /*****************************************************************************/ void mm_register_qmi_errors (void) { static gsize qmi_errors_registered = 0; if (!g_once_init_enter (&qmi_errors_registered)) return; /* QMI core errors */ mm_register_error_mapping (QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED, MM_CORE_ERROR, MM_CORE_ERROR_FAILED); mm_register_error_mapping (QMI_CORE_ERROR, QMI_CORE_ERROR_WRONG_STATE, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE); mm_register_error_mapping (QMI_CORE_ERROR, QMI_CORE_ERROR_TIMEOUT, MM_CORE_ERROR, MM_CORE_ERROR_TIMEOUT); mm_register_error_mapping (QMI_CORE_ERROR, QMI_CORE_ERROR_INVALID_ARGS, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS); mm_register_error_mapping (QMI_CORE_ERROR, QMI_CORE_ERROR_INVALID_MESSAGE, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS); mm_register_error_mapping (QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_NOT_FOUND, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND); mm_register_error_mapping (QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS); mm_register_error_mapping (QMI_CORE_ERROR, QMI_CORE_ERROR_UNSUPPORTED, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED); mm_register_error_mapping (QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_EMPTY, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS); mm_register_error_mapping (QMI_CORE_ERROR, QMI_CORE_ERROR_UNEXPECTED_MESSAGE, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE); mm_register_error_mapping (QMI_CORE_ERROR, QMI_CORE_ERROR_INVALID_DATA, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS); /* QMI protocol errors */ /* This should never happen, because QMI operations won't fail on this type of * error. But still, just in case, treat it as an error during normalization. */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NONE, MM_CORE_ERROR, MM_CORE_ERROR_FAILED); /* This is not really an error in an operation, it is the modem reporting that the * operation was a no-op. For the purposes of returning errors to the user, we will * normalize it either way. */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NO_EFFECT, MM_CORE_ERROR, MM_CORE_ERROR_FAILED); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_MALFORMED_MESSAGE, MM_CORE_ERROR, MM_CORE_ERROR_PROTOCOL); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NO_MEMORY, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_MEMORY_FULL); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INTERNAL, MM_CORE_ERROR, MM_CORE_ERROR_FAILED); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_ABORTED, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_CLIENT_IDS_EXHAUSTED, MM_CORE_ERROR, MM_CORE_ERROR_PROTOCOL); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_UNABORTABLE_TRANSACTION, MM_CORE_ERROR, MM_CORE_ERROR_PROTOCOL); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_CLIENT_ID, MM_CORE_ERROR, MM_CORE_ERROR_PROTOCOL); /* QMI_PROTOCOL_ERROR_NO_THRESHOLDS_PROVIDED */ /* QMI_PROTOCOL_ERROR_INVALID_HANDLE */ /* QMI_PROTOCOL_ERROR_INVALID_PROFILE */ /* QMI_PROTOCOL_ERROR_INVALID_PIN_ID */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INCORRECT_PIN, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NO_NETWORK_FOUND, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NO_NETWORK); /* QMI_PROTOCOL_ERROR_CALL_FAILED */ /* QMI_PROTOCOL_ERROR_OUT_OF_CALL */ /* QMI_PROTOCOL_ERROR_NOT_PROVISIONED */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_MISSING_ARGUMENT, MM_CORE_ERROR, MM_CORE_ERROR_PROTOCOL); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_ARGUMENT_TOO_LONG, MM_CORE_ERROR, MM_CORE_ERROR_PROTOCOL); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_TRANSACTION_ID, MM_CORE_ERROR, MM_CORE_ERROR_PROTOCOL); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_DEVICE_IN_USE, MM_CORE_ERROR, MM_CORE_ERROR_RETRY); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NETWORK_UNSUPPORTED, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_DEVICE_UNSUPPORTED, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED); /* QMI_PROTOCOL_ERROR_NO_FREE_PROFILE */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_PDP_TYPE, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN_PDP_ADDRESS_OR_TYPE); /* QMI_PROTOCOL_ERROR_INVALID_TECHNOLOGY_PREFERENCE */ /* QMI_PROTOCOL_ERROR_INVALID_PROFILE_TYPE */ /* QMI_PROTOCOL_ERROR_INVALID_SERVICE_TYPE */ /* QMI_PROTOCOL_ERROR_INVALID_REGISTER_ACTION */ /* QMI_PROTOCOL_ERROR_INVALID_PS_ATTACH_ACTION */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_AUTHENTICATION_FAILED, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_USER_AUTHENTICATION_FAILED); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_PIN_BLOCKED, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_PIN_ALWAYS_BLOCKED, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_UIM_UNINITIALIZED, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE); /* QMI_PROTOCOL_ERROR_MAXIMUM_QOS_REQUESTS_IN_USE */ /* QMI_PROTOCOL_ERROR_INCORRECT_FLOW_FILTER */ /* QMI_PROTOCOL_ERROR_NETWORK_QOS_UNAWARE */ /* QMI_PROTOCOL_ERROR_INVALID_QOS_ID */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_REQUESTED_NUMBER_UNSUPPORTED, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INTERFACE_NOT_FOUND, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_FOUND); /* QMI_PROTOCOL_ERROR_FLOW_SUSPENDED */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_DATA_FORMAT, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_PHONE_FAILURE); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_GENERAL_ERROR, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_PHONE_FAILURE); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_UNKNOWN_ERROR, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_ARGUMENT, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_INDEX, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_INVALID_INDEX); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NO_ENTRY, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_FOUND); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_DEVICE_STORAGE_FULL, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_MEMORY_FULL); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_DEVICE_NOT_READY, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_PHONE_FAILURE); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NETWORK_NOT_READY, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NO_NETWORK); /* QMI_PROTOCOL_ERROR_WMS_CAUSE_CODE */ /* QMI_PROTOCOL_ERROR_WMS_MESSAGE_NOT_SENT */ /* QMI_PROTOCOL_ERROR_WMS_MESSAGE_DELIVERY_FAILURE */ /* QMI_PROTOCOL_ERROR_WMS_INVALID_MESSAGE_ID */ /* QMI_PROTOCOL_ERROR_WMS_ENCODING */ /* QMI_PROTOCOL_ERROR_AUTHENTICATION_LOCK */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_TRANSITION, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE); /* QMI_PROTOCOL_ERROR_NOT_MCAST_INTERFACE */ /* QMI_PROTOCOL_ERROR_MAXIMUM_MCAST_REQUESTS_IN_USE */ /* QMI_PROTOCOL_ERROR_INVALID_MCAST_HANDLE */ /* QMI_PROTOCOL_ERROR_INVALID_IP_FAMILY_PREFERENCE */ /* QMI_PROTOCOL_ERROR_SESSION_INACTIVE */ /* QMI_PROTOCOL_ERROR_SESSION_INVALID */ /* QMI_PROTOCOL_ERROR_SESSION_OWNERSHIP */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INSUFFICIENT_RESOURCES, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_INSUFFICIENT_RESOURCES); /* QMI_PROTOCOL_ERROR_DISABLED */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_OPERATION, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_QMI_COMMAND, MM_CORE_ERROR, MM_CORE_ERROR_PROTOCOL); /* QMI_PROTOCOL_ERROR_WMS_T_PDU_TYPE */ /* QMI_PROTOCOL_ERROR_WMS_SMSC_ADDRESS */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INFORMATION_UNAVAILABLE, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_INVALID_MANDATORY_INFORMATION); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_SEGMENT_TOO_LONG, MM_CORE_ERROR, MM_CORE_ERROR_PROTOCOL); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_SEGMENT_ORDER, MM_CORE_ERROR, MM_CORE_ERROR_PROTOCOL); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_BUNDLING_NOT_SUPPORTED, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED); /* QMI_PROTOCOL_ERROR_OPERATION_PARTIAL_FAILURE */ /* QMI_PROTOCOL_ERROR_POLICY_MISMATCH */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_SIM_FILE_NOT_FOUND, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_FOUND); /* QMI_PROTOCOL_ERROR_EXTENDED_INTERNAL */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_ACCESS_DENIED, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_ALLOWED); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_HARDWARE_RESTRICTED, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_ALLOWED); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_ACK_NOT_SENT, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INJECT_TIMEOUT, MM_CORE_ERROR, MM_CORE_ERROR_TIMEOUT); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INCOMPATIBLE_STATE, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE); /* QMI_PROTOCOL_ERROR_FDN_RESTRICT */ /* QMI_PROTOCOL_ERROR_SUPS_FAILURE_CASE */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NO_RADIO, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_ALLOWED); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NOT_SUPPORTED, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED); /* QMI_PROTOCOL_ERROR_NO_SUBSCRIPTION */ /* QMI_PROTOCOL_ERROR_CARD_CALL_CONTROL_FAILED */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NETWORK_ABORTED, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED); /* QMI_PROTOCOL_ERROR_MSG_BLOCKED */ /* QMI_PROTOCOL_ERROR_INVALID_SESSION_TYPE */ /* QMI_PROTOCOL_ERROR_INVALID_PB_TYPE */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NO_SIM, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED); /* QMI_PROTOCOL_ERROR_PB_NOT_READY */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_PIN_RESTRICTION, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_PIN2_RESTRICTION, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN2); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_PUK_RESTRICTION, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_PUK2_RESTRICTION, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK2); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_PB_ACCESS_RESTRICTED, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_ALLOWED); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_PB_DELETE_IN_PROGRESS, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_PB_TEXT_TOO_LONG, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_TEXT_TOO_LONG); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_PB_NUMBER_TOO_LONG, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_DIAL_STRING_TOO_LONG); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_PB_HIDDEN_KEY_RESTRICTION, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_ALLOWED); /* QMI_PROTOCOL_ERROR_PB_NOT_AVAILABLE */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_DEVICE_MEMORY_ERROR, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_MEMORY_FAILURE); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NO_PERMISSION, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_ALLOWED); /* QMI_PROTOCOL_ERROR_TOO_SOON */ /* QMI_PROTOCOL_ERROR_TIME_NOT_ACQUIRED */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_OPERATION_IN_PROGRESS, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS); /* QMI_PROTOCOL_ERROR_FW_WRITE_FAILED */ /* QMI_PROTOCOL_ERROR_FW_INFO_READ_FAILED */ mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_FW_FILE_NOT_FOUND, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_FOUND); mm_register_error_mapping (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_FW_DIR_NOT_FOUND, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_FOUND); /* QMI_PROTOCOL_ERROR_FW_ALREADY_ACTIVATED */ /* QMI_PROTOCOL_ERROR_FW_CANNOT_GENERIC_IMAGE */ /* QMI_PROTOCOL_ERROR_FW_FILE_OPEN_FAILED */ /* QMI_PROTOCOL_ERROR_FW_UPDATE_DISCONTINUOUS_FRAME */ /* QMI_PROTOCOL_ERROR_FW_UPDATE_FAILED */ /* QMI_PROTOCOL_ERROR_CAT_EVENT_REGISTRATION_FAILED */ /* QMI_PROTOCOL_ERROR_CAT_INVALID_TERMINAL_RESPONSE */ /* QMI_PROTOCOL_ERROR_CAT_INVALID_ENVELOPE_COMMAND */ /* QMI_PROTOCOL_ERROR_CAT_ENVELOPE_COMMAND_BUSY */ /* QMI_PROTOCOL_ERROR_CAT_ENVELOPE_COMMAND_FAILED */ g_once_init_leave (&qmi_errors_registered, 1); }