core: add DeviceIdentifier property
This is computed before any PIN is entered, and thus before we can usually get IMEI or MEID/ESN out of the device in many cases. It's therefore not the same as EquipmentIdentifier. This is intended to be used by UI programs for matching devices with PIN numbers for automatic unlocking. While the PIN number is actually *SIM* specific, no modems allow access to the IMSI before the PIN is entered, and thus we cannot actually match the PIN with the SIM. The device ID is the next best thing we can use and should allow auto unlocking in most cases.
This commit is contained in:
@@ -98,6 +98,18 @@
|
||||
</tp:docstring>
|
||||
</property>
|
||||
|
||||
<property name="DeviceIdentifier" type="s" access="read">
|
||||
<tp:docstring>
|
||||
A best-effort device identifier based on various device information like
|
||||
model name, firmware revision, USB/PCI/PCMCIA IDs, and other properties.
|
||||
This ID is not guaranteed to be unique and may be shared between
|
||||
identical devices with the same firmware, but is intended to be
|
||||
"unique enough" for use as a casual device identifier for various
|
||||
user experience operations. This is not the device's IMEI or ESN since
|
||||
those may not be available before unlocking the device via a PIN.
|
||||
</tp:docstring>
|
||||
</property>
|
||||
|
||||
<property name="MasterDevice" type="s" access="read">
|
||||
<tp:docstring>
|
||||
The physical modem device reference (ie, USB, PCI, PCMCIA device), which
|
||||
|
@@ -162,6 +162,47 @@ initial_esn_check (MMGenericCdma *self)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_info_cb (MMModem *modem,
|
||||
const char *manufacturer,
|
||||
const char *model,
|
||||
const char *version,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* Base class handles saving the info for us */
|
||||
if (modem)
|
||||
mm_serial_port_close (MM_SERIAL_PORT (MM_GENERIC_CDMA_GET_PRIVATE (modem)->primary));
|
||||
}
|
||||
|
||||
static void
|
||||
initial_info_check (MMGenericCdma *self)
|
||||
{
|
||||
GError *error = NULL;
|
||||
MMGenericCdmaPrivate *priv;
|
||||
|
||||
g_return_if_fail (MM_IS_GENERIC_CDMA (self));
|
||||
priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
|
||||
|
||||
g_return_if_fail (priv->primary != NULL);
|
||||
|
||||
if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) {
|
||||
/* Make sure echoing is off */
|
||||
mm_at_serial_port_queue_command (priv->primary, "E0", 3, NULL, NULL);
|
||||
mm_modem_base_get_card_info (MM_MODEM_BASE (self),
|
||||
priv->primary,
|
||||
NULL,
|
||||
get_info_cb,
|
||||
NULL);
|
||||
} 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)
|
||||
{
|
||||
@@ -215,6 +256,9 @@ mm_generic_cdma_grab_port (MMGenericCdma *self,
|
||||
g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE);
|
||||
}
|
||||
|
||||
/* Get the modem's general info */
|
||||
initial_info_check (self);
|
||||
|
||||
/* Get modem's ESN number */
|
||||
initial_esn_check (self);
|
||||
|
||||
|
@@ -326,6 +326,19 @@ get_imei_cb (MMModem *modem,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_info_cb (MMModem *modem,
|
||||
const char *manufacturer,
|
||||
const char *model,
|
||||
const char *version,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* Base class handles saving the info for us */
|
||||
if (modem)
|
||||
mm_serial_port_close (MM_SERIAL_PORT (MM_GENERIC_GSM_GET_PRIVATE (modem)->primary));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static MMModemGsmNetworkRegStatus
|
||||
@@ -510,6 +523,34 @@ initial_imei_check (MMGenericGsm *self)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
initial_info_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)) {
|
||||
/* Make sure echoing is off */
|
||||
mm_at_serial_port_queue_command (priv->primary, "E0", 3, NULL, NULL);
|
||||
mm_modem_base_get_card_info (MM_MODEM_BASE (self),
|
||||
priv->primary,
|
||||
NULL,
|
||||
get_info_cb,
|
||||
NULL);
|
||||
} 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)
|
||||
{
|
||||
@@ -560,12 +601,15 @@ mm_generic_gsm_grab_port (MMGenericGsm *self,
|
||||
g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE);
|
||||
}
|
||||
|
||||
/* Get modem's initial lock/unlock state */
|
||||
initial_pin_check (self);
|
||||
/* Get the modem's general info */
|
||||
initial_info_check (self);
|
||||
|
||||
/* Get modem's IMEI number */
|
||||
initial_imei_check (self);
|
||||
|
||||
/* Get modem's initial lock/unlock state */
|
||||
initial_pin_check (self);
|
||||
|
||||
} else if (ptype == MM_PORT_TYPE_SECONDARY)
|
||||
priv->secondary = MM_AT_SERIAL_PORT (port);
|
||||
} else if (MM_IS_QCDM_SERIAL_PORT (port)) {
|
||||
@@ -937,17 +981,6 @@ get_allowed_mode_done (MMModem *modem,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_enable_info_done (MMModem *modem,
|
||||
const char *manufacturer,
|
||||
const char *model,
|
||||
const char *version,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* Modem base class handles the response for us */
|
||||
}
|
||||
|
||||
void
|
||||
mm_generic_gsm_enable_complete (MMGenericGsm *self,
|
||||
GError *error,
|
||||
@@ -985,9 +1018,6 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self,
|
||||
/* Try to enable XON/XOFF flow control */
|
||||
mm_at_serial_port_queue_command (priv->primary, "+IFC=1,1", 3, NULL, NULL);
|
||||
|
||||
/* Grab device info right away */
|
||||
mm_modem_get_info (MM_MODEM (self), get_enable_info_done, NULL);
|
||||
|
||||
/* Get allowed mode */
|
||||
if (MM_GENERIC_GSM_GET_CLASS (self)->get_allowed_mode)
|
||||
MM_GENERIC_GSM_GET_CLASS (self)->get_allowed_mode (self, get_allowed_mode_done, NULL);
|
||||
|
@@ -14,6 +14,7 @@
|
||||
* Copyright (C) 2009 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@@ -43,6 +44,7 @@ typedef struct {
|
||||
char *plugin;
|
||||
char *device;
|
||||
char *equipment_ident;
|
||||
char *device_ident;
|
||||
char *unlock_required;
|
||||
guint32 unlock_retries;
|
||||
guint32 ip_method;
|
||||
@@ -52,6 +54,9 @@ typedef struct {
|
||||
char *manf;
|
||||
char *model;
|
||||
char *revision;
|
||||
char *ati;
|
||||
char *ati1;
|
||||
char *gsn;
|
||||
|
||||
MMAuthProvider *authp;
|
||||
|
||||
@@ -396,7 +401,7 @@ card_info_cache_invoke (MMCallbackInfo *info)
|
||||
MMModemBase *self = MM_MODEM_BASE (info->modem);
|
||||
MMModemBasePrivate *priv = MM_MODEM_BASE_GET_PRIVATE (self);
|
||||
MMModemInfoFn callback = (MMModemInfoFn) info->callback;
|
||||
const char *manf, *cmanf, *model, *cmodel, *rev, *crev;
|
||||
const char *manf, *cmanf, *model, *cmodel, *rev, *crev, *ati, *ati1, *gsn, *cgsn;
|
||||
|
||||
manf = mm_callback_info_get_data (info, "card-info-manf");
|
||||
cmanf = mm_callback_info_get_data (info, "card-info-c-manf");
|
||||
@@ -415,6 +420,32 @@ card_info_cache_invoke (MMCallbackInfo *info)
|
||||
g_free (priv->revision);
|
||||
priv->revision = g_strdup (crev ? crev : rev);
|
||||
|
||||
ati = mm_callback_info_get_data (info, "card-info-ati");
|
||||
g_free (priv->ati);
|
||||
priv->ati = g_strdup (ati);
|
||||
|
||||
ati1 = mm_callback_info_get_data (info, "card-info-ati1");
|
||||
g_free (priv->ati1);
|
||||
priv->ati1 = g_strdup (ati1);
|
||||
|
||||
gsn = mm_callback_info_get_data (info, "card-info-gsn");
|
||||
cgsn = mm_callback_info_get_data (info, "card-info-c-gsn");
|
||||
g_free (priv->gsn);
|
||||
priv->gsn = g_strdup (cgsn ? cgsn : gsn);
|
||||
|
||||
/* Build up the device identifier */
|
||||
g_free (priv->device_ident);
|
||||
priv->device_ident = mm_create_device_identifier (NULL,
|
||||
NULL,
|
||||
priv->ati,
|
||||
priv->ati1,
|
||||
priv->gsn,
|
||||
priv->revision,
|
||||
priv->model,
|
||||
priv->manf,
|
||||
mm_options_debug ());
|
||||
g_object_notify (G_OBJECT (self), MM_MODEM_DEVICE_IDENTIFIER);
|
||||
|
||||
callback (info->modem, priv->manf, priv->model, priv->revision, info->error, info->user_data);
|
||||
}
|
||||
|
||||
@@ -425,10 +456,11 @@ info_item_done (MMCallbackInfo *info,
|
||||
const char *tag,
|
||||
const char *desc)
|
||||
{
|
||||
const char *p;
|
||||
const char *p = response->str;
|
||||
|
||||
if (!error) {
|
||||
p = mm_strip_tag (response->str, tag);
|
||||
if (tag)
|
||||
p = mm_strip_tag (response->str, tag);
|
||||
mm_callback_info_set_data (info, desc, strlen (p) ? g_strdup (p) : NULL, g_free);
|
||||
}
|
||||
|
||||
@@ -453,6 +485,11 @@ GET_INFO_RESP_FN(get_c_revision_done, "+CGMR:", "card-info-c-revision")
|
||||
GET_INFO_RESP_FN(get_c_model_done, "+CGMM:", "card-info-c-model")
|
||||
GET_INFO_RESP_FN(get_c_manf_done, "+CGMI:", "card-info-c-manf")
|
||||
|
||||
GET_INFO_RESP_FN(get_ati_done, NULL, "card-info-ati")
|
||||
GET_INFO_RESP_FN(get_ati1_done, NULL, "card-info-ati1")
|
||||
GET_INFO_RESP_FN(get_gsn_done, "+GSN:", "card-info-gsn")
|
||||
GET_INFO_RESP_FN(get_cgsn_done, "+CGSN:", "card-info-c-gsn")
|
||||
|
||||
void
|
||||
mm_modem_base_get_card_info (MMModemBase *self,
|
||||
MMAtSerialPort *port,
|
||||
@@ -462,7 +499,6 @@ mm_modem_base_get_card_info (MMModemBase *self,
|
||||
{
|
||||
MMModemBasePrivate *priv;
|
||||
MMCallbackInfo *info;
|
||||
MMModemState state;
|
||||
gboolean cached = FALSE;
|
||||
GError *error = port_error;
|
||||
|
||||
@@ -479,16 +515,8 @@ mm_modem_base_get_card_info (MMModemBase *self,
|
||||
*/
|
||||
if (priv->manf || priv->model || priv->revision)
|
||||
cached = TRUE;
|
||||
else {
|
||||
state = mm_modem_get_state (MM_MODEM (self));
|
||||
|
||||
if (port_error)
|
||||
error = g_error_copy (port_error);
|
||||
else if (state < MM_MODEM_STATE_ENABLING) {
|
||||
error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
|
||||
"The modem is not enabled.");
|
||||
}
|
||||
}
|
||||
else if (port_error)
|
||||
error = g_error_copy (port_error);
|
||||
|
||||
/* If we have cached info or an error, don't hit up the card */
|
||||
if (cached || error) {
|
||||
@@ -507,13 +535,19 @@ mm_modem_base_get_card_info (MMModemBase *self,
|
||||
G_CALLBACK (callback),
|
||||
user_data);
|
||||
|
||||
mm_callback_info_chain_start (info, 6);
|
||||
mm_callback_info_chain_start (info, 10);
|
||||
|
||||
mm_at_serial_port_queue_command_cached (port, "+GMI", 3, get_manf_done, info);
|
||||
mm_at_serial_port_queue_command_cached (port, "+GMM", 3, get_model_done, info);
|
||||
mm_at_serial_port_queue_command_cached (port, "+GMR", 3, get_revision_done, info);
|
||||
mm_at_serial_port_queue_command_cached (port, "+CGMI", 3, get_c_manf_done, info);
|
||||
mm_at_serial_port_queue_command_cached (port, "+CGMM", 3, get_c_model_done, info);
|
||||
mm_at_serial_port_queue_command_cached (port, "+CGMR", 3, get_c_revision_done, info);
|
||||
|
||||
mm_at_serial_port_queue_command_cached (port, "I", 3, get_ati_done, info);
|
||||
mm_at_serial_port_queue_command_cached (port, "I1", 3, get_ati1_done, info);
|
||||
mm_at_serial_port_queue_command_cached (port, "+GSN", 3, get_gsn_done, info);
|
||||
mm_at_serial_port_queue_command_cached (port, "+CGSN", 3, get_cgsn_done, info);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -573,6 +607,10 @@ mm_modem_base_init (MMModemBase *self)
|
||||
MM_MODEM_EQUIPMENT_IDENTIFIER,
|
||||
NULL,
|
||||
MM_MODEM_DBUS_INTERFACE);
|
||||
mm_properties_changed_signal_register_property (G_OBJECT (self),
|
||||
MM_MODEM_DEVICE_IDENTIFIER,
|
||||
NULL,
|
||||
MM_MODEM_DBUS_INTERFACE);
|
||||
mm_properties_changed_signal_register_property (G_OBJECT (self),
|
||||
MM_MODEM_UNLOCK_REQUIRED,
|
||||
NULL,
|
||||
@@ -630,6 +668,7 @@ set_property (GObject *object, guint prop_id,
|
||||
case MM_MODEM_PROP_TYPE:
|
||||
case MM_MODEM_PROP_ENABLED:
|
||||
case MM_MODEM_PROP_EQUIPMENT_IDENTIFIER:
|
||||
case MM_MODEM_PROP_DEVICE_IDENTIFIER:
|
||||
case MM_MODEM_PROP_UNLOCK_REQUIRED:
|
||||
case MM_MODEM_PROP_UNLOCK_RETRIES:
|
||||
break;
|
||||
@@ -676,6 +715,9 @@ get_property (GObject *object, guint prop_id,
|
||||
case MM_MODEM_PROP_EQUIPMENT_IDENTIFIER:
|
||||
g_value_set_string (value, priv->equipment_ident);
|
||||
break;
|
||||
case MM_MODEM_PROP_DEVICE_IDENTIFIER:
|
||||
g_value_set_string (value, priv->device_ident);
|
||||
break;
|
||||
case MM_MODEM_PROP_UNLOCK_REQUIRED:
|
||||
g_value_set_string (value, priv->unlock_required);
|
||||
break;
|
||||
@@ -701,7 +743,14 @@ finalize (GObject *object)
|
||||
g_free (priv->plugin);
|
||||
g_free (priv->device);
|
||||
g_free (priv->equipment_ident);
|
||||
g_free (priv->device_ident);
|
||||
g_free (priv->unlock_required);
|
||||
g_free (priv->manf);
|
||||
g_free (priv->model);
|
||||
g_free (priv->revision);
|
||||
g_free (priv->ati);
|
||||
g_free (priv->ati1);
|
||||
g_free (priv->gsn);
|
||||
|
||||
G_OBJECT_CLASS (mm_modem_base_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -758,6 +807,10 @@ mm_modem_base_class_init (MMModemBaseClass *klass)
|
||||
MM_MODEM_PROP_EQUIPMENT_IDENTIFIER,
|
||||
MM_MODEM_EQUIPMENT_IDENTIFIER);
|
||||
|
||||
g_object_class_override_property (object_class,
|
||||
MM_MODEM_PROP_DEVICE_IDENTIFIER,
|
||||
MM_MODEM_DEVICE_IDENTIFIER);
|
||||
|
||||
g_object_class_override_property (object_class,
|
||||
MM_MODEM_PROP_UNLOCK_REQUIRED,
|
||||
MM_MODEM_UNLOCK_REQUIRED);
|
||||
|
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <ctype.h>
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
@@ -803,3 +804,67 @@ mm_gsm_string_to_access_tech (const char *string)
|
||||
return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
char *
|
||||
mm_create_device_identifier (const char *vid,
|
||||
const char *pid,
|
||||
const char *ati,
|
||||
const char *ati1,
|
||||
const char *gsn,
|
||||
const char *revision,
|
||||
const char *model,
|
||||
const char *manf,
|
||||
gboolean debug)
|
||||
{
|
||||
GString *devid;
|
||||
GChecksum *sum;
|
||||
char *p, *ret = NULL, *j = NULL, *dbg = NULL;
|
||||
|
||||
/* Build up the device identifier */
|
||||
devid = g_string_sized_new (50);
|
||||
if (ati)
|
||||
g_string_append (devid, ati);
|
||||
if (ati1) {
|
||||
/* Only append "ATI1" if it's differnet than "ATI" */
|
||||
if (!ati || (strcmp (ati, ati1) != 0))
|
||||
g_string_append (devid, ati1);
|
||||
}
|
||||
if (gsn)
|
||||
g_string_append (devid, gsn);
|
||||
if (revision)
|
||||
g_string_append (devid, revision);
|
||||
if (model)
|
||||
g_string_append (devid, model);
|
||||
if (manf)
|
||||
g_string_append (devid, manf);
|
||||
|
||||
if (!strlen (devid->str))
|
||||
return NULL;
|
||||
|
||||
p = devid->str;
|
||||
if (debug)
|
||||
j = dbg = g_malloc0 (strlen (devid->str) + 1);
|
||||
|
||||
sum = g_checksum_new (G_CHECKSUM_SHA1);
|
||||
while (*p) {
|
||||
/* Strip spaces and linebreaks */
|
||||
if (!isblank (*p) && !isspace (*p) && isascii (*p)) {
|
||||
g_checksum_update (sum, (const guchar *) p, 1);
|
||||
if (dbg)
|
||||
*j++ = *p;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
ret = g_strdup (g_checksum_get_string (sum));
|
||||
g_checksum_free (sum);
|
||||
|
||||
if (dbg) {
|
||||
g_debug ("Device ID source '%s'", dbg);
|
||||
g_debug ("Device ID '%s'", ret);
|
||||
g_free (dbg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@@ -59,5 +59,15 @@ gboolean mm_gsm_parse_cscs_support_response (const char *reply,
|
||||
|
||||
MMModemGsmAccessTech mm_gsm_string_to_access_tech (const char *string);
|
||||
|
||||
char *mm_create_device_identifier (const char *vid,
|
||||
const char *pid,
|
||||
const char *ati,
|
||||
const char *ati1,
|
||||
const char *gsn,
|
||||
const char *revision,
|
||||
const char *model,
|
||||
const char *manf,
|
||||
gboolean debug);
|
||||
|
||||
#endif /* MM_MODEM_HELPERS_H */
|
||||
|
||||
|
@@ -868,6 +868,14 @@ mm_modem_init (gpointer g_iface)
|
||||
NULL,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
g_object_interface_install_property
|
||||
(g_iface,
|
||||
g_param_spec_string (MM_MODEM_DEVICE_IDENTIFIER,
|
||||
"DeviceIdentifier",
|
||||
"A best-effort identifer of the device",
|
||||
NULL,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
g_object_interface_install_property
|
||||
(g_iface,
|
||||
g_param_spec_string (MM_MODEM_UNLOCK_REQUIRED,
|
||||
|
@@ -59,6 +59,7 @@ typedef enum {
|
||||
#define MM_MODEM_IP_METHOD "ip-method"
|
||||
#define MM_MODEM_ENABLED "enabled"
|
||||
#define MM_MODEM_EQUIPMENT_IDENTIFIER "equipment-identifier"
|
||||
#define MM_MODEM_DEVICE_IDENTIFIER "device-identifier"
|
||||
#define MM_MODEM_UNLOCK_REQUIRED "unlock-required"
|
||||
#define MM_MODEM_UNLOCK_RETRIES "unlock-retries"
|
||||
#define MM_MODEM_VALID "valid" /* not exported */
|
||||
@@ -87,7 +88,8 @@ typedef enum {
|
||||
MM_MODEM_PROP_ENABLED,
|
||||
MM_MODEM_PROP_EQUIPMENT_IDENTIFIER,
|
||||
MM_MODEM_PROP_UNLOCK_REQUIRED,
|
||||
MM_MODEM_PROP_UNLOCK_RETRIES
|
||||
MM_MODEM_PROP_UNLOCK_RETRIES,
|
||||
MM_MODEM_PROP_DEVICE_IDENTIFIER
|
||||
} MMModemProp;
|
||||
|
||||
typedef struct _MMModem MMModem;
|
||||
|
@@ -232,6 +232,7 @@ elif mtype == 2:
|
||||
print "Driver: '%s'" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'Driver'))
|
||||
print "Modem device: '%s'" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'MasterDevice'))
|
||||
print "Data device: '%s'" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'Device'))
|
||||
print "Device ID: '%s'" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'DeviceIdentifier'))
|
||||
print ""
|
||||
|
||||
modem = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM)
|
||||
|
Reference in New Issue
Block a user