diff --git a/include/NetworkManager.h b/include/NetworkManager.h index b25cfbc2ba..ce2a81b228 100644 --- a/include/NetworkManager.h +++ b/include/NetworkManager.h @@ -366,6 +366,9 @@ typedef enum { /* The supplicant is now available */ NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, + /* The modem could not be found */ + NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND, + /* Unused */ NM_DEVICE_STATE_REASON_LAST = 0xFFFF } NMDeviceStateReason; diff --git a/introspection/nm-device.xml b/introspection/nm-device.xml index c23b596c4b..49b77a5ba0 100644 --- a/introspection/nm-device.xml +++ b/introspection/nm-device.xml @@ -392,7 +392,12 @@ The 802.1x supplicant is now available. - + + + The modem could not be found. + + + diff --git a/marshallers/nm-marshal.list b/marshallers/nm-marshal.list index 36e0fbe6d0..e19f8befcf 100644 --- a/marshallers/nm-marshal.list +++ b/marshallers/nm-marshal.list @@ -21,6 +21,9 @@ VOID:OBJECT,OBJECT,ENUM VOID:POINTER,STRING VOID:STRING,BOXED BOOLEAN:POINTER,STRING,BOOLEAN,UINT,STRING,STRING +VOID:STRING,BOOLEAN,UINT,STRING,STRING BOOLEAN:VOID VOID:STRING,BOOLEAN +VOID:STRING,OBJECT,POINTER +VOID:BOOLEAN,UINT diff --git a/src/Makefile.am b/src/Makefile.am index db255ca357..a1505002bf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -76,6 +76,10 @@ NetworkManager_SOURCES = \ nm-device-olpc-mesh.h \ nm-device-bt.c \ nm-device-bt.h \ + nm-device-cdma.c \ + nm-device-cdma.h \ + nm-device-gsm.c \ + nm-device-gsm.h \ NetworkManagerAP.c \ NetworkManagerAP.h \ nm-dbus-manager.h \ @@ -155,6 +159,12 @@ nm-dhcp4-config-glue.h: $(top_srcdir)/introspection/nm-dhcp4-config.xml nm-dhcp6-config-glue.h: $(top_srcdir)/introspection/nm-dhcp6-config.xml dbus-binding-tool --prefix=nm_dhcp6_config --mode=glib-server --output=$@ $< +nm-device-cdma-glue.h: $(top_srcdir)/introspection/nm-device-cdma.xml + dbus-binding-tool --prefix=nm_device_cdma --mode=glib-server --output=$@ $< + +nm-device-gsm-glue.h: $(top_srcdir)/introspection/nm-device-gsm.xml + dbus-binding-tool --prefix=nm_device_gsm --mode=glib-server --output=$@ $< + BUILT_SOURCES = \ nm-access-point-glue.h \ nm-manager-glue.h \ @@ -163,6 +173,8 @@ BUILT_SOURCES = \ nm-device-wifi-glue.h \ nm-device-olpc-mesh-glue.h \ nm-device-bt-glue.h \ + nm-device-cdma-glue.h \ + nm-device-gsm-glue.h \ nm-ip4-config-glue.h \ nm-ip6-config-glue.h \ nm-active-connection-glue.h \ diff --git a/src/modem-manager/Makefile.am b/src/modem-manager/Makefile.am index fef879ac44..932a041c0d 100644 --- a/src/modem-manager/Makefile.am +++ b/src/modem-manager/Makefile.am @@ -7,12 +7,12 @@ INCLUDES = \ noinst_LTLIBRARIES = libmodem-manager.la libmodem_manager_la_SOURCES = \ + nm-modem.c \ + nm-modem.h \ nm-modem-cdma.c \ nm-modem-cdma.h \ nm-modem-gsm.c \ nm-modem-gsm.h \ - nm-modem.c \ - nm-modem.h \ nm-modem-manager.h \ nm-modem-manager.c \ nm-modem-types.h @@ -24,18 +24,10 @@ libmodem_manager_la_LIBADD = \ $(top_builddir)/marshallers/libmarshallers.la \ $(DBUS_LIBS) -nm-device-cdma-glue.h: $(top_srcdir)/introspection/nm-device-cdma.xml - dbus-binding-tool --prefix=nm_device_cdma --mode=glib-server --output=$@ $< - -nm-device-gsm-glue.h: $(top_srcdir)/introspection/nm-device-gsm.xml - dbus-binding-tool --prefix=nm_device_gsm --mode=glib-server --output=$@ $< - nm-serial-device-glue.h: $(top_srcdir)/introspection/nm-device-serial.xml dbus-binding-tool --prefix=nm_serial_device --mode=glib-server --output=$@ $< BUILT_SOURCES = \ - nm-device-cdma-glue.h \ - nm-device-gsm-glue.h \ nm-serial-device-glue.h CLEANFILES = $(BUILT_SOURCES) diff --git a/src/modem-manager/nm-modem-cdma.c b/src/modem-manager/nm-modem-cdma.c index 5e8405bcf4..f2a04dc076 100644 --- a/src/modem-manager/nm-modem-cdma.c +++ b/src/modem-manager/nm-modem-cdma.c @@ -24,18 +24,23 @@ #include "nm-dbus-glib-types.h" #include "nm-modem-cdma.h" #include "nm-modem-types.h" -#include "nm-device-interface.h" -#include "nm-device-private.h" +#include "nm-device.h" #include "nm-dbus-manager.h" #include "nm-setting-connection.h" #include "nm-setting-cdma.h" #include "nm-utils.h" #include "NetworkManagerUtils.h" -#include "nm-device-cdma-glue.h" - G_DEFINE_TYPE (NMModemCdma, nm_modem_cdma, NM_TYPE_MODEM) +#define NM_MODEM_CDMA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM_CDMA, NMModemCdmaPrivate)) + +typedef struct { + DBusGProxyCall *call; + + GHashTable *connect_properties; +} NMModemCdmaPrivate; + typedef enum { NM_CDMA_ERROR_CONNECTION_NOT_CDMA = 0, @@ -79,43 +84,77 @@ nm_cdma_error_get_type (void) } -NMDevice * +NMModem * nm_modem_cdma_new (const char *path, const char *device, const char *data_device, - const char *driver) + guint32 ip_method) { g_return_val_if_fail (path != NULL, NULL); g_return_val_if_fail (device != NULL, NULL); g_return_val_if_fail (data_device != NULL, NULL); - g_return_val_if_fail (driver != NULL, NULL); - return (NMDevice *) g_object_new (NM_TYPE_MODEM_CDMA, - NM_DEVICE_INTERFACE_UDI, path, - NM_DEVICE_INTERFACE_IFACE, data_device, - NM_DEVICE_INTERFACE_DRIVER, driver, - NM_MODEM_PATH, path, - NM_MODEM_DEVICE, device, - NM_DEVICE_INTERFACE_TYPE_DESC, "CDMA", - NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_CDMA, - NULL); + return (NMModem *) g_object_new (NM_TYPE_MODEM_CDMA, + NM_MODEM_PATH, path, + NM_MODEM_DEVICE, device, + NM_MODEM_IFACE, data_device, + NM_MODEM_IP_METHOD, ip_method, + NULL); } static void -stage1_prepare_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +stage1_prepare_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) { - NMDevice *device = NM_DEVICE (user_data); + NMModemCdma *self = NM_MODEM_CDMA (user_data); + NMModemCdmaPrivate *priv = NM_MODEM_CDMA_GET_PRIVATE (self); GError *error = NULL; - dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID); - if (!error) - nm_device_activate_schedule_stage2_device_config (device); + priv->call = NULL; + + if (priv->connect_properties) { + g_hash_table_destroy (priv->connect_properties); + priv->connect_properties = NULL; + } + + if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, TRUE, NM_DEVICE_STATE_REASON_NONE); else { - nm_warning ("CDMA modem connection failed: (%d) %s", + nm_warning ("CDMA connection failed: (%d) %s", error ? error->code : -1, error && error->message ? error->message : "(unknown)"); g_error_free (error); - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NONE); + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_NONE); + } +} + +static void +do_connect (NMModemCdma *self) +{ + NMModemCdmaPrivate *priv = NM_MODEM_CDMA_GET_PRIVATE (self); + DBusGProxy *proxy; + + proxy = nm_modem_get_proxy (NM_MODEM (self), MM_DBUS_INTERFACE_MODEM_SIMPLE); + priv->call = dbus_g_proxy_begin_call_with_timeout (proxy, + "Connect", stage1_prepare_done, + self, NULL, 120000, + DBUS_TYPE_G_MAP_OF_VARIANT, priv->connect_properties, + G_TYPE_INVALID); +} + +static void +stage1_enable_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +{ + NMModemCdma *self = NM_MODEM_CDMA (user_data); + GError *error = NULL; + + if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) + do_connect (self); + else { + nm_warning ("CDMA modem enable failed: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_error_free (error); + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); } } @@ -136,61 +175,48 @@ create_connect_properties (NMConnection *connection) return properties; } -static void -do_connect (NMModem *modem) +static NMActStageReturn +real_act_stage1_prepare (NMModem *modem, + NMActRequest *req, + GPtrArray **out_hints, + const char **out_setting_name, + NMDeviceStateReason *reason) { + NMModemCdma *self = NM_MODEM_CDMA (modem); + NMModemCdmaPrivate *priv = NM_MODEM_CDMA_GET_PRIVATE (self); NMConnection *connection; - GHashTable *properties; - connection = nm_act_request_get_connection (nm_device_get_act_request (NM_DEVICE (modem))); + connection = nm_act_request_get_connection (req); g_assert (connection); - properties = create_connect_properties (connection); - dbus_g_proxy_begin_call_with_timeout (nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM_SIMPLE), - "Connect", stage1_prepare_done, - modem, NULL, 120000, - DBUS_TYPE_G_MAP_OF_VARIANT, properties, - G_TYPE_INVALID); - g_hash_table_destroy (properties); -} + *out_setting_name = nm_connection_need_secrets (connection, out_hints); + if (!*out_setting_name) { + gboolean enabled = nm_modem_get_mm_enabled (modem); + DBusGProxy *proxy; -static void -stage1_enable_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - GError *error = NULL; + if (priv->connect_properties) + g_hash_table_destroy (priv->connect_properties); + priv->connect_properties = create_connect_properties (connection); - if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) - do_connect (NM_MODEM (device)); - else { - nm_warning ("CDMA modem enable failed: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_error_free (error); - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NONE); - } -} - -static NMActStageReturn -real_act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) -{ - gboolean enabled = nm_modem_get_mm_enabled (NM_MODEM (device)); - - if (enabled) - do_connect (NM_MODEM (device)); - else { - dbus_g_proxy_begin_call_with_timeout (nm_modem_get_proxy (NM_MODEM (device), MM_DBUS_INTERFACE_MODEM), - "Enable", stage1_enable_done, - device, NULL, 20000, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_INVALID); + if (enabled) + do_connect (self); + else { + proxy = nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM); + dbus_g_proxy_begin_call_with_timeout (proxy, + "Enable", stage1_enable_done, + modem, NULL, 20000, + G_TYPE_BOOLEAN, TRUE, + G_TYPE_INVALID); + } + } else { + /* NMModem will handle requesting secrets... */ } return NM_ACT_STAGE_RETURN_POSTPONE; } static NMConnection * -real_get_best_auto_connection (NMDevice *dev, +real_get_best_auto_connection (NMModem *modem, GSList *connections, char **specific_object) { @@ -214,71 +240,8 @@ real_get_best_auto_connection (NMDevice *dev, return NULL; } -static void -real_connection_secrets_updated (NMDevice *dev, - NMConnection *connection, - GSList *updated_settings, - RequestSecretsCaller caller) -{ - NMActRequest *req; - gboolean found = FALSE; - GSList *iter; - - g_return_if_fail (IS_ACTIVATING_STATE (nm_device_get_state (dev))); - - if (caller == SECRETS_CALLER_PPP) { - NMPPPManager *ppp_manager; - NMSettingCdma *s_cdma = NULL; - - ppp_manager = nm_modem_get_ppp_manager (NM_MODEM (dev)); - g_return_if_fail (ppp_manager != NULL); - - s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA); - if (!s_cdma) { - /* Shouldn't ever happen */ - nm_ppp_manager_update_secrets (ppp_manager, - nm_device_get_iface (dev), - NULL, - NULL, - "missing CDMA setting; no secrets could be found."); - } else { - const char *username = nm_setting_cdma_get_username (s_cdma); - const char *password = nm_setting_cdma_get_password (s_cdma); - - nm_ppp_manager_update_secrets (ppp_manager, - nm_device_get_iface (dev), - username ? username : "", - password ? password : "", - NULL); - } - return; - } - - g_return_if_fail (caller == SECRETS_CALLER_CDMA); - g_return_if_fail (nm_device_get_state (dev) == NM_DEVICE_STATE_NEED_AUTH); - - for (iter = updated_settings; iter; iter = g_slist_next (iter)) { - const char *setting_name = (const char *) iter->data; - - if (!strcmp (setting_name, NM_SETTING_CDMA_SETTING_NAME)) - found = TRUE; - else - nm_warning ("Ignoring updated secrets for setting '%s'.", setting_name); - } - - if (!found) - return; - - req = nm_device_get_act_request (dev); - g_assert (req); - - g_return_if_fail (nm_act_request_get_connection (req) == connection); - - nm_device_activate_schedule_stage1_device_prepare (dev); -} - static gboolean -real_check_connection_compatible (NMDevice *device, +real_check_connection_compatible (NMModem *modem, NMConnection *connection, GError **error) { @@ -306,15 +269,46 @@ real_check_connection_compatible (NMDevice *device, return TRUE; } -static const char * -real_get_ppp_name (NMModem *device, NMConnection *connection) +static gboolean +real_get_user_pass (NMModem *modem, + NMConnection *connection, + const char **user, + const char **pass) { NMSettingCdma *s_cdma; s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA); - g_assert (s_cdma); + if (!s_cdma) + return FALSE; - return nm_setting_cdma_get_username (s_cdma); + if (user) + *user = nm_setting_cdma_get_username (s_cdma); + if (pass) + *pass = nm_setting_cdma_get_password (s_cdma); + + return TRUE; +} + +static const char * +real_get_setting_name (NMModem *modem) +{ + return NM_SETTING_CDMA_SETTING_NAME; +} + +static void +real_deactivate_quickly (NMModem *modem, NMDevice *device) +{ + NMModemCdmaPrivate *priv = NM_MODEM_CDMA_GET_PRIVATE (modem); + + if (priv->call) { + DBusGProxy *proxy; + + proxy = nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM_SIMPLE); + dbus_g_proxy_cancel_call (proxy, priv->call); + priv->call = NULL; + } + + NM_MODEM_CLASS (nm_modem_cdma_parent_class)->deactivate_quickly (modem, device); } /*****************************************************************************/ @@ -324,22 +318,34 @@ nm_modem_cdma_init (NMModemCdma *self) { } +static void +dispose (GObject *object) +{ + NMModemCdma *self = NM_MODEM_CDMA (object); + NMModemCdmaPrivate *priv = NM_MODEM_CDMA_GET_PRIVATE (self); + + if (priv->connect_properties) + g_hash_table_destroy (priv->connect_properties); + + G_OBJECT_CLASS (nm_modem_cdma_parent_class)->dispose (object); +} + static void nm_modem_cdma_class_init (NMModemCdmaClass *klass) { - NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); NMModemClass *modem_class = NM_MODEM_CLASS (klass); + g_type_class_add_private (object_class, sizeof (NMModemCdmaPrivate)); + /* Virtual methods */ - device_class->get_best_auto_connection = real_get_best_auto_connection; - device_class->connection_secrets_updated = real_connection_secrets_updated; - device_class->act_stage1_prepare = real_act_stage1_prepare; - device_class->check_connection_compatible = real_check_connection_compatible; - - modem_class->get_ppp_name = real_get_ppp_name; - - dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_cdma_object_info); + object_class->dispose = dispose; + modem_class->get_user_pass = real_get_user_pass; + modem_class->get_setting_name = real_get_setting_name; + modem_class->get_best_auto_connection = real_get_best_auto_connection; + modem_class->check_connection_compatible = real_check_connection_compatible; + modem_class->act_stage1_prepare = real_act_stage1_prepare; + modem_class->deactivate_quickly = real_deactivate_quickly; dbus_g_error_domain_register (NM_CDMA_ERROR, NULL, NM_TYPE_CDMA_ERROR); } diff --git a/src/modem-manager/nm-modem-cdma.h b/src/modem-manager/nm-modem-cdma.h index 7c98ab287a..0abe4e0cfa 100644 --- a/src/modem-manager/nm-modem-cdma.h +++ b/src/modem-manager/nm-modem-cdma.h @@ -46,10 +46,10 @@ typedef struct { GType nm_modem_cdma_get_type (void); -NMDevice *nm_modem_cdma_new (const char *path, - const char *device, - const char *data_device, - const char *driver); +NMModem *nm_modem_cdma_new (const char *path, + const char *device, + const char *data_device, + guint32 ip_method); G_END_DECLS diff --git a/src/modem-manager/nm-modem-gsm.c b/src/modem-manager/nm-modem-gsm.c index fcc811fc4c..a7bd361c0d 100644 --- a/src/modem-manager/nm-modem-gsm.c +++ b/src/modem-manager/nm-modem-gsm.c @@ -22,16 +22,13 @@ #include #include "nm-dbus-glib-types.h" #include "nm-modem-gsm.h" -#include "nm-device-private.h" -#include "nm-device-interface.h" +#include "nm-device.h" #include "nm-setting-connection.h" #include "nm-setting-gsm.h" #include "nm-modem-types.h" #include "nm-utils.h" #include "NetworkManagerUtils.h" -#include "nm-device-gsm-glue.h" - typedef enum { MM_MODEM_GSM_MODE_UNKNOWN = 0x00000000, MM_MODEM_GSM_MODE_ANY = 0x00000001, @@ -50,11 +47,17 @@ typedef enum { } MMModemGsmMode; -#define GSM_SECRETS_TRIES "gsm-secrets-tries" -#define PIN_TRIES "pin-tries" - G_DEFINE_TYPE (NMModemGsm, nm_modem_gsm, NM_TYPE_MODEM) +#define NM_MODEM_GSM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM_GSM, NMModemGsmPrivate)) + +typedef struct { + DBusGProxyCall *call; + + GHashTable *connect_properties; + guint32 pin_tries; +} NMModemGsmPrivate; + typedef enum { NM_GSM_ERROR_CONNECTION_NOT_GSM = 0, @@ -98,28 +101,22 @@ nm_gsm_error_get_type (void) } -NMDevice * +NMModem * nm_modem_gsm_new (const char *path, const char *device, const char *data_device, - const char *driver, guint32 ip_method) { g_return_val_if_fail (path != NULL, NULL); g_return_val_if_fail (device != NULL, NULL); g_return_val_if_fail (data_device != NULL, NULL); - g_return_val_if_fail (driver != NULL, NULL); - return (NMDevice *) g_object_new (NM_TYPE_MODEM_GSM, - NM_DEVICE_INTERFACE_UDI, path, - NM_DEVICE_INTERFACE_IFACE, data_device, - NM_DEVICE_INTERFACE_DRIVER, driver, - NM_MODEM_PATH, path, - NM_MODEM_IP_METHOD, ip_method, - NM_MODEM_DEVICE, device, - NM_DEVICE_INTERFACE_TYPE_DESC, "GSM", - NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_GSM, - NULL); + return (NMModem *) g_object_new (NM_TYPE_MODEM_GSM, + NM_MODEM_PATH, path, + NM_MODEM_DEVICE, device, + NM_MODEM_IFACE, data_device, + NM_MODEM_IP_METHOD, ip_method, + NULL); } static NMDeviceStateReason @@ -158,93 +155,159 @@ translate_mm_error (GError *error) } static void -clear_pin (NMDevice *device) +ask_for_pin (NMModemGsm *self, gboolean always_ask) { - NMActRequest *req; - NMConnection *connection; - NMSettingGsm *setting; - - req = nm_device_get_act_request (device); - g_assert (req); - connection = nm_act_request_get_connection (req); - g_assert (connection); - setting = NM_SETTING_GSM (nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM)); - g_assert (setting); - - g_object_set (G_OBJECT (setting), NM_SETTING_GSM_PIN, NULL, NULL); -} - -static void -request_secrets (NMDevice *device, - const char *setting_name, - const char *hint1, - const char *hint2, - const char *tries_tag, - gboolean always_ask) -{ - NMActRequest *req; - NMConnection *connection; + NMModemGsmPrivate *priv; guint32 tries = 0; - g_return_if_fail (device != NULL); - g_return_if_fail (hint1 || hint2); + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_MODEM_GSM (self)); - req = nm_device_get_act_request (device); - g_assert (req); - connection = nm_act_request_get_connection (req); - g_assert (connection); - - nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); + priv = NM_MODEM_GSM_GET_PRIVATE (self); if (!always_ask) - tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (connection), tries_tag)); + tries = priv->pin_tries++; - nm_act_request_get_secrets (req, - setting_name ? setting_name : NM_SETTING_GSM_SETTING_NAME, - (tries || always_ask) ? TRUE : FALSE, - SECRETS_CALLER_GSM, - hint1, - hint2); - - if (!always_ask) - g_object_set_data (G_OBJECT (connection), tries_tag, GUINT_TO_POINTER (++tries)); + g_signal_emit_by_name (self, NM_MODEM_NEED_AUTH, + NM_SETTING_GSM_SETTING_NAME, + (tries || always_ask) ? TRUE : FALSE, + SECRETS_CALLER_MOBILE_BROADBAND, + NM_SETTING_GSM_PIN, + NULL); } static void -stage1_prepare_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +stage1_prepare_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) { - NMDevice *device = NM_DEVICE (user_data); + NMModemGsm *self = NM_MODEM_GSM (user_data); + NMModemGsmPrivate *priv = NM_MODEM_GSM_GET_PRIVATE (self); GError *error = NULL; - dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID); - if (!error) - nm_device_activate_schedule_stage2_device_config (device); - else { - const char *required_secret = NULL; - gboolean retry_secret = FALSE; + priv->call = NULL; - if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_PIN)) { - clear_pin (device); - required_secret = NM_SETTING_GSM_PIN; - } else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_WRONG)) { - clear_pin (device); - required_secret = NM_SETTING_GSM_PIN; - retry_secret = TRUE; - } else { - nm_warning ("GSM modem connection failed: (%d) %s", + if (priv->connect_properties) { + g_hash_table_destroy (priv->connect_properties); + priv->connect_properties = NULL; + } + + if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, TRUE, NM_DEVICE_STATE_REASON_NONE); + else { + if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_PIN)) + ask_for_pin (self, FALSE); + else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_WRONG)) + ask_for_pin (self, TRUE); + else { + nm_warning ("GSM connection failed: (%d) %s", error ? error->code : -1, error && error->message ? error->message : "(unknown)"); - } - if (required_secret) - request_secrets (device, NULL, required_secret, NULL, PIN_TRIES, retry_secret); - else - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, translate_mm_error (error)); + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (error)); + } g_error_free (error); } } +static void +do_connect (NMModemGsm *self) +{ + NMModemGsmPrivate *priv = NM_MODEM_GSM_GET_PRIVATE (self); + DBusGProxy *proxy; + + proxy = nm_modem_get_proxy (NM_MODEM (self), MM_DBUS_INTERFACE_MODEM_SIMPLE); + dbus_g_proxy_begin_call_with_timeout (proxy, + "Connect", stage1_prepare_done, + self, NULL, 120000, + DBUS_TYPE_G_MAP_OF_VARIANT, priv->connect_properties, + G_TYPE_INVALID); +} + +static void stage1_enable_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data); + +static void +do_enable (NMModemGsm *self) +{ + DBusGProxy *proxy; + + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_MODEM_GSM (self)); + + proxy = nm_modem_get_proxy (NM_MODEM (self), MM_DBUS_INTERFACE_MODEM); + dbus_g_proxy_begin_call_with_timeout (proxy, + "Enable", stage1_enable_done, + self, NULL, 20000, + G_TYPE_BOOLEAN, TRUE, + G_TYPE_INVALID); +} + +static void +stage1_pin_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +{ + NMModemGsm *self = NM_MODEM_GSM (user_data); + GError *error = NULL; + + if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) { + /* Success; go back and try the enable again */ + do_enable (self); + } else { + nm_warning ("GSM PIN unlock failed: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_error_free (error); + + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); + } +} + +static void +handle_enable_pin_required (NMModemGsm *self) +{ + NMModemGsmPrivate *priv = NM_MODEM_GSM_GET_PRIVATE (self); + const char *pin = NULL; + GValue *value; + DBusGProxy *proxy; + + /* See if we have a PIN already */ + value = g_hash_table_lookup (priv->connect_properties, "pin"); + if (value && G_VALUE_HOLDS_STRING (value)) + pin = g_value_get_string (value); + + /* If we do, send it */ + if (pin) { + proxy = nm_modem_get_proxy (NM_MODEM (self), MM_DBUS_INTERFACE_MODEM_GSM_CARD); + dbus_g_proxy_begin_call_with_timeout (proxy, + "SendPin", stage1_pin_done, + self, NULL, 10000, + G_TYPE_STRING, pin, + G_TYPE_INVALID); + } else + ask_for_pin (self, FALSE); +} + +static void +stage1_enable_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +{ + NMModemGsm *self = NM_MODEM_GSM (user_data); + GError *error = NULL; + + if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) + do_connect (self); + else { + nm_warning ("GSM modem enable failed: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + + if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_PIN)) + handle_enable_pin_required (self); + else + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); + + g_error_free (error); + } +} + + static GHashTable * create_connect_properties (NMConnection *connection) { @@ -301,149 +364,41 @@ create_connect_properties (NMConnection *connection) return properties; } -static void -do_connect (NMModem *modem) -{ - NMConnection *connection; - GHashTable *properties; - - connection = nm_act_request_get_connection (nm_device_get_act_request (NM_DEVICE (modem))); - g_assert (connection); - - properties = create_connect_properties (connection); - dbus_g_proxy_begin_call_with_timeout (nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM_SIMPLE), - "Connect", stage1_prepare_done, - modem, NULL, 120000, - DBUS_TYPE_G_MAP_OF_VARIANT, properties, - G_TYPE_INVALID); - g_hash_table_destroy (properties); -} - -static void -stage1_pin_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - GError *error = NULL; - - if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) { - /* Success; go back and try the enable again */ - nm_device_activate_schedule_stage1_device_prepare (device); - } else { - nm_warning ("GSM PIN unlock failed: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_error_free (error); - - clear_pin (device); - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED); - } -} - -static void -handle_enable_pin_required (NMDevice *device) -{ - NMActRequest *req; - NMConnection *connection; - NMSettingGsm *s_gsm; - const char *pin = NULL; - - req = nm_device_get_act_request (device); - g_assert (req); - connection = nm_act_request_get_connection (req); - g_assert (connection); - - /* See if we have a PIN already */ - s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM); - if (s_gsm) - pin = nm_setting_gsm_get_pin (s_gsm); - - /* If we do, send it */ - if (pin) { - NMModem *modem = NM_MODEM (device); - - dbus_g_proxy_begin_call_with_timeout (nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM_GSM_CARD), - "SendPin", stage1_pin_done, - modem, NULL, 10000, - G_TYPE_STRING, pin, - G_TYPE_INVALID); - } else { - /* Otherwise try to get the PIN */ - request_secrets (device, NULL, NM_SETTING_GSM_PIN, NULL, PIN_TRIES, FALSE); - } -} - -static void -stage1_enable_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - GError *error = NULL; - - if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) - do_connect (NM_MODEM (device)); - else { - nm_warning ("GSM modem enable failed: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - - if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_PIN)) - handle_enable_pin_required (device); - else - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, translate_mm_error (error)); - - g_error_free (error); - } -} - static NMActStageReturn -real_act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) +real_act_stage1_prepare (NMModem *modem, + NMActRequest *req, + GPtrArray **out_hints, + const char **out_setting_name, + NMDeviceStateReason *reason) { - NMActRequest *req; + NMModemGsm *self = NM_MODEM_GSM (modem); + NMModemGsmPrivate *priv = NM_MODEM_GSM_GET_PRIVATE (self); NMConnection *connection; - const char *setting_name; - GPtrArray *hints = NULL; - const char *hint1 = NULL, *hint2 = NULL; - req = nm_device_get_act_request (device); - g_assert (req); connection = nm_act_request_get_connection (req); g_assert (connection); - setting_name = nm_connection_need_secrets (connection, &hints); - if (!setting_name) { - NMModem *modem = NM_MODEM (device); + *out_setting_name = nm_connection_need_secrets (connection, out_hints); + if (!*out_setting_name) { gboolean enabled = nm_modem_get_mm_enabled (modem); + if (priv->connect_properties) + g_hash_table_destroy (priv->connect_properties); + priv->connect_properties = create_connect_properties (connection); + if (enabled) - do_connect (modem); - else { - dbus_g_proxy_begin_call_with_timeout (nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM), - "Enable", stage1_enable_done, - modem, NULL, 20000, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_INVALID); - } - - return NM_ACT_STAGE_RETURN_POSTPONE; + do_connect (self); + else + do_enable (self); + } else { + /* NMModem will handle requesting secrets... */ } - /* Get the required secrets */ - if (hints) { - if (hints->len > 0) - hint1 = g_ptr_array_index (hints, 0); - if (hints->len > 1) - hint2 = g_ptr_array_index (hints, 1); - } - - request_secrets (device, setting_name, hint1, hint2, GSM_SECRETS_TRIES, FALSE); - - if (hints) - g_ptr_array_free (hints, TRUE); - return NM_ACT_STAGE_RETURN_POSTPONE; } static NMConnection * -real_get_best_auto_connection (NMDevice *dev, +real_get_best_auto_connection (NMModem *modem, GSList *connections, char **specific_object) { @@ -467,112 +422,8 @@ real_get_best_auto_connection (NMDevice *dev, return NULL; } -static void -real_connection_secrets_updated (NMDevice *dev, - NMConnection *connection, - GSList *updated_settings, - RequestSecretsCaller caller) -{ - NMActRequest *req; - gboolean found = FALSE; - GSList *iter; - - g_return_if_fail (IS_ACTIVATING_STATE (nm_device_get_state (dev))); - - if (caller == SECRETS_CALLER_PPP) { - NMPPPManager *ppp_manager; - NMSettingGsm *s_gsm = NULL; - - ppp_manager = nm_modem_get_ppp_manager (NM_MODEM (dev)); - g_return_if_fail (ppp_manager != NULL); - - s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM); - if (!s_gsm) { - /* Shouldn't ever happen */ - nm_ppp_manager_update_secrets (ppp_manager, - nm_device_get_iface (dev), - NULL, - NULL, - "missing GSM setting; no secrets could be found."); - } else { - const char *username = nm_setting_gsm_get_username (s_gsm); - const char *password = nm_setting_gsm_get_password (s_gsm); - - nm_ppp_manager_update_secrets (ppp_manager, - nm_device_get_iface (dev), - username ? username : "", - password ? password : "", - NULL); - } - return; - } - - g_return_if_fail (caller == SECRETS_CALLER_GSM); - g_return_if_fail (nm_device_get_state (dev) == NM_DEVICE_STATE_NEED_AUTH); - - for (iter = updated_settings; iter; iter = g_slist_next (iter)) { - const char *setting_name = (const char *) iter->data; - - if (!strcmp (setting_name, NM_SETTING_GSM_SETTING_NAME)) - found = TRUE; - else - nm_warning ("Ignoring updated secrets for setting '%s'.", setting_name); - } - - if (!found) - return; - - req = nm_device_get_act_request (dev); - g_assert (req); - - g_return_if_fail (nm_act_request_get_connection (req) == connection); - - nm_device_activate_schedule_stage1_device_prepare (dev); -} - -static NMActStageReturn -real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) -{ - NMActRequest *req; - NMConnection *connection; - - req = nm_device_get_act_request (device); - g_assert (req); - - /* Clear secrets tries counter since secrets were successfully used - * already if we get here. - */ - connection = nm_act_request_get_connection (req); - g_assert (connection); - g_object_set_data (G_OBJECT (connection), GSM_SECRETS_TRIES, NULL); - - if (NM_DEVICE_CLASS (nm_modem_gsm_parent_class)->act_stage2_config) - return NM_DEVICE_CLASS (nm_modem_gsm_parent_class)->act_stage2_config (device, reason); - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static void -real_deactivate_quickly (NMDevice *device) -{ - NMActRequest *req; - NMConnection *connection; - - req = nm_device_get_act_request (device); - if (req) { - /* Clear the secrets attempts counter */ - connection = nm_act_request_get_connection (req); - g_assert (connection); - g_object_set_data (G_OBJECT (connection), GSM_SECRETS_TRIES, NULL); - g_object_set_data (G_OBJECT (connection), PIN_TRIES, NULL); - } - - if (NM_DEVICE_CLASS (nm_modem_gsm_parent_class)->deactivate_quickly) - NM_DEVICE_CLASS (nm_modem_gsm_parent_class)->deactivate_quickly (device); -} - static gboolean -real_check_connection_compatible (NMDevice *device, +real_check_connection_compatible (NMModem *modem, NMConnection *connection, GError **error) { @@ -600,17 +451,51 @@ real_check_connection_compatible (NMDevice *device, return TRUE; } -static const char * -real_get_ppp_name (NMModem *device, NMConnection *connection) +static gboolean +real_get_user_pass (NMModem *modem, + NMConnection *connection, + const char **user, + const char **pass) { NMSettingGsm *s_gsm; s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM); - g_assert (s_gsm); + if (!s_gsm) + return FALSE; - return nm_setting_gsm_get_username (s_gsm); + if (user) + *user = nm_setting_gsm_get_username (s_gsm); + if (pass) + *pass = nm_setting_gsm_get_password (s_gsm); + + return TRUE; } +static const char * +real_get_setting_name (NMModem *modem) +{ + return NM_SETTING_GSM_SETTING_NAME; +} + +static void +real_deactivate_quickly (NMModem *modem, NMDevice *device) +{ + NMModemGsmPrivate *priv = NM_MODEM_GSM_GET_PRIVATE (modem); + + if (priv->call) { + DBusGProxy *proxy; + + proxy = nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM_SIMPLE); + dbus_g_proxy_cancel_call (proxy, priv->call); + priv->call = NULL; + } + + priv->pin_tries = 0; + + NM_MODEM_CLASS (nm_modem_gsm_parent_class)->deactivate_quickly (modem, device); +} + + /*****************************************************************************/ static void @@ -618,24 +503,34 @@ nm_modem_gsm_init (NMModemGsm *self) { } +static void +dispose (GObject *object) +{ + NMModemGsm *self = NM_MODEM_GSM (object); + NMModemGsmPrivate *priv = NM_MODEM_GSM_GET_PRIVATE (self); + + if (priv->connect_properties) + g_hash_table_destroy (priv->connect_properties); + + G_OBJECT_CLASS (nm_modem_gsm_parent_class)->dispose (object); +} + static void nm_modem_gsm_class_init (NMModemGsmClass *klass) { - NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); NMModemClass *modem_class = NM_MODEM_CLASS (klass); + g_type_class_add_private (object_class, sizeof (NMModemGsmPrivate)); + /* Virtual methods */ - device_class->get_best_auto_connection = real_get_best_auto_connection; - device_class->connection_secrets_updated = real_connection_secrets_updated; - device_class->act_stage1_prepare = real_act_stage1_prepare; - device_class->act_stage2_config = real_act_stage2_config; - device_class->deactivate_quickly = real_deactivate_quickly; - device_class->check_connection_compatible = real_check_connection_compatible; - - modem_class->get_ppp_name = real_get_ppp_name; - - dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_gsm_object_info); + object_class->dispose = dispose; + modem_class->get_user_pass = real_get_user_pass; + modem_class->get_setting_name = real_get_setting_name; + modem_class->get_best_auto_connection = real_get_best_auto_connection; + modem_class->check_connection_compatible = real_check_connection_compatible; + modem_class->act_stage1_prepare = real_act_stage1_prepare; + modem_class->deactivate_quickly = real_deactivate_quickly; dbus_g_error_domain_register (NM_GSM_ERROR, NULL, NM_TYPE_GSM_ERROR); } diff --git a/src/modem-manager/nm-modem-gsm.h b/src/modem-manager/nm-modem-gsm.h index 84794739f9..f481bdb817 100644 --- a/src/modem-manager/nm-modem-gsm.h +++ b/src/modem-manager/nm-modem-gsm.h @@ -46,11 +46,10 @@ typedef struct { GType nm_modem_gsm_get_type (void); -NMDevice *nm_modem_gsm_new (const char *path, - const char *device, - const char *data_device, - const char *driver, - guint32 ip_method); +NMModem *nm_modem_gsm_new (const char *path, + const char *device, + const char *data_device, + guint32 ip_method); G_END_DECLS diff --git a/src/modem-manager/nm-modem-manager.c b/src/modem-manager/nm-modem-manager.c index 94e1a111b3..6a7de07ef9 100644 --- a/src/modem-manager/nm-modem-manager.c +++ b/src/modem-manager/nm-modem-manager.c @@ -28,6 +28,7 @@ #include "nm-dbus-manager.h" #include "nm-utils.h" #include "nm-modem-types.h" +#include "nm-marshal.h" #define MODEM_POKE_INTERVAL 120 @@ -44,8 +45,8 @@ typedef struct { } NMModemManagerPrivate; enum { - DEVICE_ADDED, - DEVICE_REMOVED, + MODEM_ADDED, + MODEM_REMOVED, LAST_SIGNAL }; @@ -67,25 +68,6 @@ nm_modem_manager_get (void) return singleton; } -gboolean -nm_modem_manager_has_modem_for_iface (NMModemManager *manager, - const gchar *iface) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (manager); - GList *iter; - g_assert (manager); - g_assert (NM_IS_MODEM_MANAGER(manager)); - g_assert (iface); - - for (iter = g_hash_table_get_values(priv->modems); iter != NULL; iter = iter->next) { - NMDevice *device = NM_DEVICE(iter->data); - const gchar *device_iface = nm_device_get_iface (device); - if (!g_strcmp0 (iface, device_iface)) - return TRUE; - } - return FALSE; -} - static gboolean get_modem_properties (DBusGConnection *connection, const char *path, @@ -182,7 +164,7 @@ static void create_modem (NMModemManager *manager, const char *path) { NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (manager); - NMDevice *device; + NMModem *modem; char *data_device = NULL, *driver = NULL, *master_device = NULL; uint modem_type = MM_MODEM_TYPE_UNKNOWN; uint ip_method = MM_MODEM_IP_METHOD_PPP; @@ -218,19 +200,20 @@ create_modem (NMModemManager *manager, const char *path) } if (modem_type == MM_MODEM_TYPE_GSM) - device = nm_modem_gsm_new (path, master_device, data_device, driver, ip_method); + modem = nm_modem_gsm_new (path, master_device, data_device, ip_method); else if (modem_type == MM_MODEM_TYPE_CDMA) - device = nm_modem_cdma_new (path, master_device, data_device, driver); + modem = nm_modem_cdma_new (path, master_device, data_device, ip_method); else g_error ("Invalid modem type"); g_free (data_device); - g_free (driver); - if (device) { - g_hash_table_insert (priv->modems, g_strdup (path), device); - g_signal_emit (manager, signals[DEVICE_ADDED], 0, device); + if (modem) { + g_hash_table_insert (priv->modems, g_strdup (path), modem); + g_signal_emit (manager, signals[MODEM_ADDED], 0, modem, driver); } + + g_free (driver); } static void @@ -247,7 +230,7 @@ modem_removed (DBusGProxy *proxy, const char *path, gpointer user_data) modem = (NMModem *) g_hash_table_lookup (priv->modems, path); if (modem) { - g_signal_emit (user_data, signals[DEVICE_REMOVED], 0, modem); + g_signal_emit (user_data, signals[MODEM_REMOVED], 0, modem); g_hash_table_remove (priv->modems, path); } } @@ -330,7 +313,7 @@ modem_manager_appeared (NMModemManager *self, gboolean enumerate_devices) static gboolean remove_one_modem (gpointer key, gpointer value, gpointer user_data) { - g_signal_emit (user_data, signals[DEVICE_REMOVED], 0, value); + g_signal_emit (user_data, signals[MODEM_REMOVED], 0, value); return TRUE; } @@ -440,23 +423,21 @@ nm_modem_manager_class_init (NMModemManagerClass *klass) object_class->dispose = dispose; /* signals */ - signals[DEVICE_ADDED] = - g_signal_new ("device-added", + signals[MODEM_ADDED] = + g_signal_new ("modem-added", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMModemManagerClass, device_added), + G_STRUCT_OFFSET (NMModemManagerClass, modem_added), NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - G_TYPE_OBJECT); + _nm_marshal_VOID__OBJECT_STRING, + G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_STRING); - signals[DEVICE_REMOVED] = - g_signal_new ("device-removed", + signals[MODEM_REMOVED] = + g_signal_new ("modem-removed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMModemManagerClass, device_removed), + G_STRUCT_OFFSET (NMModemManagerClass, modem_removed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - G_TYPE_OBJECT); + G_TYPE_NONE, 1, G_TYPE_OBJECT); } diff --git a/src/modem-manager/nm-modem-manager.h b/src/modem-manager/nm-modem-manager.h index f9d8ded015..56427baf0d 100644 --- a/src/modem-manager/nm-modem-manager.h +++ b/src/modem-manager/nm-modem-manager.h @@ -24,7 +24,7 @@ #define NM_MODEM_MANAGER_H #include -#include "nm-device.h" +#include "nm-modem.h" #define NM_TYPE_MODEM_MANAGER (nm_modem_manager_get_type ()) #define NM_MODEM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_MANAGER, NMModemManager)) @@ -41,18 +41,13 @@ typedef struct { GObjectClass parent; /* Signals */ - void (*device_added) (NMModemManager *manager, - NMDevice *device); + void (*modem_added) (NMModemManager *manager, NMModem *modem, const char *driver); - void (*device_removed) (NMModemManager *manager, - NMDevice *device); + void (*modem_removed) (NMModemManager *manager, NMModem *modem); } NMModemManagerClass; GType nm_modem_manager_get_type (void); NMModemManager *nm_modem_manager_get (void); -gboolean nm_modem_manager_has_modem_for_iface (NMModemManager *manager, - const gchar *iface); - #endif /* NM_MODEM_MANAGER_H */ diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c index 5b001eec52..40a76b1db5 100644 --- a/src/modem-manager/nm-modem.c +++ b/src/modem-manager/nm-modem.c @@ -21,31 +21,28 @@ #include #include "nm-modem.h" -#include "nm-device-private.h" #include "NetworkManagerSystem.h" -#include "nm-device-interface.h" #include "nm-dbus-manager.h" #include "nm-setting-connection.h" -#include "nm-setting-gsm.h" -#include "nm-setting-cdma.h" #include "nm-marshal.h" #include "nm-properties-changed-signal.h" #include "nm-modem-types.h" #include "nm-utils.h" -#include "nm-serial-device-glue.h" #include "NetworkManagerUtils.h" +#include "nm-device-private.h" +#include "nm-device-interface.h" #include "nm-dbus-glib-types.h" -static void device_interface_init (NMDeviceInterface *iface_class); +#include "nm-serial-device-glue.h" -G_DEFINE_TYPE_EXTENDED (NMModem, nm_modem, NM_TYPE_DEVICE, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_INTERFACE, device_interface_init)) +G_DEFINE_TYPE (NMModem, nm_modem, G_TYPE_OBJECT) #define NM_MODEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM, NMModemPrivate)) enum { PROP_0, PROP_DEVICE, + PROP_IFACE, PROP_PATH, PROP_IP_METHOD, PROP_ENABLED, @@ -63,6 +60,11 @@ typedef struct { NMIP4Config *pending_ip4_config; guint32 ip_method; char *device; + char *iface; + + guint32 secrets_tries; + + DBusGProxyCall *call; gboolean mm_enabled; @@ -73,7 +75,10 @@ typedef struct { enum { PPP_STATS, - PROPERTIES_CHANGED, + PPP_FAILED, + PREPARE_RESULT, + IP4_CONFIG_RESULT, + NEED_AUTH, LAST_SIGNAL }; @@ -120,17 +125,19 @@ nm_modem_get_proxy (NMModem *self, return priv->proxy; } -const char * -nm_modem_get_ppp_name (NMModem *self, - NMConnection *connection) +static void +merge_ip4_config (NMActRequest *req, NMIP4Config *config) { - g_return_val_if_fail (NM_IS_MODEM (self), NULL); - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + NMConnection *connection; + NMSettingIP4Config *s_ip4; - if (NM_MODEM_GET_CLASS (self)->get_ppp_name) - return NM_MODEM_GET_CLASS (self)->get_ppp_name (self, connection); + /* Merge user-defined overrides into the IP4Config to be applied */ + connection = nm_act_request_get_connection (req); + g_assert (connection); - return NULL; + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + if (s_ip4) + nm_utils_merge_ip4_config (config, s_ip4); } /*****************************************************************************/ @@ -139,14 +146,12 @@ nm_modem_get_ppp_name (NMModem *self, static void ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_data) { - NMDevice *device = NM_DEVICE (user_data); - switch (status) { case NM_PPP_STATUS_DISCONNECT: - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_DISCONNECT); + g_signal_emit (NM_MODEM (user_data), signals[PPP_FAILED], 0, NM_DEVICE_STATE_REASON_PPP_DISCONNECT); break; case NM_PPP_STATUS_DEAD: - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_FAILED); + g_signal_emit (NM_MODEM (user_data), signals[PPP_FAILED], 0, NM_DEVICE_STATE_REASON_PPP_FAILED); break; default: break; @@ -159,7 +164,8 @@ ppp_ip4_config (NMPPPManager *ppp_manager, NMIP4Config *config, gpointer user_data) { - NMDevice *device = NM_DEVICE (user_data); + NMModem *self = NM_MODEM (user_data); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); guint32 i, num; guint32 bad_dns1 = htonl (0x0A0B0C0D); guint32 good_dns1 = htonl (0x04020201); /* GTE nameserver */ @@ -167,10 +173,6 @@ ppp_ip4_config (NMPPPManager *ppp_manager, guint32 good_dns2 = htonl (0x04020202); /* GTE nameserver */ gboolean dns_workaround = FALSE; - /* Ignore PPP IP4 events that come in after initial configuration */ - if (nm_device_get_state (device) != NM_DEVICE_STATE_IP_CONFIG) - return; - /* Work around a PPP bug (#1732) which causes many mobile broadband * providers to return 10.11.12.13 and 10.11.12.14 for the DNS servers. * Apparently fixed in ppp-2.4.5 but we've had some reports that this is @@ -206,9 +208,8 @@ ppp_ip4_config (NMPPPManager *ppp_manager, nm_ip4_config_add_nameserver (config, good_dns2); } - nm_device_set_ip_iface (device, iface); - NM_MODEM_GET_PRIVATE (device)->pending_ip4_config = g_object_ref (config); - nm_device_activate_schedule_stage4_ip4_config_get (device); + priv->pending_ip4_config = g_object_ref (config); + g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, iface, config, NULL); } static void @@ -229,36 +230,48 @@ ppp_stats (NMPPPManager *ppp_manager, } static NMActStageReturn -ppp_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason) +ppp_stage3_ip4_config_start (NMModem *self, + NMActRequest *req, + NMDeviceStateReason *reason) { - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (device); - NMActRequest *req; + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); const char *ppp_name = NULL; - GError *err = NULL; + GError *error = NULL; NMActStageReturn ret; - req = nm_device_get_act_request (device); - g_assert (req); + g_return_val_if_fail (self != NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - ppp_name = nm_modem_get_ppp_name (NM_MODEM (device), - nm_act_request_get_connection (req)); + if (NM_MODEM_GET_CLASS (self)->get_user_pass) { + NMConnection *connection = nm_act_request_get_connection (req); - priv->ppp_manager = nm_ppp_manager_new (nm_device_get_iface (device)); - if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, 20, &err)) { + g_assert (connection); + if (!NM_MODEM_GET_CLASS (self)->get_user_pass (self, connection, &ppp_name, NULL)) + return NM_ACT_STAGE_RETURN_FAILURE; + } + + priv->ppp_manager = nm_ppp_manager_new (priv->iface); + if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, 20, &error)) { g_signal_connect (priv->ppp_manager, "state-changed", G_CALLBACK (ppp_state_changed), - device); + self); g_signal_connect (priv->ppp_manager, "ip4-config", G_CALLBACK (ppp_ip4_config), - device); + self); g_signal_connect (priv->ppp_manager, "stats", G_CALLBACK (ppp_stats), - device); + self); ret = NM_ACT_STAGE_RETURN_POSTPONE; } else { - nm_warning ("%s", err->message); - g_error_free (err); + nm_warning ("%s: error starting PPP: (%d) %s", + __func__, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_error_free (error); g_object_unref (priv->ppp_manager); priv->ppp_manager = NULL; @@ -271,20 +284,17 @@ ppp_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason) } static NMActStageReturn -ppp_stage4 (NMDevice *device, NMIP4Config **config, NMDeviceStateReason *reason) +ppp_stage4 (NMModem *self, + NMActRequest *req, + NMIP4Config **config, + NMDeviceStateReason *reason) { - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (device); - NMConnection *connection; - NMSettingIP4Config *s_ip4; + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); *config = priv->pending_ip4_config; priv->pending_ip4_config = NULL; - /* Merge user-defined overrides into the IP4Config to be applied */ - connection = nm_act_request_get_connection (nm_device_get_act_request (device)); - g_assert (connection); - s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); - nm_utils_merge_ip4_config (*config, s_ip4); + merge_ip4_config (req, *config); return NM_ACT_STAGE_RETURN_SUCCESS; } @@ -293,57 +303,75 @@ ppp_stage4 (NMDevice *device, NMIP4Config **config, NMDeviceStateReason *reason) /* IP method static */ static void -static_stage3_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +static_stage3_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) { - NMDevice *device = NM_DEVICE (user_data); + NMModem *self = NM_MODEM (user_data); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); GValueArray *ret_array = NULL; GError *error = NULL; + NMIP4Config *config = NULL; - if (dbus_g_proxy_end_call (proxy, call_id, &error, + priv->call = NULL; + + if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_VALUE_ARRAY, &ret_array, G_TYPE_INVALID)) { - - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (device); NMIP4Address *addr; int i; + config = nm_ip4_config_new (); + addr = nm_ip4_address_new (); nm_ip4_address_set_address (addr, g_value_get_uint (g_value_array_get_nth (ret_array, 0))); nm_ip4_address_set_prefix (addr, 32); + nm_ip4_config_take_address (config, addr); - priv->pending_ip4_config = nm_ip4_config_new (); - nm_ip4_config_take_address (priv->pending_ip4_config, addr); - - for (i = 1; i < ret_array->n_values; i++) - nm_ip4_config_add_nameserver (priv->pending_ip4_config, - g_value_get_uint (g_value_array_get_nth (ret_array, i))); + for (i = 0; i < ret_array->n_values; i++) { + GValue *value = g_value_array_get_nth (ret_array, i); + nm_ip4_config_add_nameserver (config, g_value_get_uint (value)); + } g_value_array_free (ret_array); - nm_device_activate_schedule_stage4_ip4_config_get (device); - } else { - nm_warning ("Retrieving IP4 configuration failed: %s", error->message); - g_error_free (error); - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + + priv->pending_ip4_config = g_object_ref (config); + g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, NULL, config, NULL); } + + g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, NULL, config, error); + g_clear_error (&error); } static NMActStageReturn -static_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason) +static_stage3_ip4_config_start (NMModem *self, + NMActRequest *req, + NMDeviceStateReason *reason) { - dbus_g_proxy_begin_call (nm_modem_get_proxy (NM_MODEM (device), MM_DBUS_INTERFACE_MODEM), - "GetIP4Config", static_stage3_done, - device, NULL, - G_TYPE_INVALID); + NMModemPrivate *priv; + + g_return_val_if_fail (self != NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + priv = NM_MODEM_GET_PRIVATE (self); + + priv->call = dbus_g_proxy_begin_call (nm_modem_get_proxy (self, MM_DBUS_INTERFACE_MODEM), + "GetIP4Config", static_stage3_done, + self, NULL, + G_TYPE_INVALID); return NM_ACT_STAGE_RETURN_POSTPONE; } static NMActStageReturn -static_stage4 (NMDevice *device, NMIP4Config **config, NMDeviceStateReason *reason) +static_stage4 (NMModem *self, + NMActRequest *req, + NMDevice *device, + NMIP4Config **config, + NMDeviceStateReason *reason) { - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (device); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); gboolean no_firmware = FALSE; if (!nm_device_hw_bring_up (device, TRUE, &no_firmware)) { @@ -357,25 +385,42 @@ static_stage4 (NMDevice *device, NMIP4Config **config, NMDeviceStateReason *reas *config = priv->pending_ip4_config; priv->pending_ip4_config = NULL; + merge_ip4_config (req, *config); + return NM_ACT_STAGE_RETURN_SUCCESS; } /*****************************************************************************/ -static NMActStageReturn -real_act_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason) +NMActStageReturn +nm_modem_stage3_ip4_config_start (NMModem *self, + NMDevice *device, + NMDeviceClass *device_class, + NMDeviceStateReason *reason) { + NMActRequest *req; NMActStageReturn ret; - switch (NM_MODEM_GET_PRIVATE (device)->ip_method) { + g_return_val_if_fail (self != NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (device != NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (NM_IS_DEVICE (device), NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (device_class != NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (NM_IS_DEVICE_CLASS (device_class), NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + req = nm_device_get_act_request (device); + g_assert (req); + + switch (NM_MODEM_GET_PRIVATE (self)->ip_method) { case MM_MODEM_IP_METHOD_PPP: - ret = ppp_stage3_ip4_config_start (device, reason); + ret = ppp_stage3_ip4_config_start (self, req, reason); break; case MM_MODEM_IP_METHOD_STATIC: - ret = static_stage3_ip4_config_start (device, reason); + ret = static_stage3_ip4_config_start (self, req, reason); break; case MM_MODEM_IP_METHOD_DHCP: - ret = NM_DEVICE_CLASS (nm_modem_parent_class)->act_stage3_ip4_config_start (device, reason); + ret = device_class->act_stage3_ip4_config_start (device, reason); break; default: g_warning ("Invalid IP method"); @@ -386,22 +431,36 @@ real_act_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason) return ret; } -static NMActStageReturn -real_act_stage4_get_ip4_config (NMDevice *device, +NMActStageReturn +nm_modem_stage4_get_ip4_config (NMModem *self, + NMDevice *device, + NMDeviceClass *device_class, NMIP4Config **config, NMDeviceStateReason *reason) { + NMActRequest *req; NMActStageReturn ret; - switch (NM_MODEM_GET_PRIVATE (device)->ip_method) { + g_return_val_if_fail (self != NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (device != NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (NM_IS_DEVICE (device), NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (device_class != NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (NM_IS_DEVICE_CLASS (device_class), NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + req = nm_device_get_act_request (device); + g_assert (req); + + switch (NM_MODEM_GET_PRIVATE (self)->ip_method) { case MM_MODEM_IP_METHOD_PPP: - ret = ppp_stage4 (device, config, reason); + ret = ppp_stage4 (self, req, config, reason); break; case MM_MODEM_IP_METHOD_STATIC: - ret = static_stage4 (device, config, reason); + ret = static_stage4 (self, req, device, config, reason); break; case MM_MODEM_IP_METHOD_DHCP: - ret = NM_DEVICE_CLASS (nm_modem_parent_class)->act_stage4_get_ip4_config (device, config, reason); + ret = device_class->act_stage4_get_ip4_config (device, config, reason); break; default: g_warning ("Invalid IP method"); @@ -412,12 +471,175 @@ real_act_stage4_get_ip4_config (NMDevice *device, return ret; } -static void -real_deactivate_quickly (NMDevice *device) +gboolean +nm_modem_connection_secrets_updated (NMModem *self, + NMActRequest *req, + NMConnection *connection, + GSList *updated_settings, + RequestSecretsCaller caller) { - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (device); + NMModemPrivate *priv; + gboolean found = FALSE; + const char *setting_name; + GSList *iter; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (NM_IS_MODEM (self), FALSE); + g_return_val_if_fail (req != NULL, FALSE); + g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); + g_return_val_if_fail (connection != NULL, FALSE); + g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); + + priv = NM_MODEM_GET_PRIVATE (self); + + if (caller == SECRETS_CALLER_PPP) { + const char *user = NULL; + const char *pass = NULL; + + g_return_val_if_fail (priv->ppp_manager != NULL, FALSE); + + if (!NM_MODEM_GET_CLASS (self)->get_user_pass (self, connection, &user, &pass)) { + /* Shouldn't ever happen */ + nm_ppp_manager_update_secrets (priv->ppp_manager, + priv->iface, + NULL, + NULL, + "missing GSM/CDMA setting; no secrets could be found."); + } else { + nm_ppp_manager_update_secrets (priv->ppp_manager, + priv->iface, + user ? user : "", + pass ? pass : "", + NULL); + } + return TRUE; + } + + g_return_val_if_fail (caller == SECRETS_CALLER_MOBILE_BROADBAND, FALSE); + + g_assert (NM_MODEM_GET_CLASS (self)->get_setting_name); + setting_name = NM_MODEM_GET_CLASS (self)->get_setting_name (self); + + for (iter = updated_settings; iter; iter = g_slist_next (iter)) { + const char *candidate_setting_name = (const char *) iter->data; + + if (!strcmp (candidate_setting_name, setting_name)) + found = TRUE; + else { + nm_warning ("Ignoring updated secrets for setting '%s'.", + candidate_setting_name); + } + } + + return found; +} + +static NMActStageReturn +real_act_stage1_prepare (NMModem *modem, + NMActRequest *req, + GPtrArray **out_hints, + const char **out_setting_name, + NMDeviceStateReason *reason) +{ + *reason = NM_DEVICE_STATE_REASON_UNKNOWN; + return NM_ACT_STAGE_RETURN_FAILURE; +} + +NMActStageReturn +nm_modem_act_stage1_prepare (NMModem *self, + NMActRequest *req, + NMDeviceStateReason *reason) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + NMActStageReturn ret; + GPtrArray *hints = NULL; + const char *setting_name = NULL; + + ret = NM_MODEM_GET_CLASS (self)->act_stage1_prepare (self, + req, + &hints, + &setting_name, + reason); + if ((ret == NM_ACT_STAGE_RETURN_POSTPONE) && setting_name) { + const char *hint1 = NULL, *hint2 = NULL; + + /* Need some secrets */ + if (hints) { + if (hints->len > 0) + hint1 = g_ptr_array_index (hints, 0); + if (hints->len > 1) + hint2 = g_ptr_array_index (hints, 1); + } + + g_signal_emit (self, signals[NEED_AUTH], 0, + setting_name, + priv->secrets_tries++ ? TRUE : FALSE, + SECRETS_CALLER_MOBILE_BROADBAND, + hint1, + hint2); + + if (hints) + g_ptr_array_free (hints, TRUE); + } + + return ret; +} + +NMActStageReturn +nm_modem_act_stage2_config (NMModem *self, + NMActRequest *req, + NMDeviceStateReason *reason) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + + /* Clear secrets tries counter since secrets were successfully used + * already if we get here. + */ + priv->secrets_tries = 0; + + return NM_ACT_STAGE_RETURN_SUCCESS; +} + +NMConnection * +nm_modem_get_best_auto_connection (NMModem *self, + GSList *connections, + char **specific_object) +{ + if (NM_MODEM_GET_CLASS (self)->get_best_auto_connection) + return NM_MODEM_GET_CLASS (self)->get_best_auto_connection (self, connections, specific_object); + return NULL; +} + +gboolean +nm_modem_check_connection_compatible (NMModem *self, + NMConnection *connection, + GError **error) +{ + if (NM_MODEM_GET_CLASS (self)->check_connection_compatible) + return NM_MODEM_GET_CLASS (self)->check_connection_compatible (self, connection, error); + return FALSE; +} + +static void +real_deactivate_quickly (NMModem *self, NMDevice *device) +{ + NMModemPrivate *priv; const char *iface; + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_MODEM (self)); + g_return_if_fail (device != NULL); + g_return_if_fail (NM_IS_DEVICE (device)); + + priv = NM_MODEM_GET_PRIVATE (self); + + priv->secrets_tries = 0; + + if (priv->call) { + dbus_g_proxy_cancel_call (priv->proxy, priv->call); + priv->call = NULL; + } + if (priv->pending_ip4_config) { g_object_unref (priv->pending_ip4_config); priv->pending_ip4_config = NULL; @@ -425,7 +647,7 @@ real_deactivate_quickly (NMDevice *device) priv->in_bytes = priv->out_bytes = 0; - switch (NM_MODEM_GET_PRIVATE (device)->ip_method) { + switch (priv->ip_method) { case MM_MODEM_IP_METHOD_PPP: if (priv->ppp_manager) { g_object_unref (priv->ppp_manager); @@ -434,8 +656,7 @@ real_deactivate_quickly (NMDevice *device) break; case MM_MODEM_IP_METHOD_STATIC: case MM_MODEM_IP_METHOD_DHCP: - iface = nm_device_get_iface (device); - + iface = nm_device_get_ip_iface (device); nm_system_device_flush_routes_with_iface (iface); nm_system_device_flush_addresses_with_iface (iface); nm_system_device_set_up_down_with_iface (iface, FALSE, NULL); @@ -444,35 +665,32 @@ real_deactivate_quickly (NMDevice *device) g_warning ("Invalid IP method"); break; } - - if (NM_DEVICE_CLASS (nm_modem_parent_class)->deactivate) - NM_DEVICE_CLASS (nm_modem_parent_class)->deactivate (device); } -static guint32 -real_get_generic_capabilities (NMDevice *dev) +void +nm_modem_deactivate_quickly (NMModem *self, NMDevice *device) { - return NM_DEVICE_CAP_NM_SUPPORTED; + NM_MODEM_GET_CLASS (self)->deactivate_quickly (self, device); } -static void -device_state_changed (NMDeviceInterface *device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) +void +nm_modem_device_state_changed (NMModem *self, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason) { - NMModem *self = NM_MODEM (user_data); - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); gboolean was_connected = FALSE; + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_MODEM (self)); + if (IS_ACTIVATING_STATE (old_state) || (old_state == NM_DEVICE_STATE_ACTIVATED)) was_connected = TRUE; /* Make sure we don't leave the serial device open */ switch (new_state) { case NM_DEVICE_STATE_NEED_AUTH: - if (priv->ppp_manager) + if (NM_MODEM_GET_PRIVATE (self)->ppp_manager) break; /* else fall through */ case NM_DEVICE_STATE_UNMANAGED: @@ -490,13 +708,13 @@ device_state_changed (NMDeviceInterface *device, } } -static gboolean -real_hw_is_up (NMDevice *device) +gboolean +nm_modem_hw_is_up (NMModem *self, NMDevice *device) { - guint32 ip_method = NM_MODEM_GET_PRIVATE (device)->ip_method; + guint32 ip_method = NM_MODEM_GET_PRIVATE (self)->ip_method; if (ip_method == MM_MODEM_IP_METHOD_STATIC || ip_method == MM_MODEM_IP_METHOD_DHCP) { - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (device); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); NMDeviceState state; state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device)); @@ -507,13 +725,13 @@ real_hw_is_up (NMDevice *device) return TRUE; } -static gboolean -real_hw_bring_up (NMDevice *device, gboolean *no_firmware) +gboolean +nm_modem_hw_bring_up (NMModem *self, NMDevice *device, gboolean *no_firmware) { - guint32 ip_method = NM_MODEM_GET_PRIVATE (device)->ip_method; + guint32 ip_method = NM_MODEM_GET_PRIVATE (self)->ip_method; if (ip_method == MM_MODEM_IP_METHOD_STATIC || ip_method == MM_MODEM_IP_METHOD_DHCP) { - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (device); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); NMDeviceState state; state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device)); @@ -524,6 +742,24 @@ real_hw_bring_up (NMDevice *device, gboolean *no_firmware) return TRUE; } +const char * +nm_modem_get_iface (NMModem *self) +{ + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (NM_IS_MODEM (self), NULL); + + return NM_MODEM_GET_PRIVATE (self)->iface; +} + +const char * +nm_modem_get_path (NMModem *self) +{ + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (NM_IS_MODEM (self), NULL); + + return NM_MODEM_GET_PRIVATE (self)->path; +} + static void get_mm_enabled_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) { @@ -577,11 +813,15 @@ set_mm_enabled_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_d query_mm_enabled (NM_MODEM (user_data)); } -static void -real_set_enabled (NMDeviceInterface *device, gboolean enabled) +void +nm_modem_set_mm_enabled (NMModem *self, gboolean enabled) { - NMModem *self = NM_MODEM (device); - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + NMModemPrivate *priv; + + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_MODEM (self)); + + priv = NM_MODEM_GET_PRIVATE (self); /* FIXME: For now this just toggles the ModemManager enabled state. In the * future we want to tie this into rfkill state instead so that the user can @@ -591,10 +831,10 @@ real_set_enabled (NMDeviceInterface *device, gboolean enabled) if (priv->mm_enabled != enabled) { DBusGProxy *proxy; - proxy = nm_modem_get_proxy (NM_MODEM (device), MM_DBUS_INTERFACE_MODEM); + proxy = nm_modem_get_proxy (self, MM_DBUS_INTERFACE_MODEM); dbus_g_proxy_begin_call (proxy, "Enable", set_mm_enabled_done, - device, NULL, + self, NULL, G_TYPE_BOOLEAN, enabled, G_TYPE_INVALID); } @@ -615,30 +855,13 @@ modem_properties_changed (DBusGProxy *proxy, value = g_hash_table_lookup (props, "Enabled"); if (value && G_VALUE_HOLDS_BOOLEAN (value)) { - NMDeviceState state; - priv->mm_enabled = g_value_get_boolean (value); g_object_notify (G_OBJECT (self), NM_MODEM_ENABLED); - - if (priv->mm_enabled == FALSE) { - state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self)); - if (state == NM_DEVICE_STATE_ACTIVATED) { - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_NONE); - } - } } } /*****************************************************************************/ -static void -device_interface_init (NMDeviceInterface *iface_class) -{ - iface_class->set_enabled = real_set_enabled; -} - static void nm_modem_init (NMModem *self) { @@ -665,7 +888,12 @@ constructor (GType type, priv = NM_MODEM_GET_PRIVATE (object); if (!priv->device) { - g_warning ("Modem device not provided"); + g_warning ("Modem parent device not provided"); + goto err; + } + + if (!priv->device) { + g_warning ("Modem command interface not provided"); goto err; } @@ -696,8 +924,6 @@ constructor (GType type, object, NULL); - g_signal_connect (object, "state-changed", G_CALLBACK (device_state_changed), object); - query_mm_enabled (NM_MODEM (object)); return object; @@ -720,6 +946,9 @@ get_property (GObject *object, guint prop_id, case PROP_DEVICE: g_value_set_string (value, priv->device); break; + case PROP_IFACE: + g_value_set_string (value, priv->iface); + break; case PROP_IP_METHOD: g_value_set_uint (value, priv->ip_method); break; @@ -748,7 +977,12 @@ set_property (GObject *object, guint prop_id, /* Construct only */ priv->device = g_value_dup_string (value); break; + case PROP_IFACE: + /* Construct only */ + priv->iface = g_value_dup_string (value); + break; case PROP_IP_METHOD: + /* Construct only */ priv->ip_method = g_value_get_uint (value); break; case PROP_ENABLED: @@ -772,6 +1006,7 @@ finalize (GObject *object) g_object_unref (priv->dbus_mgr); + g_free (priv->iface); g_free (priv->path); g_free (priv->device); @@ -782,7 +1017,6 @@ static void nm_modem_class_init (NMModemClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); g_type_class_add_private (object_class, sizeof (NMModemPrivate)); @@ -792,12 +1026,8 @@ nm_modem_class_init (NMModemClass *klass) object_class->get_property = get_property; object_class->finalize = finalize; - device_class->get_generic_capabilities = real_get_generic_capabilities; - device_class->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start; - device_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; - device_class->deactivate_quickly = real_deactivate_quickly; - device_class->hw_is_up = real_hw_is_up; - device_class->hw_bring_up = real_hw_bring_up; + klass->act_stage1_prepare = real_act_stage1_prepare; + klass->deactivate_quickly = real_deactivate_quickly; /* Properties */ g_object_class_install_property @@ -806,7 +1036,7 @@ nm_modem_class_init (NMModemClass *klass) "DBus path", "DBus path", NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT)); + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_DEVICE, @@ -814,7 +1044,15 @@ nm_modem_class_init (NMModemClass *klass) "Device", "Master modem parent device", NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT)); + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, PROP_IFACE, + g_param_spec_string (NM_MODEM_IFACE, + "Interface", + "Modem command interface", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_IP_METHOD, @@ -824,7 +1062,7 @@ nm_modem_class_init (NMModemClass *klass) MM_MODEM_IP_METHOD_PPP, MM_MODEM_IP_METHOD_DHCP, MM_MODEM_IP_METHOD_PPP, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT)); + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_ENABLED, @@ -845,10 +1083,47 @@ nm_modem_class_init (NMModemClass *klass) G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); - signals[PROPERTIES_CHANGED] = - nm_properties_changed_signal_new (object_class, - G_STRUCT_OFFSET (NMModemClass, properties_changed)); + signals[PPP_FAILED] = + g_signal_new ("ppp-failed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMModemClass, ppp_failed), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); - dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_serial_device_object_info); + signals[IP4_CONFIG_RESULT] = + g_signal_new (NM_MODEM_IP4_CONFIG_RESULT, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMModemClass, ip4_config_result), + NULL, NULL, + _nm_marshal_VOID__STRING_OBJECT_POINTER, + G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_OBJECT, G_TYPE_POINTER); + + signals[PREPARE_RESULT] = + g_signal_new (NM_MODEM_PREPARE_RESULT, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMModemClass, prepare_result), + NULL, NULL, + _nm_marshal_VOID__BOOLEAN_UINT, + G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_UINT); + + signals[NEED_AUTH] = + g_signal_new (NM_MODEM_NEED_AUTH, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMModemClass, need_auth), + NULL, NULL, + _nm_marshal_VOID__STRING_BOOLEAN_UINT_STRING_STRING, + G_TYPE_NONE, 5, + G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING); } + +const DBusGObjectInfo * +nm_modem_get_serial_dbus_info (void) +{ + return &dbus_glib_nm_serial_device_object_info; +} + diff --git a/src/modem-manager/nm-modem.h b/src/modem-manager/nm-modem.h index 0a722764c2..a2aed57e00 100644 --- a/src/modem-manager/nm-modem.h +++ b/src/modem-manager/nm-modem.h @@ -23,8 +23,9 @@ #define NM_MODEM_H #include -#include +#include #include "ppp-manager/nm-ppp-manager.h" +#include "nm-device.h" G_BEGIN_DECLS @@ -37,36 +38,119 @@ G_BEGIN_DECLS #define NM_MODEM_PATH "path" #define NM_MODEM_DEVICE "device" +#define NM_MODEM_IFACE "iface" #define NM_MODEM_IP_METHOD "ip-method" #define NM_MODEM_ENABLED "enabled" +#define NM_MODEM_PPP_STATS "ppp-stats" +#define NM_MODEM_PPP_FAILED "ppp-failed" +#define NM_MODEM_PREPARE_RESULT "prepare-result" +#define NM_MODEM_IP4_CONFIG_RESULT "ip4-config-result" +#define NM_MODEM_NEED_AUTH "need-auth" + typedef struct { - NMDevice parent; + GObject parent; } NMModem; typedef struct { - NMDeviceClass parent; + GObjectClass parent; - const char *(*get_ppp_name) (NMModem *self, - NMConnection *connection); + gboolean (*get_user_pass) (NMModem *modem, + NMConnection *connection, + const char **user, + const char **pass); + + const char * (*get_setting_name) (NMModem *modem); + + gboolean (*check_connection_compatible) (NMModem *modem, + NMConnection *connection, + GError **error); + + NMConnection * (*get_best_auto_connection) (NMModem *modem, + GSList *connections, + char **specific_object); + + NMActStageReturn (*act_stage1_prepare) (NMModem *modem, + NMActRequest *req, + GPtrArray **out_hints, + const char **out_setting_name, + NMDeviceStateReason *reason); + + void (*deactivate_quickly) (NMModem *self, NMDevice *device); /* Signals */ - void (*ppp_stats) (NMModem *self, guint32 in_bytes, guint32 out_bytes); - void (*properties_changed) (NMModem *self, GHashTable *properties); + void (*ppp_stats) (NMModem *self, guint32 in_bytes, guint32 out_bytes); + void (*ppp_failed) (NMModem *self, NMDeviceStateReason reason); + + void (*prepare_result) (NMModem *self, gboolean success, NMDeviceStateReason reason); + void (*ip4_config_result) (NMModem *self, const char *iface, NMIP4Config *config, GError *error); + + void (*need_auth) (NMModem *self, + const char *setting_name, + gboolean retry, + RequestSecretsCaller caller, + const char *hint1, + const char *hint2); } NMModemClass; GType nm_modem_get_type (void); /* Protected */ -NMPPPManager *nm_modem_get_ppp_manager (NMModem *self); -DBusGProxy *nm_modem_get_proxy (NMModem *self, - const char *interface); +NMPPPManager *nm_modem_get_ppp_manager (NMModem *modem); +DBusGProxy * nm_modem_get_proxy (NMModem *modem, const char *interface); +const char * nm_modem_get_iface (NMModem *modem); +const char * nm_modem_get_path (NMModem *modem); -const char *nm_modem_get_ppp_name (NMModem *self, - NMConnection *connection); +NMConnection *nm_modem_get_best_auto_connection (NMModem *self, + GSList *connections, + char **specific_object); -gboolean nm_modem_get_mm_enabled (NMModem *self); +gboolean nm_modem_check_connection_compatible (NMModem *self, + NMConnection *connection, + GError **error); + +NMActStageReturn nm_modem_act_stage1_prepare (NMModem *modem, + NMActRequest *req, + NMDeviceStateReason *reason); + +NMActStageReturn nm_modem_act_stage2_config (NMModem *modem, + NMActRequest *req, + NMDeviceStateReason *reason); + +NMActStageReturn nm_modem_stage3_ip4_config_start (NMModem *modem, + NMDevice *device, + NMDeviceClass *device_class, + NMDeviceStateReason *reason); + +NMActStageReturn nm_modem_stage4_get_ip4_config (NMModem *modem, + NMDevice *device, + NMDeviceClass *device_class, + NMIP4Config **config, + NMDeviceStateReason *reason); + +void nm_modem_deactivate_quickly (NMModem *modem, NMDevice *device); + +void nm_modem_device_state_changed (NMModem *modem, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason); + +gboolean nm_modem_hw_is_up (NMModem *modem, NMDevice *device); + +gboolean nm_modem_hw_bring_up (NMModem *modem, NMDevice *device, gboolean *no_firmware); + +gboolean nm_modem_connection_secrets_updated (NMModem *modem, + NMActRequest *req, + NMConnection *connection, + GSList *updated_settings, + RequestSecretsCaller caller); + +const DBusGObjectInfo *nm_modem_get_serial_dbus_info (void); + +gboolean nm_modem_get_mm_enabled (NMModem *self); + +void nm_modem_set_mm_enabled (NMModem *self, gboolean enabled); G_END_DECLS diff --git a/src/nm-device-bt.c b/src/nm-device-bt.c index 444c7ff056..ab2572536e 100644 --- a/src/nm-device-bt.c +++ b/src/nm-device-bt.c @@ -52,13 +52,12 @@ typedef struct { guint32 capabilities; DBusGProxy *type_proxy; + DBusGProxy *dev_proxy; - NMPPPManager *ppp_manager; char *rfcomm_iface; - guint32 in_bytes; - guint32 out_bytes; + NMModem *modem; + guint32 timeout_id; - NMIP4Config *pending_ip4_config; guint32 bt_type; /* BT type of the current connection */ } NMDeviceBtPrivate; @@ -122,31 +121,6 @@ nm_bt_error_get_type (void) } -NMDevice * -nm_device_bt_new (const char *udi, - const char *bdaddr, - const char *name, - guint32 capabilities, - gboolean managed) -{ - g_return_val_if_fail (udi != NULL, NULL); - g_return_val_if_fail (bdaddr != NULL, NULL); - g_return_val_if_fail (name != NULL, NULL); - g_return_val_if_fail (capabilities != NM_BT_CAPABILITY_NONE, NULL); - - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BT, - NM_DEVICE_INTERFACE_UDI, udi, - NM_DEVICE_INTERFACE_IFACE, bdaddr, - NM_DEVICE_INTERFACE_DRIVER, "bluez", - NM_DEVICE_BT_HW_ADDRESS, bdaddr, - NM_DEVICE_BT_NAME, name, - NM_DEVICE_BT_CAPABILITIES, capabilities, - NM_DEVICE_INTERFACE_MANAGED, managed, - NM_DEVICE_INTERFACE_TYPE_DESC, "Bluetooth", - NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_BT, - NULL); -} - guint32 nm_device_bt_get_capabilities (NMDeviceBt *self) { g_return_val_if_fail (self != NULL, NM_BT_CAPABILITY_NONE); @@ -281,16 +255,26 @@ real_get_generic_capabilities (NMDevice *dev) /* IP method PPP */ static void -ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_data) +ppp_stats (NMModem *modem, + guint32 in_bytes, + guint32 out_bytes, + gpointer user_data) +{ + g_signal_emit (NM_DEVICE_BT (user_data), signals[PPP_STATS], 0, in_bytes, out_bytes); +} + +static void +ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data) { NMDevice *device = NM_DEVICE (user_data); - switch (status) { - case NM_PPP_STATUS_DISCONNECT: - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_DISCONNECT); - break; - case NM_PPP_STATUS_DEAD: - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_FAILED); + switch (nm_device_interface_get_state (NM_DEVICE_INTERFACE (device))) { + case NM_DEVICE_STATE_PREPARE: + case NM_DEVICE_STATE_CONFIG: + case NM_DEVICE_STATE_NEED_AUTH: + case NM_DEVICE_STATE_IP_CONFIG: + case NM_DEVICE_STATE_ACTIVATED: + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); break; default: break; @@ -298,68 +282,126 @@ ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_ } static void -ppp_ip4_config (NMPPPManager *ppp_manager, - const char *iface, - NMIP4Config *config, - gpointer user_data) +modem_need_auth (NMModem *modem, + const char *setting_name, + gboolean retry, + RequestSecretsCaller caller, + const char *hint1, + const char *hint2, + gpointer user_data) { - NMDevice *device = NM_DEVICE (user_data); + NMDeviceBt *self = NM_DEVICE_BT (user_data); + NMActRequest *req; - /* Ignore PPP IP4 events that come in after initial configuration */ - if (nm_device_get_state (device) != NM_DEVICE_STATE_IP_CONFIG) - return; + req = nm_device_get_act_request (NM_DEVICE (self)); + g_assert (req); - nm_device_set_ip_iface (device, iface); - NM_DEVICE_BT_GET_PRIVATE (device)->pending_ip4_config = g_object_ref (config); - nm_device_activate_schedule_stage4_ip4_config_get (device); + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); + nm_act_request_get_secrets (req, setting_name, retry, caller, hint1, hint2); } static void -ppp_stats (NMPPPManager *ppp_manager, - guint32 in_bytes, - guint32 out_bytes, - gpointer user_data) +modem_prepare_result (NMModem *modem, + gboolean success, + NMDeviceStateReason reason, + gpointer user_data) { - NMDeviceBt *self = NM_DEVICE_BT (user_data); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + NMDevice *device = NM_DEVICE (user_data); + NMDeviceState state; - if (priv->in_bytes != in_bytes || priv->out_bytes != out_bytes) { - priv->in_bytes = in_bytes; - priv->out_bytes = out_bytes; + state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device)); + g_return_if_fail (state == NM_DEVICE_STATE_CONFIG); - g_signal_emit (self, signals[PPP_STATS], 0, in_bytes, out_bytes); + if (success) { + NMActRequest *req; + NMActStageReturn ret; + NMDeviceStateReason stage2_reason = NM_DEVICE_STATE_REASON_NONE; + + req = nm_device_get_act_request (device); + g_assert (req); + + ret = nm_modem_act_stage2_config (modem, req, &stage2_reason); + switch (ret) { + case NM_ACT_STAGE_RETURN_POSTPONE: + break; + case NM_ACT_STAGE_RETURN_SUCCESS: + nm_device_activate_schedule_stage3_ip_config_start (device); + break; + case NM_ACT_STAGE_RETURN_FAILURE: + default: + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, stage2_reason); + break; + } + } else + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); +} + +static void +device_state_changed (NMDevice *device, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason, + gpointer user_data) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); + + if (priv->modem) + nm_modem_device_state_changed (priv->modem, new_state, old_state, reason); +} + +static void +modem_ip4_config_result (NMModem *self, + const char *iface, + NMIP4Config *config, + GError *error, + gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDeviceState state; + + state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device)); + g_return_if_fail (state == NM_DEVICE_STATE_IP_CONFIG); + + if (error) { + nm_warning ("%s: retrieving IP4 configuration failed: (%d) %s", + __func__, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + } else { + if (iface) + nm_device_set_ip_iface (device, iface); + + nm_device_activate_schedule_stage4_ip4_config_get (device); } } static gboolean -get_ppp_credentials (NMConnection *connection, - const char **username, - const char **password) +modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *reason) { - NMSettingGsm *s_gsm; - NMSettingCdma *s_cdma = NULL; + NMActRequest *req; + NMActStageReturn ret; - s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM); - if (s_gsm) { - if (username) - *username = nm_setting_gsm_get_username (s_gsm); - if (password) - *password = nm_setting_gsm_get_password (s_gsm); - } else { - /* Try CDMA then */ - s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA); - if (s_cdma) { - if (username) - *username = nm_setting_cdma_get_username (s_cdma); - if (password) - *password = nm_setting_cdma_get_password (s_cdma); - } + g_return_val_if_fail (reason != NULL, FALSE); + + req = nm_device_get_act_request (NM_DEVICE (self)); + g_assert (req); + + ret = nm_modem_act_stage1_prepare (modem, req, reason); + switch (ret) { + case NM_ACT_STAGE_RETURN_POSTPONE: + case NM_ACT_STAGE_RETURN_SUCCESS: + /* Success, wait for the 'prepare-result' signal */ + return TRUE; + case NM_ACT_STAGE_RETURN_FAILURE: + default: + break; } - return (s_cdma || s_gsm) ? TRUE : FALSE; + return FALSE; } - static void real_connection_secrets_updated (NMDevice *device, NMConnection *connection, @@ -369,111 +411,134 @@ real_connection_secrets_updated (NMDevice *device, NMDeviceBt *self = NM_DEVICE_BT (device); NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); NMActRequest *req; - const char *username = NULL, *password = NULL; - gboolean success = FALSE; + NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; - if (caller != SECRETS_CALLER_PPP) - return; - - g_return_if_fail (priv->ppp_manager); + g_return_if_fail (IS_ACTIVATING_STATE (nm_device_get_state (device))); req = nm_device_get_act_request (device); g_assert (req); - success = get_ppp_credentials (nm_act_request_get_connection (req), - &username, - &password); - if (success) { - nm_ppp_manager_update_secrets (priv->ppp_manager, - nm_device_get_ip_iface (device), - username ? username : "", - password ? password : "", - NULL); + if (!nm_modem_connection_secrets_updated (priv->modem, + req, + connection, + updated_settings, + caller)) { + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); return; } - /* Shouldn't ever happen */ - nm_ppp_manager_update_secrets (priv->ppp_manager, - nm_device_get_ip_iface (device), - NULL, - NULL, - "missing GSM/CDMA setting; no secrets could be found."); -} + /* PPP handles stuff itself... */ + if (caller == SECRETS_CALLER_PPP) + return; -static NMActStageReturn -ppp_stage3_start (NMDevice *device, NMDeviceStateReason *reason) -{ - NMDeviceBt *self = NM_DEVICE_BT (device); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - NMActRequest *req; - const char *ppp_name = NULL; - GError *err = NULL; - NMActStageReturn ret; - gboolean success; - - req = nm_device_get_act_request (device); - g_assert (req); - - success = get_ppp_credentials (nm_act_request_get_connection (req), - &ppp_name, - NULL); - if (!success) { - // FIXME: set reason to something plausible - return NM_ACT_STAGE_RETURN_FAILURE; - } - - priv->ppp_manager = nm_ppp_manager_new (priv->rfcomm_iface); - if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, 20, &err)) { - g_signal_connect (priv->ppp_manager, "state-changed", - G_CALLBACK (ppp_state_changed), - device); - g_signal_connect (priv->ppp_manager, "ip4-config", - G_CALLBACK (ppp_ip4_config), - device); - g_signal_connect (priv->ppp_manager, "stats", - G_CALLBACK (ppp_stats), - device); - - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else { - nm_warning ("%s", err->message); - g_error_free (err); - - g_object_unref (priv->ppp_manager); - priv->ppp_manager = NULL; - - *reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED; - ret = NM_ACT_STAGE_RETURN_FAILURE; - } - - return ret; -} - -static NMActStageReturn -ppp_stage4 (NMDevice *device, NMIP4Config **config, NMDeviceStateReason *reason) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); - NMConnection *connection; - NMSettingIP4Config *s_ip4; - - *config = priv->pending_ip4_config; - priv->pending_ip4_config = NULL; - - /* Merge user-defined overrides into the IP4Config to be applied */ - connection = nm_act_request_get_connection (nm_device_get_act_request (device)); - g_assert (connection); - s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); - nm_utils_merge_ip4_config (*config, s_ip4); - - return NM_ACT_STAGE_RETURN_SUCCESS; + /* Otherwise, on success for GSM/CDMA secrets we need to schedule modem stage1 again */ + g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH); + if (!modem_stage1 (self, priv->modem, &reason)) + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, reason); } /*****************************************************************************/ +gboolean +nm_device_bt_modem_added (NMDeviceBt *self, + NMModem *modem, + const char *driver) +{ + NMDeviceBtPrivate *priv; + const char *modem_iface; + char *base; + NMDeviceState state; + NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (NM_IS_DEVICE_BT (self), FALSE); + g_return_val_if_fail (modem != NULL, FALSE); + g_return_val_if_fail (NM_IS_MODEM (modem), FALSE); + + priv = NM_DEVICE_BT_GET_PRIVATE (self); + modem_iface = nm_modem_get_iface (modem); + g_return_val_if_fail (modem_iface != NULL, FALSE); + + if (!priv->rfcomm_iface) + return FALSE; + + base = g_path_get_basename (priv->rfcomm_iface); + if (strcmp (base, modem_iface)) { + g_free (base); + return FALSE; + } + g_free (base); + + /* Got the modem */ + if (priv->timeout_id) { + g_source_remove (priv->timeout_id); + priv->timeout_id = 0; + } + + /* Can only accept the modem in stage2, but since the interface matched + * what we were expecting, don't let anything else claim the modem either. + */ + state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self)); + if (state != NM_DEVICE_STATE_CONFIG) { + nm_warning ("(%s): modem found but device not in correct state (%d)", + nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_state (NM_DEVICE (self))); + return TRUE; + } + + nm_info ("Activation (%s/bluetooth) Stage 2 of 5 (Device Configure) modem found.", + nm_device_get_iface (NM_DEVICE (self))); + + if (priv->modem) { + g_warn_if_reached (); + g_object_unref (priv->modem); + } + + priv->modem = g_object_ref (modem); + g_signal_connect (modem, NM_MODEM_PPP_STATS, G_CALLBACK (ppp_stats), self); + g_signal_connect (modem, NM_MODEM_PPP_FAILED, G_CALLBACK (ppp_failed), self); + g_signal_connect (modem, NM_MODEM_PREPARE_RESULT, G_CALLBACK (modem_prepare_result), self); + g_signal_connect (modem, NM_MODEM_IP4_CONFIG_RESULT, G_CALLBACK (modem_ip4_config_result), self); + g_signal_connect (modem, NM_MODEM_NEED_AUTH, G_CALLBACK (modem_need_auth), self); + + /* Kick off the modem connection */ + if (!modem_stage1 (self, modem, &reason)) + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, reason); + + return TRUE; +} + +gboolean +nm_device_bt_modem_removed (NMDeviceBt *self, NMModem *modem) +{ + NMDeviceBtPrivate *priv; + NMDeviceState state; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (NM_IS_DEVICE_BT (self), FALSE); + g_return_val_if_fail (modem != NULL, FALSE); + g_return_val_if_fail (NM_IS_MODEM (modem), FALSE); + + priv = NM_DEVICE_BT_GET_PRIVATE (self); + + if (modem != priv->modem) + return FALSE; + + state = nm_device_get_state (NM_DEVICE (self)); + nm_modem_device_state_changed (priv->modem, + NM_DEVICE_STATE_DISCONNECTED, + state, + NM_DEVICE_STATE_REASON_USER_REQUESTED); + + g_object_unref (priv->modem); + priv->modem = NULL; + return TRUE; +} + static void -nm_device_bt_connect_cb (DBusGProxy *proxy, - DBusGProxyCall *call_id, - void *user_data) +bluez_connect_cb (DBusGProxy *proxy, + DBusGProxyCall *call_id, + void *user_data) { NMDeviceBt *self = NM_DEVICE_BT (user_data); NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); @@ -481,8 +546,8 @@ nm_device_bt_connect_cb (DBusGProxy *proxy, char *device; if (dbus_g_proxy_end_call (proxy, call_id, &error, - G_TYPE_STRING, &device, - G_TYPE_INVALID) == FALSE) { + G_TYPE_STRING, &device, + G_TYPE_INVALID) == FALSE) { nm_warning ("Error connecting with bluez: %s", error && error->message ? error->message : "(unknown)"); g_clear_error (&error); @@ -510,6 +575,20 @@ nm_device_bt_connect_cb (DBusGProxy *proxy, /* Stage 3 gets scheduled when Bluez says we're connected */ } +static gboolean +modem_find_timeout (gpointer user_data) +{ + NMDeviceBt *self = NM_DEVICE_BT (user_data); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + + priv->timeout_id = 0; + + nm_device_state_changed (NM_DEVICE (user_data), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND); + return FALSE; +} + static void bluez_property_changed (DBusGProxy *proxy, const char *property, @@ -528,18 +607,29 @@ bluez_property_changed (DBusGProxy *proxy, state = nm_device_get_state (device); connected = g_value_get_boolean (value); if (connected) { - /* Bluez says we're connected now. Start IP config. */ - if (state == NM_DEVICE_STATE_CONFIG) { gboolean pan = (priv->bt_type == NM_BT_CAPABILITY_NAP); gboolean dun = (priv->bt_type == NM_BT_CAPABILITY_DUN); nm_info ("Activation (%s/bluetooth) Stage 2 of 5 (Device Configure) " - "successful. Connected via %s.", + "successful. Will connect via %s.", nm_device_get_iface (device), dun ? "DUN" : (pan ? "PAN" : "unknown")); - nm_device_activate_schedule_stage3_ip_config_start (device); + if (pan) { + /* Bluez says we're connected now. Start IP config. */ + nm_device_activate_schedule_stage3_ip_config_start (device); + } else if (dun) { + /* Wait for ModemManager to find the modem */ + if (priv->timeout_id) + g_source_remove (priv->timeout_id); + priv->timeout_id = g_timeout_add_seconds (20, modem_find_timeout, self); + + nm_info ("Activation (%s/bluetooth) Stage 2 of 5 (Device Configure) " + "waiting for modem to appear.", + nm_device_get_iface (device)); + } else + g_assert_not_reached (); } } else { gboolean fail = FALSE; @@ -567,6 +657,7 @@ real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) NMActRequest *req; NMDBusManager *dbus_mgr; DBusGConnection *g_connection; + gboolean dun = FALSE; req = nm_device_get_act_request (device); g_assert (req); @@ -581,53 +672,50 @@ real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) g_connection = nm_dbus_manager_get_connection (dbus_mgr); g_object_unref (dbus_mgr); - if (priv->bt_type == NM_BT_CAPABILITY_DUN) { - priv->type_proxy = dbus_g_proxy_new_for_name (g_connection, - BLUEZ_SERVICE, - nm_device_get_udi (device), - BLUEZ_SERIAL_INTERFACE); - if (!priv->type_proxy) { - // FIXME: set a reason code - return NM_ACT_STAGE_RETURN_FAILURE; - } - - dbus_g_proxy_begin_call_with_timeout (priv->type_proxy, "Connect", - nm_device_bt_connect_cb, - device, - NULL, - 20000, - G_TYPE_STRING, BLUETOOTH_DUN_UUID, - G_TYPE_INVALID); - } else if (priv->bt_type == NM_BT_CAPABILITY_NAP) { - priv->type_proxy = dbus_g_proxy_new_for_name (g_connection, - BLUEZ_SERVICE, - nm_device_get_udi (device), - BLUEZ_NETWORK_INTERFACE); - if (!priv->type_proxy) { - // FIXME: set a reason code - return NM_ACT_STAGE_RETURN_FAILURE; - } - - dbus_g_proxy_begin_call_with_timeout (priv->type_proxy, "Connect", - nm_device_bt_connect_cb, - device, - NULL, - 20000, - G_TYPE_STRING, BLUETOOTH_NAP_UUID, - G_TYPE_INVALID); - } else + if (priv->bt_type == NM_BT_CAPABILITY_DUN) + dun = TRUE; + else if (priv->bt_type == NM_BT_CAPABILITY_NAP) + dun = FALSE; + else g_assert_not_reached (); + priv->dev_proxy = dbus_g_proxy_new_for_name (g_connection, + BLUEZ_SERVICE, + nm_device_get_udi (device), + BLUEZ_DEVICE_INTERFACE); + if (!priv->dev_proxy) { + // FIXME: set a reason code + return NM_ACT_STAGE_RETURN_FAILURE; + } + /* Watch for BT device property changes */ dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_BOXED, G_TYPE_NONE, G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID); - dbus_g_proxy_add_signal (priv->type_proxy, "PropertyChanged", + dbus_g_proxy_add_signal (priv->dev_proxy, "PropertyChanged", G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->type_proxy, "PropertyChanged", + dbus_g_proxy_connect_signal (priv->dev_proxy, "PropertyChanged", G_CALLBACK (bluez_property_changed), device, NULL); + priv->type_proxy = dbus_g_proxy_new_for_name (g_connection, + BLUEZ_SERVICE, + nm_device_get_udi (device), + dun ? BLUEZ_SERIAL_INTERFACE : BLUEZ_NETWORK_INTERFACE); + if (!priv->type_proxy) { + // FIXME: set a reason code + return NM_ACT_STAGE_RETURN_FAILURE; + } + + /* Connect to the BT device */ + dbus_g_proxy_begin_call_with_timeout (priv->type_proxy, "Connect", + bluez_connect_cb, + device, + NULL, + 20000, + G_TYPE_STRING, dun ? BLUETOOTH_DUN_UUID : BLUETOOTH_NAP_UUID, + G_TYPE_INVALID); + return NM_ACT_STAGE_RETURN_POSTPONE; } @@ -637,9 +725,12 @@ real_act_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason) NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); NMActStageReturn ret; - if (priv->bt_type == NM_BT_CAPABILITY_DUN) - ret = ppp_stage3_start (device, reason); - else + if (priv->bt_type == NM_BT_CAPABILITY_DUN) { + ret = nm_modem_stage3_ip4_config_start (NM_DEVICE_BT_GET_PRIVATE (device)->modem, + device, + NM_DEVICE_CLASS (nm_device_bt_parent_class), + reason); + } else ret = NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage3_ip4_config_start (device, reason); return ret; @@ -653,9 +744,13 @@ real_act_stage4_get_ip4_config (NMDevice *device, NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); NMActStageReturn ret; - if (priv->bt_type == NM_BT_CAPABILITY_DUN) - ret = ppp_stage4 (device, config, reason); - else + if (priv->bt_type == NM_BT_CAPABILITY_DUN) { + ret = nm_modem_stage4_get_ip4_config (NM_DEVICE_BT_GET_PRIVATE (device)->modem, + device, + NM_DEVICE_CLASS (nm_device_bt_parent_class), + config, + reason); + } else ret = NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage4_get_ip4_config (device, config, reason); return ret; @@ -666,17 +761,20 @@ real_deactivate_quickly (NMDevice *device) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); - if (priv->pending_ip4_config) { - g_object_unref (priv->pending_ip4_config); - priv->pending_ip4_config = NULL; - } - - priv->in_bytes = priv->out_bytes = 0; - if (priv->bt_type == NM_BT_CAPABILITY_DUN) { - if (priv->ppp_manager) { - g_object_unref (priv->ppp_manager); - priv->ppp_manager = NULL; + + if (priv->modem) { + nm_modem_deactivate_quickly (priv->modem, device); + + /* Since we're killing the Modem object before it'll get the + * state change signal, simulate the state change here. + */ + nm_modem_device_state_changed (priv->modem, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_ACTIVATED, + NM_DEVICE_STATE_REASON_USER_REQUESTED); + g_object_unref (priv->modem); + priv->modem = NULL; } if (priv->type_proxy) { @@ -700,6 +798,16 @@ real_deactivate_quickly (NMDevice *device) } } + if (priv->dev_proxy) { + g_object_unref (priv->dev_proxy); + priv->dev_proxy = NULL; + } + + if (priv->timeout_id) { + g_source_remove (priv->timeout_id); + priv->timeout_id = 0; + } + priv->bt_type = NM_BT_CAPABILITY_NONE; g_free (priv->rfcomm_iface); @@ -709,6 +817,39 @@ real_deactivate_quickly (NMDevice *device) NM_DEVICE_CLASS (nm_device_bt_parent_class)->deactivate_quickly (device); } +/*****************************************************************************/ + +NMDevice * +nm_device_bt_new (const char *udi, + const char *bdaddr, + const char *name, + guint32 capabilities, + gboolean managed) +{ + NMDevice *device; + + g_return_val_if_fail (udi != NULL, NULL); + g_return_val_if_fail (bdaddr != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (capabilities != NM_BT_CAPABILITY_NONE, NULL); + + device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_BT, + NM_DEVICE_INTERFACE_UDI, udi, + NM_DEVICE_INTERFACE_IFACE, bdaddr, + NM_DEVICE_INTERFACE_DRIVER, "bluez", + NM_DEVICE_BT_HW_ADDRESS, bdaddr, + NM_DEVICE_BT_NAME, name, + NM_DEVICE_BT_CAPABILITIES, capabilities, + NM_DEVICE_INTERFACE_MANAGED, managed, + NM_DEVICE_INTERFACE_TYPE_DESC, "Bluetooth", + NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_BT, + NULL); + if (device) + g_signal_connect (device, "state-changed", G_CALLBACK (device_state_changed), device); + + return device; +} + static void nm_device_bt_init (NMDeviceBt *self) { @@ -766,9 +907,21 @@ finalize (GObject *object) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); + if (priv->timeout_id) { + g_source_remove (priv->timeout_id); + priv->timeout_id = 0; + } + if (priv->type_proxy) g_object_unref (priv->type_proxy); + if (priv->dev_proxy) + g_object_unref (priv->dev_proxy); + + if (priv->modem) + g_object_unref (priv->modem); + + g_free (priv->rfcomm_iface); g_free (priv->bdaddr); g_free (priv->name); diff --git a/src/nm-device-bt.h b/src/nm-device-bt.h index 67ef6f5f25..d3187d766f 100644 --- a/src/nm-device-bt.h +++ b/src/nm-device-bt.h @@ -22,6 +22,7 @@ #define NM_DEVICE_BT_H #include +#include "nm-modem.h" G_BEGIN_DECLS @@ -60,6 +61,12 @@ guint32 nm_device_bt_get_capabilities (NMDeviceBt *device); const char *nm_device_bt_get_hw_address (NMDeviceBt *device); +gboolean nm_device_bt_modem_added (NMDeviceBt *device, + NMModem *modem, + const char *driver); + +gboolean nm_device_bt_modem_removed (NMDeviceBt *device, NMModem *modem); + G_END_DECLS #endif /* NM_GSM_DEVICE_H */ diff --git a/src/nm-device-cdma.c b/src/nm-device-cdma.c new file mode 100644 index 0000000000..bc73e9dab0 --- /dev/null +++ b/src/nm-device-cdma.c @@ -0,0 +1,411 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2009 - 2010 Red Hat, Inc. + */ + +#include + +#include "nm-dbus-glib-types.h" +#include "nm-modem.h" +#include "nm-modem-cdma.h" +#include "nm-device-interface.h" +#include "nm-device-private.h" +#include "nm-device-cdma.h" +#include "nm-utils.h" +#include "NetworkManagerUtils.h" +#include "nm-marshal.h" +#include "nm-properties-changed-signal.h" + +#include "nm-device-cdma-glue.h" + +static void device_interface_init (NMDeviceInterface *iface_class); + +G_DEFINE_TYPE_EXTENDED (NMDeviceCdma, nm_device_cdma, NM_TYPE_DEVICE, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_INTERFACE, device_interface_init)) + +#define NM_DEVICE_CDMA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_CDMA, NMDeviceCdmaPrivate)) + +typedef struct { + NMModem *modem; +} NMDeviceCdmaPrivate; + +enum { + PPP_STATS, + PROPERTIES_CHANGED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +ppp_stats (NMModem *modem, + guint32 in_bytes, + guint32 out_bytes, + gpointer user_data) +{ + g_signal_emit (NM_DEVICE_CDMA (user_data), signals[PPP_STATS], 0, in_bytes, out_bytes); +} + +static void +ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + + switch (nm_device_interface_get_state (NM_DEVICE_INTERFACE (device))) { + case NM_DEVICE_STATE_PREPARE: + case NM_DEVICE_STATE_CONFIG: + case NM_DEVICE_STATE_NEED_AUTH: + case NM_DEVICE_STATE_IP_CONFIG: + case NM_DEVICE_STATE_ACTIVATED: + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); + break; + default: + break; + } +} + +static void +device_state_changed (NMDevice *device, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason, + gpointer user_data) +{ + NMDeviceCdmaPrivate *priv = NM_DEVICE_CDMA_GET_PRIVATE (device); + + nm_modem_device_state_changed (priv->modem, new_state, old_state, reason); +} + +static gboolean +real_hw_is_up (NMDevice *device) +{ + return nm_modem_hw_is_up (NM_DEVICE_CDMA_GET_PRIVATE (device)->modem, device); +} + +static gboolean +real_hw_bring_up (NMDevice *device, gboolean *no_firmware) +{ + return nm_modem_hw_bring_up (NM_DEVICE_CDMA_GET_PRIVATE (device)->modem, device, no_firmware); +} + +static NMConnection * +real_get_best_auto_connection (NMDevice *device, + GSList *connections, + char **specific_object) +{ + NMDeviceCdmaPrivate *priv = NM_DEVICE_CDMA_GET_PRIVATE (device); + + return nm_modem_get_best_auto_connection (priv->modem, connections, specific_object); +} + +static void +real_connection_secrets_updated (NMDevice *device, + NMConnection *connection, + GSList *updated_settings, + RequestSecretsCaller caller) +{ + NMDeviceCdmaPrivate *priv = NM_DEVICE_CDMA_GET_PRIVATE (device); + NMActRequest *req; + + g_return_if_fail (IS_ACTIVATING_STATE (nm_device_get_state (device))); + + req = nm_device_get_act_request (device); + g_assert (req); + + if (!nm_modem_connection_secrets_updated (priv->modem, + req, + connection, + updated_settings, + caller)) { + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); + return; + } + + /* PPP handles stuff itself... */ + if (caller == SECRETS_CALLER_PPP) + return; + + /* Otherwise, on success for CDMA secrets we need to schedule stage1 again */ + g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH); + nm_device_activate_schedule_stage1_device_prepare (device); +} + +static gboolean +real_check_connection_compatible (NMDevice *device, + NMConnection *connection, + GError **error) +{ + NMDeviceCdmaPrivate *priv = NM_DEVICE_CDMA_GET_PRIVATE (device); + + return nm_modem_check_connection_compatible (priv->modem, connection, error); +} + + +static void +modem_need_auth (NMModem *modem, + const char *setting_name, + gboolean retry, + RequestSecretsCaller caller, + const char *hint1, + const char *hint2, + gpointer user_data) +{ + NMDeviceCdma *self = NM_DEVICE_CDMA (user_data); + NMActRequest *req; + + req = nm_device_get_act_request (NM_DEVICE (self)); + g_assert (req); + + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); + nm_act_request_get_secrets (req, setting_name, retry, caller, hint1, hint2); +} + +static void +modem_prepare_result (NMModem *modem, + gboolean success, + NMDeviceStateReason reason, + gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDeviceState state; + + state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device)); + g_return_if_fail (state == NM_DEVICE_STATE_PREPARE); + + if (success) + nm_device_activate_schedule_stage2_device_config (device); + else + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); +} + +static NMActStageReturn +real_act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) +{ + NMActRequest *req; + + req = nm_device_get_act_request (device); + g_assert (req); + + return nm_modem_act_stage1_prepare (NM_DEVICE_CDMA_GET_PRIVATE (device)->modem, req, reason); +} + +static NMActStageReturn +real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) +{ + NMActRequest *req; + + req = nm_device_get_act_request (device); + g_assert (req); + + return nm_modem_act_stage2_config (NM_DEVICE_CDMA_GET_PRIVATE (device)->modem, req, reason); +} + +static void +modem_ip4_config_result (NMModem *self, + const char *iface, + NMIP4Config *config, + GError *error, + gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDeviceState state; + + state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device)); + g_return_if_fail (state == NM_DEVICE_STATE_IP_CONFIG); + + if (error) { + nm_warning ("%s: retrieving IP4 configuration failed: (%d) %s", + __func__, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + } else { + if (iface) + nm_device_set_ip_iface (device, iface); + + nm_device_activate_schedule_stage4_ip4_config_get (device); + } +} + +static NMActStageReturn +real_act_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason) +{ + return nm_modem_stage3_ip4_config_start (NM_DEVICE_CDMA_GET_PRIVATE (device)->modem, + device, + NM_DEVICE_CLASS (nm_device_cdma_parent_class), + reason); +} + +static NMActStageReturn +real_act_stage4_get_ip4_config (NMDevice *device, + NMIP4Config **config, + NMDeviceStateReason *reason) +{ + return nm_modem_stage4_get_ip4_config (NM_DEVICE_CDMA_GET_PRIVATE (device)->modem, + device, + NM_DEVICE_CLASS (nm_device_cdma_parent_class), + config, + reason); +} + +static void +real_deactivate_quickly (NMDevice *device) +{ + NMDeviceCdmaPrivate *priv = NM_DEVICE_CDMA_GET_PRIVATE (device); + + nm_modem_deactivate_quickly (priv->modem, device); +} + +static guint32 +real_get_generic_capabilities (NMDevice *device) +{ + return NM_DEVICE_CAP_NM_SUPPORTED; +} + +static void +real_set_enabled (NMDeviceInterface *device, gboolean enabled) +{ + NMDeviceCdma *self = NM_DEVICE_CDMA (device); + NMDeviceCdmaPrivate *priv = NM_DEVICE_CDMA_GET_PRIVATE (self); + NMDeviceState state; + + if (priv->modem) { + nm_modem_set_mm_enabled (priv->modem, enabled); + + if (enabled == FALSE) { + state = nm_device_interface_get_state (device); + if (state == NM_DEVICE_STATE_ACTIVATED) { + nm_device_state_changed (NM_DEVICE (device), + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_NONE); + } + } + } +} + +static void +modem_enabled_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) +{ + NMDeviceCdma *self = NM_DEVICE_CDMA (user_data); + NMDeviceCdmaPrivate *priv = NM_DEVICE_CDMA_GET_PRIVATE (self); + + real_set_enabled (NM_DEVICE_INTERFACE (self), nm_modem_get_mm_enabled (priv->modem)); +} + +/*****************************************************************************/ + +NMDevice * +nm_device_cdma_new (NMModemCdma *modem, const char *driver) +{ + NMDevice *device; + + g_return_val_if_fail (modem != NULL, NULL); + g_return_val_if_fail (NM_IS_MODEM_CDMA (modem), NULL); + g_return_val_if_fail (driver != NULL, NULL); + + device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_CDMA, + NM_DEVICE_INTERFACE_UDI, nm_modem_get_path (NM_MODEM (modem)), + NM_DEVICE_INTERFACE_IFACE, nm_modem_get_iface (NM_MODEM (modem)), + NM_DEVICE_INTERFACE_DRIVER, driver, + NM_DEVICE_INTERFACE_TYPE_DESC, "CDMA", + NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_CDMA, + NULL); + if (device) { + g_signal_connect (device, "state-changed", G_CALLBACK (device_state_changed), device); + + NM_DEVICE_CDMA_GET_PRIVATE (device)->modem = g_object_ref (modem); + g_signal_connect (modem, NM_MODEM_PPP_STATS, G_CALLBACK (ppp_stats), device); + g_signal_connect (modem, NM_MODEM_PPP_FAILED, G_CALLBACK (ppp_failed), device); + g_signal_connect (modem, NM_MODEM_PREPARE_RESULT, G_CALLBACK (modem_prepare_result), device); + g_signal_connect (modem, NM_MODEM_IP4_CONFIG_RESULT, G_CALLBACK (modem_ip4_config_result), device); + g_signal_connect (modem, NM_MODEM_NEED_AUTH, G_CALLBACK (modem_need_auth), device); + g_signal_connect (modem, "notify::" NM_MODEM_ENABLED, G_CALLBACK (modem_enabled_cb), device); + } + + return device; +} + +static void +device_interface_init (NMDeviceInterface *iface_class) +{ + iface_class->set_enabled = real_set_enabled; +} + +static void +nm_device_cdma_init (NMDeviceCdma *self) +{ +} + +static void +finalize (GObject *object) +{ + NMDeviceCdmaPrivate *priv = NM_DEVICE_CDMA_GET_PRIVATE (object); + + g_object_unref (priv->modem); + priv->modem = NULL; + + G_OBJECT_CLASS (nm_device_cdma_parent_class)->finalize (object); +} + +static void +nm_device_cdma_class_init (NMDeviceCdmaClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMDeviceCdmaPrivate)); + + /* Virtual methods */ + object_class->finalize = finalize; + + device_class->get_best_auto_connection = real_get_best_auto_connection; + device_class->connection_secrets_updated = real_connection_secrets_updated; + device_class->check_connection_compatible = real_check_connection_compatible; + device_class->hw_is_up = real_hw_is_up; + device_class->hw_bring_up = real_hw_bring_up; + device_class->get_generic_capabilities = real_get_generic_capabilities; + device_class->act_stage1_prepare = real_act_stage1_prepare; + device_class->act_stage2_config = real_act_stage2_config; + device_class->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start; + device_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; + device_class->deactivate_quickly = real_deactivate_quickly; + + /* Signals */ + signals[PPP_STATS] = + g_signal_new ("ppp-stats", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMDeviceCdmaClass, ppp_stats), + NULL, NULL, + _nm_marshal_VOID__UINT_UINT, + G_TYPE_NONE, 2, + G_TYPE_UINT, G_TYPE_UINT); + + signals[PROPERTIES_CHANGED] = + nm_properties_changed_signal_new (object_class, + G_STRUCT_OFFSET (NMDeviceCdmaClass, properties_changed)); + + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), + nm_modem_get_serial_dbus_info ()); + + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), + &dbus_glib_nm_device_cdma_object_info); +} + diff --git a/src/nm-device-cdma.h b/src/nm-device-cdma.h new file mode 100644 index 0000000000..ec4496d742 --- /dev/null +++ b/src/nm-device-cdma.h @@ -0,0 +1,56 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2009 Red Hat, Inc. + */ + +#ifndef NM_DEVICE_CDMA_H +#define NM_DEVICE_CDMA_H + +#include "nm-device.h" +#include "nm-modem-cdma.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_CDMA (nm_device_cdma_get_type ()) +#define NM_DEVICE_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_CDMA, NMDeviceCdma)) +#define NM_DEVICE_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_CDMA, NMDeviceCdmaClass)) +#define NM_IS_DEVICE_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_CDMA)) +#define NM_IS_DEVICE_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_CDMA)) +#define NM_DEVICE_CDMA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_CDMA, NMDeviceCdmaClass)) + +typedef struct { + NMDevice parent; +} NMDeviceCdma; + +typedef struct { + NMDeviceClass parent; + + /* Signals */ + void (*signal_quality) (NMDeviceCdma *self, guint32 quality); + + void (*ppp_stats) (NMDeviceCdma *self, guint32 in_bytes, guint32 out_bytes); + void (*properties_changed) (NMDeviceCdma *self, GHashTable *properties); +} NMDeviceCdmaClass; + +GType nm_device_cdma_get_type (void); + +NMDevice *nm_device_cdma_new (NMModemCdma *modem, const char *driver); + +G_END_DECLS + +#endif /* NM_DEVICE_CDMA_H */ diff --git a/src/nm-device-gsm.c b/src/nm-device-gsm.c new file mode 100644 index 0000000000..1bb7017533 --- /dev/null +++ b/src/nm-device-gsm.c @@ -0,0 +1,411 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2009 - 2010 Red Hat, Inc. + */ + +#include + +#include "nm-dbus-glib-types.h" +#include "nm-modem.h" +#include "nm-modem-gsm.h" +#include "nm-device-interface.h" +#include "nm-device-private.h" +#include "nm-device-gsm.h" +#include "nm-utils.h" +#include "NetworkManagerUtils.h" +#include "nm-marshal.h" +#include "nm-properties-changed-signal.h" + +#include "nm-device-gsm-glue.h" + +static void device_interface_init (NMDeviceInterface *iface_class); + +G_DEFINE_TYPE_EXTENDED (NMDeviceGsm, nm_device_gsm, NM_TYPE_DEVICE, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_INTERFACE, device_interface_init)) + +#define NM_DEVICE_GSM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_GSM, NMDeviceGsmPrivate)) + +typedef struct { + NMModem *modem; +} NMDeviceGsmPrivate; + +enum { + PPP_STATS, + PROPERTIES_CHANGED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +ppp_stats (NMModem *modem, + guint32 in_bytes, + guint32 out_bytes, + gpointer user_data) +{ + g_signal_emit (NM_DEVICE_GSM (user_data), signals[PPP_STATS], 0, in_bytes, out_bytes); +} + +static void +ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + + switch (nm_device_interface_get_state (NM_DEVICE_INTERFACE (device))) { + case NM_DEVICE_STATE_PREPARE: + case NM_DEVICE_STATE_CONFIG: + case NM_DEVICE_STATE_NEED_AUTH: + case NM_DEVICE_STATE_IP_CONFIG: + case NM_DEVICE_STATE_ACTIVATED: + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); + break; + default: + break; + } +} + +static void +device_state_changed (NMDevice *device, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason, + gpointer user_data) +{ + NMDeviceGsmPrivate *priv = NM_DEVICE_GSM_GET_PRIVATE (device); + + nm_modem_device_state_changed (priv->modem, new_state, old_state, reason); +} + +static gboolean +real_hw_is_up (NMDevice *device) +{ + return nm_modem_hw_is_up (NM_DEVICE_GSM_GET_PRIVATE (device)->modem, device); +} + +static gboolean +real_hw_bring_up (NMDevice *device, gboolean *no_firmware) +{ + return nm_modem_hw_bring_up (NM_DEVICE_GSM_GET_PRIVATE (device)->modem, device, no_firmware); +} + +static NMConnection * +real_get_best_auto_connection (NMDevice *device, + GSList *connections, + char **specific_object) +{ + NMDeviceGsmPrivate *priv = NM_DEVICE_GSM_GET_PRIVATE (device); + + return nm_modem_get_best_auto_connection (priv->modem, connections, specific_object); +} + +static void +real_connection_secrets_updated (NMDevice *device, + NMConnection *connection, + GSList *updated_settings, + RequestSecretsCaller caller) +{ + NMDeviceGsmPrivate *priv = NM_DEVICE_GSM_GET_PRIVATE (device); + NMActRequest *req; + + g_return_if_fail (IS_ACTIVATING_STATE (nm_device_get_state (device))); + + req = nm_device_get_act_request (device); + g_assert (req); + + if (!nm_modem_connection_secrets_updated (priv->modem, + req, + connection, + updated_settings, + caller)) { + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); + return; + } + + /* PPP handles stuff itself... */ + if (caller == SECRETS_CALLER_PPP) + return; + + /* Otherwise, on success for GSM secrets we need to schedule stage1 again */ + g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH); + nm_device_activate_schedule_stage1_device_prepare (device); +} + +static gboolean +real_check_connection_compatible (NMDevice *device, + NMConnection *connection, + GError **error) +{ + NMDeviceGsmPrivate *priv = NM_DEVICE_GSM_GET_PRIVATE (device); + + return nm_modem_check_connection_compatible (priv->modem, connection, error); +} + + +static void +modem_need_auth (NMModem *modem, + const char *setting_name, + gboolean retry, + RequestSecretsCaller caller, + const char *hint1, + const char *hint2, + gpointer user_data) +{ + NMDeviceGsm *self = NM_DEVICE_GSM (user_data); + NMActRequest *req; + + req = nm_device_get_act_request (NM_DEVICE (self)); + g_assert (req); + + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); + nm_act_request_get_secrets (req, setting_name, retry, caller, hint1, hint2); +} + +static void +modem_prepare_result (NMModem *modem, + gboolean success, + NMDeviceStateReason reason, + gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDeviceState state; + + state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device)); + g_return_if_fail (state == NM_DEVICE_STATE_PREPARE); + + if (success) + nm_device_activate_schedule_stage2_device_config (device); + else + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); +} + +static NMActStageReturn +real_act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) +{ + NMActRequest *req; + + req = nm_device_get_act_request (device); + g_assert (req); + + return nm_modem_act_stage1_prepare (NM_DEVICE_GSM_GET_PRIVATE (device)->modem, req, reason); +} + +static NMActStageReturn +real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) +{ + NMActRequest *req; + + req = nm_device_get_act_request (device); + g_assert (req); + + return nm_modem_act_stage2_config (NM_DEVICE_GSM_GET_PRIVATE (device)->modem, req, reason); +} + +static void +modem_ip4_config_result (NMModem *self, + const char *iface, + NMIP4Config *config, + GError *error, + gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDeviceState state; + + state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device)); + g_return_if_fail (state == NM_DEVICE_STATE_IP_CONFIG); + + if (error) { + nm_warning ("%s: retrieving IP4 configuration failed: (%d) %s", + __func__, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + } else { + if (iface) + nm_device_set_ip_iface (device, iface); + + nm_device_activate_schedule_stage4_ip4_config_get (device); + } +} + +static NMActStageReturn +real_act_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason) +{ + return nm_modem_stage3_ip4_config_start (NM_DEVICE_GSM_GET_PRIVATE (device)->modem, + device, + NM_DEVICE_CLASS (nm_device_gsm_parent_class), + reason); +} + +static NMActStageReturn +real_act_stage4_get_ip4_config (NMDevice *device, + NMIP4Config **config, + NMDeviceStateReason *reason) +{ + return nm_modem_stage4_get_ip4_config (NM_DEVICE_GSM_GET_PRIVATE (device)->modem, + device, + NM_DEVICE_CLASS (nm_device_gsm_parent_class), + config, + reason); +} + +static void +real_deactivate_quickly (NMDevice *device) +{ + NMDeviceGsmPrivate *priv = NM_DEVICE_GSM_GET_PRIVATE (device); + + nm_modem_deactivate_quickly (priv->modem, device); +} + +static guint32 +real_get_generic_capabilities (NMDevice *device) +{ + return NM_DEVICE_CAP_NM_SUPPORTED; +} + +static void +real_set_enabled (NMDeviceInterface *device, gboolean enabled) +{ + NMDeviceGsm *self = NM_DEVICE_GSM (device); + NMDeviceGsmPrivate *priv = NM_DEVICE_GSM_GET_PRIVATE (self); + NMDeviceState state; + + if (priv->modem) { + nm_modem_set_mm_enabled (priv->modem, enabled); + + if (enabled == FALSE) { + state = nm_device_interface_get_state (device); + if (state == NM_DEVICE_STATE_ACTIVATED) { + nm_device_state_changed (NM_DEVICE (device), + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_NONE); + } + } + } +} + +static void +modem_enabled_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) +{ + NMDeviceGsm *self = NM_DEVICE_GSM (user_data); + NMDeviceGsmPrivate *priv = NM_DEVICE_GSM_GET_PRIVATE (self); + + real_set_enabled (NM_DEVICE_INTERFACE (self), nm_modem_get_mm_enabled (priv->modem)); +} + +/*****************************************************************************/ + +NMDevice * +nm_device_gsm_new (NMModemGsm *modem, const char *driver) +{ + NMDevice *device; + + g_return_val_if_fail (modem != NULL, NULL); + g_return_val_if_fail (NM_IS_MODEM_GSM (modem), NULL); + g_return_val_if_fail (driver != NULL, NULL); + + device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_GSM, + NM_DEVICE_INTERFACE_UDI, nm_modem_get_path (NM_MODEM (modem)), + NM_DEVICE_INTERFACE_IFACE, nm_modem_get_iface (NM_MODEM (modem)), + NM_DEVICE_INTERFACE_DRIVER, driver, + NM_DEVICE_INTERFACE_TYPE_DESC, "GSM", + NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_GSM, + NULL); + if (device) { + g_signal_connect (device, "state-changed", G_CALLBACK (device_state_changed), device); + + NM_DEVICE_GSM_GET_PRIVATE (device)->modem = g_object_ref (modem); + g_signal_connect (modem, NM_MODEM_PPP_STATS, G_CALLBACK (ppp_stats), device); + g_signal_connect (modem, NM_MODEM_PPP_FAILED, G_CALLBACK (ppp_failed), device); + g_signal_connect (modem, NM_MODEM_PREPARE_RESULT, G_CALLBACK (modem_prepare_result), device); + g_signal_connect (modem, NM_MODEM_IP4_CONFIG_RESULT, G_CALLBACK (modem_ip4_config_result), device); + g_signal_connect (modem, NM_MODEM_NEED_AUTH, G_CALLBACK (modem_need_auth), device); + g_signal_connect (modem, "notify::" NM_MODEM_ENABLED, G_CALLBACK (modem_enabled_cb), device); + } + + return device; +} + +static void +device_interface_init (NMDeviceInterface *iface_class) +{ + iface_class->set_enabled = real_set_enabled; +} + +static void +nm_device_gsm_init (NMDeviceGsm *self) +{ +} + +static void +finalize (GObject *object) +{ + NMDeviceGsmPrivate *priv = NM_DEVICE_GSM_GET_PRIVATE (object); + + g_object_unref (priv->modem); + priv->modem = NULL; + + G_OBJECT_CLASS (nm_device_gsm_parent_class)->finalize (object); +} + +static void +nm_device_gsm_class_init (NMDeviceGsmClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMDeviceGsmPrivate)); + + /* Virtual methods */ + object_class->finalize = finalize; + + device_class->get_best_auto_connection = real_get_best_auto_connection; + device_class->connection_secrets_updated = real_connection_secrets_updated; + device_class->check_connection_compatible = real_check_connection_compatible; + device_class->hw_is_up = real_hw_is_up; + device_class->hw_bring_up = real_hw_bring_up; + device_class->get_generic_capabilities = real_get_generic_capabilities; + device_class->act_stage1_prepare = real_act_stage1_prepare; + device_class->act_stage2_config = real_act_stage2_config; + device_class->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start; + device_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; + device_class->deactivate_quickly = real_deactivate_quickly; + + /* Signals */ + signals[PPP_STATS] = + g_signal_new ("ppp-stats", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMDeviceGsmClass, ppp_stats), + NULL, NULL, + _nm_marshal_VOID__UINT_UINT, + G_TYPE_NONE, 2, + G_TYPE_UINT, G_TYPE_UINT); + + signals[PROPERTIES_CHANGED] = + nm_properties_changed_signal_new (object_class, + G_STRUCT_OFFSET (NMDeviceGsmClass, properties_changed)); + + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), + nm_modem_get_serial_dbus_info ()); + + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), + &dbus_glib_nm_device_gsm_object_info); +} + diff --git a/src/nm-device-gsm.h b/src/nm-device-gsm.h new file mode 100644 index 0000000000..1a74cfa1cd --- /dev/null +++ b/src/nm-device-gsm.h @@ -0,0 +1,56 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2009 Red Hat, Inc. + */ + +#ifndef NM_DEVICE_GSM_H +#define NM_DEVICE_GSM_H + +#include "nm-device.h" +#include "nm-modem-gsm.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_GSM (nm_device_gsm_get_type ()) +#define NM_DEVICE_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_GSM, NMDeviceGsm)) +#define NM_DEVICE_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_GSM, NMDeviceGsmClass)) +#define NM_IS_DEVICE_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_GSM)) +#define NM_IS_DEVICE_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_GSM)) +#define NM_DEVICE_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_GSM, NMDeviceGsmClass)) + +typedef struct { + NMDevice parent; +} NMDeviceGsm; + +typedef struct { + NMDeviceClass parent; + + /* Signals */ + void (*signal_quality) (NMDeviceGsm *self, guint32 quality); + + void (*ppp_stats) (NMDeviceGsm *self, guint32 in_bytes, guint32 out_bytes); + void (*properties_changed) (NMDeviceGsm *self, GHashTable *properties); +} NMDeviceGsmClass; + +GType nm_device_gsm_get_type (void); + +NMDevice *nm_device_gsm_new (NMModemGsm *modem, const char *driver); + +G_END_DECLS + +#endif /* NM_DEVICE_GSM_H */ diff --git a/src/nm-manager.c b/src/nm-manager.c index ff7535591d..f49c670b2c 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -37,6 +37,8 @@ #include "nm-device-ethernet.h" #include "nm-device-wifi.h" #include "nm-device-olpc-mesh.h" +#include "nm-device-cdma.h" +#include "nm-device-gsm.h" #include "NetworkManagerSystem.h" #include "nm-properties-changed-signal.h" #include "nm-setting-bluetooth.h" @@ -127,15 +129,15 @@ static const char *internal_activate_device (NMManager *manager, gboolean assumed, GError **error); -static NMDevice * -find_device_by_iface (NMManager *self, const gchar *iface); +static NMDevice *find_device_by_iface (NMManager *self, const gchar *iface); -static GSList * -remove_one_device (NMManager *manager, - GSList *list, - NMDevice *device, - gboolean quitting, - gboolean force_unmanage); +static GSList * remove_one_device (NMManager *manager, + GSList *list, + NMDevice *device, + gboolean quitting, + gboolean force_unmanage); + +static NMDevice *nm_manager_get_device_by_udi (NMManager *manager, const char *udi); #define SSD_POKE_INTERVAL 120 #define ORIGDEV_TAG "originating-device" @@ -310,26 +312,17 @@ vpn_manager_connection_deactivated_cb (NMVPNManager *manager, static void modem_added (NMModemManager *modem_manager, - NMDevice *modem, + NMModem *modem, + const char *driver, gpointer user_data) { - NMManagerPrivate *priv; - NMDeviceType type; - NMDevice *replace_device; - const char *type_name; + NMManager *self = NM_MANAGER (user_data); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMDevice *replace_device, *device = NULL; const char *ip_iface; + GSList *iter; - priv = NM_MANAGER_GET_PRIVATE (user_data); - - type = nm_device_get_device_type (NM_DEVICE (modem)); - if (type == NM_DEVICE_TYPE_GSM) - type_name = "GSM modem"; - else if (type == NM_DEVICE_TYPE_CDMA) - type_name = "CDMA modem"; - else - type_name = "Unknown modem"; - - ip_iface = nm_device_get_ip_iface (modem); + ip_iface = nm_modem_get_iface (modem); replace_device = find_device_by_iface (NM_MANAGER (user_data), ip_iface); if (replace_device) { @@ -340,7 +333,34 @@ modem_added (NMModemManager *modem_manager, TRUE); } - add_device (NM_MANAGER (user_data), NM_DEVICE (g_object_ref (modem))); + /* Give Bluetooth DUN devices first chance to claim the modem */ + for (iter = priv->devices; iter; iter = g_slist_next (iter)) { + if (NM_IS_DEVICE_BT (iter->data)) { + if (nm_device_bt_modem_added (NM_DEVICE_BT (iter->data), modem, driver)) + return; + } + } + + /* If it was a Bluetooth modem and no bluetooth device claimed it, ignore + * it. The rfcomm port (and thus the modem) gets created automatically + * by the Bluetooth code during the connection process. + */ + if (driver && !strcmp (driver, "bluetooth")) { + g_message ("%s: ignoring modem '%s' (no associated Bluetooth device)", + __func__, ip_iface); + return; + } + + /* Otherwise make a new top-level NMDevice for it */ + if (NM_IS_MODEM_GSM (modem)) + device = nm_device_gsm_new (NM_MODEM_GSM (modem), driver); + else if (NM_IS_MODEM_CDMA (modem)) + device = nm_device_cdma_new (NM_MODEM_CDMA (modem), driver); + else + g_message ("%s: unhandled modem '%s'", __func__, ip_iface); + + if (device) + add_device (self, device); } static void @@ -438,13 +458,26 @@ remove_one_device (NMManager *manager, static void modem_removed (NMModemManager *modem_manager, - NMDevice *modem, + NMModem *modem, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMDevice *found; + GSList *iter; - priv->devices = remove_one_device (self, priv->devices, modem, FALSE, TRUE); + /* Give Bluetooth DUN devices first chance to handle the modem removal */ + for (iter = priv->devices; iter; iter = g_slist_next (iter)) { + if (NM_IS_DEVICE_BT (iter->data)) { + if (nm_device_bt_modem_removed (NM_DEVICE_BT (iter->data), modem)) + return; + } + } + + /* Otherwise remove the standalone modem */ + found = nm_manager_get_device_by_udi (self, nm_modem_get_path (modem)); + if (found) + priv->devices = remove_one_device (self, priv->devices, found, FALSE, TRUE); } static void @@ -1440,7 +1473,7 @@ add_device (NMManager *self, NMDevice *device) iface = nm_device_get_ip_iface (device); g_assert (iface); - if (!NM_IS_MODEM(device) && nm_modem_manager_has_modem_for_iface (priv->modem_manager, iface)) { + if (!NM_IS_MODEM (device) && find_device_by_iface (self, iface)) { g_object_unref (device); return; } @@ -1733,12 +1766,14 @@ find_device_by_iface (NMManager *self, const gchar *iface) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); GSList *iter; + for (iter = priv->devices; iter; iter = g_slist_next (iter)) { NMDevice *device = NM_DEVICE (iter->data); const gchar *d_iface = nm_device_get_ip_iface (device); if (!strcmp (d_iface, iface)) return device; } + return NULL; } @@ -3124,9 +3159,9 @@ nm_manager_init (NMManager *manager) g_object_unref); priv->modem_manager = nm_modem_manager_get (); - priv->modem_added_id = g_signal_connect (priv->modem_manager, "device-added", + priv->modem_added_id = g_signal_connect (priv->modem_manager, "modem-added", G_CALLBACK (modem_added), manager); - priv->modem_removed_id = g_signal_connect (priv->modem_manager, "device-removed", + priv->modem_removed_id = g_signal_connect (priv->modem_manager, "modem-removed", G_CALLBACK (modem_removed), manager); priv->vpn_manager = nm_vpn_manager_get (); diff --git a/src/nm-secrets-provider-interface.h b/src/nm-secrets-provider-interface.h index 299e8c2dc8..3d9e08b186 100644 --- a/src/nm-secrets-provider-interface.h +++ b/src/nm-secrets-provider-interface.h @@ -28,8 +28,7 @@ typedef enum { SECRETS_CALLER_NONE = 0, SECRETS_CALLER_ETHERNET, SECRETS_CALLER_WIFI, - SECRETS_CALLER_GSM, - SECRETS_CALLER_CDMA, + SECRETS_CALLER_MOBILE_BROADBAND, SECRETS_CALLER_PPP, SECRETS_CALLER_VPN } RequestSecretsCaller;