diff options
-rw-r--r-- | src/mm-base-call.c | 7 | ||||
-rw-r--r-- | src/mm-base-sim.c | 22 | ||||
-rw-r--r-- | src/mm-base-sim.h | 3 | ||||
-rw-r--r-- | src/mm-iface-modem-voice.c | 103 | ||||
-rw-r--r-- | src/mm-iface-modem-voice.h | 5 |
5 files changed, 140 insertions, 0 deletions
diff --git a/src/mm-base-call.c b/src/mm-base-call.c index ce41112e..40dd6edd 100644 --- a/src/mm-base-call.c +++ b/src/mm-base-call.c @@ -225,6 +225,13 @@ handle_start_auth_ready (MMBaseModem *modem, mm_info ("user request to start call"); + /* Disallow non-emergency calls when in emergency-only state */ + if (!mm_iface_modem_voice_authorize_outgoing_call (MM_IFACE_MODEM_VOICE (modem), ctx->self, &error)) { + g_dbus_method_invocation_take_error (ctx->invocation, error); + handle_start_context_free (ctx); + return; + } + /* Check if we do support doing it */ if (!MM_BASE_CALL_GET_CLASS (ctx->self)->start || !MM_BASE_CALL_GET_CLASS (ctx->self)->start_finish) { diff --git a/src/mm-base-sim.c b/src/mm-base-sim.c index acb44125..73ed0882 100644 --- a/src/mm-base-sim.c +++ b/src/mm-base-sim.c @@ -953,6 +953,28 @@ mm_base_sim_get_path (MMBaseSim *self) /*****************************************************************************/ +gboolean +mm_base_sim_is_emergency_number (MMBaseSim *self, + const gchar *number) +{ + const gchar *const *emergency_numbers; + guint i; + + emergency_numbers = mm_gdbus_sim_get_emergency_numbers (MM_GDBUS_SIM (self)); + + if (!emergency_numbers) + return FALSE; + + for (i = 0; emergency_numbers[i]; i++) { + if (g_strcmp0 (number, emergency_numbers[i]) == 0) + return TRUE; + } + + return FALSE; +} + +/*****************************************************************************/ + #undef STR_REPLY_READY_FN #define STR_REPLY_READY_FN(NAME) \ static void \ diff --git a/src/mm-base-sim.h b/src/mm-base-sim.h index 7b9ea158..afafa376 100644 --- a/src/mm-base-sim.h +++ b/src/mm-base-sim.h @@ -180,4 +180,7 @@ gchar *mm_base_sim_load_sim_identifier_finish (MMBaseSim *self, GAsyncResult *res, GError **error); +gboolean mm_base_sim_is_emergency_number (MMBaseSim *self, + const gchar *number); + #endif /* MM_BASE_SIM_H */ diff --git a/src/mm-iface-modem-voice.c b/src/mm-iface-modem-voice.c index 32f6a4d1..ff685aa5 100644 --- a/src/mm-iface-modem-voice.c +++ b/src/mm-iface-modem-voice.c @@ -39,6 +39,109 @@ mm_iface_modem_voice_bind_simple_status (MMIfaceModemVoice *self, /*****************************************************************************/ +gboolean +mm_iface_modem_voice_authorize_outgoing_call (MMIfaceModemVoice *self, + MMBaseCall *call, + GError **error) +{ + MmGdbusModemVoice *skeleton = NULL; + MMBaseSim *sim = NULL; + gboolean emergency_only = FALSE; + gboolean call_allowed = FALSE; + GError *inner_error = NULL; + guint i; + const gchar *number; + + static const gchar *always_valid_emergency_numbers[] = { "112", "911" }; + static const gchar *no_sim_valid_emergency_numbers[] = { "000", "08", "110", "999", "118", "119" }; + + g_assert (mm_base_call_get_direction (call) == MM_CALL_DIRECTION_OUTGOING); + number = mm_base_call_get_number (call); + g_assert (number); + + g_object_get (self, + MM_IFACE_MODEM_VOICE_DBUS_SKELETON, &skeleton, + NULL); + + if (!skeleton) { + g_set_error (&inner_error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "voice operations unsupported"); + goto out; + } + + g_object_get (skeleton, + "emergency-only", &emergency_only, + NULL); + + /* Identification of emergency numbers. 3GPP TS 22.101 + * + * a) 112 and 911 shall always be available. + * b) Any emergency call number stored on a SIM/USIM when the SIM/USIM is + * present. + * c) 000, 08, 110, 999, 118 and 119 when a SIM/USIM is not present. + * d) Additional emergency call numbers that may have been downloaded by + * the serving network when the SIM/USIM is present. + * + * In ModemManager we're not flagging any call as being "emergency" or + * "normal", but we can right away limit non-emergency calls if we're in + * "emergency-only" mode. + */ + + /* If we're not in emergency mode, the call (emergency or normal) is always allowed */ + if (!emergency_only) { + mm_dbg ("voice call to %s allowed", number); + call_allowed = TRUE; + goto out; + } + + for (i = 0; i < G_N_ELEMENTS (always_valid_emergency_numbers); i++) { + if (g_strcmp0 (number, always_valid_emergency_numbers[i]) == 0) { + mm_dbg ("voice call to %s allowed: emergency call number always valid", number); + call_allowed = TRUE; + goto out; + } + } + + /* Check if we have a SIM */ + g_object_get (self, + MM_IFACE_MODEM_SIM, &sim, + NULL); + if (!sim) { + /* If no SIM available, some additional numbers may be valid emergency numbers */ + for (i = 0; i < G_N_ELEMENTS (no_sim_valid_emergency_numbers); i++) { + if (g_strcmp0 (number, no_sim_valid_emergency_numbers[i]) == 0) { + mm_dbg ("voice call to %s allowed: emergency call number valid when no SIM", number); + call_allowed = TRUE; + goto out; + } + } + + mm_dbg ("voice call to %s NOT allowed: not a valid emergency call number when no SIM", number); + goto out; + } + + /* Check if the number is programmed in EF_ECC */ + if (mm_base_sim_is_emergency_number (sim, number)) { + mm_dbg ("voice call to %s allowed: emergency call number programmed in the SIM", number); + call_allowed = TRUE; + } else + mm_dbg ("voice call to %s NOT allowed: not a valid emergency call number programmed in the SIM", number); + + out: + + if (inner_error) + g_propagate_error (error, inner_error); + else if (!call_allowed) + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNAUTHORIZED, + "only emergency calls allowed"); + + g_clear_object (&skeleton); + g_clear_object (&sim); + return call_allowed; +} + +/*****************************************************************************/ + /* new calls will inherit audio settings if the modem is already in-call state */ static void update_audio_settings_in_call (MMIfaceModemVoice *self, MMBaseCall *call); diff --git a/src/mm-iface-modem-voice.h b/src/mm-iface-modem-voice.h index 7f793dcc..2a9e52e0 100644 --- a/src/mm-iface-modem-voice.h +++ b/src/mm-iface-modem-voice.h @@ -243,6 +243,11 @@ void mm_iface_modem_voice_received_dtmf (MMIfaceModemVoice *self, guint index, const gchar *dtmf); +/* Authorize outgoing call based on modem status and ECC list */ +gboolean mm_iface_modem_voice_authorize_outgoing_call (MMIfaceModemVoice *self, + MMBaseCall *call, + GError **error); + /* Join/Leave multiparty calls * * These actions are provided in the Call API, but implemented in the |