aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mm-base-call.c7
-rw-r--r--src/mm-base-sim.c22
-rw-r--r--src/mm-base-sim.h3
-rw-r--r--src/mm-iface-modem-voice.c103
-rw-r--r--src/mm-iface-modem-voice.h5
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