call: disallow non-emergency calls when in emergency-only state
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user