diff options
-rw-r--r-- | introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml | 6 | ||||
-rw-r--r-- | introspection/org.freedesktop.ModemManager.Modem.Gsm.xml | 37 | ||||
-rw-r--r-- | src/mm-generic-gsm.c | 214 | ||||
-rw-r--r-- | src/mm-generic-gsm.h | 3 | ||||
-rw-r--r-- | src/mm-modem-gsm-card.c | 10 | ||||
-rw-r--r-- | src/mm-modem-gsm-card.h | 3 | ||||
-rw-r--r-- | src/mm-modem-helpers.c | 145 | ||||
-rw-r--r-- | src/mm-modem-helpers.h | 7 |
8 files changed, 357 insertions, 68 deletions
diff --git a/introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml index 03c8a9fb..9159052b 100644 --- a/introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml +++ b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml @@ -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> diff --git a/introspection/org.freedesktop.ModemManager.Modem.Gsm.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.xml index 1abf9155..354ce4a3 100644 --- a/introspection/org.freedesktop.ModemManager.Modem.Gsm.xml +++ b/introspection/org.freedesktop.ModemManager.Modem.Gsm.xml @@ -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> 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, |