gsm: add new property to track which facility locks are enabled

The property EnabledFacilityLocks on the .Modem.Gsm.Card interface
is a bit mask that indicates which of the various personalization
codes from 3GPP TS 22.022, plus the SIM PIN lock and SIM PIN2 lock,
are enabled. The set of facility locks supported by the modem is
determined at the time the modem is initialized, and the state of
each supported lock (enabled or disabled) is determined. When the
state of a lock changes, a property-change signal is sent out. Note
that ModemManager only supports enabling and disabling SIM-PIN, via
the EnablePin method on Modem.Gsm.Card.
This commit is contained in:
Eric Shienbrood
2011-08-11 13:58:59 -04:00
committed by Dan Williams
parent e7b6b2dc1c
commit eede5bb621
8 changed files with 357 additions and 68 deletions

View File

@@ -144,5 +144,11 @@
</tp:docstring>
</property>
<property name="EnabledFacilityLocks" type="u" access="read" tp:type="MM_MODEM_GSM_FACILITY">
<tp:docstring>
Facilities for which PIN locking is enabled.
</tp:docstring>
</property>
</interface>
</node>

View File

@@ -4,7 +4,7 @@
<interface name="org.freedesktop.ModemManager.Modem.Gsm">
<tp:flags name="MM_MODEM_GSM_MODE" value-prefix="MM_MODEM_GSM_MODE" type="u">
<tp:docstring>
A bitfield describing the specifc access modes and technologies
A bitfield describing the specific access modes and technologies
supported by a device and the access technology in-use when connected to
a mobile network.
</tp:docstring>
@@ -168,6 +168,41 @@
</tp:enumvalue>
</tp:enum>
<tp:flags name="MM_MODEM_GSM_FACILITY" value-prefix="MM_MODEM_GSM_FACILITY" type="u">
<tp:docstring>
A bitfield describing which facilities have a lock enabled, i.e.,
requires a pin or unlock code. The facilities include the
personalizations (device locks) described in 3GPP spec TS 22.022,
and the PIN and PIN2 locks, which are SIM locks.
</tp:docstring>
<tp:flag suffix="NONE" value="0x0">
<tp:docstring>No facility</tp:docstring>
</tp:flag>
<tp:flag suffix="SIM" value="0x1">
<tp:docstring>SIM lock</tp:docstring>
</tp:flag>
<tp:flag suffix="FIXED_DIALING" value="0x2">
<tp:docstring>Fixed dialing (PIN2) SIM lock</tp:docstring>
</tp:flag>
<tp:flag suffix="PH_SIM" value="0x4">
<tp:docstring>Device is locked to a specific SIM</tp:docstring>
</tp:flag>
<tp:flag suffix="PH_FSIM" value="0x8">
<tp:docstring>Device is locked to first SIM inserted</tp:docstring>
</tp:flag>
<tp:flag suffix="NET_PERS" value="0x10">
<tp:docstring>Network personalization</tp:docstring>
</tp:flag>
<tp:flag suffix="NET_SUB_PERS" value="0x20">
<tp:docstring>Network subset personalization</tp:docstring>
</tp:flag>
<tp:flag suffix="PROVIDER_PERS" value="0x40">
<tp:docstring>Service provider personalization</tp:docstring>
</tp:flag>
<tp:flag suffix="CORP_PERS" value="0x80">
<tp:docstring>Corporate personalization</tp:docstring>
</tp:flag>
</tp:flags>
</interface>
</node>

View File

@@ -138,6 +138,9 @@ typedef struct {
GHashTable *sms_parts;
guint sms_fetch_pending;
/* Facility locks */
MMModemGsmFacility enabled_facilities;
} MMGenericGsmPrivate;
static void get_registration_status (MMAtSerialPort *port, MMCallbackInfo *info);
@@ -809,6 +812,30 @@ initial_info_check (MMGenericGsm *self)
}
}
static void clck_cb (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data);
static void
initial_facility_lock_check (MMGenericGsm *self)
{
GError *error = NULL;
MMGenericGsmPrivate *priv;
g_return_if_fail (MM_IS_GENERIC_GSM (self));
priv = MM_GENERIC_GSM_GET_PRIVATE (self);
g_return_if_fail (priv->primary != NULL);
if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) {
mm_at_serial_port_queue_command (priv->primary, "+CLCK=?", 3, clck_cb, self);
} else {
g_warning ("%s: failed to open serial port: (%d) %s",
__func__,
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
}
static gboolean
owns_port (MMModem *modem, const char *subsys, const char *name)
{
@@ -882,6 +909,9 @@ mm_generic_gsm_grab_port (MMGenericGsm *self,
*/
initial_pin_check (self);
/* Determine what facility locks are supported */
initial_facility_lock_check (self);
} else if (ptype == MM_PORT_TYPE_SECONDARY)
priv->secondary = MM_AT_SERIAL_PORT (port);
} else if (MM_IS_QCDM_SERIAL_PORT (port)) {
@@ -1699,6 +1729,73 @@ cusd_enable_cb (MMAtSerialPort *port,
MM_GENERIC_GSM_GET_PRIVATE (user_data)->ussd_enabled = TRUE;
}
typedef struct {
MMGenericGsmPrivate *priv;
MMModemGsmFacility facility;
} FacilityLockInfo;
static void
get_facility_lock_state_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
gboolean enabled = FALSE;
FacilityLockInfo *finfo = (FacilityLockInfo *)user_data;
if (!error && mm_gsm_parse_clck_response (response->str, &enabled)) {
if (enabled)
finfo->priv->enabled_facilities |= finfo->facility;
else
finfo->priv->enabled_facilities &= ~finfo->facility;
}
mm_serial_port_close (MM_SERIAL_PORT (port));
g_free (finfo);
}
static void
get_facility_lock_states (MMGenericGsm *self,
MMModemGsmFacility facilities,
MMAtSerialPort *port,
GError *error)
{
gchar *cmd;
MMGenericGsmPrivate *priv;
gchar *facility_name;
FacilityLockInfo *finfo;
int i;
priv = MM_GENERIC_GSM_GET_PRIVATE (self);
for (i = 0; i < sizeof (MMModemGsmFacility) * 8; i++) {
guint32 facility = 1 << i;
if (facilities & facility) {
facility_name = mm_gsm_get_facility_name (facility);
if (facility_name != NULL && mm_serial_port_open (MM_SERIAL_PORT (port), &error)) {
cmd = g_strdup_printf ("+CLCK=\"%s\",2", facility_name);
finfo = g_malloc0 (sizeof (FacilityLockInfo));
finfo->facility = facility;
finfo->priv = priv;
mm_at_serial_port_queue_command (port, cmd, 3, get_facility_lock_state_done, finfo);
g_free (cmd);
}
}
}
}
static void
clck_cb (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMModemGsmFacility facilities;
if (!error && mm_gsm_parse_clck_test_response (response->str, &facilities))
get_facility_lock_states (MM_GENERIC_GSM (user_data), facilities, port, error);
mm_serial_port_close (MM_SERIAL_PORT (port));
}
void
mm_generic_gsm_enable_complete (MMGenericGsm *self,
GError *error,
@@ -2517,10 +2614,10 @@ update_pin_puk_status (MMModem *modem, GError *error)
}
static void
send_puk_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
send_pin_puk_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
@@ -2581,44 +2678,10 @@ send_puk (MMModemGsmCard *modem,
mm_callback_info_set_data (info, PIN_PORT_TAG, port, NULL);
command = g_strdup_printf ("+CPIN=\"%s\",\"%s\"", puk, pin);
mm_at_serial_port_queue_command (port, command, 3, send_puk_done, info);
mm_at_serial_port_queue_command (port, command, 3, send_pin_puk_done, info);
g_free (command);
}
static void
send_pin_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
/* If the modem has already been removed, return without
* scheduling callback */
if (mm_callback_info_check_modem_removed (info))
return;
if (error) {
if (error->domain != MM_MOBILE_ERROR) {
info->error = g_error_copy (error);
mm_callback_info_schedule (info);
mm_serial_port_close (MM_SERIAL_PORT (port));
return;
} else {
/* Keep the real error around so we can send it back
* when we're done rechecking CPIN status.
*/
mm_callback_info_set_data (info, SAVED_ERROR_TAG,
g_error_copy (error),
(GDestroyNotify) g_error_free);
}
}
/* Get latest PIN status */
MM_GENERIC_GSM_GET_PRIVATE (info->modem)->pin_check_tries = 0;
check_pin (MM_GENERIC_GSM (info->modem), pin_puk_recheck_done, info);
}
static void
send_pin (MMModemGsmCard *modem,
const char *pin,
@@ -2649,24 +2712,47 @@ send_pin (MMModemGsmCard *modem,
mm_callback_info_set_data (info, PIN_PORT_TAG, port, NULL);
command = g_strdup_printf ("+CPIN=\"%s\"", pin);
mm_at_serial_port_queue_command (port, command, 3, send_pin_done, info);
mm_at_serial_port_queue_command (port, command, 3, send_pin_puk_done, info);
g_free (command);
}
#define ENABLED_FACILITY_TAG "enabled-facility"
#define ENABLED_TAG "enabled"
static void
enable_pin_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
pin_operation_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMGenericGsmPrivate *priv;
MMModem *modem;
MMModemGsmFacility facility;
gboolean enabled;
/* If the modem has already been removed, return without
* scheduling callback */
if (mm_callback_info_check_modem_removed (info))
return;
update_pin_puk_status (info->modem, error);
modem = info->modem;
priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
if (!error) {
facility = GPOINTER_TO_UINT (mm_callback_info_get_data (info, ENABLED_FACILITY_TAG));
enabled = GPOINTER_TO_UINT (mm_callback_info_get_data (info, ENABLED_TAG));
if (facility != MM_MODEM_GSM_FACILITY_NONE) {
MMModemGsmFacility old = priv->enabled_facilities;
if (enabled)
priv->enabled_facilities |= facility;
else
priv->enabled_facilities &= ~facility;
if (priv->enabled_facilities != old)
g_object_notify (G_OBJECT (modem),
MM_MODEM_GSM_CARD_ENABLED_FACILITY_LOCKS);
}
}
update_pin_puk_status (modem, error);
if (error)
info->error = g_error_copy (error);
mm_callback_info_schedule (info);
@@ -2685,29 +2771,12 @@ enable_pin (MMModemGsmCard *modem,
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
command = g_strdup_printf ("+CLCK=\"SC\",%d,\"%s\"", enabled ? 1 : 0, pin);
mm_at_serial_port_queue_command (priv->primary, command, 3, enable_pin_done, info);
mm_callback_info_set_data (info, ENABLED_FACILITY_TAG, GUINT_TO_POINTER (MM_MODEM_GSM_FACILITY_SIM), NULL);
mm_callback_info_set_data (info, ENABLED_TAG, GUINT_TO_POINTER (enabled), NULL);
mm_at_serial_port_queue_command (priv->primary, command, 3, pin_operation_done, info);
g_free (command);
}
static void
change_pin_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
/* If the modem has already been removed, return without
* scheduling callback */
if (mm_callback_info_check_modem_removed (info))
return;
update_pin_puk_status (info->modem, error);
if (error)
info->error = g_error_copy (error);
mm_callback_info_schedule (info);
}
static void
change_pin (MMModemGsmCard *modem,
const char *old_pin,
@@ -2721,7 +2790,7 @@ change_pin (MMModemGsmCard *modem,
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
command = g_strdup_printf ("+CPWD=\"SC\",\"%s\",\"%s\"", old_pin, new_pin);
mm_at_serial_port_queue_command (priv->primary, command, 3, change_pin_done, info);
mm_at_serial_port_queue_command (priv->primary, command, 3, pin_operation_done, info);
g_free (command);
}
@@ -6042,6 +6111,11 @@ mm_generic_gsm_init (MMGenericGsm *self)
NULL,
MM_MODEM_GSM_NETWORK_DBUS_INTERFACE);
mm_properties_changed_signal_register_property (G_OBJECT (self),
MM_MODEM_GSM_CARD_ENABLED_FACILITY_LOCKS,
NULL,
MM_MODEM_GSM_CARD_DBUS_INTERFACE);
mm_properties_changed_signal_register_property (G_OBJECT (self),
MM_MODEM_LOCATION_CAPABILITIES,
"Capabilities",
@@ -6096,6 +6170,7 @@ set_property (GObject *object, guint prop_id,
case MM_GENERIC_GSM_PROP_ALLOWED_MODE:
case MM_GENERIC_GSM_PROP_ACCESS_TECHNOLOGY:
case MM_GENERIC_GSM_PROP_SIM_IDENTIFIER:
case MM_GENERIC_GSM_PROP_ENABLED_FACILITY_LOCKS:
case MM_GENERIC_GSM_PROP_LOC_CAPABILITIES:
case MM_GENERIC_GSM_PROP_LOC_ENABLED:
case MM_GENERIC_GSM_PROP_LOC_SIGNAL:
@@ -6186,6 +6261,9 @@ get_property (GObject *object, guint prop_id,
case MM_GENERIC_GSM_PROP_SIM_IDENTIFIER:
g_value_set_string (value, priv->simid);
break;
case MM_GENERIC_GSM_PROP_ENABLED_FACILITY_LOCKS:
g_value_set_uint (value, priv->enabled_facilities);
break;
case MM_GENERIC_GSM_PROP_LOC_CAPABILITIES:
g_value_set_uint (value, priv->loc_caps);
break;
@@ -6305,6 +6383,10 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass)
MM_GENERIC_GSM_PROP_SUPPORTED_MODES,
MM_MODEM_GSM_CARD_SUPPORTED_MODES);
g_object_class_override_property (object_class,
MM_GENERIC_GSM_PROP_ENABLED_FACILITY_LOCKS,
MM_MODEM_GSM_CARD_ENABLED_FACILITY_LOCKS);
g_object_class_override_property (object_class,
MM_GENERIC_GSM_PROP_ALLOWED_MODE,
MM_MODEM_GSM_NETWORK_ALLOWED_MODE);

View File

@@ -64,7 +64,8 @@ typedef enum {
MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD,
MM_GENERIC_GSM_PROP_SMS_INDICATION_ENABLE_CMD,
MM_GENERIC_GSM_PROP_SMS_STORAGE_LOCATION_CMD,
MM_GENERIC_GSM_PROP_CMER_ENABLE_CMD
MM_GENERIC_GSM_PROP_CMER_ENABLE_CMD,
MM_GENERIC_GSM_PROP_ENABLED_FACILITY_LOCKS
} MMGenericGsmProp;
typedef enum {

View File

@@ -659,6 +659,16 @@ mm_modem_gsm_card_init (gpointer g_iface)
G_MAXUINT32,
MM_MODEM_GSM_MODE_UNKNOWN,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_interface_install_property
(g_iface,
g_param_spec_uint (MM_MODEM_GSM_CARD_ENABLED_FACILITY_LOCKS,
"Enabled Facility Locks",
"Facility locks (i.e. PINs) that are enabled",
MM_MODEM_GSM_FACILITY_NONE,
G_MAXUINT32,
MM_MODEM_GSM_FACILITY_NONE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
GType

View File

@@ -19,6 +19,8 @@
#include <mm-modem.h>
#define MM_MODEM_GSM_CARD_DBUS_INTERFACE "org.freedesktop.ModemManager.Modem.Gsm.Card"
#define MM_TYPE_MODEM_GSM_CARD (mm_modem_gsm_card_get_type ())
#define MM_MODEM_GSM_CARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_GSM_CARD, MMModemGsmCard))
#define MM_IS_MODEM_GSM_CARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_GSM_CARD))
@@ -27,6 +29,7 @@
#define MM_MODEM_GSM_CARD_SUPPORTED_BANDS "supported-bands"
#define MM_MODEM_GSM_CARD_SUPPORTED_MODES "supported-modes"
#define MM_MODEM_GSM_CARD_SIM_IDENTIFIER "sim-identifier"
#define MM_MODEM_GSM_CARD_ENABLED_FACILITY_LOCKS "enabled-facility-locks"
#define MM_MODEM_GSM_CARD_SIM_PIN "sim-pin"
#define MM_MODEM_GSM_CARD_SIM_PIN2 "sim-pin2"

View File

@@ -819,6 +819,151 @@ mm_gsm_parse_cscs_support_response (const char *reply,
/*************************************************************************/
/* Map two letter facility codes into flag values. There are
* many more facilities defined (for various flavors of call
* barring); we only map the ones we care about. */
static MMModemGsmFacility
mm_gsm_string_to_facility (const char *string)
{
g_return_val_if_fail (string != NULL, MM_MODEM_GSM_FACILITY_NONE);
if (!strcmp (string, "SC"))
return MM_MODEM_GSM_FACILITY_SIM;
else if (!strcmp (string, "PS"))
return MM_MODEM_GSM_FACILITY_PH_SIM;
else if (!strcmp (string, "PF"))
return MM_MODEM_GSM_FACILITY_PH_FSIM;
else if (!strcmp (string, "FD"))
return MM_MODEM_GSM_FACILITY_FIXED_DIALING;
else if (!strcmp (string, "PN"))
return MM_MODEM_GSM_FACILITY_NET_PERS;
else if (!strcmp (string, "PU"))
return MM_MODEM_GSM_FACILITY_NET_SUB_PERS;
else if (!strcmp (string, "PP"))
return MM_MODEM_GSM_FACILITY_PROVIDER_PERS;
else if (!strcmp (string, "PC"))
return MM_MODEM_GSM_FACILITY_CORP_PERS;
else
return MM_MODEM_GSM_FACILITY_NONE;
}
/*************************************************************************/
char *
mm_gsm_get_facility_name (MMModemGsmFacility facility)
{
switch (facility) {
case MM_MODEM_GSM_FACILITY_SIM:
return "SC";
case MM_MODEM_GSM_FACILITY_PH_SIM:
return "PS";
case MM_MODEM_GSM_FACILITY_PH_FSIM:
return "PF";
case MM_MODEM_GSM_FACILITY_FIXED_DIALING:
return "FD";
case MM_MODEM_GSM_FACILITY_NET_PERS:
return "PN";
case MM_MODEM_GSM_FACILITY_NET_SUB_PERS:
return "PU";
case MM_MODEM_GSM_FACILITY_PROVIDER_PERS:
return "PP";
case MM_MODEM_GSM_FACILITY_CORP_PERS:
return "PC";
default:
return NULL;
}
}
gboolean
mm_gsm_parse_clck_test_response (const char *reply,
MMModemGsmFacility *out_facilities)
{
MMModemGsmFacility facilities = MM_MODEM_GSM_FACILITY_NONE;
GRegex *r;
GMatchInfo *match_info;
char *p, *str;
gboolean success = FALSE;
g_return_val_if_fail (reply != NULL, FALSE);
g_return_val_if_fail (out_facilities != NULL, FALSE);
/* the general format is:
*
* +CLCK: ("SC","AO","AI","PN")
*/
p = strchr (reply, '(');
if (p)
p++;
else {
p = strchr (reply, '"');
if (!p)
return FALSE;
}
/* Now parse each facility */
r = g_regex_new ("\\s*\"([^,\\)]+)\"\\s*", 0, 0, NULL);
if (!r)
return FALSE;
if (g_regex_match_full (r, p, strlen (p), 0, 0, &match_info, NULL)) {
while (g_match_info_matches (match_info)) {
str = g_match_info_fetch (match_info, 1);
if (str)
facilities |= mm_gsm_string_to_facility (str);
g_free (str);
g_match_info_next (match_info, NULL);
success = TRUE;
}
}
g_match_info_free (match_info);
g_regex_unref (r);
if (success)
*out_facilities = facilities;
return success;
}
gboolean
mm_gsm_parse_clck_response (const char *reply, gboolean *enabled)
{
GRegex *r;
GMatchInfo *match_info;
char *p, *str;
gboolean success = FALSE;
g_return_val_if_fail (reply != NULL, FALSE);
g_return_val_if_fail (enabled != NULL, FALSE);
p = strchr (reply, ':');
if (p)
p++;
r = g_regex_new ("\\s*([01])\\s*", 0, 0, NULL);
if (!r)
return FALSE;
if (g_regex_match (r, p, 0, &match_info)) {
success = TRUE;
str = g_match_info_fetch (match_info, 1);
if (str) {
if (*str == '0')
*enabled = FALSE;
else if (*str == '1')
*enabled = TRUE;
else
success = FALSE;
}
}
g_match_info_free (match_info);
g_regex_unref (r);
return success;
}
/*************************************************************************/
MMModemGsmAccessTech
mm_gsm_string_to_access_tech (const char *string)
{

View File

@@ -58,6 +58,13 @@ gboolean mm_cdma_parse_eri (const char *reply,
gboolean mm_gsm_parse_cscs_support_response (const char *reply,
MMModemCharset *out_charsets);
gboolean mm_gsm_parse_clck_test_response (const char *reply,
MMModemGsmFacility *out_facilities);
gboolean mm_gsm_parse_clck_response (const char *reply,
gboolean *enabled);
char *mm_gsm_get_facility_name (MMModemGsmFacility facility);
MMModemGsmAccessTech mm_gsm_string_to_access_tech (const char *string);
char *mm_create_device_identifier (guint vid,