aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEric Shienbrood <ers@chromium.org>2011-08-11 13:58:59 -0400
committerDan Williams <dcbw@redhat.com>2011-11-16 23:41:49 -0600
commiteede5bb621152eb1774495d9cd403b1e653c076c (patch)
treed8fc5bfcb140e444aba52f8d64d1738d441ccca6 /src
parente7b6b2dc1c709ae877e3cd472d4134b918bb5fb7 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/mm-generic-gsm.c214
-rw-r--r--src/mm-generic-gsm.h3
-rw-r--r--src/mm-modem-gsm-card.c10
-rw-r--r--src/mm-modem-gsm-card.h3
-rw-r--r--src/mm-modem-helpers.c145
-rw-r--r--src/mm-modem-helpers.h7
6 files changed, 315 insertions, 67 deletions
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index da0bf5cb..1a0a7fa9 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -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,45 +2678,11 @@ 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,
MMModemFn callback,
@@ -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,30 +2771,13 @@ 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,
const char *new_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);
}
@@ -6043,6 +6112,11 @@ mm_generic_gsm_init (MMGenericGsm *self)
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",
MM_MODEM_LOCATION_DBUS_INTERFACE);
@@ -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;
@@ -6306,6 +6384,10 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass)
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);
diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h
index 7fba1f31..bbf7988c 100644
--- a/src/mm-generic-gsm.h
+++ b/src/mm-generic-gsm.h
@@ -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 {
diff --git a/src/mm-modem-gsm-card.c b/src/mm-modem-gsm-card.c
index 35360db5..abf642af 100644
--- a/src/mm-modem-gsm-card.c
+++ b/src/mm-modem-gsm-card.c
@@ -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
diff --git a/src/mm-modem-gsm-card.h b/src/mm-modem-gsm-card.h
index 34a5d5b7..e6e39dd1 100644
--- a/src/mm-modem-gsm-card.h
+++ b/src/mm-modem-gsm-card.h
@@ -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"
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index 0bf62378..25e0561d 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -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)
{
diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
index a47f4695..0827abf2 100644
--- a/src/mm-modem-helpers.h
+++ b/src/mm-modem-helpers.h
@@ -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,