From fe6b86a0789551e364908bf21e205c21b75dc0a1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 10 Feb 2014 06:56:54 -0600 Subject: core: don't ref the Manager singleton The OLPC mesh code did rely on nm_manager_get() referencing the singleton when returning it, but all other callers of nm_manager_get() did not. Thus the manager's refcount would always increase and almost never decrease. Fix the refcounting so that the manager always has only one ref, and it's lifetime is controlled by main() and nothing else. --- src/devices/nm-device-olpc-mesh.c | 14 +++----------- src/main.c | 2 +- src/nm-manager.c | 2 +- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/devices/nm-device-olpc-mesh.c b/src/devices/nm-device-olpc-mesh.c index c419daa5e7..b85956ef63 100644 --- a/src/devices/nm-device-olpc-mesh.c +++ b/src/devices/nm-device-olpc-mesh.c @@ -362,7 +362,6 @@ dispose (GObject *object) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (object); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); - NMManager *manager; if (priv->dispose_has_run) { G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object); @@ -375,12 +374,10 @@ dispose (GObject *object) companion_cleanup (self); - manager = nm_manager_get (); if (priv->device_added_id) - g_signal_handler_disconnect (manager, priv->device_added_id); + g_signal_handler_disconnect (nm_manager_get (), priv->device_added_id); if (priv->device_removed_id) - g_signal_handler_disconnect (manager, priv->device_removed_id); - g_object_unref (manager); + g_signal_handler_disconnect (nm_manager_get (), priv->device_removed_id); G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object); } @@ -536,7 +533,6 @@ is_companion (NMDeviceOlpcMesh *self, NMDevice *other) NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); const guint8 *my_addr, *their_addr; guint their_addr_len; - NMManager *manager; if (!NM_IS_DEVICE_WIFI (other)) return FALSE; @@ -550,12 +546,10 @@ is_companion (NMDeviceOlpcMesh *self, NMDevice *other) priv->companion = other; /* When we've found the companion, stop listening for other devices */ - manager = nm_manager_get (); if (priv->device_added_id) { - g_signal_handler_disconnect (manager, priv->device_added_id); + g_signal_handler_disconnect (nm_manager_get (), priv->device_added_id); priv->device_added_id = 0; } - g_object_unref (manager); nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, @@ -632,8 +626,6 @@ check_companion_cb (gpointer user_data) break; } - g_object_unref (manager); - done: nm_device_remove_pending_action (NM_DEVICE (self), "waiting for companion"); return FALSE; diff --git a/src/main.c b/src/main.c index a25432feef..16a124c14f 100644 --- a/src/main.c +++ b/src/main.c @@ -66,7 +66,6 @@ /* * Globals */ -static NMManager *manager = NULL; static GMainLoop *main_loop = NULL; static gboolean quit_early = FALSE; static sigset_t signal_set; @@ -312,6 +311,7 @@ main (int argc, char *argv[]) gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE, wimax_enabled = TRUE; gboolean success, show_version = FALSE; int i; + NMManager *manager = NULL; gs_unref_object NMVPNManager *vpn_manager = NULL; gs_unref_object NMDnsManager *dns_mgr = NULL; gs_unref_object NMDBusManager *dbus_mgr = NULL; diff --git a/src/nm-manager.c b/src/nm-manager.c index da99a02d77..6126c86281 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -4690,7 +4690,7 @@ NMManager * nm_manager_get (void) { g_assert (singleton); - return g_object_ref (singleton); + return singleton; } NMManager * -- cgit v1.2.1 From fd3fe2200c13562ea9229fa8d1fa266136ed46e9 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 10 Feb 2014 06:59:05 -0600 Subject: core: add nm_connection_provider_get() In reality the connection provider (NMSettings) is always the same object, and some device plugins need access to it. Instead of cluttering up the device plugin API by passing the provider into every plugin regardless of whether the plugin needs it, create a getter function. --- src/devices/nm-device-private.h | 2 - src/devices/nm-device-vlan.c | 3 +- src/devices/nm-device-wifi.c | 3 +- src/devices/nm-device.c | 88 +++++++++++------------------------------ src/devices/nm-device.h | 2 - src/nm-connection-provider.h | 7 ++++ src/nm-manager.c | 10 ++++- 7 files changed, 41 insertions(+), 74 deletions(-) diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index 3da14795c4..e4e5a4dbca 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -80,8 +80,6 @@ void nm_device_set_dhcp_anycast_address (NMDevice *device, guint8 *addr); gboolean nm_device_dhcp4_renew (NMDevice *device, gboolean release); -NMConnectionProvider *nm_device_get_connection_provider (NMDevice *device); - void nm_device_recheck_available_connections (NMDevice *device); void nm_device_queued_state_clear (NMDevice *device); diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index f64fd87eb7..8e10aef5d8 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -341,11 +341,10 @@ update_connection (NMDevice *device, NMConnection *connection) new_parent = nm_device_get_iface (parent); setting_parent = nm_setting_vlan_get_parent (s_vlan); if (setting_parent && nm_utils_is_uuid (setting_parent)) { - NMConnectionProvider *cp = nm_device_get_connection_provider (device); NMConnection *parent_connection; /* Don't change a parent specified by UUID if it's still valid */ - parent_connection = nm_connection_provider_get_connection_by_uuid (cp, setting_parent); + parent_connection = nm_connection_provider_get_connection_by_uuid (nm_connection_provider_get (), setting_parent); if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection, NULL)) new_parent = NULL; } diff --git a/src/devices/nm-device-wifi.c b/src/devices/nm-device-wifi.c index fe4c7e0f91..f9c77d1409 100644 --- a/src/devices/nm-device-wifi.c +++ b/src/devices/nm-device-wifi.c @@ -1603,7 +1603,6 @@ build_hidden_probe_list (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); guint max_scan_ssids = nm_supplicant_interface_get_max_scan_ssids (priv->supplicant.iface); - NMConnectionProvider *provider = nm_device_get_connection_provider (NM_DEVICE (self)); GSList *connections, *iter; GPtrArray *ssids = NULL; static GByteArray *nullssid = NULL; @@ -1616,7 +1615,7 @@ build_hidden_probe_list (NMDeviceWifi *self) if (G_UNLIKELY (nullssid == NULL)) nullssid = g_byte_array_new (); - connections = nm_connection_provider_get_best_connections (provider, + connections = nm_connection_provider_get_best_connections (nm_connection_provider_get (), max_scan_ssids - 1, NM_SETTING_WIRELESS_SETTING_NAME, NULL, diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index e5db1f5f89..5c18a3cb8c 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -315,13 +315,6 @@ typedef struct { GSList * slaves; /* list of SlaveInfo */ NMConnectionProvider *con_provider; - - /* connection provider signals for available connections property */ - guint cp_added_id; - guint cp_loaded_id; - guint cp_removed_id; - guint cp_updated_id; - } NMDevicePrivate; static gboolean nm_device_set_ip4_config (NMDevice *dev, @@ -613,6 +606,23 @@ constructed (GObject *object) if (priv->ifindex > 0) priv->mtu = nm_platform_link_get_mtu (priv->ifindex); + priv->con_provider = nm_connection_provider_get (); + g_assert (priv->con_provider); + g_signal_connect (priv->con_provider, + NM_CP_SIGNAL_CONNECTION_ADDED, + G_CALLBACK (cp_connection_added), + dev); + + g_signal_connect (priv->con_provider, + NM_CP_SIGNAL_CONNECTION_REMOVED, + G_CALLBACK (cp_connection_removed), + dev); + + g_signal_connect (priv->con_provider, + NM_CP_SIGNAL_CONNECTION_UPDATED, + G_CALLBACK (cp_connection_updated), + dev); + if (G_OBJECT_CLASS (nm_device_parent_class)->constructed) G_OBJECT_CLASS (nm_device_parent_class)->constructed (object); } @@ -884,43 +894,6 @@ nm_device_get_type_desc (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->type_desc; } -void -nm_device_set_connection_provider (NMDevice *device, - NMConnectionProvider *provider) -{ - NMDevicePrivate *priv; - - g_return_if_fail (device != NULL); - g_return_if_fail (NM_IS_CONNECTION_PROVIDER (provider)); - - priv = NM_DEVICE_GET_PRIVATE (device); - g_return_if_fail (priv->con_provider == NULL); - - priv->con_provider = provider; - priv->cp_added_id = g_signal_connect (priv->con_provider, - NM_CP_SIGNAL_CONNECTION_ADDED, - G_CALLBACK (cp_connection_added), - device); - - priv->cp_removed_id = g_signal_connect (priv->con_provider, - NM_CP_SIGNAL_CONNECTION_REMOVED, - G_CALLBACK (cp_connection_removed), - device); - - priv->cp_updated_id = g_signal_connect (priv->con_provider, - NM_CP_SIGNAL_CONNECTION_UPDATED, - G_CALLBACK (cp_connection_updated), - device); -} - -NMConnectionProvider * -nm_device_get_connection_provider (NMDevice *device) -{ - g_return_val_if_fail (device != NULL, NULL); - - return NM_DEVICE_GET_PRIVATE (device)->con_provider; -} - static SlaveInfo * find_slave_info (NMDevice *self, NMDevice *slave) { @@ -5508,34 +5481,21 @@ dispose (GObject *object) priv->carrier_defer_id = 0; } - if (priv->cp_added_id) { - g_signal_handler_disconnect (priv->con_provider, priv->cp_added_id); - priv->cp_added_id = 0; - } - - if (priv->cp_loaded_id) { - g_signal_handler_disconnect (priv->con_provider, priv->cp_loaded_id); - priv->cp_loaded_id = 0; - } - - if (priv->cp_removed_id) { - g_signal_handler_disconnect (priv->con_provider, priv->cp_removed_id); - priv->cp_removed_id = 0; + if (priv->con_provider) { + g_signal_handlers_disconnect_by_func (priv->con_provider, cp_connection_added, self); + g_signal_handlers_disconnect_by_func (priv->con_provider, cp_connection_removed, self); + g_signal_handlers_disconnect_by_func (priv->con_provider, cp_connection_updated, self); + priv->con_provider = NULL; } - if (priv->cp_updated_id) { - g_signal_handler_disconnect (priv->con_provider, priv->cp_updated_id); - priv->cp_updated_id = 0; - } + g_hash_table_unref (priv->available_connections); + priv->available_connections = NULL; if (priv->carrier_wait_id) { g_source_remove (priv->carrier_wait_id); priv->carrier_wait_id = 0; } - g_hash_table_unref (priv->available_connections); - priv->available_connections = NULL; - g_clear_pointer (&priv->physical_port_id, g_free); activation_source_clear (self, TRUE, AF_INET); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index c346ccb42e..c973b9864d 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -316,8 +316,6 @@ gboolean nm_device_get_firmware_missing (NMDevice *self); void nm_device_queue_activation (NMDevice *device, NMActRequest *req); -void nm_device_set_connection_provider (NMDevice *device, NMConnectionProvider *provider); - gboolean nm_device_supports_vlans (NMDevice *device); void nm_device_add_pending_action (NMDevice *device, const char *action); diff --git a/src/nm-connection-provider.h b/src/nm-connection-provider.h index 96db76adf7..5093d05536 100644 --- a/src/nm-connection-provider.h +++ b/src/nm-connection-provider.h @@ -76,6 +76,13 @@ struct _NMConnectionProvider { GType nm_connection_provider_get_type (void); +/** + * nm_connection_provider_get: + * + * Returns: the global #NMConnectionProvider + */ +NMConnectionProvider *nm_connection_provider_get (void); + /** * nm_connection_provider_get_best_connections: * @self: the #NMConnectionProvider diff --git a/src/nm-manager.c b/src/nm-manager.c index 6126c86281..9b00f7e7da 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1842,8 +1842,6 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con) return; } - nm_device_set_connection_provider (device, NM_CONNECTION_PROVIDER (priv->settings)); - priv->devices = g_slist_append (priv->devices, device); g_signal_connect (device, "state-changed", @@ -4693,6 +4691,14 @@ nm_manager_get (void) return singleton; } +NMConnectionProvider * +nm_connection_provider_get (void) +{ + g_assert (singleton); + g_assert (NM_MANAGER_GET_PRIVATE (singleton)->settings); + return NM_CONNECTION_PROVIDER (NM_MANAGER_GET_PRIVATE (singleton)->settings); +} + NMManager * nm_manager_new (NMSettings *settings, const char *state_file, -- cgit v1.2.1 From ee66964208c7c0c404e61fe293a380e500f840eb Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 10 Feb 2014 08:49:47 -0600 Subject: core: allow devices to indicate when they should be removed Devices created by plugins will use this to indicate when their backing resources have disappeared, at which point the manager should remove them. --- src/devices/nm-device.c | 8 ++++++++ src/devices/nm-device.h | 3 ++- src/nm-manager.c | 10 ++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 5c18a3cb8c..e43df20d07 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -112,6 +112,7 @@ enum { AUTH_REQUEST, IP4_CONFIG_CHANGED, IP6_CONFIG_CHANGED, + REMOVED, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -6117,6 +6118,13 @@ nm_device_class_init (NMDeviceClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT); + signals[REMOVED] = + g_signal_new (NM_DEVICE_REMOVED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), G_TYPE_FROM_CLASS (klass), &dbus_glib_nm_device_object_info); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index c973b9864d..807cf6873e 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -71,9 +71,10 @@ #define NM_DEVICE_HAS_PENDING_ACTION "has-pending-action" /* Internal only */ /* Internal signals */ -#define NM_DEVICE_AUTH_REQUEST "auth-request" +#define NM_DEVICE_AUTH_REQUEST "auth-request" #define NM_DEVICE_IP4_CONFIG_CHANGED "ip4-config-changed" #define NM_DEVICE_IP6_CONFIG_CHANGED "ip6-config-changed" +#define NM_DEVICE_REMOVED "removed" G_BEGIN_DECLS diff --git a/src/nm-manager.c b/src/nm-manager.c index 9b00f7e7da..a91e1bf153 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -836,6 +836,12 @@ remove_device (NMManager *manager, NMDevice *device, gboolean quitting) check_if_startup_complete (manager); } +static void +device_removed_cb (NMDevice *device, gpointer user_data) +{ + remove_device (NM_MANAGER (user_data), device, FALSE); +} + static void modem_removed (NMModemManager *modem_manager, NMModem *modem, @@ -1852,6 +1858,10 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con) G_CALLBACK (device_auth_request_cb), self); + g_signal_connect (device, NM_DEVICE_REMOVED, + G_CALLBACK (device_removed_cb), + self); + if (priv->startup) { g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION, G_CALLBACK (device_has_pending_action_changed), -- cgit v1.2.1 From 8e9b9fe4234916cdb02c2d893a571c87c9c37f6b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 10 Feb 2014 09:12:46 -0600 Subject: mobile: convert to device removed signals Instead of having NMManager listen directly to the ModemManager for modem removal signals, have the NMDeviceModem and NMDeviceBt listen for them (since they obviously have a pointer to the backing NMModem object) and then re-emit any necessary device removal signals to the manager. --- src/devices/nm-device-bt.c | 65 ++++++++++++++++++------------------ src/devices/nm-device-bt.h | 2 -- src/devices/nm-device-modem.c | 7 ++++ src/modem-manager/nm-modem-manager.c | 17 ++-------- src/modem-manager/nm-modem.c | 15 +++++++++ src/modem-manager/nm-modem.h | 6 ++++ src/nm-manager.c | 31 ----------------- 7 files changed, 63 insertions(+), 80 deletions(-) diff --git a/src/devices/nm-device-bt.c b/src/devices/nm-device-bt.c index 3e5b693354..79371ee05a 100644 --- a/src/devices/nm-device-bt.c +++ b/src/devices/nm-device-bt.c @@ -560,6 +560,34 @@ modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *reason) /*****************************************************************************/ +static void +modem_cleanup (NMDeviceBt *self) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + + if (priv->modem) { + g_signal_handlers_disconnect_matched (priv->modem, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self); + g_clear_object (&priv->modem); + } +} + +static void +modem_removed_cb (NMModem *modem, gpointer user_data) +{ + NMDeviceBt *self = NM_DEVICE_BT (user_data); + NMDeviceState state; + + /* Fail the device if the modem was removed while active */ + state = nm_device_get_state (NM_DEVICE (self)); + if ( state == NM_DEVICE_STATE_ACTIVATED + || nm_device_is_activating (NM_DEVICE (self))) { + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_BT_FAILED); + } else + modem_cleanup (self); +} + gboolean nm_device_bt_modem_added (NMDeviceBt *self, NMModem *modem, @@ -614,7 +642,7 @@ nm_device_bt_modem_added (NMDeviceBt *self, if (priv->modem) { g_warn_if_reached (); - g_object_unref (priv->modem); + modem_cleanup (self); } priv->modem = g_object_ref (modem); @@ -624,6 +652,7 @@ nm_device_bt_modem_added (NMDeviceBt *self, g_signal_connect (modem, NM_MODEM_IP4_CONFIG_RESULT, G_CALLBACK (modem_ip4_config_result), self); g_signal_connect (modem, NM_MODEM_AUTH_REQUESTED, G_CALLBACK (modem_auth_requested), self); g_signal_connect (modem, NM_MODEM_AUTH_RESULT, G_CALLBACK (modem_auth_result), self); + g_signal_connect (modem, NM_MODEM_REMOVED, G_CALLBACK (modem_removed_cb), self); /* In the old ModemManager the data port is known from the very beginning; * while in the new ModemManager the data port is set afterwards when the bearer gets @@ -639,35 +668,6 @@ nm_device_bt_modem_added (NMDeviceBt *self, return TRUE; } -gboolean -nm_device_bt_modem_removed (NMDeviceBt *self, NMModem *modem) -{ - NMDeviceBtPrivate *priv; - NMDeviceState state; - - g_return_val_if_fail (NM_IS_DEVICE_BT (self), FALSE); - g_return_val_if_fail (NM_IS_MODEM (modem), FALSE); - - priv = NM_DEVICE_BT_GET_PRIVATE (self); - - if (modem != priv->modem) - return FALSE; - - /* Fail the device if the modem was removed while active */ - state = nm_device_get_state (NM_DEVICE (self)); - if ( state == NM_DEVICE_STATE_ACTIVATED - || nm_device_is_activating (NM_DEVICE (self))) { - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BT_FAILED); - } else { - g_object_unref (priv->modem); - priv->modem = NULL; - } - - return TRUE; -} - static gboolean modem_find_timeout (gpointer user_data) { @@ -905,8 +905,7 @@ deactivate (NMDevice *device) NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_USER_REQUESTED); - g_object_unref (priv->modem); - priv->modem = NULL; + modem_cleanup (NM_DEVICE_BT (device)); } } @@ -1166,7 +1165,7 @@ dispose (GObject *object) } priv->dbus_mgr = NULL; - g_clear_object (&priv->modem); + modem_cleanup (NM_DEVICE_BT (object)); g_clear_object (&priv->bt_device); G_OBJECT_CLASS (nm_device_bt_parent_class)->dispose (object); diff --git a/src/devices/nm-device-bt.h b/src/devices/nm-device-bt.h index d983285fb7..83732bc09e 100644 --- a/src/devices/nm-device-bt.h +++ b/src/devices/nm-device-bt.h @@ -69,8 +69,6 @@ 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_DEVICE_BT_H */ diff --git a/src/devices/nm-device-modem.c b/src/devices/nm-device-modem.c index e047c03e11..5c10a8e05d 100644 --- a/src/devices/nm-device-modem.c +++ b/src/devices/nm-device-modem.c @@ -196,6 +196,12 @@ modem_connected_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) } } +static void +modem_removed_cb (NMModem *modem, gpointer user_data) +{ + g_signal_emit_by_name (NM_DEVICE (user_data), NM_DEVICE_REMOVED); +} + /*****************************************************************************/ NMModem * @@ -398,6 +404,7 @@ set_modem (NMDeviceModem *self, NMModem *modem) g_signal_connect (modem, NM_MODEM_AUTH_RESULT, G_CALLBACK (modem_auth_result), self); g_signal_connect (modem, "notify::" NM_MODEM_ENABLED, G_CALLBACK (modem_enabled_cb), self); g_signal_connect (modem, "notify::" NM_MODEM_CONNECTED, G_CALLBACK (modem_connected_cb), self); + g_signal_connect (modem, NM_MODEM_REMOVED, G_CALLBACK (modem_removed_cb), self); /* In the old ModemManager the data port is known from the very beginning; * while in the new ModemManager the data port is set afterwards when the bearer gets diff --git a/src/modem-manager/nm-modem-manager.c b/src/modem-manager/nm-modem-manager.c index bb85b774ea..f68a569666 100644 --- a/src/modem-manager/nm-modem-manager.c +++ b/src/modem-manager/nm-modem-manager.c @@ -63,8 +63,6 @@ struct _NMModemManagerPrivate { enum { MODEM_ADDED, - MODEM_REMOVED, - LAST_SIGNAL }; @@ -159,7 +157,7 @@ modem_removed (DBusGProxy *proxy, const char *path, gpointer user_data) modem = (NMModem *) g_hash_table_lookup (self->priv->modems, path); if (modem) { - g_signal_emit (self, signals[MODEM_REMOVED], 0, modem); + nm_modem_emit_removed (modem); g_hash_table_remove (self->priv->modems, path); } } @@ -274,8 +272,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[MODEM_REMOVED], 0, value); - + nm_modem_emit_removed (NM_MODEM (value)); return TRUE; } @@ -426,7 +423,7 @@ modem_object_removed (MMManager *manager, if (!modem) return; - g_signal_emit (self, signals[MODEM_REMOVED], 0, modem); + nm_modem_emit_removed (modem); g_hash_table_remove (self->priv->modems, path); } @@ -760,12 +757,4 @@ nm_modem_manager_class_init (NMModemManagerClass *klass) G_STRUCT_OFFSET (NMModemManagerClass, modem_added), NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_STRING); - - signals[MODEM_REMOVED] = - g_signal_new ("modem-removed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMModemManagerClass, modem_removed), - NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_OBJECT); } diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c index e88ebe1bd7..8327c1c5d9 100644 --- a/src/modem-manager/nm-modem.c +++ b/src/modem-manager/nm-modem.c @@ -81,6 +81,7 @@ enum { IP4_CONFIG_RESULT, AUTH_REQUESTED, AUTH_RESULT, + REMOVED, LAST_SIGNAL }; @@ -126,6 +127,12 @@ nm_modem_get_mm_connected (NMModem *self) return NM_MODEM_GET_PRIVATE (self)->mm_connected; } +void +nm_modem_emit_removed (NMModem *self) +{ + g_signal_emit (self, signals[REMOVED], 0); +} + /*****************************************************************************/ /* IP method PPP */ @@ -988,6 +995,14 @@ nm_modem_class_init (NMModemClass *klass) NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_POINTER); + signals[REMOVED] = + g_signal_new (NM_MODEM_REMOVED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMModemClass, removed), + NULL, NULL, NULL, + G_TYPE_NONE, 0); + dbus_g_error_domain_register (NM_MODEM_ERROR, NM_DBUS_INTERFACE_DEVICE_MODEM, NM_TYPE_MODEM_ERROR); diff --git a/src/modem-manager/nm-modem.h b/src/modem-manager/nm-modem.h index db20407006..f15be26769 100644 --- a/src/modem-manager/nm-modem.h +++ b/src/modem-manager/nm-modem.h @@ -52,6 +52,7 @@ G_BEGIN_DECLS #define NM_MODEM_IP4_CONFIG_RESULT "ip4-config-result" #define NM_MODEM_AUTH_REQUESTED "auth-requested" #define NM_MODEM_AUTH_RESULT "auth-result" +#define NM_MODEM_REMOVED "removed" #define MM_MODEM_IP_METHOD_PPP 0 #define MM_MODEM_IP_METHOD_STATIC 1 @@ -119,6 +120,8 @@ typedef struct { void (*auth_requested) (NMModem *self); void (*auth_result) (NMModem *self, GError *error); + + void (*removed) (NMModem *self); } NMModemClass; GType nm_modem_get_type (void); @@ -182,6 +185,9 @@ void nm_modem_set_mm_enabled (NMModem *self, gboolean enabled); gboolean nm_modem_get_mm_connected (NMModem *self); +/* For the modem-manager only */ +void nm_modem_emit_removed (NMModem *self); + G_END_DECLS #endif /* NM_MODEM_H */ diff --git a/src/nm-manager.c b/src/nm-manager.c index a91e1bf153..fc439f0921 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -237,7 +237,6 @@ typedef struct { NMModemManager *modem_manager; guint modem_added_id; - guint modem_removed_id; DBusGProxy *aipd_proxy; NMSleepMonitor *sleep_monitor; @@ -842,30 +841,6 @@ device_removed_cb (NMDevice *device, gpointer user_data) remove_device (NM_MANAGER (user_data), device, FALSE); } -static void -modem_removed (NMModemManager *modem_manager, - NMModem *modem, - gpointer user_data) -{ - NMManager *self = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *found; - GSList *iter; - - /* Give Bluetooth DUN devices first chance to handle the modem removal */ - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - if (nm_device_get_device_type (iter->data) == NM_DEVICE_TYPE_BT) { - 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) - remove_device (self, found, FALSE); -} - static void aipd_handle_event (DBusGProxy *proxy, const char *event, @@ -4886,8 +4861,6 @@ nm_manager_init (NMManager *manager) priv->modem_manager = nm_modem_manager_get (); 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, "modem-removed", - G_CALLBACK (modem_removed), manager); priv->vpn_manager = nm_vpn_manager_get (); @@ -5111,10 +5084,6 @@ dispose (GObject *object) g_source_remove (priv->modem_added_id); priv->modem_added_id = 0; } - if (priv->modem_removed_id) { - g_source_remove (priv->modem_removed_id); - priv->modem_removed_id = 0; - } g_clear_object (&priv->modem_manager); /* Unregister property filter */ -- cgit v1.2.1 From 2a04df856b0cffd7c8c3db27c48a018f3dc0cf69 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 9 Feb 2014 10:22:19 -0600 Subject: devices: rework device plugin interface to be more flexible In preparation for making WWAN and Bluetooth plugins, rework the device plugin interface to meet those plugins' needs and port WiMAX over in the process. --- src/Makefile.am | 1 + src/devices/nm-device-bt.c | 17 +-- src/devices/nm-device-factory.c | 114 +++++++++++++++++++ src/devices/nm-device-factory.h | 125 +++++++++++++++------ src/devices/nm-device-modem.c | 10 ++ src/devices/nm-device.c | 42 +++++++ src/devices/nm-device.h | 8 ++ src/devices/wimax/nm-wimax-factory.c | 88 +++++++++++++-- src/nm-manager.c | 207 +++++++++++++++++++---------------- 9 files changed, 465 insertions(+), 147 deletions(-) create mode 100644 src/devices/nm-device-factory.c diff --git a/src/Makefile.am b/src/Makefile.am index 305a9a0dac..aeae2a0698 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -80,6 +80,7 @@ nm_sources = \ devices/nm-device-bt.h \ devices/nm-device-ethernet.c \ devices/nm-device-ethernet.h \ + devices/nm-device-factory.c \ devices/nm-device-factory.h \ devices/nm-device-generic.c \ devices/nm-device-generic.h \ diff --git a/src/devices/nm-device-bt.c b/src/devices/nm-device-bt.c index 79371ee05a..ecb015b03c 100644 --- a/src/devices/nm-device-bt.c +++ b/src/devices/nm-device-bt.c @@ -588,22 +588,22 @@ modem_removed_cb (NMModem *modem, gpointer user_data) modem_cleanup (self); } -gboolean -nm_device_bt_modem_added (NMDeviceBt *self, - NMModem *modem, - const char *driver) +static gboolean +component_added (NMDevice *device, GObject *component) { - NMDeviceBtPrivate *priv; + NMDeviceBt *self = NM_DEVICE_BT (device); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + NMModem *modem; const gchar *modem_data_port; const gchar *modem_control_port; char *base; NMDeviceState state; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; - g_return_val_if_fail (NM_IS_DEVICE_BT (self), FALSE); - g_return_val_if_fail (NM_IS_MODEM (modem), FALSE); + if (!NM_IS_MODEM (component)) + return FALSE; + modem = NM_MODEM (component); - priv = NM_DEVICE_BT_GET_PRIVATE (self); modem_data_port = nm_modem_get_data_port (modem); modem_control_port = nm_modem_get_control_port (modem); g_return_val_if_fail (modem_data_port != NULL || modem_control_port != NULL, FALSE); @@ -1207,6 +1207,7 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) device_class->check_connection_available = check_connection_available; device_class->complete_connection = complete_connection; device_class->is_available = is_available; + device_class->component_added = component_added; device_class->state_changed = device_state_changed; diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c new file mode 100644 index 0000000000..423a26f6a7 --- /dev/null +++ b/src/devices/nm-device-factory.c @@ -0,0 +1,114 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager + * + * 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) 2014 Red Hat, Inc. + */ + +#include "nm-device-factory.h" + +enum { + DEVICE_ADDED, + COMPONENT_ADDED, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +gboolean +nm_device_factory_emit_component_added (NMDeviceFactory *factory, GObject *component) +{ + gboolean consumed = FALSE; + + g_signal_emit (factory, signals[COMPONENT_ADDED], 0, component, &consumed); + return consumed; +} + +static void +interface_init (gpointer g_iface) +{ + GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); + static gboolean initialized = FALSE; + + if (G_LIKELY (initialized)) + return; + + g_object_interface_install_property + (g_iface, + g_param_spec_uint (NM_DEVICE_FACTORY_DEVICE_TYPE, + "Device type", + "Device type", + 0, G_MAXUINT32, NM_DEVICE_TYPE_UNKNOWN, + G_PARAM_READABLE)); + + /* Signals */ + signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED, + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMDeviceFactory, device_added), + NULL, NULL, NULL, + G_TYPE_NONE, 1, NM_TYPE_DEVICE); + + signals[COMPONENT_ADDED] = g_signal_new (NM_DEVICE_FACTORY_COMPONENT_ADDED, + iface_type, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMDeviceFactory, component_added), + g_signal_accumulator_true_handled, NULL, NULL, + G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT); + + initialized = TRUE; +} + +GType +nm_device_factory_get_type (void) +{ + static GType device_factory_type = 0; + + if (!device_factory_type) { + const GTypeInfo device_factory_info = { + sizeof (NMDeviceFactory), /* class_size */ + interface_init, /* base_init */ + NULL, /* base_finalize */ + NULL, + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL + }; + + device_factory_type = g_type_register_static (G_TYPE_INTERFACE, + "NMDeviceFactory", + &device_factory_info, + 0); + g_type_interface_add_prerequisite (device_factory_type, G_TYPE_OBJECT); + } + + return device_factory_type; +} + +NMDevice * +nm_device_factory_new_link (NMDeviceFactory *factory, + NMPlatformLink *plink, + GError **error) +{ + g_return_if_fail (factory != NULL); + g_return_if_fail (plink != NULL); + + if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->new_link) + return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->new_link (factory, plink, error); + return NULL; +} + diff --git a/src/devices/nm-device-factory.h b/src/devices/nm-device-factory.h index 7b7efc8702..45ae77a9fb 100644 --- a/src/devices/nm-device-factory.h +++ b/src/devices/nm-device-factory.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2007 - 2011 Red Hat, Inc. + * Copyright (C) 2007 - 2014 Red Hat, Inc. */ #ifndef NM_DEVICE_FACTORY_H @@ -26,6 +26,7 @@ #include "NetworkManager.h" #include "nm-platform.h" +#include "nm-device.h" /* WARNING: this file is private API between NetworkManager and its internal * device plugins. Its API can change at any time and is not guaranteed to be @@ -33,52 +34,106 @@ * not meant to enable third-party plugins. */ +typedef struct _NMDeviceFactory NMDeviceFactory; + /** - * nm_device_factory_create_device: - * @devpath: sysfs path of the device - * @ifname: interface name of the device - * @driver: driver of the device - * @error: error for failure information + * nm_device_factory_create: + * @error: an error if creation of the factory failed, or %NULL * - * Creates a #NMDevice subclass if the given information represents a device - * the factory is capable of creating. If the information does represent a - * device the factory is capable of creating, but the device could not be - * created, %NULL should be returned and @error should be set. If the - * factory is not capable of creating a device with the given information - * (ie, the factory creates Ethernet devices but the information represents - * a WiFi device) it should return %NULL and leave @error untouched. + * Creates a #GObject that implements the #NMDeviceFactory interface. This + * function must not emit any signals or perform any actions that would cause + * devices or components to be created immediately. Instead these should be + * deferred to an idle handler. * - * Returns: the device object (a subclass of #NMDevice) or %NULL + * Returns: the #GObject implementing #NMDeviceFactory or %NULL */ -GObject *nm_device_factory_create_device (NMPlatformLink *platform_device, - GError **error); +NMDeviceFactory *nm_device_factory_create (GError **error); -/* Should match nm_device_factory() */ -typedef GObject * (*NMDeviceFactoryCreateFunc) (NMPlatformLink *platform_device, - GError **error); +/* Should match nm_device_factory_create() */ +typedef NMDeviceFactory * (*NMDeviceFactoryCreateFunc) (GError **error); /** - * nm_device_factory_get_priority: - * - * Returns the priority of this plugin. Higher numbers mean a higher priority. + * nm_device_factory_get_device_type: * - * Returns: plugin priority + * Returns: the #NMDeviceType that this plugin creates */ -guint32 nm_device_factory_get_priority (void); +NMDeviceType nm_device_factory_get_device_type (void); -typedef guint32 (*NMDeviceFactoryPriorityFunc) (void); +/* Should match nm_device_factory_get_device_type() */ +typedef NMDeviceType (*NMDeviceFactoryDeviceTypeFunc) (void); -/** - * nm_device_factory_get_type: - * - * Returns the type of device this factory can create. Only one factory for - * each type of device is allowed. - * - * Returns: the %NMDeviceType - */ -NMDeviceType nm_device_factory_get_type (void); +/********************************************************************/ + +#define NM_TYPE_DEVICE_FACTORY (nm_device_factory_get_type ()) +#define NM_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_FACTORY, NMDeviceFactory)) +#define NM_IS_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_FACTORY)) +#define NM_DEVICE_FACTORY_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_DEVICE_FACTORY, NMDeviceFactory)) + +/* properties */ +#define NM_DEVICE_FACTORY_DEVICE_TYPE "device-type" + +/* signals */ +#define NM_DEVICE_FACTORY_COMPONENT_ADDED "component-added" +#define NM_DEVICE_FACTORY_DEVICE_ADDED "device-added" + +struct _NMDeviceFactory { + GTypeInterface g_iface; + + /** + * new_link: + * @factory: the #NMDeviceFactory + * @link: the new link + * @error: error if the link could be claimed but an error occurred + * + * The NetworkManager core was notified of a new link which the plugin + * may want to claim and create a #NMDevice subclass for. If the link + * represents a device the factory is capable of claiming, but the device + * could not be created, %NULL should be returned and @error should be set. + * %NULL should always be returned and @error should never be set if the + * factory cannot create devices for the type which @link represents. + * + * Returns: the #NMDevice if the link was claimed and created, %NULL if not + */ + NMDevice * (*new_link) (NMDeviceFactory *factory, + NMPlatformLink *plink, + GError **error); + + /* Signals */ + + /** + * device_added: + * @factory: the #NMDeviceFactory + * @device: the new #NMDevice subclass + * + * The factory emits this signal if it finds a new device by itself. + */ + void (*device_added) (NMDeviceFactory *factory, NMDevice *device); + + /** + * component_added: + * @factory: the #NMDeviceFactory + * @component: a new component which existing devices may wish to claim + * + * The factory emits this signal when it finds a new component. For example, + * the WWAN factory may indicate that a new modem is available, which an + * existing Bluetooth device may wish to claim. If no device claims the + * component, the plugin is allowed to create a new #NMDevice instance for + * that component and emit the "device-added" signal. + * + * Returns: %TRUE if the component was claimed by a device, %FALSE if not + */ + gboolean (*component_added) (NMDeviceFactory *factory, GObject *component); +}; + +GType nm_device_factory_get_type (void); + +NMDevice * nm_device_factory_new_link (NMDeviceFactory *factory, + NMPlatformLink *plink, + GError **error); -typedef NMDeviceType (*NMDeviceFactoryTypeFunc) (void); +/* For use by implementations */ +gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory, + GObject *component); #endif /* NM_DEVICE_FACTORY_H */ diff --git a/src/devices/nm-device-modem.c b/src/devices/nm-device-modem.c index 5c10a8e05d..6a3656c4e9 100644 --- a/src/devices/nm-device-modem.c +++ b/src/devices/nm-device-modem.c @@ -212,6 +212,15 @@ nm_device_modem_get_modem (NMDeviceModem *self) return NM_DEVICE_MODEM_GET_PRIVATE (self)->modem; } +static gboolean +owns_iface (NMDevice *device, const char *iface) +{ + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); + + g_assert (priv->modem); + return nm_modem_owns_port (priv->modem, iface); +} + /*****************************************************************************/ static void @@ -492,6 +501,7 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) device_class->ip4_config_pre_commit = ip4_config_pre_commit; device_class->get_enabled = get_enabled; device_class->set_enabled = set_enabled; + device_class->owns_iface = owns_iface; device_class->state_changed = device_state_changed; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index e43df20d07..d4f16a62e7 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1193,6 +1193,48 @@ link_changed (NMDevice *device, NMPlatformLink *info) nm_device_set_carrier (device, info->connected); } +/** + * nm_device_notify_component_added(): + * @device: the #NMDevice + * @component: the component being added by a plugin + * + * Called by the manager to notify the device that a new component has + * been found. The device implementation should return %TRUE if it + * wishes to claim the component, or %FALSE if it cannot. + * + * Returns: %TRUE to claim the component, %FALSE if the component cannot be + * claimed. + */ +gboolean +nm_device_notify_component_added (NMDevice *device, GObject *component) +{ + if (NM_DEVICE_GET_CLASS (device)->component_added) + return NM_DEVICE_GET_CLASS (device)->component_added (device, component); + return FALSE; +} + +/** + * nm_device_owns_iface(): + * @device: the #NMDevice + * @iface: an interface name + * + * Called by the manager to ask if the device or any of its components owns + * @iface. For example, a WWAN implementation would return %TRUE for an + * ethernet interface name that was owned by the WWAN device's modem component, + * because that ethernet interface is controlled by the WWAN device and cannot + * be used independently of the WWAN device. + * + * Returns: %TRUE if @device or it's components owns the interface name, + * %FALSE if not + */ +gboolean +nm_device_owns_iface (NMDevice *device, const char *iface) +{ + if (NM_DEVICE_GET_CLASS (device)->owns_iface) + return NM_DEVICE_GET_CLASS (device)->owns_iface (device, iface); + return FALSE; +} + static void check_carrier (NMDevice *device) { diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 807cf6873e..03e3b87ed0 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -196,6 +196,10 @@ typedef struct { gboolean (* have_any_ready_slaves) (NMDevice *self, const GSList *slaves); + + gboolean (* component_added) (NMDevice *self, GObject *component); + + gboolean (* owns_iface) (NMDevice *self, const char *iface); } NMDeviceClass; @@ -332,6 +336,10 @@ guint32 nm_device_get_mtu (NMDevice *device); gboolean nm_device_connection_is_available (NMDevice *device, NMConnection *connection); +gboolean nm_device_notify_component_added (NMDevice *device, GObject *component); + +gboolean nm_device_owns_iface (NMDevice *device, const char *iface); + G_END_DECLS /* For testing only */ diff --git a/src/devices/wimax/nm-wimax-factory.c b/src/devices/wimax/nm-wimax-factory.c index 738c12eb31..d5bf57f602 100644 --- a/src/devices/wimax/nm-wimax-factory.c +++ b/src/devices/wimax/nm-wimax-factory.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2011 Red Hat, Inc. + * Copyright (C) 2011 - 2014 Red Hat, Inc. */ #include @@ -23,28 +23,92 @@ #include "nm-device-factory.h" #include "nm-device-wimax.h" -G_MODULE_EXPORT GObject * -nm_device_factory_create_device (NMPlatformLink *platform_device, - GError **error) +#define NM_TYPE_WIMAX_FACTORY (nm_wimax_factory_get_type ()) +#define NM_WIMAX_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_WIMAX_FACTORY, NMWimaxFactory)) + +typedef struct { + GObject parent; +} NMWimaxFactory; + +typedef struct { + GObjectClass parent; +} NMWimaxFactoryClass; + +static GType nm_wimax_factory_get_type (void); + +static void device_factory_interface_init (NMDeviceFactory *factory_iface); + +G_DEFINE_TYPE_EXTENDED (NMWimaxFactory, nm_wimax_factory, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_FACTORY, device_factory_interface_init)) + +/**************************************************************************/ + +#define PLUGIN_TYPE NM_DEVICE_TYPE_WIMAX + +G_MODULE_EXPORT NMDeviceFactory * +nm_device_factory_create (GError **error) +{ + return (NMDeviceFactory *) g_object_new (NM_TYPE_WIMAX_FACTORY, NULL); +} + +G_MODULE_EXPORT NMDeviceType +nm_device_factory_get_device_type (void) +{ + return PLUGIN_TYPE; +} + +/**************************************************************************/ + +static NMDevice * +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) { /* FIXME: check udev 'DEVTYPE' instead; but since we only support Intel * WiMAX devices for now this is appropriate. */ - if (g_strcmp0 (platform_device->driver, "i2400m_usb") != 0) + if (g_strcmp0 (plink->driver, "i2400m_usb") != 0) return NULL; /* unsupported */ - return (GObject *) nm_device_wimax_new (platform_device); + return (NMDevice *) nm_device_wimax_new (plink); } -G_MODULE_EXPORT guint32 -nm_device_factory_get_priority (void) +enum { + PROP_0 = 0x1000, + PROP_DEVICE_TYPE, +}; + +static void +get_property (GObject *object, guint prop, GValue *value, GParamSpec *pspec) { - return 0; + switch (prop) { + case PROP_DEVICE_TYPE: + g_value_set_uint (value, PLUGIN_TYPE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop, pspec); + break; + } } -G_MODULE_EXPORT NMDeviceType -nm_device_factory_get_type (void) +static void +device_factory_interface_init (NMDeviceFactory *factory_iface) { - return NM_DEVICE_TYPE_WIMAX; + factory_iface->new_link = new_link; +} + +static void +nm_wimax_factory_init (NMWimaxFactory *factory) +{ +} + +static void +nm_wimax_factory_class_init (NMWimaxFactoryClass *wf_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (wf_class); + + object_class->get_property = get_property; + + g_object_class_override_property (object_class, + PROP_DEVICE_TYPE, + NM_DEVICE_FACTORY_DEVICE_TYPE); } diff --git a/src/nm-manager.c b/src/nm-manager.c index fc439f0921..22e8a32f57 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -551,27 +551,12 @@ modem_added (NMModemManager *modem_manager, NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDevice *device = NULL; const char *modem_iface; - GSList *iter, *remove = NULL; - - /* Remove ethernet devices that are actually owned by the modem, since - * they cannot be used as normal ethernet. - */ - for (iter = priv->devices; iter; iter = iter->next) { - if (nm_device_get_device_type (iter->data) == NM_DEVICE_TYPE_ETHERNET) { - if (nm_modem_owns_port (modem, nm_device_get_ip_iface (iter->data))) - remove = g_slist_prepend (remove, iter->data); - } - } - for (iter = remove; iter; iter = iter->next) - remove_device (self, NM_DEVICE (iter->data), FALSE); - g_slist_free (remove); + GSList *iter; /* Give Bluetooth DUN devices first chance to claim the modem */ - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - if (nm_device_get_device_type (iter->data) == NM_DEVICE_TYPE_BT) { - if (nm_device_bt_modem_added (NM_DEVICE_BT (iter->data), modem, driver)) - return; - } + for (iter = priv->devices; iter; iter = iter->next) { + if (nm_device_notify_component_added (device, G_OBJECT (modem))) + return; } /* If it was a Bluetooth modem and no bluetooth device claimed it, ignore @@ -589,8 +574,10 @@ modem_added (NMModemManager *modem_manager, /* Make the new modem device */ device = nm_device_modem_new (modem, driver); - if (device) + if (device) { add_device (self, device, FALSE); + g_object_unref (device); + } } static void @@ -1182,6 +1169,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) if (device) { nm_device_set_is_nm_owned (device, TRUE); add_device (self, device, FALSE); + g_object_unref (device); } g_signal_handlers_unblock_by_func (nm_platform_get (), G_CALLBACK (platform_link_added_cb), self); @@ -1792,6 +1780,15 @@ get_existing_connection (NMManager *manager, NMDevice *device) return added ? NM_CONNECTION (added) : NULL; } +/** + * add_device: + * @self: the #NMManager + * @device: the #NMDevice to add + * @generate_con: %TRUE if existing connection (if any) should be assumed + * + * If successful, this function will increase the references count of @device. + * Callers should decrease the reference count. + */ static void add_device (NMManager *self, NMDevice *device, gboolean generate_con) { @@ -1804,26 +1801,31 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con) gboolean enabled = FALSE; RfKillType rtype; NMDeviceType devtype; - - iface = nm_device_get_ip_iface (device); - g_assert (iface); + GSList *iter, *remove = NULL; devtype = nm_device_get_device_type (device); - /* Ignore the device if we already know about it. But some modems will - * provide pseudo-ethernet devices that NM has already claimed while - * ModemManager is still detecting the modem's serial ports, so when the - * MM modem object finally shows up it may have the same IP interface as the - * ethernet interface we've already detected. In this case we skip the - * check for an existing device with the same IP interface name and kill - * the ethernet device later in favor of the modem device. - */ - if ((devtype != NM_DEVICE_TYPE_MODEM) && find_device_by_ip_iface (self, iface)) { - g_object_unref (device); + /* No duplicates */ + if (nm_manager_get_device_by_udi (self, nm_device_get_udi (device))) return; + + /* Remove existing devices owned by the new device; eg remove ethernet + * ports that are owned by a WWAN modem, since udev may announce them + * before the modem is fully discovered. + * + * FIXME: use parent/child device relationships instead of removing + * the child NMDevice entirely + */ + for (iter = priv->devices; iter; iter = iter->next) { + iface = nm_device_get_ip_iface (iter->data); + if (nm_device_owns_iface (device, iface)) + remove = g_slist_prepend (remove, iter->data); } + for (iter = remove; iter; iter = iter->next) + remove_device (self, NM_DEVICE (iter->data), FALSE); + g_slist_free (remove); - priv->devices = g_slist_append (priv->devices, device); + priv->devices = g_slist_append (priv->devices, g_object_ref (device)); g_signal_connect (device, "state-changed", G_CALLBACK (manager_device_state_changed), @@ -1874,6 +1876,9 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con) nm_device_set_enabled (device, enabled); } + iface = nm_device_get_iface (device); + g_assert (iface); + type_desc = nm_device_get_type_desc (device); g_assert (type_desc); driver = nm_device_get_driver (device); @@ -1983,6 +1988,7 @@ bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr, has_nap ? "NAP" : ""); add_device (manager, device, FALSE); + g_object_unref (device); } } @@ -2050,25 +2056,31 @@ find_device_by_ifindex (NMManager *self, guint32 ifindex) return NULL; } -#define PLUGIN_PREFIX "libnm-device-plugin-" - -typedef struct { - NMDeviceType t; - guint priority; - NMDeviceFactoryCreateFunc create_func; -} PluginInfo; +static void +factory_device_added_cb (NMDeviceFactory *factory, + NMDevice *device, + gpointer user_data) +{ + add_device (NM_MANAGER (user_data), device, FALSE); +} -static gint -plugin_sort (PluginInfo *a, PluginInfo *b) +static gboolean +factory_component_added_cb (NMDeviceFactory *factory, + GObject *component, + gpointer user_data) { - /* Higher priority means sort earlier in the list (ie, return -1) */ - if (a->priority > b->priority) - return -1; - else if (a->priority < b->priority) - return 1; - return 0; + NMManager *self = NM_MANAGER (user_data); + GSList *iter; + + for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) { + if (nm_device_notify_component_added (NM_DEVICE (iter->data), component)) + return TRUE; + } + return FALSE; } +#define PLUGIN_PREFIX "libnm-device-plugin-" + static void load_device_factories (NMManager *self) { @@ -2077,7 +2089,7 @@ load_device_factories (NMManager *self) GError *error = NULL; const char *item; char *path; - GSList *list = NULL, *iter; + GSList *iter; dir = g_dir_open (NMPLUGINDIR, 0, &error); if (!dir) { @@ -2090,11 +2102,11 @@ load_device_factories (NMManager *self) while ((item = g_dir_read_name (dir))) { GModule *plugin; + NMDeviceFactory *factory; NMDeviceFactoryCreateFunc create_func; - NMDeviceFactoryPriorityFunc priority_func; - NMDeviceFactoryTypeFunc type_func; - PluginInfo *info = NULL; - NMDeviceType plugin_type; + NMDeviceFactoryDeviceTypeFunc type_func; + NMDeviceType dev_type; + gboolean found = FALSE; if (!g_str_has_prefix (item, PLUGIN_PREFIX)) continue; @@ -2109,60 +2121,63 @@ load_device_factories (NMManager *self) continue; } - if (!g_module_symbol (plugin, "nm_device_factory_get_type", (gpointer) (&type_func))) { - nm_log_warn (LOGD_HW, "(%s): failed to find device factory: %s", item, g_module_error ()); + if (!g_module_symbol (plugin, "nm_device_factory_get_device_type", (gpointer) &type_func)) { + nm_log_warn (LOGD_HW, "(%s): failed to find device factory type: %s", item, g_module_error ()); g_module_close (plugin); continue; } /* Make sure we don't double-load plugins */ - plugin_type = type_func (); - for (iter = list; iter; iter = g_slist_next (iter)) { - PluginInfo *candidate = iter->data; - - if (plugin_type == candidate->t) { - info = candidate; + dev_type = type_func (); + for (iter = priv->factories; iter; iter = iter->next) { + NMDeviceType t = NM_DEVICE_TYPE_UNKNOWN; + + g_object_get (G_OBJECT (iter->data), + NM_DEVICE_FACTORY_DEVICE_TYPE, &t, + NULL); + if (dev_type == t) { + found = TRUE; break; } } - if (info) { + if (found) { g_module_close (plugin); continue; } - if (!g_module_symbol (plugin, "nm_device_factory_create_device", (gpointer) (&create_func))) { - nm_log_warn (LOGD_HW, "(%s): failed to find device creator: %s", item, g_module_error ()); + if (!g_module_symbol (plugin, "nm_device_factory_create", (gpointer) &create_func)) { + nm_log_warn (LOGD_HW, "(%s): failed to find device factory creator: %s", item, g_module_error ()); g_module_close (plugin); continue; } - info = g_malloc0 (sizeof (*info)); - info->create_func = create_func; - info->t = plugin_type; - - /* Grab priority; higher number equals higher priority */ - if (g_module_symbol (plugin, "nm_device_factory_get_priority", (gpointer) (&priority_func))) - info->priority = priority_func (); - else { - nm_log_dbg (LOGD_HW, "(%s): failed to find device factory priority func: %s", - item, g_module_error ()); + factory = create_func (&error); + if (!factory) { + nm_log_warn (LOGD_HW, "(%s): failed to initialize device factory: %s", + item, error ? error->message : "unknown"); + g_clear_error (&error); + g_module_close (plugin); + continue; } + g_clear_error (&error); g_module_make_resident (plugin); - list = g_slist_insert_sorted (list, info, (GCompareFunc) plugin_sort); + priv->factories = g_slist_prepend (priv->factories, factory); + + g_signal_connect (factory, + NM_DEVICE_FACTORY_DEVICE_ADDED, + G_CALLBACK (factory_device_added_cb), + self); + g_signal_connect (factory, + NM_DEVICE_FACTORY_COMPONENT_ADDED, + G_CALLBACK (factory_component_added_cb), + self); - nm_log_info (LOGD_HW, "Loaded device factory: %s", g_module_name (plugin)); + nm_log_info (LOGD_HW, "Loaded device plugin: %s", g_module_name (plugin)); }; g_dir_close (dir); - /* Ditch the priority info and copy the factory functions to our private data */ - for (iter = list; iter; iter = g_slist_next (iter)) { - PluginInfo *info = iter->data; - - priv->factories = g_slist_append (priv->factories, info->create_func); - g_free (info); - } - g_slist_free (list); + priv->factories = g_slist_reverse (priv->factories); } static void @@ -2184,11 +2199,10 @@ platform_link_added_cb (NMPlatform *platform, return; /* Try registered device factories */ - for (iter = priv->factories; iter; iter = g_slist_next (iter)) { - NMDeviceFactoryCreateFunc create_func = iter->data; + for (iter = priv->factories; iter; iter = iter->next) { + NMDeviceFactory *factory = NM_DEVICE_FACTORY (iter->data); - g_clear_error (&error); - device = (NMDevice *) create_func (plink, &error); + device = nm_device_factory_new_link (factory, plink, &error); if (device && NM_IS_DEVICE (device)) { g_assert_no_error (error); break; /* success! */ @@ -2281,8 +2295,10 @@ platform_link_added_cb (NMPlatform *platform, } } - if (device) + if (device) { add_device (self, device, plink->type != NM_LINK_TYPE_LOOPBACK); + g_object_unref (device); + } } static void @@ -4807,6 +4823,8 @@ nm_manager_new (NMSettings *settings, */ rfkill_change_wifi (priv->radio_states[RFKILL_TYPE_WLAN].desc, initial_wifi_enabled); + load_device_factories (singleton); + return singleton; } @@ -4917,8 +4935,6 @@ nm_manager_init (NMManager *manager) KERNEL_FIRMWARE_DIR); } - load_device_factories (manager); - /* Update timestamps in active connections */ priv->timestamp_update_id = g_timeout_add_seconds (300, (GSourceFunc) periodic_update_active_connection_timestamps, manager); } @@ -5046,6 +5062,7 @@ dispose (GObject *object) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); DBusGConnection *bus; DBusConnection *dbus_connection; + GSList *iter; g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref); priv->auth_chains = NULL; @@ -5116,6 +5133,12 @@ dispose (GObject *object) g_clear_object (&priv->fw_monitor); } + for (iter = priv->factories; iter; iter = iter->next) { + NMDeviceFactory *factory = iter->data; + + g_signal_handlers_disconnect_matched (factory, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, manager); + g_object_unref (factory); + } g_clear_pointer (&priv->factories, g_slist_free); if (priv->timestamp_update_id) { -- cgit v1.2.1 From 71a52347f32d0436c58d4c77eea703011d4157dc Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 12 Feb 2014 05:22:57 -0600 Subject: atm: make ADSL support a plugin Make ADSL support a plugin using the new device factory interface. Provides a 1% size reduction in the core NM binary. Before After NM: 1265336 1253016 (-1%) ATM: 0 27360 (all results from stripped files) --- configure.ac | 1 + po/POTFILES.in | 2 +- src/Makefile.am | 6 +- src/devices/atm/Makefile.am | 48 +++ src/devices/atm/nm-atm-manager.c | 290 +++++++++++++++++ src/devices/atm/nm-atm-manager.h | 42 +++ src/devices/atm/nm-device-adsl.c | 686 +++++++++++++++++++++++++++++++++++++++ src/devices/atm/nm-device-adsl.h | 62 ++++ src/devices/nm-device-adsl.c | 686 --------------------------------------- src/devices/nm-device-adsl.h | 62 ---- src/nm-atm-manager.c | 215 ------------ src/nm-atm-manager.h | 63 ---- src/nm-manager.c | 73 ----- 13 files changed, 1131 insertions(+), 1105 deletions(-) create mode 100644 src/devices/atm/Makefile.am create mode 100644 src/devices/atm/nm-atm-manager.c create mode 100644 src/devices/atm/nm-atm-manager.h create mode 100644 src/devices/atm/nm-device-adsl.c create mode 100644 src/devices/atm/nm-device-adsl.h delete mode 100644 src/devices/nm-device-adsl.c delete mode 100644 src/devices/nm-device-adsl.h delete mode 100644 src/nm-atm-manager.c delete mode 100644 src/nm-atm-manager.h diff --git a/configure.ac b/configure.ac index 1acfbb2069..b428649997 100644 --- a/configure.ac +++ b/configure.ac @@ -762,6 +762,7 @@ src/platform/Makefile src/platform/tests/Makefile src/rdisc/Makefile src/rdisc/tests/Makefile +src/devices/atm/Makefile src/devices/wimax/Makefile libnm-util/libnm-util.pc libnm-util/Makefile diff --git a/po/POTFILES.in b/po/POTFILES.in index b1a4fcc512..9806ceba19 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -47,10 +47,10 @@ src/dhcp-manager/nm-dhcp-manager.c src/dns-manager/nm-dns-manager.c src/logging/nm-logging.c src/config/nm-config.c +src/devices/atm/nm-device-adsl.c src/modem-manager/nm-modem-broadband.c src/modem-manager/nm-modem-old.c src/devices/nm-device-bond.c -src/devices/nm-device-adsl.c src/devices/nm-device-bridge.c src/devices/nm-device-bt.c src/devices/nm-device-ethernet.c diff --git a/src/Makefile.am b/src/Makefile.am index aeae2a0698..9ca1d68438 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,6 +4,7 @@ include $(GLIB_MAKEFILE) SUBDIRS = \ . \ + devices/atm \ dhcp-manager \ ppp-manager \ settings/plugins @@ -70,8 +71,6 @@ nm_sources = \ \ devices/nm-device.c \ devices/nm-device.h \ - devices/nm-device-adsl.c \ - devices/nm-device-adsl.h \ devices/nm-device-bond.c \ devices/nm-device-bond.h \ devices/nm-device-bridge.c \ @@ -225,8 +224,6 @@ nm_sources = \ nm-activation-request.h \ nm-active-connection.c \ nm-active-connection.h \ - nm-atm-manager.c \ - nm-atm-manager.h \ nm-connection-provider.c \ nm-connection-provider.h \ nm-connectivity.c \ @@ -320,7 +317,6 @@ glue_sources = \ nm-access-point-glue.h \ nm-active-connection-glue.h \ nm-agent-manager-glue.h \ - nm-device-adsl-glue.h \ nm-device-bond-glue.h \ nm-device-bridge-glue.h \ nm-device-bt-glue.h \ diff --git a/src/devices/atm/Makefile.am b/src/devices/atm/Makefile.am new file mode 100644 index 0000000000..8d1e2b3f96 --- /dev/null +++ b/src/devices/atm/Makefile.am @@ -0,0 +1,48 @@ +include $(GLIB_MAKEFILE) + +@GNOME_CODE_COVERAGE_RULES@ + +AM_CPPFLAGS = \ + -I${top_srcdir}/src \ + -I${top_builddir}/src \ + -I${top_srcdir}/src/logging \ + -I${top_srcdir}/src/devices \ + -I${top_srcdir}/src/settings \ + -I${top_srcdir}/src/platform \ + -I${top_srcdir}/src/ppp-manager \ + -I${top_builddir}/include \ + -I${top_srcdir}/include \ + -I${top_builddir}/libnm-util \ + -I${top_srcdir}/libnm-util \ + $(DBUS_CFLAGS) \ + $(POLKIT_CFLAGS) \ + $(LIBNL_CFLAGS) \ + $(GUDEV_CFLAGS) + +GLIB_GENERATED = nm-adsl-enum-types.h nm-adsl-enum-types.c +GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM +GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM +nm_adsl_enum_types_sources = $(srcdir)/nm-device-adsl.h + +nm-device-adsl-glue.h: $(top_srcdir)/introspection/nm-device-adsl.xml + dbus-binding-tool --prefix=nm_device_adsl --mode=glib-server --output=$@ $< + +BUILT_SOURCES = $(GLIB_GENERATED) nm-device-adsl-glue.h + +pkglib_LTLIBRARIES = libnm-device-plugin-atm.la + +libnm_device_plugin_atm_la_SOURCES = \ + nm-atm-manager.c \ + nm-atm-manager.h \ + nm-device-adsl.c \ + nm-device-adsl.h \ + \ + $(BUILT_SOURCES) + +libnm_device_plugin_atm_la_LDFLAGS = -module -avoid-version +libnm_device_plugin_atm_la_LIBADD = \ + $(DBUS_LIBS) \ + $(GUDEV_LIBS) + +CLEANFILES = $(BUILT_SOURCES) + diff --git a/src/devices/atm/nm-atm-manager.c b/src/devices/atm/nm-atm-manager.c new file mode 100644 index 0000000000..886095dad3 --- /dev/null +++ b/src/devices/atm/nm-atm-manager.c @@ -0,0 +1,290 @@ +/* -*- 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 - 2013 Red Hat, Inc. + */ + +#include + +#include +#include + +#include "nm-atm-manager.h" +#include "nm-device-adsl.h" +#include "nm-device-factory.h" +#include "nm-logging.h" + +typedef struct { + GUdevClient *client; + GSList *devices; + guint start_id; +} NMAtmManagerPrivate; + +#define NM_ATM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_ATM_MANAGER, NMAtmManagerPrivate)) + +static GType nm_atm_manager_get_type (void); + +static void device_factory_interface_init (NMDeviceFactory *factory_iface); + +G_DEFINE_TYPE_EXTENDED (NMAtmManager, nm_atm_manager, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_FACTORY, device_factory_interface_init)) + +enum { + PROP_0, + PROP_DEVICE_TYPE, + LAST_PROP +}; + +/**************************************************************************/ + +#define PLUGIN_TYPE NM_DEVICE_TYPE_ADSL + +G_MODULE_EXPORT NMDeviceFactory * +nm_device_factory_create (GError **error) +{ + return (NMDeviceFactory *) g_object_new (NM_TYPE_ATM_MANAGER, NULL); +} + +G_MODULE_EXPORT NMDeviceType +nm_device_factory_get_device_type (void) +{ + return PLUGIN_TYPE; +} + +/************************************************************************/ + +static gboolean +dev_get_attrs (GUdevDevice *udev_device, + const char **out_path, + char **out_driver) +{ + GUdevDevice *parent = NULL; + const char *driver, *path; + + g_return_val_if_fail (udev_device != NULL, FALSE); + g_return_val_if_fail (out_path != NULL, FALSE); + g_return_val_if_fail (out_driver != NULL, FALSE); + + path = g_udev_device_get_sysfs_path (udev_device); + if (!path) { + nm_log_warn (LOGD_HW, "couldn't determine device path; ignoring..."); + return FALSE; + } + + driver = g_udev_device_get_driver (udev_device); + if (!driver) { + /* Try the parent */ + parent = g_udev_device_get_parent (udev_device); + if (parent) + driver = g_udev_device_get_driver (parent); + } + + *out_path = path; + *out_driver = g_strdup (driver); + + g_clear_object (&parent); + return TRUE; +} + +static void +device_destroyed (gpointer user_data, GObject *dead) +{ + NMAtmManager *self = NM_ATM_MANAGER (user_data); + NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self); + + priv->devices = g_slist_remove (priv->devices, dead); +} + +static void +adsl_add (NMAtmManager *self, GUdevDevice *udev_device) +{ + NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self); + const char *ifname, *sysfs_path = NULL; + char *driver = NULL; + NMDevice *device; + + g_return_if_fail (udev_device != NULL); + + ifname = g_udev_device_get_name (udev_device); + if (!ifname) { + nm_log_warn (LOGD_HW, "failed to get device's interface name"); + return; + } + + nm_log_dbg (LOGD_HW, "(%s): found ATM device", ifname); + + if (dev_get_attrs (udev_device, &sysfs_path, &driver)) { + g_assert (sysfs_path); + + device = nm_device_adsl_new (sysfs_path, ifname, driver); + g_assert (device); + + priv->devices = g_slist_prepend (priv->devices, device); + g_object_weak_ref (G_OBJECT (device), device_destroyed, self); + + g_signal_emit_by_name (self, NM_DEVICE_FACTORY_DEVICE_ADDED, device); + g_object_unref (device); + + g_free (driver); + } +} + +static void +adsl_remove (NMAtmManager *self, GUdevDevice *udev_device) +{ + NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self); + const char *iface = g_udev_device_get_name (udev_device); + GSList *iter; + + nm_log_dbg (LOGD_HW, "(%s): removing ATM device", iface); + + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *device = iter->data; + + /* Match 'iface' not 'ip_iface' to the ATM device instead of the + * NAS bridge interface or PPPoE interface. + */ + if (g_strcmp0 (nm_device_get_iface (device), iface) != 0) + continue; + + g_object_weak_unref (G_OBJECT (iter->data), device_destroyed, self); + priv->devices = g_slist_remove (priv->devices, device); + g_signal_emit_by_name (device, NM_DEVICE_REMOVED); + break; + } +} + +static gboolean +query_devices (NMAtmManager *self) +{ + NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self); + GUdevEnumerator *enumerator; + GList *devices, *iter; + + enumerator = g_udev_enumerator_new (priv->client); + g_udev_enumerator_add_match_subsystem (enumerator, "atm"); + g_udev_enumerator_add_match_is_initialized (enumerator); + devices = g_udev_enumerator_execute (enumerator); + for (iter = devices; iter; iter = g_list_next (iter)) { + adsl_add (self, G_UDEV_DEVICE (iter->data)); + g_object_unref (G_UDEV_DEVICE (iter->data)); + } + g_list_free (devices); + g_object_unref (enumerator); + + return G_SOURCE_REMOVE; +} + +static void +handle_uevent (GUdevClient *client, + const char *action, + GUdevDevice *device, + gpointer user_data) +{ + NMAtmManager *self = NM_ATM_MANAGER (user_data); + const char *subsys; + const char *ifindex; + guint64 seqnum; + + g_return_if_fail (action != NULL); + + /* A bit paranoid */ + subsys = g_udev_device_get_subsystem (device); + g_return_if_fail (!g_strcmp0 (subsys, "atm")); + + ifindex = g_udev_device_get_property (device, "IFINDEX"); + seqnum = g_udev_device_get_seqnum (device); + nm_log_dbg (LOGD_HW, "UDEV event: action '%s' subsys '%s' device '%s' (%s); seqnum=%" G_GUINT64_FORMAT, + action, subsys, g_udev_device_get_name (device), ifindex ? ifindex : "unknown", seqnum); + + if (!strcmp (action, "add")) + adsl_add (self, device); + else if (!strcmp (action, "remove")) + adsl_remove (self, device); +} + +/*********************************************************************/ + +static void +nm_atm_manager_init (NMAtmManager *self) +{ + NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self); + const char *subsys[] = { "atm", NULL }; + + priv->client = g_udev_client_new (subsys); + g_signal_connect (priv->client, "uevent", G_CALLBACK (handle_uevent), self); + + priv->start_id = g_idle_add ((GSourceFunc) query_devices, self); +} + +static void +device_factory_interface_init (NMDeviceFactory *factory_iface) +{ +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_DEVICE_TYPE: + g_value_set_uint (value, PLUGIN_TYPE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + NMAtmManager *self = NM_ATM_MANAGER (object); + NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self); + GSList *iter; + + if (priv->client) + g_signal_handlers_disconnect_by_func (priv->client, handle_uevent, self); + g_clear_object (&priv->client); + + if (priv->start_id) { + g_source_remove (priv->start_id); + priv->start_id = 0; + } + + for (iter = priv->devices; iter; iter = iter->next) + g_object_weak_unref (G_OBJECT (iter->data), device_destroyed, self); + g_clear_pointer (&priv->devices, g_slist_free); + + G_OBJECT_CLASS (nm_atm_manager_parent_class)->dispose (object); +} + +static void +nm_atm_manager_class_init (NMAtmManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (NMAtmManagerPrivate)); + + /* virtual methods */ + object_class->dispose = dispose; + object_class->get_property = get_property; + + g_object_class_override_property (object_class, + PROP_DEVICE_TYPE, + NM_DEVICE_FACTORY_DEVICE_TYPE); +} diff --git a/src/devices/atm/nm-atm-manager.h b/src/devices/atm/nm-atm-manager.h new file mode 100644 index 0000000000..0052522075 --- /dev/null +++ b/src/devices/atm/nm-atm-manager.h @@ -0,0 +1,42 @@ +/* -*- 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) 2007 - 2008 Novell, Inc. + * Copyright (C) 2007 - 2014 Red Hat, Inc. + */ + +#ifndef NM_ATM_MANAGER_H +#define NM_ATM_MANAGER_H + +#include +#include + +G_BEGIN_DECLS + +#define NM_TYPE_ATM_MANAGER (nm_atm_manager_get_type ()) +#define NM_ATM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ATM_MANAGER, NMAtmManager)) + +typedef struct { + GObject parent; +} NMAtmManager; + +typedef struct { + GObjectClass parent; +} NMAtmManagerClass; + +#endif /* NM_ATM_MANAGER_H */ + diff --git a/src/devices/atm/nm-device-adsl.c b/src/devices/atm/nm-device-adsl.c new file mode 100644 index 0000000000..7fe626e7ca --- /dev/null +++ b/src/devices/atm/nm-device-adsl.c @@ -0,0 +1,686 @@ +/* -*- 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. + * + * Pantelis Koukousoulas + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "nm-device-adsl.h" +#include "nm-device-private.h" +#include "NetworkManagerUtils.h" +#include "nm-logging.h" +#include "nm-enum-types.h" +#include "nm-dbus-manager.h" +#include "nm-platform.h" + +#include "ppp-manager/nm-ppp-manager.h" +#include "nm-setting-adsl.h" + +#include "nm-device-adsl-glue.h" + +G_DEFINE_TYPE (NMDeviceAdsl, nm_device_adsl, NM_TYPE_DEVICE) + +#define NM_DEVICE_ADSL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_ADSL, NMDeviceAdslPrivate)) + +#define NM_ADSL_ERROR (nm_adsl_error_quark ()) + +static GQuark +nm_adsl_error_quark (void) +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string ("nm-adsl-error"); + return quark; +} + +/**********************************************/ + +typedef struct { + gboolean disposed; + guint carrier_poll_id; + int atm_index; + + /* Watch for 'nas' interfaces going away */ + guint lost_link_id; + + /* PPP */ + NMPPPManager *ppp_manager; + + /* RFC 2684 bridging (PPPoE over ATM) */ + int brfd; + int nas_ifindex; + char * nas_ifname; +} NMDeviceAdslPrivate; + +/**************************************************************/ + +static guint32 +get_generic_capabilities (NMDevice *dev) +{ + return (NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NONSTANDARD_CARRIER); +} + +static gboolean +check_connection_compatible (NMDevice *device, + NMConnection *connection, + GError **error) +{ + NMSettingAdsl *s_adsl; + const char *protocol; + + if (!NM_DEVICE_CLASS (nm_device_adsl_parent_class)->check_connection_compatible (device, connection, error)) + return FALSE; + + if (!nm_connection_is_type (connection, NM_SETTING_ADSL_SETTING_NAME)) { + g_set_error (error, + NM_ADSL_ERROR, NM_ADSL_ERROR_CONNECTION_NOT_ADSL, + "The connection was not an ADSL connection."); + return FALSE; + } + + s_adsl = nm_connection_get_setting_adsl (connection); + if (!s_adsl) { + g_set_error (error, + NM_ADSL_ERROR, NM_ADSL_ERROR_CONNECTION_INVALID, + "The connection was not a valid ADSL connection."); + return FALSE; + } + + /* FIXME: we don't yet support IPoATM */ + protocol = nm_setting_adsl_get_protocol (s_adsl); + if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_IPOATM) == 0) { + g_set_error (error, + NM_ADSL_ERROR, NM_ADSL_ERROR_CONNECTION_INVALID, + "IPoATM connections are not yet supported."); + return FALSE; + } + + return TRUE; +} + +static gboolean +complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMSettingAdsl *s_adsl; + + /* + * We can't telepathically figure out the username, so if + * it wasn't given, we can't complete the connection. + */ + s_adsl = nm_connection_get_setting_adsl (connection); + if (s_adsl && !nm_setting_verify (NM_SETTING (s_adsl), NULL, error)) + return FALSE; + + nm_utils_complete_generic (connection, + NM_SETTING_ADSL_SETTING_NAME, + existing_connections, + _("ADSL connection %d"), + NULL, + FALSE); /* No IPv6 yet by default */ + + + return TRUE; +} + +/**************************************************************/ + +static void +set_nas_iface (NMDeviceAdsl *self, int idx, const char *name) +{ + NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); + + g_return_if_fail (name != NULL); + + g_warn_if_fail (priv->nas_ifindex <= 0); + priv->nas_ifindex = idx > 0 ? idx : nm_platform_link_get_ifindex (name); + g_warn_if_fail (priv->nas_ifindex > 0); + + g_warn_if_fail (priv->nas_ifname == NULL); + priv->nas_ifname = g_strdup (name); + + /* Update NAS interface's MAC address */ + nm_device_update_hw_address (NM_DEVICE (self)); +} + +static gboolean +br2684_create_iface (NMDeviceAdsl *self, NMSettingAdsl *s_adsl) +{ + NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); + const char *iface = nm_device_get_iface (NM_DEVICE (self)); + struct atm_newif_br2684 ni; + int err, fd; + gboolean success = FALSE; + guint num = 0; + + g_return_val_if_fail (s_adsl != NULL, FALSE); + + fd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5); + if (fd < 0) { + nm_log_err (LOGD_ADSL, "(%s): failed to open ATM control socket (%d)", + iface, errno); + return FALSE; + } + + memset (&ni, 0, sizeof (ni)); + ni.backend_num = ATM_BACKEND_BR2684; + ni.media = BR2684_MEDIA_ETHERNET; + ni.mtu = 1500; + + /* Loop attempting to create an interface that doesn't exist yet. The + * kernel can create one for us automatically, but due to API issues it + * cannot return that name to us. Since we want to know the name right + * away, just brute-force it. + */ + while (num < 10000) { + memset (&ni.ifname, 0, sizeof (ni.ifname)); + g_snprintf (ni.ifname, sizeof (ni.ifname), "nas%d", num); + + err = ioctl (fd, ATM_NEWBACKENDIF, &ni); + if (err == 0) { + set_nas_iface (self, -1, ni.ifname); + nm_log_info (LOGD_ADSL, "(%s): using NAS interface %s (%d)", + iface, priv->nas_ifname, priv->nas_ifindex); + success = TRUE; + break; + } else if (errno == -EEXIST) { + /* Try again */ + num++; + } else { + nm_log_warn (LOGD_ADSL, "(%s): failed to create br2684 interface (%d)", + iface, errno); + break; + } + } + + close (fd); + return success; +} + +static gboolean +br2684_assign_vcc (NMDeviceAdsl *self, NMSettingAdsl *s_adsl) +{ + NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); + const char *iface = nm_device_get_iface (NM_DEVICE (self)); + struct sockaddr_atmpvc addr; + struct atm_backend_br2684 be; + struct atm_qos qos; + int err, bufsize = 8192; + const char *encapsulation; + gboolean is_llc; + + g_return_val_if_fail (priv->brfd == -1, FALSE); + g_return_val_if_fail (priv->nas_ifname != NULL, FALSE); + + priv->brfd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5); + if (priv->brfd < 0) { + nm_log_err (LOGD_ADSL, "(%s): failed to open ATM control socket (%d)", + iface, errno); + return FALSE; + } + + err = setsockopt (priv->brfd, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof (bufsize)); + if (err != 0) { + nm_log_err (LOGD_ADSL, "(%s): failed to set SNDBUF option (%d)", + iface, errno); + goto error; + } + + /* QoS */ + memset (&qos, 0, sizeof (qos)); + qos.aal = ATM_AAL5; + qos.txtp.traffic_class = ATM_UBR; + qos.txtp.max_sdu = 1524; + qos.txtp.pcr = ATM_MAX_PCR; + qos.rxtp = qos.txtp; + + err = setsockopt (priv->brfd, SOL_ATM, SO_ATMQOS, &qos, sizeof (qos)); + if (err != 0) { + nm_log_err (LOGD_ADSL, "(%s): failed to set QoS (%d)", + iface, errno); + goto error; + } + + encapsulation = nm_setting_adsl_get_encapsulation (s_adsl); + + /* VPI/VCI */ + memset (&addr, 0, sizeof (addr)); + addr.sap_family = AF_ATMPVC; + addr.sap_addr.itf = priv->atm_index; + addr.sap_addr.vpi = (guint16) nm_setting_adsl_get_vpi (s_adsl); + addr.sap_addr.vci = (int) nm_setting_adsl_get_vci (s_adsl); + + nm_log_dbg (LOGD_ADSL, "(%s): assigning address %d.%d.%d encapsulation %s", + nm_device_get_iface (NM_DEVICE (self)), + priv->atm_index, addr.sap_addr.vpi, addr.sap_addr.vci, + encapsulation); + + err = connect (priv->brfd, (struct sockaddr*) &addr, sizeof (addr)); + if (err != 0) { + nm_log_err (LOGD_ADSL, "(%s): failed to set VPI/VCI (%d)", + iface, errno); + goto error; + } + + /* And last attach the VCC to the interface */ + is_llc = (g_strcmp0 (encapsulation, "llc") == 0); + + memset (&be, 0, sizeof (be)); + be.backend_num = ATM_BACKEND_BR2684; + be.ifspec.method = BR2684_FIND_BYIFNAME; + strcpy (be.ifspec.spec.ifname, priv->nas_ifname); + be.fcs_in = BR2684_FCSIN_NO; + be.fcs_out = BR2684_FCSOUT_NO; + be.encaps = is_llc ? BR2684_ENCAPS_LLC : BR2684_ENCAPS_VC; + err = ioctl (priv->brfd, ATM_SETBACKEND, &be); + if (err != 0) { + nm_log_err (LOGD_ADSL, "(%s): failed to attach VCC (%d)", + iface, errno); + goto error; + } + + return TRUE; + +error: + close (priv->brfd); + priv->brfd = -1; + return FALSE; +} + +static void +lost_link (NMPlatform *platform, int ifindex, NMPlatformLink *info, NMPlatformReason reason, NMDeviceAdsl *device_adsl) +{ + NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (device_adsl); + NMDevice *device = NM_DEVICE (device_adsl); + + /* This only gets called for PPPoE connections and "nas" interfaces */ + + if (priv->nas_ifindex >= 0 && ifindex == priv->nas_ifindex) { + /* NAS device went away for some reason; kill the connection */ + nm_log_dbg (LOGD_ADSL, "(%s): NAS interface disappeared", + nm_device_get_iface (device)); + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_BR2684_FAILED); + } +} + +static NMActStageReturn +act_stage2_config (NMDevice *device, NMDeviceStateReason *out_reason) +{ + NMDeviceAdsl *self = NM_DEVICE_ADSL (device); + NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + NMSettingAdsl *s_adsl; + const char *protocol; + + g_assert (out_reason); + + s_adsl = nm_connection_get_setting_adsl (nm_device_get_connection (device)); + g_assert (s_adsl); + + protocol = nm_setting_adsl_get_protocol (s_adsl); + nm_log_dbg (LOGD_ADSL, "(%s): using ADSL protocol '%s'", + nm_device_get_iface (device), protocol); + + if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOE) == 0) { + + /* PPPoE needs RFC2684 bridging before we can do PPP over it */ + if (!br2684_create_iface (self, s_adsl)) { + *out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED; + goto done; + } + + /* Set up the VCC */ + if (!br2684_assign_vcc (self, s_adsl)) { + *out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED; + goto done; + } + + /* Watch for the 'nas' interface going away */ + priv->lost_link_id = g_signal_connect (nm_platform_get (), NM_PLATFORM_LINK_REMOVED, + G_CALLBACK (lost_link), + self); + + nm_log_dbg (LOGD_ADSL, "(%s): ATM setup successful", nm_device_get_iface (device)); + + /* otherwise we're good for stage3 */ + nm_platform_link_set_up (priv->nas_ifindex); + ret = NM_ACT_STAGE_RETURN_SUCCESS; + + } else if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOA) == 0) { + /* PPPoA doesn't need anything special */ + ret = NM_ACT_STAGE_RETURN_SUCCESS; + } else { + nm_log_warn (LOGD_ADSL, "(%s): unhandled ADSL protocol '%s'", + nm_device_get_iface (device), protocol); + } + +done: + return ret; +} + +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); + break; + case NM_PPP_STATUS_DEAD: + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_FAILED); + break; + default: + break; + } +} + +static void +ppp_ip4_config (NMPPPManager *ppp_manager, + const char *iface, + NMIP4Config *config, + gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + + /* Ignore PPP IP4 events that come in after initial configuration */ + if (nm_device_activate_ip4_state_in_conf (device)) { + nm_device_set_ip_iface (device, iface); + nm_device_activate_schedule_ip4_config_result (device, config); + } +} + +static NMActStageReturn +act_stage3_ip4_config_start (NMDevice *device, + NMIP4Config **out_config, + NMDeviceStateReason *reason) +{ + NMDeviceAdsl *self = NM_DEVICE_ADSL (device); + NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); + NMConnection *connection; + NMSettingAdsl *s_adsl; + NMActRequest *req; + GError *err = NULL; + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + const char *iface = nm_device_get_iface (device); + const char *ppp_iface; + + req = nm_device_get_act_request (device); + g_assert (req); + + connection = nm_act_request_get_connection (req); + g_assert (req); + + s_adsl = nm_connection_get_setting_adsl (connection); + g_assert (s_adsl); + + /* PPPoE uses the NAS interface, not the ATM interface */ + if (g_strcmp0 (nm_setting_adsl_get_protocol (s_adsl), NM_SETTING_ADSL_PROTOCOL_PPPOE) == 0) { + g_assert (priv->nas_ifname); + ppp_iface = priv->nas_ifname; + + nm_log_dbg (LOGD_ADSL, "(%s): starting PPPoE on NAS interface %s", + iface, priv->nas_ifname); + } else { + ppp_iface = iface; + nm_log_dbg (LOGD_ADSL, "(%s): starting PPPoA", iface); + } + + priv->ppp_manager = nm_ppp_manager_new (ppp_iface); + if (nm_ppp_manager_start (priv->ppp_manager, req, nm_setting_adsl_get_username (s_adsl), 30, &err)) { + g_signal_connect (priv->ppp_manager, "state-changed", + G_CALLBACK (ppp_state_changed), + self); + g_signal_connect (priv->ppp_manager, "ip4-config", + G_CALLBACK (ppp_ip4_config), + self); + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } else { + nm_log_warn (LOGD_ADSL, "(%s): PPP failed to start: %s", iface, err->message); + g_error_free (err); + + g_object_unref (priv->ppp_manager); + priv->ppp_manager = NULL; + + *reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED; + } + + return ret; +} + +static void +deactivate (NMDevice *device) +{ + NMDeviceAdsl *self = NM_DEVICE_ADSL (device); + NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); + + if (priv->ppp_manager) { + g_object_unref (priv->ppp_manager); + priv->ppp_manager = NULL; + } + + if (priv->lost_link_id) { + g_signal_handler_disconnect (nm_platform_get (), priv->lost_link_id); + priv->lost_link_id = 0; + } + + if (priv->brfd >= 0) { + close (priv->brfd); + priv->brfd = -1; + } + + /* FIXME: kernel has no way of explicitly deleting the 'nasX' interface yet, + * so it gets leaked. It does get destroyed when it's no longer in use, + * but we have no control over that. + */ + if (priv->nas_ifindex >= 0) + priv->nas_ifindex = -1; + g_free (priv->nas_ifname); + priv->nas_ifname = NULL; + + /* Poke NMDevice to notice that our hw_address is no longer valid */ + nm_device_update_hw_address (NM_DEVICE (self)); +} + +/**************************************************************/ + +static guint +get_hw_address_length (NMDevice *device, gboolean *out_permanent) +{ + NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (device); + + return priv->nas_ifname ? ETH_ALEN : 0; +} + +static gboolean +carrier_update_cb (gpointer user_data) +{ + NMDeviceAdsl *self = NM_DEVICE_ADSL (user_data); + GError *error = NULL; + gboolean carrier = FALSE; + char *path, *contents; + const char *iface; + gboolean success; + + iface = nm_device_get_iface (NM_DEVICE (self)); + + path = g_strdup_printf ("/sys/class/atm/%s/carrier", iface); + success = g_file_get_contents (path, &contents, NULL, &error); + g_free (path); + + if (!success) { + nm_log_dbg (LOGD_ADSL, "error reading %s: (%d) %s", + path, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + return TRUE; + } + + carrier = (gboolean) atoi (contents); + g_free (contents); + nm_device_set_carrier (NM_DEVICE (self), carrier); + return TRUE; +} + +/**************************************************************/ + +NMDevice * +nm_device_adsl_new (const char *udi, + const char *iface, + const char *driver) +{ + g_return_val_if_fail (udi != NULL, NULL); + + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ADSL, + NM_DEVICE_UDI, udi, + NM_DEVICE_IFACE, iface, + NM_DEVICE_DRIVER, driver, + NM_DEVICE_TYPE_DESC, "ADSL", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ADSL, + NULL); +} + +static int +get_atm_index (const char *iface, GError **error) +{ + char *path, *contents; + int idx = -1; + + path = g_strdup_printf ("/sys/class/atm/%s/atmindex", iface); + if (g_file_get_contents (path, &contents, NULL, error)) + idx = atoi (contents); + g_free (path); + g_free (contents); + return idx; +} + +static GObject* +constructor (GType type, + guint n_construct_params, + GObjectConstructParam *construct_params) +{ + GObject *object; + NMDeviceAdslPrivate *priv; + GError *error = NULL; + + object = G_OBJECT_CLASS (nm_device_adsl_parent_class)->constructor (type, + n_construct_params, + construct_params); + if (!object) + return NULL; + + priv = NM_DEVICE_ADSL_GET_PRIVATE (object); + + priv->atm_index = get_atm_index (nm_device_get_iface (NM_DEVICE (object)), &error); + if (priv->atm_index < 0) { + nm_log_dbg (LOGD_ADSL, "error reading ATM device index: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + g_object_unref (object); + return NULL; + } else { + nm_log_dbg (LOGD_ADSL, "(%s): ATM device index %d", + nm_device_get_iface (NM_DEVICE (object)), priv->atm_index); + } + + /* Poll the carrier */ + priv->carrier_poll_id = g_timeout_add_seconds (5, carrier_update_cb, object); + + return object; +} + +static void +dispose (GObject *object) +{ + NMDeviceAdsl *self = NM_DEVICE_ADSL (object); + NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); + + if (priv->disposed) { + G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object); + return; + } + + priv->disposed = TRUE; + + if (priv->carrier_poll_id) { + g_source_remove (priv->carrier_poll_id); + priv->carrier_poll_id = 0; + } + + if (priv->lost_link_id) { + g_signal_handler_disconnect (nm_platform_get (), priv->lost_link_id); + priv->lost_link_id = 0; + } + + g_free (priv->nas_ifname); + priv->nas_ifname = NULL; + + G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object); +} + +static void +nm_device_adsl_init (NMDeviceAdsl *self) +{ +} + +static void +nm_device_adsl_class_init (NMDeviceAdslClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMDeviceAdslPrivate)); + + object_class->constructor = constructor; + object_class->dispose = dispose; + + parent_class->get_generic_capabilities = get_generic_capabilities; + + parent_class->check_connection_compatible = check_connection_compatible; + parent_class->complete_connection = complete_connection; + + parent_class->get_hw_address_length = get_hw_address_length; + parent_class->act_stage2_config = act_stage2_config; + parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + parent_class->deactivate = deactivate; + + nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), + G_TYPE_FROM_CLASS (klass), + &dbus_glib_nm_device_adsl_object_info); +} diff --git a/src/devices/atm/nm-device-adsl.h b/src/devices/atm/nm-device-adsl.h new file mode 100644 index 0000000000..b0a094dd95 --- /dev/null +++ b/src/devices/atm/nm-device-adsl.h @@ -0,0 +1,62 @@ +/* -*- 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. + * + * Author: Pantelis Koukousoulas + * Copyright (C) 2009 - 2011 Red Hat Inc. + */ + +#ifndef NM_DEVICE_ADSL_H +#define NM_DEVICE_ADSL_H + +#include + +// Parent class +#include "nm-device.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_ADSL (nm_device_adsl_get_type ()) +#define NM_DEVICE_ADSL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_ADSL, NMDeviceAdsl)) +#define NM_DEVICE_ADSL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_ADSL, NMDeviceAdslClass)) +#define NM_IS_DEVICE_ADSL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_ADSL)) +#define NM_IS_DEVICE_ADSL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_ADSL)) +#define NM_DEVICE_ADSL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_ADSL, NMDeviceAdslClass)) + +typedef enum { + NM_ADSL_ERROR_CONNECTION_NOT_ADSL = 0, /*< nick=ConnectionNotAdsl >*/ + NM_ADSL_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/ + NM_ADSL_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ +} NMAdslError; + +typedef struct { + NMDevice parent; +} NMDeviceAdsl; + +typedef struct { + NMDeviceClass parent; + +} NMDeviceAdslClass; + +GType nm_device_adsl_get_type (void); + +NMDevice *nm_device_adsl_new (const char *udi, + const char *iface, + const char *driver); + +G_END_DECLS + +#endif /* NM_DEVICE_ADSL_H */ diff --git a/src/devices/nm-device-adsl.c b/src/devices/nm-device-adsl.c deleted file mode 100644 index 7fe626e7ca..0000000000 --- a/src/devices/nm-device-adsl.c +++ /dev/null @@ -1,686 +0,0 @@ -/* -*- 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. - * - * Pantelis Koukousoulas - */ - -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "nm-device-adsl.h" -#include "nm-device-private.h" -#include "NetworkManagerUtils.h" -#include "nm-logging.h" -#include "nm-enum-types.h" -#include "nm-dbus-manager.h" -#include "nm-platform.h" - -#include "ppp-manager/nm-ppp-manager.h" -#include "nm-setting-adsl.h" - -#include "nm-device-adsl-glue.h" - -G_DEFINE_TYPE (NMDeviceAdsl, nm_device_adsl, NM_TYPE_DEVICE) - -#define NM_DEVICE_ADSL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_ADSL, NMDeviceAdslPrivate)) - -#define NM_ADSL_ERROR (nm_adsl_error_quark ()) - -static GQuark -nm_adsl_error_quark (void) -{ - static GQuark quark = 0; - if (!quark) - quark = g_quark_from_static_string ("nm-adsl-error"); - return quark; -} - -/**********************************************/ - -typedef struct { - gboolean disposed; - guint carrier_poll_id; - int atm_index; - - /* Watch for 'nas' interfaces going away */ - guint lost_link_id; - - /* PPP */ - NMPPPManager *ppp_manager; - - /* RFC 2684 bridging (PPPoE over ATM) */ - int brfd; - int nas_ifindex; - char * nas_ifname; -} NMDeviceAdslPrivate; - -/**************************************************************/ - -static guint32 -get_generic_capabilities (NMDevice *dev) -{ - return (NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NONSTANDARD_CARRIER); -} - -static gboolean -check_connection_compatible (NMDevice *device, - NMConnection *connection, - GError **error) -{ - NMSettingAdsl *s_adsl; - const char *protocol; - - if (!NM_DEVICE_CLASS (nm_device_adsl_parent_class)->check_connection_compatible (device, connection, error)) - return FALSE; - - if (!nm_connection_is_type (connection, NM_SETTING_ADSL_SETTING_NAME)) { - g_set_error (error, - NM_ADSL_ERROR, NM_ADSL_ERROR_CONNECTION_NOT_ADSL, - "The connection was not an ADSL connection."); - return FALSE; - } - - s_adsl = nm_connection_get_setting_adsl (connection); - if (!s_adsl) { - g_set_error (error, - NM_ADSL_ERROR, NM_ADSL_ERROR_CONNECTION_INVALID, - "The connection was not a valid ADSL connection."); - return FALSE; - } - - /* FIXME: we don't yet support IPoATM */ - protocol = nm_setting_adsl_get_protocol (s_adsl); - if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_IPOATM) == 0) { - g_set_error (error, - NM_ADSL_ERROR, NM_ADSL_ERROR_CONNECTION_INVALID, - "IPoATM connections are not yet supported."); - return FALSE; - } - - return TRUE; -} - -static gboolean -complete_connection (NMDevice *device, - NMConnection *connection, - const char *specific_object, - const GSList *existing_connections, - GError **error) -{ - NMSettingAdsl *s_adsl; - - /* - * We can't telepathically figure out the username, so if - * it wasn't given, we can't complete the connection. - */ - s_adsl = nm_connection_get_setting_adsl (connection); - if (s_adsl && !nm_setting_verify (NM_SETTING (s_adsl), NULL, error)) - return FALSE; - - nm_utils_complete_generic (connection, - NM_SETTING_ADSL_SETTING_NAME, - existing_connections, - _("ADSL connection %d"), - NULL, - FALSE); /* No IPv6 yet by default */ - - - return TRUE; -} - -/**************************************************************/ - -static void -set_nas_iface (NMDeviceAdsl *self, int idx, const char *name) -{ - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); - - g_return_if_fail (name != NULL); - - g_warn_if_fail (priv->nas_ifindex <= 0); - priv->nas_ifindex = idx > 0 ? idx : nm_platform_link_get_ifindex (name); - g_warn_if_fail (priv->nas_ifindex > 0); - - g_warn_if_fail (priv->nas_ifname == NULL); - priv->nas_ifname = g_strdup (name); - - /* Update NAS interface's MAC address */ - nm_device_update_hw_address (NM_DEVICE (self)); -} - -static gboolean -br2684_create_iface (NMDeviceAdsl *self, NMSettingAdsl *s_adsl) -{ - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); - const char *iface = nm_device_get_iface (NM_DEVICE (self)); - struct atm_newif_br2684 ni; - int err, fd; - gboolean success = FALSE; - guint num = 0; - - g_return_val_if_fail (s_adsl != NULL, FALSE); - - fd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5); - if (fd < 0) { - nm_log_err (LOGD_ADSL, "(%s): failed to open ATM control socket (%d)", - iface, errno); - return FALSE; - } - - memset (&ni, 0, sizeof (ni)); - ni.backend_num = ATM_BACKEND_BR2684; - ni.media = BR2684_MEDIA_ETHERNET; - ni.mtu = 1500; - - /* Loop attempting to create an interface that doesn't exist yet. The - * kernel can create one for us automatically, but due to API issues it - * cannot return that name to us. Since we want to know the name right - * away, just brute-force it. - */ - while (num < 10000) { - memset (&ni.ifname, 0, sizeof (ni.ifname)); - g_snprintf (ni.ifname, sizeof (ni.ifname), "nas%d", num); - - err = ioctl (fd, ATM_NEWBACKENDIF, &ni); - if (err == 0) { - set_nas_iface (self, -1, ni.ifname); - nm_log_info (LOGD_ADSL, "(%s): using NAS interface %s (%d)", - iface, priv->nas_ifname, priv->nas_ifindex); - success = TRUE; - break; - } else if (errno == -EEXIST) { - /* Try again */ - num++; - } else { - nm_log_warn (LOGD_ADSL, "(%s): failed to create br2684 interface (%d)", - iface, errno); - break; - } - } - - close (fd); - return success; -} - -static gboolean -br2684_assign_vcc (NMDeviceAdsl *self, NMSettingAdsl *s_adsl) -{ - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); - const char *iface = nm_device_get_iface (NM_DEVICE (self)); - struct sockaddr_atmpvc addr; - struct atm_backend_br2684 be; - struct atm_qos qos; - int err, bufsize = 8192; - const char *encapsulation; - gboolean is_llc; - - g_return_val_if_fail (priv->brfd == -1, FALSE); - g_return_val_if_fail (priv->nas_ifname != NULL, FALSE); - - priv->brfd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5); - if (priv->brfd < 0) { - nm_log_err (LOGD_ADSL, "(%s): failed to open ATM control socket (%d)", - iface, errno); - return FALSE; - } - - err = setsockopt (priv->brfd, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof (bufsize)); - if (err != 0) { - nm_log_err (LOGD_ADSL, "(%s): failed to set SNDBUF option (%d)", - iface, errno); - goto error; - } - - /* QoS */ - memset (&qos, 0, sizeof (qos)); - qos.aal = ATM_AAL5; - qos.txtp.traffic_class = ATM_UBR; - qos.txtp.max_sdu = 1524; - qos.txtp.pcr = ATM_MAX_PCR; - qos.rxtp = qos.txtp; - - err = setsockopt (priv->brfd, SOL_ATM, SO_ATMQOS, &qos, sizeof (qos)); - if (err != 0) { - nm_log_err (LOGD_ADSL, "(%s): failed to set QoS (%d)", - iface, errno); - goto error; - } - - encapsulation = nm_setting_adsl_get_encapsulation (s_adsl); - - /* VPI/VCI */ - memset (&addr, 0, sizeof (addr)); - addr.sap_family = AF_ATMPVC; - addr.sap_addr.itf = priv->atm_index; - addr.sap_addr.vpi = (guint16) nm_setting_adsl_get_vpi (s_adsl); - addr.sap_addr.vci = (int) nm_setting_adsl_get_vci (s_adsl); - - nm_log_dbg (LOGD_ADSL, "(%s): assigning address %d.%d.%d encapsulation %s", - nm_device_get_iface (NM_DEVICE (self)), - priv->atm_index, addr.sap_addr.vpi, addr.sap_addr.vci, - encapsulation); - - err = connect (priv->brfd, (struct sockaddr*) &addr, sizeof (addr)); - if (err != 0) { - nm_log_err (LOGD_ADSL, "(%s): failed to set VPI/VCI (%d)", - iface, errno); - goto error; - } - - /* And last attach the VCC to the interface */ - is_llc = (g_strcmp0 (encapsulation, "llc") == 0); - - memset (&be, 0, sizeof (be)); - be.backend_num = ATM_BACKEND_BR2684; - be.ifspec.method = BR2684_FIND_BYIFNAME; - strcpy (be.ifspec.spec.ifname, priv->nas_ifname); - be.fcs_in = BR2684_FCSIN_NO; - be.fcs_out = BR2684_FCSOUT_NO; - be.encaps = is_llc ? BR2684_ENCAPS_LLC : BR2684_ENCAPS_VC; - err = ioctl (priv->brfd, ATM_SETBACKEND, &be); - if (err != 0) { - nm_log_err (LOGD_ADSL, "(%s): failed to attach VCC (%d)", - iface, errno); - goto error; - } - - return TRUE; - -error: - close (priv->brfd); - priv->brfd = -1; - return FALSE; -} - -static void -lost_link (NMPlatform *platform, int ifindex, NMPlatformLink *info, NMPlatformReason reason, NMDeviceAdsl *device_adsl) -{ - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (device_adsl); - NMDevice *device = NM_DEVICE (device_adsl); - - /* This only gets called for PPPoE connections and "nas" interfaces */ - - if (priv->nas_ifindex >= 0 && ifindex == priv->nas_ifindex) { - /* NAS device went away for some reason; kill the connection */ - nm_log_dbg (LOGD_ADSL, "(%s): NAS interface disappeared", - nm_device_get_iface (device)); - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BR2684_FAILED); - } -} - -static NMActStageReturn -act_stage2_config (NMDevice *device, NMDeviceStateReason *out_reason) -{ - NMDeviceAdsl *self = NM_DEVICE_ADSL (device); - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - NMSettingAdsl *s_adsl; - const char *protocol; - - g_assert (out_reason); - - s_adsl = nm_connection_get_setting_adsl (nm_device_get_connection (device)); - g_assert (s_adsl); - - protocol = nm_setting_adsl_get_protocol (s_adsl); - nm_log_dbg (LOGD_ADSL, "(%s): using ADSL protocol '%s'", - nm_device_get_iface (device), protocol); - - if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOE) == 0) { - - /* PPPoE needs RFC2684 bridging before we can do PPP over it */ - if (!br2684_create_iface (self, s_adsl)) { - *out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED; - goto done; - } - - /* Set up the VCC */ - if (!br2684_assign_vcc (self, s_adsl)) { - *out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED; - goto done; - } - - /* Watch for the 'nas' interface going away */ - priv->lost_link_id = g_signal_connect (nm_platform_get (), NM_PLATFORM_LINK_REMOVED, - G_CALLBACK (lost_link), - self); - - nm_log_dbg (LOGD_ADSL, "(%s): ATM setup successful", nm_device_get_iface (device)); - - /* otherwise we're good for stage3 */ - nm_platform_link_set_up (priv->nas_ifindex); - ret = NM_ACT_STAGE_RETURN_SUCCESS; - - } else if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOA) == 0) { - /* PPPoA doesn't need anything special */ - ret = NM_ACT_STAGE_RETURN_SUCCESS; - } else { - nm_log_warn (LOGD_ADSL, "(%s): unhandled ADSL protocol '%s'", - nm_device_get_iface (device), protocol); - } - -done: - return ret; -} - -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); - break; - case NM_PPP_STATUS_DEAD: - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_FAILED); - break; - default: - break; - } -} - -static void -ppp_ip4_config (NMPPPManager *ppp_manager, - const char *iface, - NMIP4Config *config, - gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - - /* Ignore PPP IP4 events that come in after initial configuration */ - if (nm_device_activate_ip4_state_in_conf (device)) { - nm_device_set_ip_iface (device, iface); - nm_device_activate_schedule_ip4_config_result (device, config); - } -} - -static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *device, - NMIP4Config **out_config, - NMDeviceStateReason *reason) -{ - NMDeviceAdsl *self = NM_DEVICE_ADSL (device); - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); - NMConnection *connection; - NMSettingAdsl *s_adsl; - NMActRequest *req; - GError *err = NULL; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - const char *iface = nm_device_get_iface (device); - const char *ppp_iface; - - req = nm_device_get_act_request (device); - g_assert (req); - - connection = nm_act_request_get_connection (req); - g_assert (req); - - s_adsl = nm_connection_get_setting_adsl (connection); - g_assert (s_adsl); - - /* PPPoE uses the NAS interface, not the ATM interface */ - if (g_strcmp0 (nm_setting_adsl_get_protocol (s_adsl), NM_SETTING_ADSL_PROTOCOL_PPPOE) == 0) { - g_assert (priv->nas_ifname); - ppp_iface = priv->nas_ifname; - - nm_log_dbg (LOGD_ADSL, "(%s): starting PPPoE on NAS interface %s", - iface, priv->nas_ifname); - } else { - ppp_iface = iface; - nm_log_dbg (LOGD_ADSL, "(%s): starting PPPoA", iface); - } - - priv->ppp_manager = nm_ppp_manager_new (ppp_iface); - if (nm_ppp_manager_start (priv->ppp_manager, req, nm_setting_adsl_get_username (s_adsl), 30, &err)) { - g_signal_connect (priv->ppp_manager, "state-changed", - G_CALLBACK (ppp_state_changed), - self); - g_signal_connect (priv->ppp_manager, "ip4-config", - G_CALLBACK (ppp_ip4_config), - self); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else { - nm_log_warn (LOGD_ADSL, "(%s): PPP failed to start: %s", iface, err->message); - g_error_free (err); - - g_object_unref (priv->ppp_manager); - priv->ppp_manager = NULL; - - *reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED; - } - - return ret; -} - -static void -deactivate (NMDevice *device) -{ - NMDeviceAdsl *self = NM_DEVICE_ADSL (device); - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); - - if (priv->ppp_manager) { - g_object_unref (priv->ppp_manager); - priv->ppp_manager = NULL; - } - - if (priv->lost_link_id) { - g_signal_handler_disconnect (nm_platform_get (), priv->lost_link_id); - priv->lost_link_id = 0; - } - - if (priv->brfd >= 0) { - close (priv->brfd); - priv->brfd = -1; - } - - /* FIXME: kernel has no way of explicitly deleting the 'nasX' interface yet, - * so it gets leaked. It does get destroyed when it's no longer in use, - * but we have no control over that. - */ - if (priv->nas_ifindex >= 0) - priv->nas_ifindex = -1; - g_free (priv->nas_ifname); - priv->nas_ifname = NULL; - - /* Poke NMDevice to notice that our hw_address is no longer valid */ - nm_device_update_hw_address (NM_DEVICE (self)); -} - -/**************************************************************/ - -static guint -get_hw_address_length (NMDevice *device, gboolean *out_permanent) -{ - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (device); - - return priv->nas_ifname ? ETH_ALEN : 0; -} - -static gboolean -carrier_update_cb (gpointer user_data) -{ - NMDeviceAdsl *self = NM_DEVICE_ADSL (user_data); - GError *error = NULL; - gboolean carrier = FALSE; - char *path, *contents; - const char *iface; - gboolean success; - - iface = nm_device_get_iface (NM_DEVICE (self)); - - path = g_strdup_printf ("/sys/class/atm/%s/carrier", iface); - success = g_file_get_contents (path, &contents, NULL, &error); - g_free (path); - - if (!success) { - nm_log_dbg (LOGD_ADSL, "error reading %s: (%d) %s", - path, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - return TRUE; - } - - carrier = (gboolean) atoi (contents); - g_free (contents); - nm_device_set_carrier (NM_DEVICE (self), carrier); - return TRUE; -} - -/**************************************************************/ - -NMDevice * -nm_device_adsl_new (const char *udi, - const char *iface, - const char *driver) -{ - g_return_val_if_fail (udi != NULL, NULL); - - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ADSL, - NM_DEVICE_UDI, udi, - NM_DEVICE_IFACE, iface, - NM_DEVICE_DRIVER, driver, - NM_DEVICE_TYPE_DESC, "ADSL", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ADSL, - NULL); -} - -static int -get_atm_index (const char *iface, GError **error) -{ - char *path, *contents; - int idx = -1; - - path = g_strdup_printf ("/sys/class/atm/%s/atmindex", iface); - if (g_file_get_contents (path, &contents, NULL, error)) - idx = atoi (contents); - g_free (path); - g_free (contents); - return idx; -} - -static GObject* -constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) -{ - GObject *object; - NMDeviceAdslPrivate *priv; - GError *error = NULL; - - object = G_OBJECT_CLASS (nm_device_adsl_parent_class)->constructor (type, - n_construct_params, - construct_params); - if (!object) - return NULL; - - priv = NM_DEVICE_ADSL_GET_PRIVATE (object); - - priv->atm_index = get_atm_index (nm_device_get_iface (NM_DEVICE (object)), &error); - if (priv->atm_index < 0) { - nm_log_dbg (LOGD_ADSL, "error reading ATM device index: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - g_object_unref (object); - return NULL; - } else { - nm_log_dbg (LOGD_ADSL, "(%s): ATM device index %d", - nm_device_get_iface (NM_DEVICE (object)), priv->atm_index); - } - - /* Poll the carrier */ - priv->carrier_poll_id = g_timeout_add_seconds (5, carrier_update_cb, object); - - return object; -} - -static void -dispose (GObject *object) -{ - NMDeviceAdsl *self = NM_DEVICE_ADSL (object); - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); - - if (priv->disposed) { - G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object); - return; - } - - priv->disposed = TRUE; - - if (priv->carrier_poll_id) { - g_source_remove (priv->carrier_poll_id); - priv->carrier_poll_id = 0; - } - - if (priv->lost_link_id) { - g_signal_handler_disconnect (nm_platform_get (), priv->lost_link_id); - priv->lost_link_id = 0; - } - - g_free (priv->nas_ifname); - priv->nas_ifname = NULL; - - G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object); -} - -static void -nm_device_adsl_init (NMDeviceAdsl *self) -{ -} - -static void -nm_device_adsl_class_init (NMDeviceAdslClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - g_type_class_add_private (object_class, sizeof (NMDeviceAdslPrivate)); - - object_class->constructor = constructor; - object_class->dispose = dispose; - - parent_class->get_generic_capabilities = get_generic_capabilities; - - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->complete_connection = complete_connection; - - parent_class->get_hw_address_length = get_hw_address_length; - parent_class->act_stage2_config = act_stage2_config; - parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - parent_class->deactivate = deactivate; - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_adsl_object_info); -} diff --git a/src/devices/nm-device-adsl.h b/src/devices/nm-device-adsl.h deleted file mode 100644 index b0a094dd95..0000000000 --- a/src/devices/nm-device-adsl.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -*- 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. - * - * Author: Pantelis Koukousoulas - * Copyright (C) 2009 - 2011 Red Hat Inc. - */ - -#ifndef NM_DEVICE_ADSL_H -#define NM_DEVICE_ADSL_H - -#include - -// Parent class -#include "nm-device.h" - -G_BEGIN_DECLS - -#define NM_TYPE_DEVICE_ADSL (nm_device_adsl_get_type ()) -#define NM_DEVICE_ADSL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_ADSL, NMDeviceAdsl)) -#define NM_DEVICE_ADSL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_ADSL, NMDeviceAdslClass)) -#define NM_IS_DEVICE_ADSL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_ADSL)) -#define NM_IS_DEVICE_ADSL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_ADSL)) -#define NM_DEVICE_ADSL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_ADSL, NMDeviceAdslClass)) - -typedef enum { - NM_ADSL_ERROR_CONNECTION_NOT_ADSL = 0, /*< nick=ConnectionNotAdsl >*/ - NM_ADSL_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/ - NM_ADSL_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ -} NMAdslError; - -typedef struct { - NMDevice parent; -} NMDeviceAdsl; - -typedef struct { - NMDeviceClass parent; - -} NMDeviceAdslClass; - -GType nm_device_adsl_get_type (void); - -NMDevice *nm_device_adsl_new (const char *udi, - const char *iface, - const char *driver); - -G_END_DECLS - -#endif /* NM_DEVICE_ADSL_H */ diff --git a/src/nm-atm-manager.c b/src/nm-atm-manager.c deleted file mode 100644 index 19701500e7..0000000000 --- a/src/nm-atm-manager.c +++ /dev/null @@ -1,215 +0,0 @@ -/* -*- 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 - 2013 Red Hat, Inc. - */ - -#include - -#include -#include - -#include "nm-atm-manager.h" -#include "nm-logging.h" - -typedef struct { - GUdevClient *client; - -} NMAtmManagerPrivate; - -#define NM_ATM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_ATM_MANAGER, NMAtmManagerPrivate)) - -G_DEFINE_TYPE (NMAtmManager, nm_atm_manager, G_TYPE_OBJECT) - -enum { - DEVICE_ADDED, - DEVICE_REMOVED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -NMAtmManager * -nm_atm_manager_new (void) -{ - return NM_ATM_MANAGER (g_object_new (NM_TYPE_ATM_MANAGER, NULL)); -} - -static gboolean -dev_get_attrs (GUdevDevice *udev_device, - const char **out_ifname, - const char **out_path, - char **out_driver) -{ - GUdevDevice *parent = NULL; - const char *ifname, *driver, *path; - - g_return_val_if_fail (udev_device != NULL, FALSE); - g_return_val_if_fail (out_ifname != NULL, FALSE); - g_return_val_if_fail (out_path != NULL, FALSE); - g_return_val_if_fail (out_driver != NULL, FALSE); - - ifname = g_udev_device_get_name (udev_device); - if (!ifname) { - nm_log_dbg (LOGD_HW, "failed to get device's interface"); - return FALSE; - } - - path = g_udev_device_get_sysfs_path (udev_device); - if (!path) { - nm_log_warn (LOGD_HW, "couldn't determine device path; ignoring..."); - return FALSE; - } - - driver = g_udev_device_get_driver (udev_device); - if (!driver) { - /* Try the parent */ - parent = g_udev_device_get_parent (udev_device); - if (parent) { - driver = g_udev_device_get_driver (parent); - g_object_unref (parent); - } - } - - *out_ifname = ifname; - *out_path = path; - *out_driver = g_strdup (driver); - - return TRUE; -} - -static void -adsl_add (NMAtmManager *self, GUdevDevice *udev_device) -{ - const char *ifname = NULL, *path = NULL; - char *driver = NULL; - - g_return_if_fail (udev_device != NULL); - - nm_log_dbg (LOGD_HW, "adsl_add: ATM Device detected from udev. Adding .."); - - if (dev_get_attrs (udev_device, &ifname, &path, &driver)) - g_signal_emit (self, signals[DEVICE_ADDED], 0, ifname, path, driver); - g_free (driver); -} - -static void -adsl_remove (NMAtmManager *self, GUdevDevice *device) -{ - nm_log_dbg (LOGD_HW, "adsl_remove: Removing ATM Device"); - - g_signal_emit (self, signals[DEVICE_REMOVED], 0, g_udev_device_get_name (device)); -} - -void -nm_atm_manager_query_devices (NMAtmManager *self) -{ - NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self); - GUdevEnumerator *enumerator; - GList *devices, *iter; - - g_return_if_fail (NM_IS_ATM_MANAGER (self)); - - enumerator = g_udev_enumerator_new (priv->client); - g_udev_enumerator_add_match_subsystem (enumerator, "atm"); - g_udev_enumerator_add_match_is_initialized (enumerator); - devices = g_udev_enumerator_execute (enumerator); - for (iter = devices; iter; iter = g_list_next (iter)) { - adsl_add (self, G_UDEV_DEVICE (iter->data)); - g_object_unref (G_UDEV_DEVICE (iter->data)); - } - g_list_free (devices); - g_object_unref (enumerator); -} - -static void -handle_uevent (GUdevClient *client, - const char *action, - GUdevDevice *device, - gpointer user_data) -{ - NMAtmManager *self = NM_ATM_MANAGER (user_data); - const char *subsys; - const char *ifindex; - guint64 seqnum; - - g_return_if_fail (action != NULL); - - /* A bit paranoid */ - subsys = g_udev_device_get_subsystem (device); - g_return_if_fail (!g_strcmp0 (subsys, "atm")); - - ifindex = g_udev_device_get_property (device, "IFINDEX"); - seqnum = g_udev_device_get_seqnum (device); - nm_log_dbg (LOGD_HW, "UDEV event: action '%s' subsys '%s' device '%s' (%s); seqnum=%" G_GUINT64_FORMAT, - action, subsys, g_udev_device_get_name (device), ifindex ? ifindex : "unknown", seqnum); - - if (!strcmp (action, "add")) - adsl_add (self, device); - else if (!strcmp (action, "remove")) - adsl_remove (self, device); -} - -static void -nm_atm_manager_init (NMAtmManager *self) -{ - NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self); - const char *subsys[] = { "atm", NULL }; - - priv->client = g_udev_client_new (subsys); - g_signal_connect (priv->client, "uevent", G_CALLBACK (handle_uevent), self); -} - -static void -dispose (GObject *object) -{ - NMAtmManager *self = NM_ATM_MANAGER (object); - NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE (self); - - g_clear_object (&priv->client); - - G_OBJECT_CLASS (nm_atm_manager_parent_class)->dispose (object); -} - -static void -nm_atm_manager_class_init (NMAtmManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (NMAtmManagerPrivate)); - - /* virtual methods */ - object_class->dispose = dispose; - - /* Signals */ - signals[DEVICE_ADDED] = - g_signal_new ("device-added", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMAtmManagerClass, device_added), - NULL, NULL, NULL, - G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); - - signals[DEVICE_REMOVED] = - g_signal_new ("device-removed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMAtmManagerClass, device_removed), - NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_STRING); -} diff --git a/src/nm-atm-manager.h b/src/nm-atm-manager.h deleted file mode 100644 index 773f33ffc7..0000000000 --- a/src/nm-atm-manager.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- 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) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2012 Red Hat, Inc. - */ - -#ifndef NM_ATM_MANAGER_H -#define NM_ATM_MANAGER_H - -#include -#include - -#include - -G_BEGIN_DECLS - -#define NM_TYPE_ATM_MANAGER (nm_atm_manager_get_type ()) -#define NM_ATM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ATM_MANAGER, NMAtmManager)) -#define NM_ATM_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ATM_MANAGER, NMAtmManagerClass)) -#define NM_IS_ATM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_ATM_MANAGER)) -#define NM_IS_ATM_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_ATM_MANAGER)) -#define NM_ATM_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ATM_MANAGER, NMAtmManagerClass)) - -typedef struct { - GObject parent; -} NMAtmManager; - -typedef struct { - GObjectClass parent; - - /* signals */ - void (*device_added) (NMAtmManager *manager, - const char *iface, - const char *sysfs_path, - const char *driver); - - void (*device_removed) (NMAtmManager *manager, - const char *iface); -} NMAtmManagerClass; - -GType nm_atm_manager_get_type (void); - -NMAtmManager *nm_atm_manager_new (void); - -void nm_atm_manager_query_devices (NMAtmManager *manager); - -#endif /* NM_ATM_MANAGER_H */ - diff --git a/src/nm-manager.c b/src/nm-manager.c index 22e8a32f57..fa76575cf0 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -51,7 +51,6 @@ #include "nm-device-team.h" #include "nm-device-bridge.h" #include "nm-device-vlan.h" -#include "nm-device-adsl.h" #include "nm-device-generic.h" #include "nm-device-veth.h" #include "nm-device-tun.h" @@ -63,7 +62,6 @@ #include "nm-setting-vpn.h" #include "nm-dbus-glib-types.h" #include "nm-platform.h" -#include "nm-atm-manager.h" #include "nm-rfkill-manager.h" #include "nm-hostname-provider.h" #include "nm-bluez-manager.h" @@ -165,7 +163,6 @@ static NMActiveConnection *_new_active_connection (NMManager *self, static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data); static NMDevice *find_device_by_ip_iface (NMManager *self, const gchar *iface); -static NMDevice *find_device_by_iface (NMManager *self, const gchar *iface); static void rfkill_change_wifi (const char *desc, gboolean enabled); @@ -219,7 +216,6 @@ typedef struct { NMDBusManager *dbus_mgr; gboolean prop_filter_added; - NMAtmManager *atm_mgr; NMRfkillManager *rfkill_mgr; NMBluezManager *bluez_mgr; @@ -2026,21 +2022,6 @@ find_device_by_ip_iface (NMManager *self, const gchar *iface) return NULL; } -static NMDevice * -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 *candidate = iter->data; - - if (g_strcmp0 (nm_device_get_iface (candidate), iface) == 0) - return candidate; - } - return NULL; -} - static NMDevice * find_device_by_ifindex (NMManager *self, guint32 ifindex) { @@ -2316,49 +2297,6 @@ platform_link_removed_cb (NMPlatform *platform, remove_device (self, device, FALSE); } -static void -atm_device_added_cb (NMAtmManager *atm_mgr, - const char *iface, - const char *sysfs_path, - const char *driver, - gpointer user_data) -{ - NMManager *self = NM_MANAGER (user_data); - NMDevice *device; - - g_return_if_fail (iface != NULL); - g_return_if_fail (sysfs_path != NULL); - - device = find_device_by_iface (self, iface); - if (device) - return; - - device = nm_device_adsl_new (sysfs_path, iface, driver); - if (device) - add_device (self, device, TRUE); -} - -static void -atm_device_removed_cb (NMAtmManager *manager, - const char *iface, - gpointer user_data) -{ - NMManager *self = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device = NULL; - GSList *iter; - - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - if (g_strcmp0 (nm_device_get_iface (NM_DEVICE (iter->data)), iface) == 0) { - device = iter->data; - break; - } - } - - if (device) - remove_device (self, device, FALSE); -} - static void rfkill_manager_rfkill_changed_cb (NMRfkillManager *rfkill_mgr, RfKillType rtype, @@ -4230,7 +4168,6 @@ nm_manager_start (NMManager *self) system_hostname_changed_cb (priv->settings, NULL, self); nm_platform_query_devices (); - nm_atm_manager_query_devices (priv->atm_mgr); nm_bluez_manager_query_devices (priv->bluez_mgr); /* @@ -4789,16 +4726,6 @@ nm_manager_new (NMSettings *settings, G_CALLBACK (platform_link_removed_cb), singleton); - priv->atm_mgr = nm_atm_manager_new (); - g_signal_connect (priv->atm_mgr, - "device-added", - G_CALLBACK (atm_device_added_cb), - singleton); - g_signal_connect (priv->atm_mgr, - "device-removed", - G_CALLBACK (atm_device_removed_cb), - singleton); - priv->rfkill_mgr = nm_rfkill_manager_new (); g_signal_connect (priv->rfkill_mgr, "rfkill-changed", -- cgit v1.2.1 From a9591aecaf0118f8e603a4ed0a40f3ea8535529b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 10 Feb 2014 06:35:56 -0600 Subject: bluez: make Bluetooth support a plugin Make Bluetooth support a plugin using the new device factory interface. Provides a 5% size reduction in the core NM binary. Before After NM: 1253016 1187224 (-5%) BT: 0 85752 (all results from stripped files) --- configure.ac | 1 + po/POTFILES.in | 4 +- src/Makefile.am | 18 +- src/bluez-manager/nm-bluez-common.h | 45 -- src/bluez-manager/nm-bluez-device.c | 1173 --------------------------- src/bluez-manager/nm-bluez-device.h | 94 --- src/bluez-manager/nm-bluez-manager.c | 514 ------------ src/bluez-manager/nm-bluez-manager.h | 71 -- src/bluez-manager/nm-bluez4-adapter.c | 413 ---------- src/bluez-manager/nm-bluez4-adapter.h | 69 -- src/bluez-manager/nm-bluez4-manager.c | 379 --------- src/bluez-manager/nm-bluez4-manager.h | 66 -- src/bluez-manager/nm-bluez5-manager.c | 436 ---------- src/bluez-manager/nm-bluez5-manager.h | 66 -- src/devices/bluetooth/Makefile.am | 56 ++ src/devices/bluetooth/nm-bluez-common.h | 45 ++ src/devices/bluetooth/nm-bluez-device.c | 1181 +++++++++++++++++++++++++++ src/devices/bluetooth/nm-bluez-device.h | 98 +++ src/devices/bluetooth/nm-bluez-manager.c | 452 +++++++++++ src/devices/bluetooth/nm-bluez-manager.h | 44 + src/devices/bluetooth/nm-bluez4-adapter.c | 413 ++++++++++ src/devices/bluetooth/nm-bluez4-adapter.h | 69 ++ src/devices/bluetooth/nm-bluez4-manager.c | 361 +++++++++ src/devices/bluetooth/nm-bluez4-manager.h | 62 ++ src/devices/bluetooth/nm-bluez5-manager.c | 421 ++++++++++ src/devices/bluetooth/nm-bluez5-manager.h | 62 ++ src/devices/bluetooth/nm-device-bt.c | 1259 +++++++++++++++++++++++++++++ src/devices/bluetooth/nm-device-bt.h | 74 ++ src/devices/nm-device-bt.c | 1254 ---------------------------- src/devices/nm-device-bt.h | 74 -- src/nm-manager.c | 88 -- 31 files changed, 4602 insertions(+), 4760 deletions(-) delete mode 100644 src/bluez-manager/nm-bluez-common.h delete mode 100644 src/bluez-manager/nm-bluez-device.c delete mode 100644 src/bluez-manager/nm-bluez-device.h delete mode 100644 src/bluez-manager/nm-bluez-manager.c delete mode 100644 src/bluez-manager/nm-bluez-manager.h delete mode 100644 src/bluez-manager/nm-bluez4-adapter.c delete mode 100644 src/bluez-manager/nm-bluez4-adapter.h delete mode 100644 src/bluez-manager/nm-bluez4-manager.c delete mode 100644 src/bluez-manager/nm-bluez4-manager.h delete mode 100644 src/bluez-manager/nm-bluez5-manager.c delete mode 100644 src/bluez-manager/nm-bluez5-manager.h create mode 100644 src/devices/bluetooth/Makefile.am create mode 100644 src/devices/bluetooth/nm-bluez-common.h create mode 100644 src/devices/bluetooth/nm-bluez-device.c create mode 100644 src/devices/bluetooth/nm-bluez-device.h create mode 100644 src/devices/bluetooth/nm-bluez-manager.c create mode 100644 src/devices/bluetooth/nm-bluez-manager.h create mode 100644 src/devices/bluetooth/nm-bluez4-adapter.c create mode 100644 src/devices/bluetooth/nm-bluez4-adapter.h create mode 100644 src/devices/bluetooth/nm-bluez4-manager.c create mode 100644 src/devices/bluetooth/nm-bluez4-manager.h create mode 100644 src/devices/bluetooth/nm-bluez5-manager.c create mode 100644 src/devices/bluetooth/nm-bluez5-manager.h create mode 100644 src/devices/bluetooth/nm-device-bt.c create mode 100644 src/devices/bluetooth/nm-device-bt.h delete mode 100644 src/devices/nm-device-bt.c delete mode 100644 src/devices/nm-device-bt.h diff --git a/configure.ac b/configure.ac index b428649997..79aa225fd5 100644 --- a/configure.ac +++ b/configure.ac @@ -764,6 +764,7 @@ src/rdisc/Makefile src/rdisc/tests/Makefile src/devices/atm/Makefile src/devices/wimax/Makefile +src/devices/bluetooth/Makefile libnm-util/libnm-util.pc libnm-util/Makefile libnm-util/tests/Makefile diff --git a/po/POTFILES.in b/po/POTFILES.in index 9806ceba19..fa7806f3f4 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -40,7 +40,6 @@ libnm-util/nm-setting-wireless.c libnm-util/nm-utils.c policy/org.freedesktop.NetworkManager.policy.in.in src/main.c -src/bluez-manager/nm-bluez-device.c src/dhcp-manager/nm-dhcp-dhclient.c src/dhcp-manager/nm-dhcp-dhclient-utils.c src/dhcp-manager/nm-dhcp-manager.c @@ -50,9 +49,10 @@ src/config/nm-config.c src/devices/atm/nm-device-adsl.c src/modem-manager/nm-modem-broadband.c src/modem-manager/nm-modem-old.c +src/devices/bluetooth/nm-bluez-device.c +src/devices/bluetooth/nm-device-bt.c src/devices/nm-device-bond.c src/devices/nm-device-bridge.c -src/devices/nm-device-bt.c src/devices/nm-device-ethernet.c src/devices/nm-device-infiniband.c src/devices/nm-device-olpc-mesh.c diff --git a/src/Makefile.am b/src/Makefile.am index 9ca1d68438..a50932ed20 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,6 +5,7 @@ include $(GLIB_MAKEFILE) SUBDIRS = \ . \ devices/atm \ + devices/bluetooth \ dhcp-manager \ ppp-manager \ settings/plugins @@ -52,18 +53,6 @@ NetworkManager_LDADD = libNetworkManager.la $(top_builddir)/libgsystem.la $(LIBN noinst_LTLIBRARIES = libNetworkManager.la nm_sources = \ - bluez-manager/nm-bluez-common.h \ - bluez-manager/nm-bluez-device.c \ - bluez-manager/nm-bluez-device.h \ - bluez-manager/nm-bluez-manager.c \ - bluez-manager/nm-bluez-manager.h \ - bluez-manager/nm-bluez4-adapter.c \ - bluez-manager/nm-bluez4-adapter.h \ - bluez-manager/nm-bluez4-manager.c \ - bluez-manager/nm-bluez4-manager.h \ - bluez-manager/nm-bluez5-manager.c \ - bluez-manager/nm-bluez5-manager.h \ - \ config/nm-config.c \ config/nm-config.h \ config/nm-config-device.c \ @@ -75,8 +64,6 @@ nm_sources = \ devices/nm-device-bond.h \ devices/nm-device-bridge.c \ devices/nm-device-bridge.h \ - devices/nm-device-bt.c \ - devices/nm-device-bt.h \ devices/nm-device-ethernet.c \ devices/nm-device-ethernet.h \ devices/nm-device-factory.c \ @@ -303,8 +290,8 @@ endif GLIB_GENERATED = nm-enum-types.h nm-enum-types.c GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM - nm_enum_types_sources = $(nm_sources) + if WITH_WIMAX nm_enum_types_sources += devices/wimax/nm-device-wimax.h AM_CPPFLAGS += -I$(top_srcdir)/src/devices/wimax @@ -319,7 +306,6 @@ glue_sources = \ nm-agent-manager-glue.h \ nm-device-bond-glue.h \ nm-device-bridge-glue.h \ - nm-device-bt-glue.h \ nm-device-ethernet-glue.h \ nm-device-generic-glue.h \ nm-device-glue.h \ diff --git a/src/bluez-manager/nm-bluez-common.h b/src/bluez-manager/nm-bluez-common.h deleted file mode 100644 index f80cfc2e39..0000000000 --- a/src/bluez-manager/nm-bluez-common.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- 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_BLUEZ_COMMON_H -#define NM_BLUEZ_COMMON_H - -#include - -#define BLUETOOTH_CONNECT_DUN "dun" -#define BLUETOOTH_CONNECT_NAP "nap" - -#define BLUEZ_SERVICE "org.bluez" - -#define BLUEZ_MANAGER_PATH "/" -#define OBJECT_MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager" - -#define BLUEZ5_ADAPTER_INTERFACE "org.bluez.Adapter1" -#define BLUEZ5_DEVICE_INTERFACE "org.bluez.Device1" -#define BLUEZ5_NETWORK_INTERFACE "org.bluez.Network1" - -#define BLUEZ4_MANAGER_INTERFACE "org.bluez.Manager" -#define BLUEZ4_ADAPTER_INTERFACE "org.bluez.Adapter" -#define BLUEZ4_DEVICE_INTERFACE "org.bluez.Device" -#define BLUEZ4_SERIAL_INTERFACE "org.bluez.Serial" -#define BLUEZ4_NETWORK_INTERFACE "org.bluez.Network" - -#endif /* NM_BLUEZ_COMMON_H */ - diff --git a/src/bluez-manager/nm-bluez-device.c b/src/bluez-manager/nm-bluez-device.c deleted file mode 100644 index 8e8f39d066..0000000000 --- a/src/bluez-manager/nm-bluez-device.c +++ /dev/null @@ -1,1173 +0,0 @@ -/* -*- 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 - 2012 Red Hat, Inc. - * Copyright (C) 2013 Intel Corporation. - */ - -#include -#include -#include -#include -#include -#include - -#include "NetworkManager.h" -#include "nm-setting-bluetooth.h" - -#include "nm-bluez-common.h" -#include "nm-bluez-device.h" -#include "nm-logging.h" -#include "nm-utils.h" -#include "nm-settings-connection.h" - - -G_DEFINE_TYPE (NMBluezDevice, nm_bluez_device, G_TYPE_OBJECT) - -#define NM_BLUEZ_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ_DEVICE, NMBluezDevicePrivate)) - -typedef struct { - char *path; - GDBusConnection *dbus_connection; - - GDBusProxy *proxy; - - GDBusProxy *adapter5; - gboolean adapter_powered; - - int bluez_version; - - gboolean initialized; - gboolean usable; - NMBluetoothCapabilities connection_bt_type; - - char *address; - guint8 bin_address[ETH_ALEN]; - char *name; - guint32 capabilities; - gboolean connected; - - char *bt_iface; - - NMConnectionProvider *provider; - GSList *connections; - - NMConnection *pan_connection; - NMConnection *pan_connection_original; - gboolean pan_connection_no_autocreate; -} NMBluezDevicePrivate; - - -enum { - PROP_0, - PROP_PATH, - PROP_ADDRESS, - PROP_NAME, - PROP_CAPABILITIES, - PROP_USABLE, - PROP_CONNECTED, - - LAST_PROP -}; - -/* Signals */ -enum { - INITIALIZED, - LAST_SIGNAL -}; -static guint signals[LAST_SIGNAL] = { 0 }; - - -static void cp_connection_added (NMConnectionProvider *provider, - NMConnection *connection, NMBluezDevice *self); -static gboolean connection_compatible (NMBluezDevice *self, NMConnection *connection); - - -#define VARIANT_IS_OF_TYPE_BOOLEAN(v) ((v) != NULL && ( g_variant_is_of_type ((v), G_VARIANT_TYPE_BOOLEAN) )) -#define VARIANT_IS_OF_TYPE_STRING(v) ((v) != NULL && ( g_variant_is_of_type ((v), G_VARIANT_TYPE_STRING) )) -#define VARIANT_IS_OF_TYPE_OBJECT_PATH(v) ((v) != NULL && ( g_variant_is_of_type ((v), G_VARIANT_TYPE_OBJECT_PATH) )) -#define VARIANT_IS_OF_TYPE_STRING_ARRAY(v) ((v) != NULL && ( g_variant_is_of_type ((v), G_VARIANT_TYPE_STRING_ARRAY) )) - -/***********************************************************/ - -const char * -nm_bluez_device_get_path (NMBluezDevice *self) -{ - g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), NULL); - - return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->path; -} - -const char * -nm_bluez_device_get_address (NMBluezDevice *self) -{ - g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), NULL); - - return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->address; -} - -gboolean -nm_bluez_device_get_initialized (NMBluezDevice *self) -{ - g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), FALSE); - - return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->initialized; -} - -gboolean -nm_bluez_device_get_usable (NMBluezDevice *self) -{ - g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), FALSE); - - return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->usable; -} - -const char * -nm_bluez_device_get_name (NMBluezDevice *self) -{ - g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), NULL); - - return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->name; -} - -guint32 -nm_bluez_device_get_capabilities (NMBluezDevice *self) -{ - g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), 0); - - return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->capabilities; -} - -gboolean -nm_bluez_device_get_connected (NMBluezDevice *self) -{ - g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), FALSE); - - return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->connected; -} - -static void -pan_connection_check_create (NMBluezDevice *self) -{ - NMConnection *connection; - NMConnection *added; - NMSetting *setting; - char *uuid, *id; - GByteArray *bdaddr_array; - GError *error = NULL; - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - - g_return_if_fail (priv->capabilities & NM_BT_CAPABILITY_NAP); - g_return_if_fail (priv->connections == NULL); - g_return_if_fail (priv->name); - - if (priv->pan_connection || priv->pan_connection_no_autocreate) { - /* already have a connection or we don't want to create one, nothing to do. */ - return; - } - - /* Only try once to create a connection. If it does not succeed, we do not try again. Also, - * if the connection gets deleted later, do not create another one for this device. */ - priv->pan_connection_no_autocreate = TRUE; - - /* create a new connection */ - - connection = nm_connection_new (); - - /* Setting: Connection */ - uuid = nm_utils_uuid_generate (); - id = g_strdup_printf (_("%s Network"), priv->name); - setting = nm_setting_connection_new (); - g_object_set (setting, - NM_SETTING_CONNECTION_ID, id, - NM_SETTING_CONNECTION_UUID, uuid, - NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, - NM_SETTING_CONNECTION_TYPE, NM_SETTING_BLUETOOTH_SETTING_NAME, - NULL); - nm_connection_add_setting (connection, setting); - - /* Setting: Bluetooth */ - bdaddr_array = g_byte_array_sized_new (sizeof (priv->bin_address)); - g_byte_array_append (bdaddr_array, priv->bin_address, sizeof (priv->bin_address)); - setting = nm_setting_bluetooth_new (); - g_object_set (G_OBJECT (setting), - NM_SETTING_BLUETOOTH_BDADDR, bdaddr_array, - NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU, - NULL); - nm_connection_add_setting (connection, setting); - g_byte_array_free (bdaddr_array, TRUE); - - /* Setting: IPv4 */ - setting = nm_setting_ip4_config_new (); - g_object_set (G_OBJECT (setting), - NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP4_CONFIG_MAY_FAIL, FALSE, - NULL); - nm_connection_add_setting (connection, setting); - - /* Setting: IPv6 */ - setting = nm_setting_ip6_config_new (); - g_object_set (G_OBJECT (setting), - NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, - NULL); - nm_connection_add_setting (connection, setting); - - /* Adding a new connection raises a signal which eventually calls check_emit_usable (again) - * which then already finds the suitable connection in priv->connections. This is confusing, - * so block the signal. check_emit_usable will succeed after this function call returns. */ - g_signal_handlers_block_by_func (priv->provider, cp_connection_added, self); - added = nm_connection_provider_add_connection (priv->provider, connection, FALSE, &error); - g_signal_handlers_unblock_by_func (priv->provider, cp_connection_added, self); - - if (added) { - g_assert (!g_slist_find (priv->connections, added)); - g_assert (connection_compatible (self, added)); - g_assert (nm_connection_compare (added, connection, NM_SETTING_COMPARE_FLAG_EXACT)); - - priv->connections = g_slist_prepend (priv->connections, g_object_ref (added)); - priv->pan_connection = added; - priv->pan_connection_original = connection; - nm_log_dbg (LOGD_BT, "bluez[%s] added new Bluetooth connection for NAP device: '%s' (%s)", priv->path, id, uuid); - } else { - nm_log_warn (LOGD_BT, "bluez[%s] couldn't add new Bluetooth connection for NAP device: '%s' (%s): %d / %s", - priv->path, id, uuid, error ? error->code : -1, - (error && error->message) ? error->message : "(unknown)"); - g_clear_error (&error); - - g_object_unref (connection); - } - - g_free (id); - g_free (uuid); -} - -static void -check_emit_usable (NMBluezDevice *self) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - gboolean new_usable; - - /* only expect the supported capabilities set. */ - g_assert (priv->bluez_version != 4 || ((priv->capabilities & ~(NM_BT_CAPABILITY_NAP | NM_BT_CAPABILITY_DUN)) == NM_BT_CAPABILITY_NONE )); - g_assert (priv->bluez_version != 5 || ((priv->capabilities & ~(NM_BT_CAPABILITY_NAP )) == NM_BT_CAPABILITY_NONE )); - - new_usable = (priv->initialized && priv->capabilities && priv->name && - ((priv->bluez_version == 4) || - (priv->bluez_version == 5 && priv->adapter5 && priv->adapter_powered) ) && - priv->dbus_connection && priv->address); - - if (!new_usable) - goto END; - - if (priv->connections) - goto END; - - if (!(priv->capabilities & NM_BT_CAPABILITY_NAP)) { - /* non NAP devices are only usable, if they already have a connection. */ - new_usable = FALSE; - goto END; - } - - pan_connection_check_create (self); - new_usable = !!priv->pan_connection; - -END: - if (new_usable != priv->usable) { - priv->usable = new_usable; - g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_USABLE); - } -} - -/********************************************************************/ - -static gboolean -connection_compatible (NMBluezDevice *self, NMConnection *connection) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - NMSettingBluetooth *s_bt; - const char *bt_type; - const GByteArray *bdaddr; - - if (!nm_connection_is_type (connection, NM_SETTING_BLUETOOTH_SETTING_NAME)) - return FALSE; - - s_bt = nm_connection_get_setting_bluetooth (connection); - if (!s_bt) - return FALSE; - - if (!priv->address) { - /* unless address is set, bin_address is not initialized. */ - return FALSE; - } - bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt); - if (!bdaddr || bdaddr->len != ETH_ALEN) - return FALSE; - if (memcmp (bdaddr->data, priv->bin_address, ETH_ALEN) != 0) - return FALSE; - - bt_type = nm_setting_bluetooth_get_connection_type (s_bt); - if ( g_str_equal (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN) - && !(priv->capabilities & NM_BT_CAPABILITY_DUN)) - return FALSE; - - if ( g_str_equal (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU) - && !(priv->capabilities & NM_BT_CAPABILITY_NAP)) - return FALSE; - - return TRUE; -} - -static void -_internal_add_connection (NMBluezDevice *self, NMConnection *connection) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - - if (!g_slist_find (priv->connections, connection)) { - priv->connections = g_slist_prepend (priv->connections, g_object_ref (connection)); - check_emit_usable (self); - } -} - -static void -cp_connection_added (NMConnectionProvider *provider, - NMConnection *connection, - NMBluezDevice *self) -{ - if (connection_compatible (self, connection)) - _internal_add_connection (self, connection); -} - -static void -cp_connection_removed (NMConnectionProvider *provider, - NMConnection *connection, - NMBluezDevice *self) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - - if (g_slist_find (priv->connections, connection)) { - priv->connections = g_slist_remove (priv->connections, connection); - if (priv->pan_connection == connection) { - priv->pan_connection = NULL; - g_clear_object (&priv->pan_connection_original); - } - g_object_unref (connection); - check_emit_usable (self); - } -} - -static void -cp_connection_updated (NMConnectionProvider *provider, - NMConnection *connection, - NMBluezDevice *self) -{ - if (connection_compatible (self, connection)) - _internal_add_connection (self, connection); - else - cp_connection_removed (provider, connection, self); -} - -static void -load_connections (NMBluezDevice *self) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - const GSList *connections, *iter; - - connections = nm_connection_provider_get_connections (priv->provider); - for (iter = connections; iter; iter = g_slist_next (iter)) - cp_connection_added (priv->provider, NM_CONNECTION (iter->data), self); -} - -/***********************************************************/ - -static void -bluez_disconnect_cb (GDBusConnection *dbus_connection, - GAsyncResult *res, - gpointer user_data) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (user_data); - GError *error = NULL; - GVariant *variant; - - variant = g_dbus_connection_call_finish (dbus_connection, res, &error); - if (!variant) { - nm_log_warn (LOGD_BT, "bluez[%s]: failed to disconnect: %s", priv->path, error->message); - g_error_free (error); - } else - g_variant_unref (variant); -} - -void -nm_bluez_device_disconnect (NMBluezDevice *self) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - GVariant *args = NULL; - const char *dbus_iface; - - g_return_if_fail (priv->dbus_connection); - - if (priv->bluez_version == 5) { - g_return_if_fail (priv->connection_bt_type == NM_BT_CAPABILITY_NAP); - dbus_iface = BLUEZ5_NETWORK_INTERFACE; - } else if (priv->bluez_version == 4 && priv->connection_bt_type == NM_BT_CAPABILITY_DUN) { - /* Can't pass a NULL interface name through dbus to bluez, so just - * ignore the disconnect if the interface isn't known. - */ - if (!priv->bt_iface) - return; - - args = g_variant_new ("(s)", priv->bt_iface), - dbus_iface = BLUEZ4_SERIAL_INTERFACE; - } else { - g_return_if_fail (priv->bluez_version == 4 && priv->connection_bt_type == NM_BT_CAPABILITY_NAP); - dbus_iface = BLUEZ4_NETWORK_INTERFACE; - } - - g_dbus_connection_call (priv->dbus_connection, - BLUEZ_SERVICE, - priv->path, - dbus_iface, - "Disconnect", - args ? args : g_variant_new ("()"), - NULL, - G_DBUS_CALL_FLAGS_NONE, - 10000, - NULL, - (GAsyncReadyCallback) bluez_disconnect_cb, - self); - - priv->connection_bt_type = NM_BT_CAPABILITY_NONE; -} - -static void -bluez_connect_cb (GDBusConnection *dbus_connection, - GAsyncResult *res, - gpointer user_data) -{ - GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); - GObject *result_object = g_async_result_get_source_object (G_ASYNC_RESULT (result)); - NMBluezDevice *self = NM_BLUEZ_DEVICE (result_object); - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - GError *error = NULL; - char *device; - GVariant *variant; - - variant = g_dbus_connection_call_finish (dbus_connection, res, &error); - - if (!variant) { - g_simple_async_result_take_error (result, error); - } else { - g_variant_get (variant, "(s)", &device); - - g_simple_async_result_set_op_res_gpointer (result, - g_strdup (device), - g_free); - priv->bt_iface = device; - g_variant_unref (variant); - } - - g_simple_async_result_complete (result); - g_object_unref (result); - g_object_unref (result_object); -} - -void -nm_bluez_device_connect_async (NMBluezDevice *self, - NMBluetoothCapabilities connection_bt_type, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - const char *dbus_iface; - const char *connect_type = BLUETOOTH_CONNECT_NAP; - - g_return_if_fail (priv->capabilities & connection_bt_type & (NM_BT_CAPABILITY_DUN | NM_BT_CAPABILITY_NAP)); - - if (priv->bluez_version == 5) { - g_return_if_fail (connection_bt_type == NM_BT_CAPABILITY_NAP); - dbus_iface = BLUEZ5_NETWORK_INTERFACE; - } else if (priv->bluez_version == 4 && connection_bt_type == NM_BT_CAPABILITY_DUN) { - dbus_iface = BLUEZ4_SERIAL_INTERFACE; - connect_type = BLUETOOTH_CONNECT_DUN; - } else { - g_return_if_fail (priv->bluez_version == 4 && connection_bt_type == NM_BT_CAPABILITY_NAP); - dbus_iface = BLUEZ4_NETWORK_INTERFACE; - } - - simple = g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - nm_bluez_device_connect_async); - - g_dbus_connection_call (priv->dbus_connection, - BLUEZ_SERVICE, - priv->path, - dbus_iface, - "Connect", - g_variant_new ("(s)", connect_type), - NULL, - G_DBUS_CALL_FLAGS_NONE, - 20000, - NULL, - (GAsyncReadyCallback) bluez_connect_cb, - simple); - - priv->connection_bt_type = connection_bt_type; -} - -const char * -nm_bluez_device_connect_finish (NMBluezDevice *self, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - const char *device; - - g_return_val_if_fail (g_simple_async_result_is_valid (result, - G_OBJECT (self), - nm_bluez_device_connect_async), - NULL); - - simple = (GSimpleAsyncResult *) result; - - if (g_simple_async_result_propagate_error (simple, error)) - return NULL; - - device = (const char *) g_simple_async_result_get_op_res_gpointer (simple); - return device; -} - -/***********************************************************/ - -static guint32 -convert_uuids_to_capabilities (const char **strings, int bluez_version) -{ - const char **iter; - guint32 capabilities = 0; - - for (iter = strings; iter && *iter; iter++) { - char **parts; - - parts = g_strsplit (*iter, "-", -1); - if (parts && parts[0]) { - switch (g_ascii_strtoull (parts[0], NULL, 16)) { - case 0x1103: - if (bluez_version == 4) - capabilities |= NM_BT_CAPABILITY_DUN; - break; - case 0x1116: - capabilities |= NM_BT_CAPABILITY_NAP; - break; - default: - break; - } - } - g_strfreev (parts); - } - - return capabilities; -} - -static void -_set_property_capabilities (NMBluezDevice *self, const char **uuids) -{ - guint32 uint_val; - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - - uint_val = convert_uuids_to_capabilities (uuids, priv->bluez_version); - if (priv->capabilities != uint_val) { - if (priv->capabilities) { - /* changing (relevant) capabilities is not supported and ignored -- except setting initially */ - nm_log_warn (LOGD_BT, "bluez[%s] ignore change of capabilities for Bluetooth device from %u to %u", - priv->path, priv->capabilities, uint_val); - return; - } - nm_log_dbg (LOGD_BT, "bluez[%s] set capabilities for Bluetooth device: %s%s%s", priv->path, - uint_val & NM_BT_CAPABILITY_NAP ? "NAP" : "", - ((uint_val & NM_BT_CAPABILITY_DUN) && (uint_val &NM_BT_CAPABILITY_NAP)) ? " | " : "", - uint_val & NM_BT_CAPABILITY_DUN ? "DUN" : ""); - priv->capabilities = uint_val; - g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_CAPABILITIES); - } -} - -/** - * priv->address can only be set one to a certain (non NULL) value. Every later attempt - * to reset it to another value will be ignored and a warning will be logged. - * - * When setting the address for the first time, we also set bin_address. - **/ -static void -_set_property_address (NMBluezDevice *self, const char *addr) -{ - struct ether_addr *tmp; - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - - if (g_strcmp0 (priv->address, addr) == 0) - return; - - if (!addr) { - nm_log_warn (LOGD_BT, "bluez[%s] cannot reset address from '%s' to NULL", priv->path, priv->address); - return; - } - - if (priv->address != NULL) { - nm_log_warn (LOGD_BT, "bluez[%s] cannot reset address from '%s' to '%s'", priv->path, priv->address, addr); - return; - } - - tmp = ether_aton (addr); - if (!tmp) { - if (priv->address) - nm_log_warn (LOGD_BT, "bluez[%s] cannot reset address from '%s' to '%s' (invalid value)", priv->path, priv->address, addr); - else - nm_log_warn (LOGD_BT, "bluez[%s] cannot reset address from NULL to '%s' (invalid value)", priv->path, addr); - return; - } - memcpy (priv->bin_address, tmp->ether_addr_octet, ETH_ALEN); - priv->address = g_strdup (addr); - g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_ADDRESS); -} - -static void -_take_variant_property_address (NMBluezDevice *self, GVariant *v) -{ - _set_property_address (self, VARIANT_IS_OF_TYPE_STRING (v) ? g_variant_get_string (v, NULL) : NULL); - if (v) - g_variant_unref (v); -} - -static void -_take_variant_property_name (NMBluezDevice *self, GVariant *v) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - const char *str; - - if (VARIANT_IS_OF_TYPE_STRING (v)) { - str = g_variant_get_string (v, NULL); - if (g_strcmp0 (priv->name, str)) { - g_free (priv->name); - priv->name = g_strdup (str); - g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_NAME); - } - } - if (v) - g_variant_unref (v); -} - -static void -_take_variant_property_uuids (NMBluezDevice *self, GVariant *v) -{ - if (VARIANT_IS_OF_TYPE_STRING_ARRAY (v)) { - const char **uuids = g_variant_get_strv (v, NULL); - - _set_property_capabilities (self, uuids); - g_free (uuids); - } - if (v) - g_variant_unref (v); -} - -static void -_take_variant_property_connected (NMBluezDevice *self, GVariant *v) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - - if (VARIANT_IS_OF_TYPE_BOOLEAN (v)) { - gboolean connected = g_variant_get_boolean (v); - - if (priv->connected != connected) { - priv->connected = connected; - g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_CONNECTED); - } - } - if (v) - g_variant_unref (v); -} - - -static void -adapter5_on_properties_changed (GDBusProxy *proxy, - GVariant *changed_properties, - GStrv invalidated_properties, - gpointer user_data) -{ - NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data); - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - GVariantIter i; - const char *property; - GVariant *v; - - g_variant_iter_init (&i, changed_properties); - while (g_variant_iter_next (&i, "{&sv}", &property, &v)) { - if (!strcmp (property, "Powered") && VARIANT_IS_OF_TYPE_BOOLEAN (v)) { - gboolean powered = g_variant_get_boolean (v); - if (priv->adapter_powered != powered) - priv->adapter_powered = powered; - } - g_variant_unref (v); - } - - check_emit_usable (self); -} - -static void -adapter5_on_acquired (GObject *object, GAsyncResult *res, NMBluezDevice *self) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - GError *error; - GVariant *v; - - priv->adapter5 = g_dbus_proxy_new_for_bus_finish (res, &error); - if (!priv->adapter5) { - nm_log_warn (LOGD_BT, "bluez[%s] failed to acquire adapter proxy: %s.", priv->path, error->message); - g_clear_error (&error); - g_signal_emit (self, signals[INITIALIZED], 0, FALSE); - } else { - g_signal_connect (priv->adapter5, "g-properties-changed", - G_CALLBACK (adapter5_on_properties_changed), self); - - /* Check adapter's powered state */ - v = g_dbus_proxy_get_cached_property (priv->adapter5, "Powered"); - priv->adapter_powered = VARIANT_IS_OF_TYPE_BOOLEAN (v) ? g_variant_get_boolean (v) : FALSE; - if (v) - g_variant_unref (v); - - priv->initialized = TRUE; - g_signal_emit (self, signals[INITIALIZED], 0, TRUE); - - check_emit_usable (self); - } - - g_object_unref (self); -} - -static void -_set_properties (NMBluezDevice *self, GVariant *properties) -{ - GVariantIter i; - const char *property; - GVariant *v; - - g_object_freeze_notify (G_OBJECT (self)); - g_variant_iter_init (&i, properties); - while (g_variant_iter_next (&i, "{&sv}", &property, &v)) { - if (!property) { - g_variant_unref (v); - } else if (!strcmp (property, "Address")) { - _take_variant_property_address (self, v); - } else if (!strcmp (property, "Connected")) { - _take_variant_property_connected (self, v); - } else if (!strcmp (property, "Name")) { - _take_variant_property_name (self, v); - } else if (!strcmp (property, "UUIDs")) { - _take_variant_property_uuids (self, v); - } else - g_variant_unref (v); - } - g_object_thaw_notify (G_OBJECT (self)); -} - -static void -properties_changed (GDBusProxy *proxy, - GVariant *changed_properties, - GStrv invalidated_properties, - gpointer user_data) -{ - NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data); - - _set_properties (self, changed_properties); - - check_emit_usable (self); -} - - -static void -get_properties_cb_4 (GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data); - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - GError *err = NULL; - GVariant *v_properties, *v_dict; - GVariantType *v_type; - - v_properties = g_dbus_proxy_call_finish (priv->proxy, res, &err); - if (!v_properties) { - nm_log_warn (LOGD_BT, "bluez[%s] error getting device properties: %s", - priv->path, err && err->message ? err->message : "(unknown)"); - g_error_free (err); - g_signal_emit (self, signals[INITIALIZED], 0, FALSE); - goto END; - } - - v_type = g_variant_type_new ("(a{sv})"); - if (g_variant_is_of_type (v_properties, v_type)) { - v_dict = g_variant_get_child_value (v_properties, 0); - _set_properties (self, v_dict); - g_variant_unref (v_dict); - } else { - nm_log_warn (LOGD_BT, "bluez[%s] GetProperties returns unexpected result of type %s", priv->path, g_variant_get_type_string (v_properties)); - } - g_variant_type_free (v_type); - - g_variant_unref (v_properties); - - /* Check if any connections match this device */ - load_connections (self); - - priv->initialized = TRUE; - g_signal_emit (self, signals[INITIALIZED], 0, TRUE); - - - check_emit_usable (self); - -END: - g_object_unref (self); -} - - -static void -query_properties (NMBluezDevice *self) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - GVariant *v; - - switch (priv->bluez_version) { - case 4: - g_dbus_proxy_call (priv->proxy, "GetProperties", NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START, 3000, - NULL, get_properties_cb_4, g_object_ref (self)); - break; - case 5: - g_object_freeze_notify (G_OBJECT (self)); - _take_variant_property_address (self, g_dbus_proxy_get_cached_property (priv->proxy, "Address")); - _take_variant_property_connected (self, g_dbus_proxy_get_cached_property (priv->proxy, "Connected")); - _take_variant_property_name (self, g_dbus_proxy_get_cached_property (priv->proxy, "Name")); - _take_variant_property_uuids (self, g_dbus_proxy_get_cached_property (priv->proxy, "UUIDs")); - g_object_thaw_notify (G_OBJECT (self)); - - v = g_dbus_proxy_get_cached_property (priv->proxy, "Adapter"); - if (VARIANT_IS_OF_TYPE_OBJECT_PATH (v)) { - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - BLUEZ_SERVICE, - g_variant_get_string (v, NULL), - BLUEZ5_ADAPTER_INTERFACE, - NULL, - (GAsyncReadyCallback) adapter5_on_acquired, - g_object_ref (self)); - g_variant_unref (v); - } else { - /* If the Adapter property is unset at this point, we won't try to acquire the adapter later on - * and the device stays unusable. This should not happen, but if it does, log a debug message. */ - nm_log_dbg (LOGD_BT, "bluez[%s] device has no adapter property and cannot be used.", priv->path); - } - - /* Check if any connections match this device */ - load_connections (self); - - break; - } -} - -static void -on_proxy_acquired (GObject *object, GAsyncResult *res, NMBluezDevice *self) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - GError *error = NULL; - - priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error); - - if (!priv->proxy) { - nm_log_warn (LOGD_BT, "bluez[%s] failed to acquire device proxy: %s.", priv->path, error->message); - g_clear_error (&error); - g_signal_emit (self, signals[INITIALIZED], 0, FALSE); - } else { - g_signal_connect (priv->proxy, "g-properties-changed", - G_CALLBACK (properties_changed), self); - - query_properties (self); - } - g_object_unref (self); -} - -static void -on_bus_acquired (GObject *object, GAsyncResult *res, NMBluezDevice *self) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - GError *error = NULL; - - priv->dbus_connection = g_bus_get_finish (res, &error); - - if (!priv->dbus_connection) { - nm_log_warn (LOGD_BT, "bluez[%s] failed to acquire bus connection: %s.", priv->path, error->message); - g_clear_error (&error); - g_signal_emit (self, signals[INITIALIZED], 0, FALSE); - } else - check_emit_usable (self); - - g_object_unref (self); -} - -/********************************************************************/ - -NMBluezDevice * -nm_bluez_device_new (const char *path, NMConnectionProvider *provider, int bluez_version) -{ - NMBluezDevice *self; - NMBluezDevicePrivate *priv; - const char *interface_name = NULL; - - g_return_val_if_fail (path != NULL, NULL); - g_return_val_if_fail (provider != NULL, NULL); - g_return_val_if_fail (bluez_version == 4 || bluez_version == 5, NULL); - - self = (NMBluezDevice *) g_object_new (NM_TYPE_BLUEZ_DEVICE, - NM_BLUEZ_DEVICE_PATH, path, - NULL); - if (!self) - return NULL; - - nm_log_dbg (LOGD_BT, "bluez[%s] create NMBluezDevice", path); - - priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - - priv->bluez_version = bluez_version; - - priv->provider = provider; - - g_signal_connect (priv->provider, - NM_CP_SIGNAL_CONNECTION_ADDED, - G_CALLBACK (cp_connection_added), - self); - - g_signal_connect (priv->provider, - NM_CP_SIGNAL_CONNECTION_REMOVED, - G_CALLBACK (cp_connection_removed), - self); - - g_signal_connect (priv->provider, - NM_CP_SIGNAL_CONNECTION_UPDATED, - G_CALLBACK (cp_connection_updated), - self); - - g_bus_get (G_BUS_TYPE_SYSTEM, - NULL, - (GAsyncReadyCallback) on_bus_acquired, - g_object_ref (self)); - - switch (priv->bluez_version) { - case 4: - interface_name = BLUEZ4_DEVICE_INTERFACE; - break; - case 5: - interface_name = BLUEZ5_DEVICE_INTERFACE; - break; - } - - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - BLUEZ_SERVICE, - priv->path, - interface_name, - NULL, - (GAsyncReadyCallback) on_proxy_acquired, - g_object_ref (self)); - return self; -} - -static void -nm_bluez_device_init (NMBluezDevice *self) -{ -} - -static void -dispose (GObject *object) -{ - NMBluezDevice *self = NM_BLUEZ_DEVICE (object); - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - NMConnection *to_delete = NULL; - - if (priv->pan_connection) { - /* Check whether we want to remove the created connection. If so, we take a reference - * and delete it at the end of dispose(). */ - if ( nm_settings_connection_get_unsaved (NM_SETTINGS_CONNECTION (priv->pan_connection)) - && nm_connection_compare (priv->pan_connection, priv->pan_connection_original, NM_SETTING_COMPARE_FLAG_EXACT)) - to_delete = g_object_ref (priv->pan_connection); - - priv->pan_connection = NULL; - g_clear_object (&priv->pan_connection_original); - } - - g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_added, self); - g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_removed, self); - g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_updated, self); - - g_slist_free_full (priv->connections, g_object_unref); - priv->connections = NULL; - - g_clear_object (&priv->adapter5); - g_clear_object (&priv->dbus_connection); - - G_OBJECT_CLASS (nm_bluez_device_parent_class)->dispose (object); - - if (to_delete) { - nm_log_dbg (LOGD_BT, "bluez[%s] removing Bluetooth connection for NAP device: '%s' (%s)", priv->path, - nm_connection_get_id (to_delete), nm_connection_get_uuid (to_delete)); - nm_settings_connection_delete (NM_SETTINGS_CONNECTION (to_delete), NULL, NULL); - g_object_unref (to_delete); - } -} - -static void -finalize (GObject *object) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (object); - - nm_log_dbg (LOGD_BT, "bluez[%s]: finalize NMBluezDevice", priv->path); - - g_free (priv->path); - g_free (priv->address); - g_free (priv->name); - g_free (priv->bt_iface); - - g_clear_object (&priv->proxy); - - G_OBJECT_CLASS (nm_bluez_device_parent_class)->finalize (object); -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_PATH: - g_value_set_string (value, priv->path); - break; - case PROP_ADDRESS: - g_value_set_string (value, priv->address); - break; - case PROP_NAME: - g_value_set_string (value, priv->name); - break; - case PROP_CAPABILITIES: - g_value_set_uint (value, priv->capabilities); - break; - case PROP_USABLE: - g_value_set_boolean (value, priv->usable); - break; - case PROP_CONNECTED: - g_value_set_boolean (value, priv->connected); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_PATH: - /* construct only */ - priv->path = g_value_dup_string (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -nm_bluez_device_class_init (NMBluezDeviceClass *config_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (config_class); - - g_type_class_add_private (config_class, sizeof (NMBluezDevicePrivate)); - - /* virtual methods */ - object_class->get_property = get_property; - object_class->set_property = set_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - /* Properties */ - g_object_class_install_property - (object_class, PROP_PATH, - g_param_spec_string (NM_BLUEZ_DEVICE_PATH, - "DBus Path", - "DBus Path", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property - (object_class, PROP_ADDRESS, - g_param_spec_string (NM_BLUEZ_DEVICE_ADDRESS, - "Address", - "Address", - NULL, - G_PARAM_READABLE)); - - g_object_class_install_property - (object_class, PROP_NAME, - g_param_spec_string (NM_BLUEZ_DEVICE_NAME, - "Name", - "Name", - NULL, - G_PARAM_READABLE)); - - g_object_class_install_property - (object_class, PROP_CAPABILITIES, - g_param_spec_uint (NM_BLUEZ_DEVICE_CAPABILITIES, - "Capabilities", - "Capabilities", - 0, G_MAXUINT, 0, - G_PARAM_READABLE)); - - g_object_class_install_property - (object_class, PROP_USABLE, - g_param_spec_boolean (NM_BLUEZ_DEVICE_USABLE, - "Usable", - "Usable", - FALSE, - G_PARAM_READABLE)); - - g_object_class_install_property - (object_class, PROP_CONNECTED, - g_param_spec_boolean (NM_BLUEZ_DEVICE_CONNECTED, - "Connected", - "Connected", - FALSE, - G_PARAM_READABLE)); - - /* Signals */ - signals[INITIALIZED] = g_signal_new ("initialized", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMBluezDeviceClass, initialized), - NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_BOOLEAN); -} - diff --git a/src/bluez-manager/nm-bluez-device.h b/src/bluez-manager/nm-bluez-device.h deleted file mode 100644 index 5e586ea5bb..0000000000 --- a/src/bluez-manager/nm-bluez-device.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- 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 - 2012 Red Hat, Inc. - */ - -#ifndef NM_BLUEZ_DEVICE_H -#define NM_BLUEZ_DEVICE_H - -#include -#include -#include - -#include -#include "nm-connection.h" -#include "nm-connection-provider.h" - -#define NM_TYPE_BLUEZ_DEVICE (nm_bluez_device_get_type ()) -#define NM_BLUEZ_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ_DEVICE, NMBluezDevice)) -#define NM_BLUEZ_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ_DEVICE, NMBluezDeviceClass)) -#define NM_IS_BLUEZ_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ_DEVICE)) -#define NM_IS_BLUEZ_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_BLUEZ_DEVICE)) -#define NM_BLUEZ_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ_DEVICE, NMBluezDeviceClass)) - -#define NM_BLUEZ_DEVICE_PATH "path" -#define NM_BLUEZ_DEVICE_ADDRESS "address" -#define NM_BLUEZ_DEVICE_NAME "name" -#define NM_BLUEZ_DEVICE_CAPABILITIES "capabilities" -#define NM_BLUEZ_DEVICE_USABLE "usable" -#define NM_BLUEZ_DEVICE_CONNECTED "connected" - -typedef struct { - GObject parent; -} NMBluezDevice; - -typedef struct { - GObjectClass parent; - - /* virtual functions */ - void (*initialized) (NMBluezDevice *self, gboolean success); - - void (*invalid) (NMBluezDevice *self); -} NMBluezDeviceClass; - -GType nm_bluez_device_get_type (void); - -NMBluezDevice *nm_bluez_device_new (const char *path, NMConnectionProvider *provider, int bluez_version); - -const char *nm_bluez_device_get_path (NMBluezDevice *self); - -gboolean nm_bluez_device_get_initialized (NMBluezDevice *self); - -gboolean nm_bluez_device_get_usable (NMBluezDevice *self); - -const char *nm_bluez_device_get_address (NMBluezDevice *self); - -const char *nm_bluez_device_get_name (NMBluezDevice *self); - -guint32 nm_bluez_device_get_class (NMBluezDevice *self); - -guint32 nm_bluez_device_get_capabilities (NMBluezDevice *self); - -gboolean nm_bluez_device_get_connected (NMBluezDevice *self); - -void -nm_bluez_device_connect_async (NMBluezDevice *self, - NMBluetoothCapabilities connection_bt_type, - GAsyncReadyCallback callback, - gpointer user_data); - -const char * -nm_bluez_device_connect_finish (NMBluezDevice *self, - GAsyncResult *result, - GError **error); - -void -nm_bluez_device_disconnect (NMBluezDevice *self); - -#endif /* NM_BLUEZ_DEVICE_H */ - diff --git a/src/bluez-manager/nm-bluez-manager.c b/src/bluez-manager/nm-bluez-manager.c deleted file mode 100644 index b3026bc1f5..0000000000 --- a/src/bluez-manager/nm-bluez-manager.c +++ /dev/null @@ -1,514 +0,0 @@ -/* -*- 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) 2013 Red Hat, Inc. - */ - -#include -#include -#include -#include - -#include "nm-logging.h" -#include "nm-bluez-manager.h" -#include "nm-bluez4-manager.h" -#include "nm-bluez5-manager.h" -#include "nm-bluez-device.h" -#include "nm-bluez-common.h" - -#include "nm-dbus-manager.h" - -typedef struct { - int bluez_version; - - NMConnectionProvider *provider; - NMBluez4Manager *manager4; - NMBluez5Manager *manager5; - - guint watch_name_id; - - GDBusProxy *introspect_proxy; - GCancellable *async_cancellable; -} NMBluezManagerPrivate; - -#define NM_BLUEZ_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerPrivate)) - -G_DEFINE_TYPE (NMBluezManager, nm_bluez_manager, G_TYPE_OBJECT) - -enum { - PROP_0, - PROP_PROVIDER, - - LAST_PROP -}; - -enum { - BDADDR_ADDED, - BDADDR_REMOVED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - - -static void check_bluez_and_try_setup (NMBluezManager *self); - - -struct AsyncData { - NMBluezManager *self; - GCancellable *async_cancellable; -}; - -static struct AsyncData * -async_data_pack (NMBluezManager *self) -{ - struct AsyncData *data = g_new (struct AsyncData, 1); - - data->self = self; - data->async_cancellable = g_object_ref (NM_BLUEZ_MANAGER_GET_PRIVATE (self)->async_cancellable); - return data; -} - -static NMBluezManager * -async_data_unpack (struct AsyncData *async_data) -{ - NMBluezManager *self = g_cancellable_is_cancelled (async_data->async_cancellable) - ? NULL : async_data->self; - - g_object_unref (async_data->async_cancellable); - g_free (async_data); - return self; -} - - -/** - * Cancel any current attempt to detect the version and cleanup - * the related fields. - **/ -static void -cleanup_checking (NMBluezManager *self, gboolean do_unwatch_name) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); - - if (priv->async_cancellable) { - g_cancellable_cancel (priv->async_cancellable); - g_clear_object (&priv->async_cancellable); - } - - g_clear_object (&priv->introspect_proxy); - - if (do_unwatch_name && priv->watch_name_id) { - g_bus_unwatch_name (priv->watch_name_id); - priv->watch_name_id = 0; - } -} - - -static void -manager_bdaddr_added_cb (NMBluez4Manager *bluez_mgr, - NMBluezDevice *bt_device, - const char *bdaddr, - const char *name, - const char *object_path, - guint32 uuids, - gpointer user_data) -{ - /* forward the signal... */ - g_signal_emit (NM_BLUEZ_MANAGER (user_data), signals[BDADDR_ADDED], 0, - bt_device, - bdaddr, - name, - object_path, - uuids); -} - -static void -manager_bdaddr_removed_cb (NMBluez4Manager *bluez_mgr, - const char *bdaddr, - const char *object_path, - gpointer user_data) -{ - /* forward the signal... */ - g_signal_emit (NM_BLUEZ_MANAGER (user_data), signals[BDADDR_REMOVED], 0, - bdaddr, - object_path); -} - - -static void -setup_version_number (NMBluezManager *self, int bluez_version) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); - - g_return_if_fail (!priv->bluez_version); - - nm_log_info (LOGD_BT, "use BlueZ version %d", bluez_version); - - priv->bluez_version = bluez_version; - - /* Just detected the version. Cleanup the ongoing checking/detection. */ - cleanup_checking (self, TRUE); -} - -static void -setup_bluez4 (NMBluezManager *self) -{ - NMBluez4Manager *manager; - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); - - g_return_if_fail (!priv->manager4 && !priv->manager5 && !priv->bluez_version); - - setup_version_number (self, 4); - priv->manager4 = manager = nm_bluez4_manager_new (priv->provider); - - g_signal_connect (manager, - NM_BLUEZ_MANAGER_BDADDR_ADDED, - G_CALLBACK (manager_bdaddr_added_cb), - self); - g_signal_connect (manager, - NM_BLUEZ_MANAGER_BDADDR_REMOVED, - G_CALLBACK (manager_bdaddr_removed_cb), - self); - - nm_bluez4_manager_query_devices (manager); -} - -static void -setup_bluez5 (NMBluezManager *self) -{ - NMBluez5Manager *manager; - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); - - g_return_if_fail (!priv->manager4 && !priv->manager5 && !priv->bluez_version); - - setup_version_number (self, 5); - priv->manager5 = manager = nm_bluez5_manager_new (priv->provider); - - g_signal_connect (manager, - NM_BLUEZ_MANAGER_BDADDR_ADDED, - G_CALLBACK (manager_bdaddr_added_cb), - self); - g_signal_connect (manager, - NM_BLUEZ_MANAGER_BDADDR_REMOVED, - G_CALLBACK (manager_bdaddr_removed_cb), - self); - - nm_bluez5_manager_query_devices (manager); -} - - -static void -watch_name_on_appeared (GDBusConnection *connection, - const gchar *name, - const gchar *name_owner, - gpointer user_data) -{ - check_bluez_and_try_setup (NM_BLUEZ_MANAGER (user_data)); -} - - -static void -check_bluez_and_try_setup_final_step (NMBluezManager *self, int bluez_version, const char *reason) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); - - g_return_if_fail (!priv->bluez_version); - - switch (bluez_version) { - case 4: - setup_bluez4 (self); - break; - case 5: - setup_bluez5 (self); - break; - default: - nm_log_dbg (LOGD_BT, "detecting BlueZ version failed: %s", reason); - - /* cancel current attempts to detect the version. */ - cleanup_checking (self, FALSE); - if (!priv->watch_name_id) { - priv->watch_name_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM, - BLUEZ_SERVICE, - G_BUS_NAME_WATCHER_FLAGS_NONE, - watch_name_on_appeared, - NULL, - self, - NULL); - } - break; - } -} - -static void -check_bluez_and_try_setup_do_introspect (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - NMBluezManager *self = async_data_unpack (user_data); - NMBluezManagerPrivate *priv; - GError *error = NULL; - GVariant *result; - const char *xml_data; - int bluez_version = 0; - const char *reason = NULL; - - if (!self) - return; - - priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); - - g_return_if_fail (priv->introspect_proxy); - g_return_if_fail (!g_cancellable_is_cancelled (priv->async_cancellable)); - g_return_if_fail (!priv->bluez_version); - - g_clear_object (&priv->async_cancellable); - - result = g_dbus_proxy_call_finish (priv->introspect_proxy, res, &error); - - if (!result) { - char *reason2 = g_strdup_printf ("introspect failed with %s", error->message); - check_bluez_and_try_setup_final_step (self, 0, reason2); - g_error_free (error); - g_free (reason2); - return; - } - - g_variant_get (result, "(&s)", &xml_data); - - /* might not be the best approach to detect the version, but it's good enough in practice. */ - if (strstr (xml_data, "org.freedesktop.DBus.ObjectManager")) - bluez_version = 5; - else if (strstr (xml_data, BLUEZ4_MANAGER_INTERFACE)) - bluez_version = 4; - else - reason = "unexpected introspect result"; - - g_variant_unref (result); - - check_bluez_and_try_setup_final_step (self, bluez_version, reason); -} - -static void -check_bluez_and_try_setup_on_new_proxy (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - NMBluezManager *self = async_data_unpack (user_data); - NMBluezManagerPrivate *priv; - GError *error = NULL; - - if (!self) - return; - - priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); - - g_return_if_fail (!priv->introspect_proxy); - g_return_if_fail (!g_cancellable_is_cancelled (priv->async_cancellable)); - g_return_if_fail (!priv->bluez_version); - - priv->introspect_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); - - if (!priv->introspect_proxy) { - char *reason = g_strdup_printf ("bluez error creating dbus proxy: %s", error->message); - check_bluez_and_try_setup_final_step (self, 0, reason); - g_error_free (error); - g_free (reason); - return; - } - - g_dbus_proxy_call (priv->introspect_proxy, - "Introspect", - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - 3000, - priv->async_cancellable, - check_bluez_and_try_setup_do_introspect, - async_data_pack (self)); -} - -static void -check_bluez_and_try_setup (NMBluezManager *self) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); - - g_return_if_fail (!priv->bluez_version); - - /* there should be no ongoing detection. Anyway, cleanup_checking. */ - cleanup_checking (self, FALSE); - - priv->async_cancellable = g_cancellable_new (); - - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - BLUEZ_SERVICE, - "/", - DBUS_INTERFACE_INTROSPECTABLE, - priv->async_cancellable, - check_bluez_and_try_setup_on_new_proxy, - async_data_pack (self)); -} - - -void -nm_bluez_manager_query_devices (NMBluezManager *self) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); - - switch (priv->bluez_version) { - case 4: - nm_bluez4_manager_query_devices (priv->manager4); - break; - case 5: - nm_bluez5_manager_query_devices (priv->manager5); - break; - default: - /* the proxy implementation does nothing in this case. */ - break; - } -} - - -NMBluezManager * -nm_bluez_manager_new (NMConnectionProvider *provider) -{ - g_return_val_if_fail (NM_IS_CONNECTION_PROVIDER (provider), NULL); - - return g_object_new (NM_TYPE_BLUEZ_MANAGER, - NM_BLUEZ_MANAGER_PROVIDER, - provider, - NULL); -} - - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_PROVIDER: - /* Construct only */ - priv->provider = g_value_dup_object (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_PROVIDER: - g_value_set_object (value, priv->provider); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static void -dispose (GObject *object) -{ - NMBluezManager *self = NM_BLUEZ_MANAGER (object); - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); - - g_clear_object (&priv->provider); - - if (priv->manager4) { - g_signal_handlers_disconnect_by_func (priv->manager4, G_CALLBACK (manager_bdaddr_added_cb), self); - g_signal_handlers_disconnect_by_func (priv->manager4, G_CALLBACK (manager_bdaddr_removed_cb), self); - g_clear_object (&priv->manager4); - } - if (priv->manager5) { - g_signal_handlers_disconnect_by_func (priv->manager5, G_CALLBACK (manager_bdaddr_added_cb), self); - g_signal_handlers_disconnect_by_func (priv->manager5, G_CALLBACK (manager_bdaddr_removed_cb), self); - g_clear_object (&priv->manager5); - } - - cleanup_checking (self, TRUE); - - priv->bluez_version = 0; -} - -static void -constructed (GObject *object) -{ - NMBluezManager *self = NM_BLUEZ_MANAGER (object); - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); - - G_OBJECT_CLASS (nm_bluez_manager_parent_class)->constructed (object); - - g_return_if_fail (priv->provider); - - check_bluez_and_try_setup (self); -} - -static void -nm_bluez_manager_init (NMBluezManager *self) -{ -} - -static void -nm_bluez_manager_class_init (NMBluezManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (NMBluezManagerPrivate)); - - /* virtual methods */ - object_class->dispose = dispose; - object_class->get_property = get_property; - object_class->set_property = set_property; - object_class->constructed = constructed; - - g_object_class_install_property - (object_class, PROP_PROVIDER, - g_param_spec_object (NM_BLUEZ_MANAGER_PROVIDER, - "Provider", - "Connection Provider", - NM_TYPE_CONNECTION_PROVIDER, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - /* Signals */ - signals[BDADDR_ADDED] = - g_signal_new (NM_BLUEZ_MANAGER_BDADDR_ADDED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMBluezManagerClass, bdaddr_added), - NULL, NULL, NULL, - G_TYPE_NONE, 5, G_TYPE_OBJECT, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT); - - signals[BDADDR_REMOVED] = - g_signal_new (NM_BLUEZ_MANAGER_BDADDR_REMOVED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMBluezManagerClass, bdaddr_removed), - NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); -} - diff --git a/src/bluez-manager/nm-bluez-manager.h b/src/bluez-manager/nm-bluez-manager.h deleted file mode 100644 index 836416fa8c..0000000000 --- a/src/bluez-manager/nm-bluez-manager.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- 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) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2013 Red Hat, Inc. - */ - -#ifndef NM_BLUEZ_MANAGER_H -#define NM_BLUEZ_MANAGER_H - -#include -#include - -#include -#include "nm-connection-provider.h" - -G_BEGIN_DECLS - -#define NM_TYPE_BLUEZ_MANAGER (nm_bluez_manager_get_type ()) -#define NM_BLUEZ_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ_MANAGER, NMBluezManager)) -#define NM_BLUEZ_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerClass)) -#define NM_IS_BLUEZ_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ_MANAGER)) -#define NM_IS_BLUEZ_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_BLUEZ_MANAGER)) -#define NM_BLUEZ_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerClass)) - -#define NM_BLUEZ_MANAGER_BDADDR_ADDED "bdaddr-added" -#define NM_BLUEZ_MANAGER_BDADDR_REMOVED "bdaddr-removed" - -#define NM_BLUEZ_MANAGER_PROVIDER "provider" - -typedef struct { - GObject parent; -} NMBluezManager; - -typedef struct { - GObjectClass parent; - - /* Virtual functions */ - void (*bdaddr_added) (NMBluezManager *manager, - const char *bdaddr, - const char *name, - const char *object_path, - guint uuids); - - void (*bdaddr_removed) (NMBluezManager *manager, - const char *bdaddr, - const char *object_path); -} NMBluezManagerClass; - -GType nm_bluez_manager_get_type (void); - -NMBluezManager *nm_bluez_manager_new (NMConnectionProvider *provider); - -void nm_bluez_manager_query_devices (NMBluezManager *manager); - -#endif /* NM_BLUEZ_MANAGER_H */ - diff --git a/src/bluez-manager/nm-bluez4-adapter.c b/src/bluez-manager/nm-bluez4-adapter.c deleted file mode 100644 index ad1786f02a..0000000000 --- a/src/bluez-manager/nm-bluez4-adapter.c +++ /dev/null @@ -1,413 +0,0 @@ -/* -*- 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 - 2012 Red Hat, Inc. - */ - -#include -#include - -#include "NetworkManager.h" -#include "nm-dbus-manager.h" -#include "nm-bluez4-adapter.h" -#include "nm-bluez-device.h" -#include "nm-bluez-common.h" -#include "nm-dbus-glib-types.h" -#include "nm-logging.h" - - -G_DEFINE_TYPE (NMBluez4Adapter, nm_bluez4_adapter, G_TYPE_OBJECT) - -#define NM_BLUEZ4_ADAPTER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ4_ADAPTER, NMBluez4AdapterPrivate)) - -typedef struct { - char *path; - DBusGProxy *proxy; - gboolean initialized; - - char *address; - GHashTable *devices; - - /* Cached for devices */ - NMConnectionProvider *provider; -} NMBluez4AdapterPrivate; - - -enum { - PROP_0, - PROP_PATH, - PROP_ADDRESS, - - LAST_PROP -}; - -/* Signals */ -enum { - INITIALIZED, - DEVICE_ADDED, - DEVICE_REMOVED, - LAST_SIGNAL -}; -static guint signals[LAST_SIGNAL] = { 0 }; - -static void device_do_remove (NMBluez4Adapter *self, NMBluezDevice *device); - -const char * -nm_bluez4_adapter_get_path (NMBluez4Adapter *self) -{ - g_return_val_if_fail (NM_IS_BLUEZ4_ADAPTER (self), NULL); - - return NM_BLUEZ4_ADAPTER_GET_PRIVATE (self)->path; -} - -const char * -nm_bluez4_adapter_get_address (NMBluez4Adapter *self) -{ - g_return_val_if_fail (NM_IS_BLUEZ4_ADAPTER (self), NULL); - - return NM_BLUEZ4_ADAPTER_GET_PRIVATE (self)->address; -} - -gboolean -nm_bluez4_adapter_get_initialized (NMBluez4Adapter *self) -{ - g_return_val_if_fail (NM_IS_BLUEZ4_ADAPTER (self), FALSE); - - return NM_BLUEZ4_ADAPTER_GET_PRIVATE (self)->initialized; -} - -GSList * -nm_bluez4_adapter_get_devices (NMBluez4Adapter *self) -{ - GSList *devices = NULL; - GHashTableIter iter; - NMBluezDevice *device; - - g_hash_table_iter_init (&iter, NM_BLUEZ4_ADAPTER_GET_PRIVATE (self)->devices); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) { - if (nm_bluez_device_get_usable (device)) - devices = g_slist_append (devices, device); - } - return devices; -} - -static void -emit_device_removed (NMBluez4Adapter *self, NMBluezDevice *device) -{ - nm_log_dbg (LOGD_BT, "(%s): bluez device now unusable", - nm_bluez_device_get_path (device)); - g_signal_emit (self, signals[DEVICE_REMOVED], 0, device); -} - -static void -device_usable (NMBluezDevice *device, GParamSpec *pspec, gpointer user_data) -{ - NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); - - if (nm_bluez_device_get_usable (device)) { - nm_log_dbg (LOGD_BT, "(%s): bluez device now usable (device address is %s)", - nm_bluez_device_get_path (device), - nm_bluez_device_get_address (device)); - g_signal_emit (self, signals[DEVICE_ADDED], 0, device); - } else - emit_device_removed (self, device); -} - -static void -device_initialized (NMBluezDevice *device, gboolean success, gpointer user_data) -{ - NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); - - nm_log_dbg (LOGD_BT, "(%s): bluez device %s", - nm_bluez_device_get_path (device), - success ? "initialized" : "failed to initialize"); - if (!success) - device_do_remove (self, device); -} - -static void -device_do_remove (NMBluez4Adapter *self, NMBluezDevice *device) -{ - NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); - - if (g_hash_table_remove (priv->devices, nm_bluez_device_get_path (device))) { - g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_initialized), self); - g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_usable), self); - - if (nm_bluez_device_get_usable (device)) - emit_device_removed (self, device); - - g_object_unref (device); - } -} - -static void -device_created (DBusGProxy *proxy, const char *path, gpointer user_data) -{ - NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); - NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); - NMBluezDevice *device; - - device = nm_bluez_device_new (path, priv->provider, 4); - g_signal_connect (device, "initialized", G_CALLBACK (device_initialized), self); - g_signal_connect (device, "notify::usable", G_CALLBACK (device_usable), self); - g_hash_table_insert (priv->devices, (gpointer) nm_bluez_device_get_path (device), device); - - nm_log_dbg (LOGD_BT, "(%s): new bluez device found", path); -} - -static void -device_removed (DBusGProxy *proxy, const char *path, gpointer user_data) -{ - NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); - NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); - NMBluezDevice *device; - - nm_log_dbg (LOGD_BT, "(%s): bluez device removed", path); - - device = g_hash_table_lookup (priv->devices, path); - if (device) - device_do_remove (self, device); -} - - -static void -get_properties_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) -{ - NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); - NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); - GHashTable *properties = NULL; - GError *err = NULL; - GValue *value; - GPtrArray *devices; - int i; - - if (!dbus_g_proxy_end_call (proxy, call, &err, - DBUS_TYPE_G_MAP_OF_VARIANT, &properties, - G_TYPE_INVALID)) { - nm_log_warn (LOGD_BT, "bluez error getting adapter properties: %s", - err && err->message ? err->message : "(unknown)"); - g_error_free (err); - goto done; - } - - value = g_hash_table_lookup (properties, "Address"); - priv->address = value ? g_value_dup_string (value) : NULL; - - value = g_hash_table_lookup (properties, "Devices"); - devices = value ? g_value_get_boxed (value) : NULL; - - for (i = 0; devices && i < devices->len; i++) - device_created (priv->proxy, g_ptr_array_index (devices, i), self); - - g_hash_table_unref (properties); - - priv->initialized = TRUE; - -done: - g_signal_emit (self, signals[INITIALIZED], 0, priv->initialized); -} - -static void -query_properties (NMBluez4Adapter *self) -{ - NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); - DBusGProxyCall *call; - - call = dbus_g_proxy_begin_call (priv->proxy, "GetProperties", - get_properties_cb, - self, - NULL, G_TYPE_INVALID); - if (!call) { - nm_log_warn (LOGD_BT, "failed to request Bluetooth adapter properties for %s.", - priv->path); - } -} - -/***********************************************************/ - -NMBluez4Adapter * -nm_bluez4_adapter_new (const char *path, NMConnectionProvider *provider) -{ - NMBluez4Adapter *self; - NMBluez4AdapterPrivate *priv; - DBusGConnection *connection; - - self = (NMBluez4Adapter *) g_object_new (NM_TYPE_BLUEZ4_ADAPTER, - NM_BLUEZ4_ADAPTER_PATH, path, - NULL); - if (!self) - return NULL; - - priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); - - priv->provider = provider; - - connection = nm_dbus_manager_get_connection (nm_dbus_manager_get ()); - - priv->proxy = dbus_g_proxy_new_for_name (connection, - BLUEZ_SERVICE, - priv->path, - BLUEZ4_ADAPTER_INTERFACE); - - dbus_g_proxy_add_signal (priv->proxy, "DeviceCreated", - DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "DeviceCreated", - G_CALLBACK (device_created), self, NULL); - - dbus_g_proxy_add_signal (priv->proxy, "DeviceRemoved", - DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "DeviceRemoved", - G_CALLBACK (device_removed), self, NULL); - - query_properties (self); - return self; -} - -static void -nm_bluez4_adapter_init (NMBluez4Adapter *self) -{ - NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); - - priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, NULL); -} - -static gboolean -_find_all (gpointer key, gpointer value, gpointer user_data) -{ - return TRUE; -} - -static void -dispose (GObject *object) -{ - NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (object); - NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); - NMBluezDevice *device; - - while ((device = g_hash_table_find (priv->devices, _find_all, NULL))) - device_do_remove (self, device); - - G_OBJECT_CLASS (nm_bluez4_adapter_parent_class)->dispose (object); -} - -static void -finalize (GObject *object) -{ - NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (object); - - g_hash_table_destroy (priv->devices); - g_free (priv->address); - g_free (priv->path); - g_object_unref (priv->proxy); - - G_OBJECT_CLASS (nm_bluez4_adapter_parent_class)->finalize (object); -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_PATH: - g_value_set_string (value, priv->path); - break; - case PROP_ADDRESS: - g_value_set_string (value, priv->address); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_PATH: - /* construct only */ - priv->path = g_value_dup_string (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -nm_bluez4_adapter_class_init (NMBluez4AdapterClass *config_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (config_class); - - g_type_class_add_private (config_class, sizeof (NMBluez4AdapterPrivate)); - - /* virtual methods */ - object_class->get_property = get_property; - object_class->set_property = set_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - /* Properties */ - g_object_class_install_property - (object_class, PROP_PATH, - g_param_spec_string (NM_BLUEZ4_ADAPTER_PATH, - "DBus Path", - "DBus Path", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property - (object_class, PROP_ADDRESS, - g_param_spec_string (NM_BLUEZ4_ADAPTER_ADDRESS, - "Address", - "Address", - NULL, - G_PARAM_READABLE)); - - /* Signals */ - signals[INITIALIZED] = g_signal_new ("initialized", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMBluez4AdapterClass, initialized), - NULL, NULL, - g_cclosure_marshal_VOID__BOOLEAN, - G_TYPE_NONE, 1, G_TYPE_BOOLEAN); - - signals[DEVICE_ADDED] = g_signal_new ("device-added", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMBluez4AdapterClass, device_added), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - signals[DEVICE_REMOVED] = g_signal_new ("device-removed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMBluez4AdapterClass, device_removed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); -} - diff --git a/src/bluez-manager/nm-bluez4-adapter.h b/src/bluez-manager/nm-bluez4-adapter.h deleted file mode 100644 index 454ca557eb..0000000000 --- a/src/bluez-manager/nm-bluez4-adapter.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- 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 - 2012 Red Hat, Inc. - */ - -#ifndef NM_BLUEZ4_ADAPTER_H -#define NM_BLUEZ4_ADAPTER_H - -#include -#include - -#include "nm-bluez-device.h" -#include "nm-connection-provider.h" - -#define NM_TYPE_BLUEZ4_ADAPTER (nm_bluez4_adapter_get_type ()) -#define NM_BLUEZ4_ADAPTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ4_ADAPTER, NMBluez4Adapter)) -#define NM_BLUEZ4_ADAPTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ4_ADAPTER, NMBluez4AdapterClass)) -#define NM_IS_BLUEZ4_ADAPTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ4_ADAPTER)) -#define NM_IS_BLUEZ4_ADAPTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_BLUEZ4_ADAPTER)) -#define NM_BLUEZ4_ADAPTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ4_ADAPTER, NMBluez4AdapterClass)) - -#define NM_BLUEZ4_ADAPTER_PATH "path" -#define NM_BLUEZ4_ADAPTER_ADDRESS "address" - -typedef struct { - GObject parent; -} NMBluez4Adapter; - -typedef struct { - GObjectClass parent; - - /* virtual functions */ - void (*initialized) (NMBluez4Adapter *self, gboolean success); - - void (*device_added) (NMBluez4Adapter *self, NMBluezDevice *device); - - void (*device_removed) (NMBluez4Adapter *self, NMBluezDevice *device); -} NMBluez4AdapterClass; - -GType nm_bluez4_adapter_get_type (void); - -NMBluez4Adapter *nm_bluez4_adapter_new (const char *path, - NMConnectionProvider *provider); - -const char *nm_bluez4_adapter_get_path (NMBluez4Adapter *self); - -const char *nm_bluez4_adapter_get_address (NMBluez4Adapter *self); - -gboolean nm_bluez4_adapter_get_initialized (NMBluez4Adapter *self); - -GSList *nm_bluez4_adapter_get_devices (NMBluez4Adapter *self); - -#endif /* NM_BLUEZ4_ADAPTER_H */ - diff --git a/src/bluez-manager/nm-bluez4-manager.c b/src/bluez-manager/nm-bluez4-manager.c deleted file mode 100644 index 58162f0a81..0000000000 --- a/src/bluez-manager/nm-bluez4-manager.c +++ /dev/null @@ -1,379 +0,0 @@ -/* -*- 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) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2013 Red Hat, Inc. - */ - -#include -#include -#include -#include - -#include "nm-logging.h" -#include "nm-dbus-glib-types.h" -#include "nm-bluez-manager.h" -#include "nm-bluez4-manager.h" -#include "nm-bluez4-adapter.h" -#include "nm-dbus-manager.h" -#include "nm-bluez-common.h" - - -typedef struct { - NMDBusManager *dbus_mgr; - gulong name_owner_changed_id; - - NMConnectionProvider *provider; - - DBusGProxy *proxy; - - NMBluez4Adapter *adapter; -} NMBluez4ManagerPrivate; - -#define NM_BLUEZ4_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ4_MANAGER, NMBluez4ManagerPrivate)) - -G_DEFINE_TYPE (NMBluez4Manager, nm_bluez4_manager, G_TYPE_OBJECT) - -enum { - BDADDR_ADDED, - BDADDR_REMOVED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static void - -emit_bdaddr_added (NMBluez4Manager *self, NMBluezDevice *device) -{ - g_signal_emit (self, signals[BDADDR_ADDED], 0, - device, - nm_bluez_device_get_address (device), - nm_bluez_device_get_name (device), - nm_bluez_device_get_path (device), - nm_bluez_device_get_capabilities (device)); -} - -void -nm_bluez4_manager_query_devices (NMBluez4Manager *self) -{ - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - GSList *devices, *iter; - - if (!priv->adapter) - return; - - devices = nm_bluez4_adapter_get_devices (priv->adapter); - for (iter = devices; iter; iter = g_slist_next (iter)) - emit_bdaddr_added (self, NM_BLUEZ_DEVICE (iter->data)); - g_slist_free (devices); -} - -static void -device_added (NMBluez4Adapter *adapter, NMBluezDevice *device, gpointer user_data) -{ - emit_bdaddr_added (NM_BLUEZ4_MANAGER (user_data), device); -} - -static void -device_removed (NMBluez4Adapter *adapter, NMBluezDevice *device, gpointer user_data) -{ - NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data); - - g_signal_emit (self, signals[BDADDR_REMOVED], 0, - nm_bluez_device_get_address (device), - nm_bluez_device_get_path (device)); -} - -static void -adapter_initialized (NMBluez4Adapter *adapter, gboolean success, gpointer user_data) -{ - NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data); - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - - if (success) { - GSList *devices, *iter; - - devices = nm_bluez4_adapter_get_devices (adapter); - for (iter = devices; iter; iter = g_slist_next (iter)) - emit_bdaddr_added (self, NM_BLUEZ_DEVICE (iter->data)); - g_slist_free (devices); - - g_signal_connect (adapter, "device-added", G_CALLBACK (device_added), self); - g_signal_connect (adapter, "device-removed", G_CALLBACK (device_removed), self); - } else { - g_object_unref (priv->adapter); - priv->adapter = NULL; - } -} - -static void -adapter_removed (DBusGProxy *proxy, const char *path, NMBluez4Manager *self) -{ - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - - if (priv->adapter && !strcmp (path, nm_bluez4_adapter_get_path (priv->adapter))) { - if (nm_bluez4_adapter_get_initialized (priv->adapter)) { - GSList *devices, *iter; - - devices = nm_bluez4_adapter_get_devices (priv->adapter); - for (iter = devices; iter; iter = g_slist_next (iter)) { - NMBluezDevice *device = NM_BLUEZ_DEVICE (iter->data); - - g_signal_emit (self, signals[BDADDR_REMOVED], 0, - nm_bluez_device_get_address (device), - nm_bluez_device_get_path (device)); - } - g_slist_free (devices); - } - - g_object_unref (priv->adapter); - priv->adapter = NULL; - } -} - -static void -default_adapter_changed (DBusGProxy *proxy, const char *path, NMBluez4Manager *self) -{ - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - const char *cur_path = NULL; - - if (priv->adapter) - cur_path = nm_bluez4_adapter_get_path (priv->adapter); - - if (cur_path) { - if (!path || strcmp (path, cur_path)) { - /* Default adapter changed */ - adapter_removed (priv->proxy, cur_path, self); - } else { - /* This adapter is already the default */ - return; - } - } - - /* Add the new default adapter */ - if (path) { - priv->adapter = nm_bluez4_adapter_new (path, priv->provider); - g_signal_connect (priv->adapter, "initialized", G_CALLBACK (adapter_initialized), self); - } -} - -static void -default_adapter_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) -{ - NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data); - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - const char *default_adapter = NULL; - GError *err = NULL; - - if (!dbus_g_proxy_end_call (proxy, call, &err, - DBUS_TYPE_G_OBJECT_PATH, &default_adapter, - G_TYPE_INVALID)) { - /* Ignore "No such adapter" errors; just means bluetooth isn't active */ - if ( !dbus_g_error_has_name (err, "org.bluez.Error.NoSuchAdapter") - && !dbus_g_error_has_name (err, "org.freedesktop.systemd1.LoadFailed") - && !g_error_matches (err, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN)) { - nm_log_warn (LOGD_BT, "bluez error getting default adapter: %s", - err && err->message ? err->message : "(unknown)"); - } - g_error_free (err); - return; - } - - default_adapter_changed (priv->proxy, default_adapter, self); -} - -static void -query_default_adapter (NMBluez4Manager *self) -{ - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - DBusGProxyCall *call; - - call = dbus_g_proxy_begin_call (priv->proxy, "DefaultAdapter", - default_adapter_cb, - self, - NULL, G_TYPE_INVALID); - if (!call) - nm_log_warn (LOGD_BT, "failed to request default Bluetooth adapter."); -} - -static void -bluez_connect (NMBluez4Manager *self) -{ - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - DBusGConnection *connection; - - g_return_if_fail (priv->proxy == NULL); - - connection = nm_dbus_manager_get_connection (priv->dbus_mgr); - if (!connection) - return; - - priv->proxy = dbus_g_proxy_new_for_name (connection, - BLUEZ_SERVICE, - BLUEZ_MANAGER_PATH, - BLUEZ4_MANAGER_INTERFACE); - - dbus_g_proxy_add_signal (priv->proxy, "AdapterRemoved", - DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "AdapterRemoved", - G_CALLBACK (adapter_removed), self, NULL); - - dbus_g_proxy_add_signal (priv->proxy, "DefaultAdapterChanged", - DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "DefaultAdapterChanged", - G_CALLBACK (default_adapter_changed), self, NULL); - - query_default_adapter (self); -} - -static void -name_owner_changed_cb (NMDBusManager *dbus_mgr, - const char *name, - const char *old_owner, - const char *new_owner, - gpointer user_data) -{ - NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data); - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - gboolean old_owner_good = (old_owner && strlen (old_owner)); - gboolean new_owner_good = (new_owner && strlen (new_owner)); - - /* Can't handle the signal if its not from the Bluez */ - if (strcmp (BLUEZ_SERVICE, name)) - return; - - if (!old_owner_good && new_owner_good) - query_default_adapter (self); - else if (old_owner_good && !new_owner_good) { - /* Throwing away the adapter removes all devices too */ - if (priv->adapter) { - g_object_unref (priv->adapter); - priv->adapter = NULL; - } - } -} - -static void -bluez_cleanup (NMBluez4Manager *self, gboolean do_signal) -{ - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - - if (priv->proxy) { - g_object_unref (priv->proxy); - priv->proxy = NULL; - } - - if (priv->adapter) { - g_object_unref (priv->adapter); - priv->adapter = NULL; - } -} - -static void -dbus_connection_changed_cb (NMDBusManager *dbus_mgr, - DBusGConnection *connection, - gpointer user_data) -{ - NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data); - - if (!connection) - bluez_cleanup (self, TRUE); - else - bluez_connect (self); -} - -/****************************************************************/ - -NMBluez4Manager * -nm_bluez4_manager_new (NMConnectionProvider *provider) -{ - NMBluez4Manager *instance; - - instance = g_object_new (NM_TYPE_BLUEZ4_MANAGER, NULL); - NM_BLUEZ4_MANAGER_GET_PRIVATE (instance)->provider = provider; - return instance; -} - -static void -nm_bluez4_manager_init (NMBluez4Manager *self) -{ - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - - priv->dbus_mgr = nm_dbus_manager_get (); - g_assert (priv->dbus_mgr); - - g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_NAME_OWNER_CHANGED, - G_CALLBACK (name_owner_changed_cb), - self); - - g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED, - G_CALLBACK (dbus_connection_changed_cb), - self); - - bluez_connect (self); -} - -static void -dispose (GObject *object) -{ - NMBluez4Manager *self = NM_BLUEZ4_MANAGER (object); - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - - bluez_cleanup (self, FALSE); - - if (priv->dbus_mgr) { - g_signal_handlers_disconnect_by_func (priv->dbus_mgr, name_owner_changed_cb, self); - g_signal_handlers_disconnect_by_func (priv->dbus_mgr, dbus_connection_changed_cb, self); - priv->dbus_mgr = NULL; - } - - G_OBJECT_CLASS (nm_bluez4_manager_parent_class)->dispose (object); -} - -static void -nm_bluez4_manager_class_init (NMBluez4ManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (NMBluez4ManagerPrivate)); - - /* virtual methods */ - object_class->dispose = dispose; - - /* Signals */ - signals[BDADDR_ADDED] = - g_signal_new (NM_BLUEZ_MANAGER_BDADDR_ADDED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMBluez4ManagerClass, bdaddr_added), - NULL, NULL, NULL, - G_TYPE_NONE, 5, G_TYPE_OBJECT, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT); - - signals[BDADDR_REMOVED] = - g_signal_new (NM_BLUEZ_MANAGER_BDADDR_REMOVED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMBluez4ManagerClass, bdaddr_removed), - NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); -} - diff --git a/src/bluez-manager/nm-bluez4-manager.h b/src/bluez-manager/nm-bluez4-manager.h deleted file mode 100644 index 20e6c1bc18..0000000000 --- a/src/bluez-manager/nm-bluez4-manager.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- 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) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2013 Red Hat, Inc. - */ - -#ifndef NM_BLUEZ4_MANAGER_H -#define NM_BLUEZ4_MANAGER_H - -#include -#include - -#include -#include "nm-connection-provider.h" - -G_BEGIN_DECLS - -#define NM_TYPE_BLUEZ4_MANAGER (nm_bluez4_manager_get_type ()) -#define NM_BLUEZ4_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ4_MANAGER, NMBluez4Manager)) -#define NM_BLUEZ4_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ4_MANAGER, NMBluez4ManagerClass)) -#define NM_IS_BLUEZ4_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ4_MANAGER)) -#define NM_IS_BLUEZ4_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_BLUEZ4_MANAGER)) -#define NM_BLUEZ4_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ4_MANAGER, NMBluez4ManagerClass)) - -typedef struct { - GObject parent; -} NMBluez4Manager; - -typedef struct { - GObjectClass parent; - - /* Virtual functions */ - void (*bdaddr_added) (NMBluez4Manager *manager, - const char *bdaddr, - const char *name, - const char *object_path, - guint uuids); - - void (*bdaddr_removed) (NMBluez4Manager *manager, - const char *bdaddr, - const char *object_path); -} NMBluez4ManagerClass; - -GType nm_bluez4_manager_get_type (void); - -NMBluez4Manager *nm_bluez4_manager_new (NMConnectionProvider *provider); - -void nm_bluez4_manager_query_devices (NMBluez4Manager *manager); - -#endif /* NM_BLUEZ4_MANAGER_H */ - diff --git a/src/bluez-manager/nm-bluez5-manager.c b/src/bluez-manager/nm-bluez5-manager.c deleted file mode 100644 index 77e5bdd4ba..0000000000 --- a/src/bluez-manager/nm-bluez5-manager.c +++ /dev/null @@ -1,436 +0,0 @@ -/* -*- 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) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2013 Red Hat, Inc. - * Copyright (C) 2013 Intel Corporation. - */ - -#include -#include -#include -#include - -#include "nm-logging.h" -#include "nm-bluez-manager.h" -#include "nm-bluez5-manager.h" -#include "nm-bluez-device.h" -#include "nm-bluez-common.h" - -#include "nm-dbus-manager.h" - -typedef struct { - NMDBusManager *dbus_mgr; - gulong name_owner_changed_id; - - NMConnectionProvider *provider; - - GDBusProxy *proxy; - - GHashTable *devices; -} NMBluez5ManagerPrivate; - -#define NM_BLUEZ5_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ5_MANAGER, NMBluez5ManagerPrivate)) - -G_DEFINE_TYPE (NMBluez5Manager, nm_bluez5_manager, G_TYPE_OBJECT) - -enum { - BDADDR_ADDED, - BDADDR_REMOVED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static void device_initialized (NMBluezDevice *device, gboolean success, NMBluez5Manager *self); -static void device_usable (NMBluezDevice *device, GParamSpec *pspec, NMBluez5Manager *self); - -static void -emit_bdaddr_added (NMBluez5Manager *self, NMBluezDevice *device) -{ - g_signal_emit (self, signals[BDADDR_ADDED], 0, - device, - nm_bluez_device_get_address (device), - nm_bluez_device_get_name (device), - nm_bluez_device_get_path (device), - nm_bluez_device_get_capabilities (device)); -} - -void -nm_bluez5_manager_query_devices (NMBluez5Manager *self) -{ - NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); - NMBluezDevice *device; - GHashTableIter iter; - - g_hash_table_iter_init (&iter, priv->devices); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) { - if (nm_bluez_device_get_usable (device)) - emit_bdaddr_added (self, device); - } -} - -static void -remove_device (NMBluez5Manager *self, NMBluezDevice *device) -{ - if (nm_bluez_device_get_usable (device)) { - g_signal_emit (self, signals[BDADDR_REMOVED], 0, - nm_bluez_device_get_address (device), - nm_bluez_device_get_path (device)); - } - g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_initialized), self); - g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_usable), self); -} - -static void -remove_all_devices (NMBluez5Manager *self) -{ - GHashTableIter iter; - NMBluezDevice *device; - NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); - - g_hash_table_iter_init (&iter, priv->devices); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) { - g_hash_table_iter_steal (&iter); - remove_device (self, device); - g_object_unref (device); - } -} - -static void -device_usable (NMBluezDevice *device, GParamSpec *pspec, NMBluez5Manager *self) -{ - gboolean usable = nm_bluez_device_get_usable (device); - - nm_log_dbg (LOGD_BT, "(%s): bluez device now %s", - nm_bluez_device_get_path (device), - usable ? "usable" : "unusable"); - - if (usable) { - nm_log_dbg (LOGD_BT, "(%s): bluez device address %s", - nm_bluez_device_get_path (device), - nm_bluez_device_get_address (device)); - emit_bdaddr_added (self, device); - } else - g_signal_emit (self, signals[BDADDR_REMOVED], 0, - nm_bluez_device_get_address (device), - nm_bluez_device_get_path (device)); -} - -static void -device_initialized (NMBluezDevice *device, gboolean success, NMBluez5Manager *self) -{ - NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); - - nm_log_dbg (LOGD_BT, "(%s): bluez device %s", - nm_bluez_device_get_path (device), - success ? "initialized" : "failed to initialize"); - if (!success) - g_hash_table_remove (priv->devices, nm_bluez_device_get_path (device)); -} - -static void -device_added (GDBusProxy *proxy, const gchar *path, NMBluez5Manager *self) -{ - NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); - NMBluezDevice *device; - - device = nm_bluez_device_new (path, priv->provider, 5); - g_signal_connect (device, "initialized", G_CALLBACK (device_initialized), self); - g_signal_connect (device, "notify::usable", G_CALLBACK (device_usable), self); - g_hash_table_insert (priv->devices, (gpointer) nm_bluez_device_get_path (device), device); - - nm_log_dbg (LOGD_BT, "(%s): new bluez device found", path); -} - -static void -device_removed (GDBusProxy *proxy, const gchar *path, NMBluez5Manager *self) -{ - NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); - NMBluezDevice *device; - - nm_log_dbg (LOGD_BT, "(%s): bluez device removed", path); - - device = g_hash_table_lookup (priv->devices, path); - if (device) { - g_hash_table_steal (priv->devices, nm_bluez_device_get_path (device)); - remove_device (NM_BLUEZ5_MANAGER (self), device); - g_object_unref (device); - } -} - -static void -object_manager_g_signal (GDBusProxy *proxy, - gchar *sender_name, - gchar *signal_name, - GVariant *parameters, - NMBluez5Manager *self) -{ - GVariant *variant; - const gchar *path; - - if (!strcmp (signal_name, "InterfacesRemoved")) { - const gchar **ifaces; - gsize i, length; - - g_variant_get (parameters, "(&o*)", &path, &variant); - - ifaces = g_variant_get_strv (variant, &length); - - for (i = 0; i < length; i++) { - if (!strcmp (ifaces[i], BLUEZ5_DEVICE_INTERFACE)) { - device_removed (proxy, path, self); - break; - } - } - - g_free (ifaces); - - } else if (!strcmp (signal_name, "InterfacesAdded")) { - g_variant_get (parameters, "(&o*)", &path, &variant); - - if (g_variant_lookup_value (variant, BLUEZ5_DEVICE_INTERFACE, - G_VARIANT_TYPE_DICTIONARY)) - device_added (proxy, path, self); - } -} - -static void -get_managed_objects_cb (GDBusProxy *proxy, - GAsyncResult *res, - NMBluez5Manager *self) -{ - GVariant *variant, *ifaces; - GVariantIter i; - GError *error = NULL; - const char *path; - - variant = g_dbus_proxy_call_finish (proxy, res, &error); - - if (!variant) { - if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) - nm_log_warn (LOGD_BT, "Couldn't get managed objects: not running Bluez5?"); - else { - nm_log_warn (LOGD_BT, "Couldn't get managed objects: %s", - error && error->message ? error->message : "(unknown)"); - } - g_clear_error (&error); - return; - } - g_variant_iter_init (&i, g_variant_get_child_value (variant, 0)); - while ((g_variant_iter_next (&i, "{&o*}", &path, &ifaces))) { - if (g_variant_lookup_value (ifaces, BLUEZ5_DEVICE_INTERFACE, - G_VARIANT_TYPE_DICTIONARY)) { - device_added (proxy, path, self); - } - } - - g_variant_unref (variant); -} - -static void -on_proxy_acquired (GObject *object, - GAsyncResult *res, - NMBluez5Manager *self) -{ - NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); - GError *error = NULL; - - priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error); - - if (!priv->proxy) { - nm_log_warn (LOGD_BT, "Couldn't acquire object manager proxy: %s", - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - return; - } - - /* Get already managed devices. */ - g_dbus_proxy_call (priv->proxy, "GetManagedObjects", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - (GAsyncReadyCallback) get_managed_objects_cb, - self); - - g_signal_connect (priv->proxy, "g-signal", - G_CALLBACK (object_manager_g_signal), self); -} - -static void -bluez_connect (NMBluez5Manager *self) -{ - NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); - - g_return_if_fail (priv->proxy == NULL); - - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - BLUEZ_SERVICE, - BLUEZ_MANAGER_PATH, - OBJECT_MANAGER_INTERFACE, - NULL, - (GAsyncReadyCallback) on_proxy_acquired, - self); -} - -static void -name_owner_changed_cb (NMDBusManager *dbus_mgr, - const char *name, - const char *old_owner, - const char *new_owner, - gpointer user_data) -{ - NMBluez5Manager *self = NM_BLUEZ5_MANAGER (user_data); - NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); - gboolean old_owner_good = (old_owner && strlen (old_owner)); - gboolean new_owner_good = (new_owner && strlen (new_owner)); - - /* Can't handle the signal if its not from the Bluez */ - if (strcmp (BLUEZ_SERVICE, name)) - return; - - if (old_owner_good && !new_owner_good) { - if (priv->devices) - remove_all_devices (self); - } -} - -static void -bluez_cleanup (NMBluez5Manager *self, gboolean do_signal) -{ - NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); - - if (priv->proxy) { - g_object_unref (priv->proxy); - priv->proxy = NULL; - } - - if (do_signal) - remove_all_devices (self); - else - g_hash_table_remove_all (priv->devices); -} - -static void -dbus_connection_changed_cb (NMDBusManager *dbus_mgr, - DBusGConnection *connection, - gpointer user_data) -{ - NMBluez5Manager *self = NM_BLUEZ5_MANAGER (user_data); - - if (!connection) - bluez_cleanup (self, TRUE); - else - bluez_connect (self); -} - -/****************************************************************/ - -NMBluez5Manager * -nm_bluez5_manager_new (NMConnectionProvider *provider) -{ - NMBluez5Manager *instance = NULL; - - instance = g_object_new (NM_TYPE_BLUEZ5_MANAGER, NULL); - NM_BLUEZ5_MANAGER_GET_PRIVATE (instance)->provider = provider; - return instance; -} - -static void -nm_bluez5_manager_init (NMBluez5Manager *self) -{ - NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); - - priv->dbus_mgr = nm_dbus_manager_get (); - g_assert (priv->dbus_mgr); - - g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_NAME_OWNER_CHANGED, - G_CALLBACK (name_owner_changed_cb), - self); - - g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED, - G_CALLBACK (dbus_connection_changed_cb), - self); - - bluez_connect (self); - - priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, g_object_unref); -} - -static void -dispose (GObject *object) -{ - NMBluez5Manager *self = NM_BLUEZ5_MANAGER (object); - NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); - - bluez_cleanup (self, FALSE); - - if (priv->dbus_mgr) { - g_signal_handlers_disconnect_by_func (priv->dbus_mgr, name_owner_changed_cb, self); - g_signal_handlers_disconnect_by_func (priv->dbus_mgr, dbus_connection_changed_cb, self); - priv->dbus_mgr = NULL; - } - - G_OBJECT_CLASS (nm_bluez5_manager_parent_class)->dispose (object); -} - -static void -finalize (GObject *object) -{ - NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (object); - - g_hash_table_destroy (priv->devices); - - G_OBJECT_CLASS (nm_bluez5_manager_parent_class)->finalize (object); -} - -static void -nm_bluez5_manager_class_init (NMBluez5ManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (NMBluez5ManagerPrivate)); - - /* virtual methods */ - object_class->dispose = dispose; - object_class->finalize = finalize; - - /* Signals */ - signals[BDADDR_ADDED] = - g_signal_new (NM_BLUEZ_MANAGER_BDADDR_ADDED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMBluez5ManagerClass, bdaddr_added), - NULL, NULL, NULL, - G_TYPE_NONE, 5, G_TYPE_OBJECT, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT); - - signals[BDADDR_REMOVED] = - g_signal_new (NM_BLUEZ_MANAGER_BDADDR_REMOVED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMBluez5ManagerClass, bdaddr_removed), - NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); -} diff --git a/src/bluez-manager/nm-bluez5-manager.h b/src/bluez-manager/nm-bluez5-manager.h deleted file mode 100644 index 9cef5fd344..0000000000 --- a/src/bluez-manager/nm-bluez5-manager.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ -/* 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) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2013 Red Hat, Inc. - */ - -#ifndef NM_BLUEZ5_MANAGER_H -#define NM_BLUEZ5_MANAGER_H - -#include -#include - -#include -#include "nm-connection-provider.h" - -G_BEGIN_DECLS - -#define NM_TYPE_BLUEZ5_MANAGER (nm_bluez5_manager_get_type ()) -#define NM_BLUEZ5_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ5_MANAGER, NMBluez5Manager)) -#define NM_BLUEZ5_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ5_MANAGER, NMBluez5ManagerClass)) -#define NM_IS_BLUEZ5_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ5_MANAGER)) -#define NM_IS_BLUEZ5_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_BLUEZ5_MANAGER)) -#define NM_BLUEZ5_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ5_MANAGER, NMBluez5ManagerClass)) - -typedef struct { - GObject parent; -} NMBluez5Manager; - -typedef struct { - GObjectClass parent; - - /* Virtual functions */ - void (*bdaddr_added) (NMBluez5Manager *manager, - const char *bdaddr, - const char *name, - const char *object_path, - guint uuids); - - void (*bdaddr_removed) (NMBluez5Manager *manager, - const char *bdaddr, - const char *object_path); -} NMBluez5ManagerClass; - -GType nm_bluez5_manager_get_type (void); - -NMBluez5Manager *nm_bluez5_manager_new (NMConnectionProvider *provider); - -void nm_bluez5_manager_query_devices (NMBluez5Manager *manager); - -#endif /* NM_BLUEZ5_MANAGER_H */ - diff --git a/src/devices/bluetooth/Makefile.am b/src/devices/bluetooth/Makefile.am new file mode 100644 index 0000000000..7713fc9124 --- /dev/null +++ b/src/devices/bluetooth/Makefile.am @@ -0,0 +1,56 @@ +include $(GLIB_MAKEFILE) + +@GNOME_CODE_COVERAGE_RULES@ + +AM_CPPFLAGS = \ + -I${top_srcdir}/src \ + -I${top_builddir}/src \ + -I${top_srcdir}/src/logging \ + -I${top_srcdir}/src/devices \ + -I${top_srcdir}/src/settings \ + -I${top_srcdir}/src/platform \ + -I${top_srcdir}/src/modem-manager \ + -I${top_builddir}/include \ + -I${top_srcdir}/include \ + -I${top_builddir}/libnm-util \ + -I${top_srcdir}/libnm-util \ + $(DBUS_CFLAGS) \ + $(POLKIT_CFLAGS) \ + $(LIBNL_CFLAGS) \ + $(GUDEV_CFLAGS) + +GLIB_GENERATED = nm-bt-enum-types.h nm-bt-enum-types.c +GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM +GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM +nm_bt_enum_types_sources = $(srcdir)/nm-device-bt.h + +nm-device-bt-glue.h: $(top_srcdir)/introspection/nm-device-bt.xml + dbus-binding-tool --prefix=nm_device_bt --mode=glib-server --output=$@ $< + +BUILT_SOURCES = $(GLIB_GENERATED) nm-device-bt-glue.h + +pkglib_LTLIBRARIES = libnm-device-plugin-bt.la + +libnm_device_plugin_bt_la_SOURCES = \ + nm-bluez-manager.c \ + nm-bluez-manager.h \ + nm-bluez-common.h \ + nm-bluez-device.c \ + nm-bluez-device.h \ + nm-bluez4-adapter.c \ + nm-bluez4-adapter.h \ + nm-bluez4-manager.c \ + nm-bluez4-manager.h \ + nm-bluez5-manager.c \ + nm-bluez5-manager.h \ + \ + nm-device-bt.c \ + nm-device-bt.h \ + \ + $(BUILT_SOURCES) + +libnm_device_plugin_bt_la_LDFLAGS = -module -avoid-version +libnm_device_plugin_bt_la_LIBADD = $(DBUS_LIBS) $(GUDEV_LIBS) + +CLEANFILES = $(BUILT_SOURCES) + diff --git a/src/devices/bluetooth/nm-bluez-common.h b/src/devices/bluetooth/nm-bluez-common.h new file mode 100644 index 0000000000..f80cfc2e39 --- /dev/null +++ b/src/devices/bluetooth/nm-bluez-common.h @@ -0,0 +1,45 @@ +/* -*- 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_BLUEZ_COMMON_H +#define NM_BLUEZ_COMMON_H + +#include + +#define BLUETOOTH_CONNECT_DUN "dun" +#define BLUETOOTH_CONNECT_NAP "nap" + +#define BLUEZ_SERVICE "org.bluez" + +#define BLUEZ_MANAGER_PATH "/" +#define OBJECT_MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager" + +#define BLUEZ5_ADAPTER_INTERFACE "org.bluez.Adapter1" +#define BLUEZ5_DEVICE_INTERFACE "org.bluez.Device1" +#define BLUEZ5_NETWORK_INTERFACE "org.bluez.Network1" + +#define BLUEZ4_MANAGER_INTERFACE "org.bluez.Manager" +#define BLUEZ4_ADAPTER_INTERFACE "org.bluez.Adapter" +#define BLUEZ4_DEVICE_INTERFACE "org.bluez.Device" +#define BLUEZ4_SERIAL_INTERFACE "org.bluez.Serial" +#define BLUEZ4_NETWORK_INTERFACE "org.bluez.Network" + +#endif /* NM_BLUEZ_COMMON_H */ + diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c new file mode 100644 index 0000000000..e04e8d4dee --- /dev/null +++ b/src/devices/bluetooth/nm-bluez-device.c @@ -0,0 +1,1181 @@ +/* -*- 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 - 2012 Red Hat, Inc. + * Copyright (C) 2013 Intel Corporation. + */ + +#include +#include +#include +#include +#include +#include + +#include "NetworkManager.h" +#include "nm-setting-bluetooth.h" + +#include "nm-bluez-common.h" +#include "nm-bluez-device.h" +#include "nm-logging.h" +#include "nm-utils.h" +#include "nm-settings-connection.h" + + +G_DEFINE_TYPE (NMBluezDevice, nm_bluez_device, G_TYPE_OBJECT) + +#define NM_BLUEZ_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ_DEVICE, NMBluezDevicePrivate)) + +typedef struct { + char *path; + GDBusConnection *dbus_connection; + + GDBusProxy *proxy; + + GDBusProxy *adapter5; + gboolean adapter_powered; + + int bluez_version; + + gboolean initialized; + gboolean usable; + NMBluetoothCapabilities connection_bt_type; + + char *address; + guint8 bin_address[ETH_ALEN]; + char *name; + guint32 capabilities; + gboolean connected; + + char *bt_iface; + + NMConnectionProvider *provider; + GSList *connections; + + NMConnection *pan_connection; + NMConnection *pan_connection_original; + gboolean pan_connection_no_autocreate; +} NMBluezDevicePrivate; + + +enum { + PROP_0, + PROP_PATH, + PROP_ADDRESS, + PROP_NAME, + PROP_CAPABILITIES, + PROP_USABLE, + PROP_CONNECTED, + + LAST_PROP +}; + +/* Signals */ +enum { + INITIALIZED, + REMOVED, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + + +static void cp_connection_added (NMConnectionProvider *provider, + NMConnection *connection, NMBluezDevice *self); +static gboolean connection_compatible (NMBluezDevice *self, NMConnection *connection); + + +#define VARIANT_IS_OF_TYPE_BOOLEAN(v) ((v) != NULL && ( g_variant_is_of_type ((v), G_VARIANT_TYPE_BOOLEAN) )) +#define VARIANT_IS_OF_TYPE_STRING(v) ((v) != NULL && ( g_variant_is_of_type ((v), G_VARIANT_TYPE_STRING) )) +#define VARIANT_IS_OF_TYPE_OBJECT_PATH(v) ((v) != NULL && ( g_variant_is_of_type ((v), G_VARIANT_TYPE_OBJECT_PATH) )) +#define VARIANT_IS_OF_TYPE_STRING_ARRAY(v) ((v) != NULL && ( g_variant_is_of_type ((v), G_VARIANT_TYPE_STRING_ARRAY) )) + +/***********************************************************/ + +const char * +nm_bluez_device_get_path (NMBluezDevice *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), NULL); + + return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->path; +} + +const char * +nm_bluez_device_get_address (NMBluezDevice *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), NULL); + + return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->address; +} + +gboolean +nm_bluez_device_get_initialized (NMBluezDevice *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), FALSE); + + return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->initialized; +} + +gboolean +nm_bluez_device_get_usable (NMBluezDevice *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), FALSE); + + return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->usable; +} + +const char * +nm_bluez_device_get_name (NMBluezDevice *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), NULL); + + return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->name; +} + +guint32 +nm_bluez_device_get_capabilities (NMBluezDevice *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), 0); + + return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->capabilities; +} + +gboolean +nm_bluez_device_get_connected (NMBluezDevice *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), FALSE); + + return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->connected; +} + +static void +pan_connection_check_create (NMBluezDevice *self) +{ + NMConnection *connection; + NMConnection *added; + NMSetting *setting; + char *uuid, *id; + GByteArray *bdaddr_array; + GError *error = NULL; + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + + g_return_if_fail (priv->capabilities & NM_BT_CAPABILITY_NAP); + g_return_if_fail (priv->connections == NULL); + g_return_if_fail (priv->name); + + if (priv->pan_connection || priv->pan_connection_no_autocreate) { + /* already have a connection or we don't want to create one, nothing to do. */ + return; + } + + /* Only try once to create a connection. If it does not succeed, we do not try again. Also, + * if the connection gets deleted later, do not create another one for this device. */ + priv->pan_connection_no_autocreate = TRUE; + + /* create a new connection */ + + connection = nm_connection_new (); + + /* Setting: Connection */ + uuid = nm_utils_uuid_generate (); + id = g_strdup_printf (_("%s Network"), priv->name); + setting = nm_setting_connection_new (); + g_object_set (setting, + NM_SETTING_CONNECTION_ID, id, + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_BLUETOOTH_SETTING_NAME, + NULL); + nm_connection_add_setting (connection, setting); + + /* Setting: Bluetooth */ + bdaddr_array = g_byte_array_sized_new (sizeof (priv->bin_address)); + g_byte_array_append (bdaddr_array, priv->bin_address, sizeof (priv->bin_address)); + setting = nm_setting_bluetooth_new (); + g_object_set (G_OBJECT (setting), + NM_SETTING_BLUETOOTH_BDADDR, bdaddr_array, + NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU, + NULL); + nm_connection_add_setting (connection, setting); + g_byte_array_free (bdaddr_array, TRUE); + + /* Setting: IPv4 */ + setting = nm_setting_ip4_config_new (); + g_object_set (G_OBJECT (setting), + NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NM_SETTING_IP4_CONFIG_MAY_FAIL, FALSE, + NULL); + nm_connection_add_setting (connection, setting); + + /* Setting: IPv6 */ + setting = nm_setting_ip6_config_new (); + g_object_set (G_OBJECT (setting), + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, + NULL); + nm_connection_add_setting (connection, setting); + + /* Adding a new connection raises a signal which eventually calls check_emit_usable (again) + * which then already finds the suitable connection in priv->connections. This is confusing, + * so block the signal. check_emit_usable will succeed after this function call returns. */ + g_signal_handlers_block_by_func (priv->provider, cp_connection_added, self); + added = nm_connection_provider_add_connection (priv->provider, connection, FALSE, &error); + g_signal_handlers_unblock_by_func (priv->provider, cp_connection_added, self); + + if (added) { + g_assert (!g_slist_find (priv->connections, added)); + g_assert (connection_compatible (self, added)); + g_assert (nm_connection_compare (added, connection, NM_SETTING_COMPARE_FLAG_EXACT)); + + priv->connections = g_slist_prepend (priv->connections, g_object_ref (added)); + priv->pan_connection = added; + priv->pan_connection_original = connection; + nm_log_dbg (LOGD_BT, "bluez[%s] added new Bluetooth connection for NAP device: '%s' (%s)", priv->path, id, uuid); + } else { + nm_log_warn (LOGD_BT, "bluez[%s] couldn't add new Bluetooth connection for NAP device: '%s' (%s): %d / %s", + priv->path, id, uuid, error ? error->code : -1, + (error && error->message) ? error->message : "(unknown)"); + g_clear_error (&error); + + g_object_unref (connection); + } + + g_free (id); + g_free (uuid); +} + +static void +check_emit_usable (NMBluezDevice *self) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + gboolean new_usable; + + /* only expect the supported capabilities set. */ + g_assert (priv->bluez_version != 4 || ((priv->capabilities & ~(NM_BT_CAPABILITY_NAP | NM_BT_CAPABILITY_DUN)) == NM_BT_CAPABILITY_NONE )); + g_assert (priv->bluez_version != 5 || ((priv->capabilities & ~(NM_BT_CAPABILITY_NAP )) == NM_BT_CAPABILITY_NONE )); + + new_usable = (priv->initialized && priv->capabilities && priv->name && + ((priv->bluez_version == 4) || + (priv->bluez_version == 5 && priv->adapter5 && priv->adapter_powered) ) && + priv->dbus_connection && priv->address); + + if (!new_usable) + goto END; + + if (priv->connections) + goto END; + + if (!(priv->capabilities & NM_BT_CAPABILITY_NAP)) { + /* non NAP devices are only usable, if they already have a connection. */ + new_usable = FALSE; + goto END; + } + + pan_connection_check_create (self); + new_usable = !!priv->pan_connection; + +END: + if (new_usable != priv->usable) { + priv->usable = new_usable; + g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_USABLE); + } +} + +/********************************************************************/ + +static gboolean +connection_compatible (NMBluezDevice *self, NMConnection *connection) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + NMSettingBluetooth *s_bt; + const char *bt_type; + const GByteArray *bdaddr; + + if (!nm_connection_is_type (connection, NM_SETTING_BLUETOOTH_SETTING_NAME)) + return FALSE; + + s_bt = nm_connection_get_setting_bluetooth (connection); + if (!s_bt) + return FALSE; + + if (!priv->address) { + /* unless address is set, bin_address is not initialized. */ + return FALSE; + } + bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt); + if (!bdaddr || bdaddr->len != ETH_ALEN) + return FALSE; + if (memcmp (bdaddr->data, priv->bin_address, ETH_ALEN) != 0) + return FALSE; + + bt_type = nm_setting_bluetooth_get_connection_type (s_bt); + if ( g_str_equal (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN) + && !(priv->capabilities & NM_BT_CAPABILITY_DUN)) + return FALSE; + + if ( g_str_equal (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU) + && !(priv->capabilities & NM_BT_CAPABILITY_NAP)) + return FALSE; + + return TRUE; +} + +static void +_internal_add_connection (NMBluezDevice *self, NMConnection *connection) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + + if (!g_slist_find (priv->connections, connection)) { + priv->connections = g_slist_prepend (priv->connections, g_object_ref (connection)); + check_emit_usable (self); + } +} + +static void +cp_connection_added (NMConnectionProvider *provider, + NMConnection *connection, + NMBluezDevice *self) +{ + if (connection_compatible (self, connection)) + _internal_add_connection (self, connection); +} + +static void +cp_connection_removed (NMConnectionProvider *provider, + NMConnection *connection, + NMBluezDevice *self) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + + if (g_slist_find (priv->connections, connection)) { + priv->connections = g_slist_remove (priv->connections, connection); + if (priv->pan_connection == connection) { + priv->pan_connection = NULL; + g_clear_object (&priv->pan_connection_original); + } + g_object_unref (connection); + check_emit_usable (self); + } +} + +static void +cp_connection_updated (NMConnectionProvider *provider, + NMConnection *connection, + NMBluezDevice *self) +{ + if (connection_compatible (self, connection)) + _internal_add_connection (self, connection); + else + cp_connection_removed (provider, connection, self); +} + +static void +load_connections (NMBluezDevice *self) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + const GSList *connections, *iter; + + connections = nm_connection_provider_get_connections (priv->provider); + for (iter = connections; iter; iter = g_slist_next (iter)) + cp_connection_added (priv->provider, NM_CONNECTION (iter->data), self); +} + +/***********************************************************/ + +static void +bluez_disconnect_cb (GDBusConnection *dbus_connection, + GAsyncResult *res, + gpointer user_data) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (user_data); + GError *error = NULL; + GVariant *variant; + + variant = g_dbus_connection_call_finish (dbus_connection, res, &error); + if (!variant) { + nm_log_warn (LOGD_BT, "bluez[%s]: failed to disconnect: %s", priv->path, error->message); + g_error_free (error); + } else + g_variant_unref (variant); +} + +void +nm_bluez_device_disconnect (NMBluezDevice *self) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + GVariant *args = NULL; + const char *dbus_iface; + + g_return_if_fail (priv->dbus_connection); + + if (priv->bluez_version == 5) { + g_return_if_fail (priv->connection_bt_type == NM_BT_CAPABILITY_NAP); + dbus_iface = BLUEZ5_NETWORK_INTERFACE; + } else if (priv->bluez_version == 4 && priv->connection_bt_type == NM_BT_CAPABILITY_DUN) { + /* Can't pass a NULL interface name through dbus to bluez, so just + * ignore the disconnect if the interface isn't known. + */ + if (!priv->bt_iface) + return; + + args = g_variant_new ("(s)", priv->bt_iface), + dbus_iface = BLUEZ4_SERIAL_INTERFACE; + } else { + g_return_if_fail (priv->bluez_version == 4 && priv->connection_bt_type == NM_BT_CAPABILITY_NAP); + dbus_iface = BLUEZ4_NETWORK_INTERFACE; + } + + g_dbus_connection_call (priv->dbus_connection, + BLUEZ_SERVICE, + priv->path, + dbus_iface, + "Disconnect", + args ? args : g_variant_new ("()"), + NULL, + G_DBUS_CALL_FLAGS_NONE, + 10000, + NULL, + (GAsyncReadyCallback) bluez_disconnect_cb, + self); + + priv->connection_bt_type = NM_BT_CAPABILITY_NONE; +} + +static void +bluez_connect_cb (GDBusConnection *dbus_connection, + GAsyncResult *res, + gpointer user_data) +{ + GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); + GObject *result_object = g_async_result_get_source_object (G_ASYNC_RESULT (result)); + NMBluezDevice *self = NM_BLUEZ_DEVICE (result_object); + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + GError *error = NULL; + char *device; + GVariant *variant; + + variant = g_dbus_connection_call_finish (dbus_connection, res, &error); + + if (!variant) { + g_simple_async_result_take_error (result, error); + } else { + g_variant_get (variant, "(s)", &device); + + g_simple_async_result_set_op_res_gpointer (result, + g_strdup (device), + g_free); + priv->bt_iface = device; + g_variant_unref (variant); + } + + g_simple_async_result_complete (result); + g_object_unref (result); + g_object_unref (result_object); +} + +void +nm_bluez_device_connect_async (NMBluezDevice *self, + NMBluetoothCapabilities connection_bt_type, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + const char *dbus_iface; + const char *connect_type = BLUETOOTH_CONNECT_NAP; + + g_return_if_fail (priv->capabilities & connection_bt_type & (NM_BT_CAPABILITY_DUN | NM_BT_CAPABILITY_NAP)); + + if (priv->bluez_version == 5) { + g_return_if_fail (connection_bt_type == NM_BT_CAPABILITY_NAP); + dbus_iface = BLUEZ5_NETWORK_INTERFACE; + } else if (priv->bluez_version == 4 && connection_bt_type == NM_BT_CAPABILITY_DUN) { + dbus_iface = BLUEZ4_SERIAL_INTERFACE; + connect_type = BLUETOOTH_CONNECT_DUN; + } else { + g_return_if_fail (priv->bluez_version == 4 && connection_bt_type == NM_BT_CAPABILITY_NAP); + dbus_iface = BLUEZ4_NETWORK_INTERFACE; + } + + simple = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + nm_bluez_device_connect_async); + + g_dbus_connection_call (priv->dbus_connection, + BLUEZ_SERVICE, + priv->path, + dbus_iface, + "Connect", + g_variant_new ("(s)", connect_type), + NULL, + G_DBUS_CALL_FLAGS_NONE, + 20000, + NULL, + (GAsyncReadyCallback) bluez_connect_cb, + simple); + + priv->connection_bt_type = connection_bt_type; +} + +const char * +nm_bluez_device_connect_finish (NMBluezDevice *self, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + const char *device; + + g_return_val_if_fail (g_simple_async_result_is_valid (result, + G_OBJECT (self), + nm_bluez_device_connect_async), + NULL); + + simple = (GSimpleAsyncResult *) result; + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + device = (const char *) g_simple_async_result_get_op_res_gpointer (simple); + return device; +} + +/***********************************************************/ + +static guint32 +convert_uuids_to_capabilities (const char **strings, int bluez_version) +{ + const char **iter; + guint32 capabilities = 0; + + for (iter = strings; iter && *iter; iter++) { + char **parts; + + parts = g_strsplit (*iter, "-", -1); + if (parts && parts[0]) { + switch (g_ascii_strtoull (parts[0], NULL, 16)) { + case 0x1103: + if (bluez_version == 4) + capabilities |= NM_BT_CAPABILITY_DUN; + break; + case 0x1116: + capabilities |= NM_BT_CAPABILITY_NAP; + break; + default: + break; + } + } + g_strfreev (parts); + } + + return capabilities; +} + +static void +_set_property_capabilities (NMBluezDevice *self, const char **uuids) +{ + guint32 uint_val; + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + + uint_val = convert_uuids_to_capabilities (uuids, priv->bluez_version); + if (priv->capabilities != uint_val) { + if (priv->capabilities) { + /* changing (relevant) capabilities is not supported and ignored -- except setting initially */ + nm_log_warn (LOGD_BT, "bluez[%s] ignore change of capabilities for Bluetooth device from %u to %u", + priv->path, priv->capabilities, uint_val); + return; + } + nm_log_dbg (LOGD_BT, "bluez[%s] set capabilities for Bluetooth device: %s%s%s", priv->path, + uint_val & NM_BT_CAPABILITY_NAP ? "NAP" : "", + ((uint_val & NM_BT_CAPABILITY_DUN) && (uint_val &NM_BT_CAPABILITY_NAP)) ? " | " : "", + uint_val & NM_BT_CAPABILITY_DUN ? "DUN" : ""); + priv->capabilities = uint_val; + g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_CAPABILITIES); + } +} + +/** + * priv->address can only be set one to a certain (non NULL) value. Every later attempt + * to reset it to another value will be ignored and a warning will be logged. + * + * When setting the address for the first time, we also set bin_address. + **/ +static void +_set_property_address (NMBluezDevice *self, const char *addr) +{ + struct ether_addr *tmp; + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + + if (g_strcmp0 (priv->address, addr) == 0) + return; + + if (!addr) { + nm_log_warn (LOGD_BT, "bluez[%s] cannot reset address from '%s' to NULL", priv->path, priv->address); + return; + } + + if (priv->address != NULL) { + nm_log_warn (LOGD_BT, "bluez[%s] cannot reset address from '%s' to '%s'", priv->path, priv->address, addr); + return; + } + + tmp = ether_aton (addr); + if (!tmp) { + if (priv->address) + nm_log_warn (LOGD_BT, "bluez[%s] cannot reset address from '%s' to '%s' (invalid value)", priv->path, priv->address, addr); + else + nm_log_warn (LOGD_BT, "bluez[%s] cannot reset address from NULL to '%s' (invalid value)", priv->path, addr); + return; + } + memcpy (priv->bin_address, tmp->ether_addr_octet, ETH_ALEN); + priv->address = g_strdup (addr); + g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_ADDRESS); +} + +static void +_take_variant_property_address (NMBluezDevice *self, GVariant *v) +{ + _set_property_address (self, VARIANT_IS_OF_TYPE_STRING (v) ? g_variant_get_string (v, NULL) : NULL); + if (v) + g_variant_unref (v); +} + +static void +_take_variant_property_name (NMBluezDevice *self, GVariant *v) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + const char *str; + + if (VARIANT_IS_OF_TYPE_STRING (v)) { + str = g_variant_get_string (v, NULL); + if (g_strcmp0 (priv->name, str)) { + g_free (priv->name); + priv->name = g_strdup (str); + g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_NAME); + } + } + if (v) + g_variant_unref (v); +} + +static void +_take_variant_property_uuids (NMBluezDevice *self, GVariant *v) +{ + if (VARIANT_IS_OF_TYPE_STRING_ARRAY (v)) { + const char **uuids = g_variant_get_strv (v, NULL); + + _set_property_capabilities (self, uuids); + g_free (uuids); + } + if (v) + g_variant_unref (v); +} + +static void +_take_variant_property_connected (NMBluezDevice *self, GVariant *v) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + + if (VARIANT_IS_OF_TYPE_BOOLEAN (v)) { + gboolean connected = g_variant_get_boolean (v); + + if (priv->connected != connected) { + priv->connected = connected; + g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_CONNECTED); + } + } + if (v) + g_variant_unref (v); +} + + +static void +adapter5_on_properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + GStrv invalidated_properties, + gpointer user_data) +{ + NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data); + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + GVariantIter i; + const char *property; + GVariant *v; + + g_variant_iter_init (&i, changed_properties); + while (g_variant_iter_next (&i, "{&sv}", &property, &v)) { + if (!strcmp (property, "Powered") && VARIANT_IS_OF_TYPE_BOOLEAN (v)) { + gboolean powered = g_variant_get_boolean (v); + if (priv->adapter_powered != powered) + priv->adapter_powered = powered; + } + g_variant_unref (v); + } + + check_emit_usable (self); +} + +static void +adapter5_on_acquired (GObject *object, GAsyncResult *res, NMBluezDevice *self) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + GError *error; + GVariant *v; + + priv->adapter5 = g_dbus_proxy_new_for_bus_finish (res, &error); + if (!priv->adapter5) { + nm_log_warn (LOGD_BT, "bluez[%s] failed to acquire adapter proxy: %s.", priv->path, error->message); + g_clear_error (&error); + g_signal_emit (self, signals[INITIALIZED], 0, FALSE); + } else { + g_signal_connect (priv->adapter5, "g-properties-changed", + G_CALLBACK (adapter5_on_properties_changed), self); + + /* Check adapter's powered state */ + v = g_dbus_proxy_get_cached_property (priv->adapter5, "Powered"); + priv->adapter_powered = VARIANT_IS_OF_TYPE_BOOLEAN (v) ? g_variant_get_boolean (v) : FALSE; + if (v) + g_variant_unref (v); + + priv->initialized = TRUE; + g_signal_emit (self, signals[INITIALIZED], 0, TRUE); + + check_emit_usable (self); + } + + g_object_unref (self); +} + +static void +_set_properties (NMBluezDevice *self, GVariant *properties) +{ + GVariantIter i; + const char *property; + GVariant *v; + + g_object_freeze_notify (G_OBJECT (self)); + g_variant_iter_init (&i, properties); + while (g_variant_iter_next (&i, "{&sv}", &property, &v)) { + if (!property) { + g_variant_unref (v); + } else if (!strcmp (property, "Address")) { + _take_variant_property_address (self, v); + } else if (!strcmp (property, "Connected")) { + _take_variant_property_connected (self, v); + } else if (!strcmp (property, "Name")) { + _take_variant_property_name (self, v); + } else if (!strcmp (property, "UUIDs")) { + _take_variant_property_uuids (self, v); + } else + g_variant_unref (v); + } + g_object_thaw_notify (G_OBJECT (self)); +} + +static void +properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + GStrv invalidated_properties, + gpointer user_data) +{ + NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data); + + _set_properties (self, changed_properties); + + check_emit_usable (self); +} + + +static void +get_properties_cb_4 (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data); + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + GError *err = NULL; + GVariant *v_properties, *v_dict; + GVariantType *v_type; + + v_properties = g_dbus_proxy_call_finish (priv->proxy, res, &err); + if (!v_properties) { + nm_log_warn (LOGD_BT, "bluez[%s] error getting device properties: %s", + priv->path, err && err->message ? err->message : "(unknown)"); + g_error_free (err); + g_signal_emit (self, signals[INITIALIZED], 0, FALSE); + goto END; + } + + v_type = g_variant_type_new ("(a{sv})"); + if (g_variant_is_of_type (v_properties, v_type)) { + v_dict = g_variant_get_child_value (v_properties, 0); + _set_properties (self, v_dict); + g_variant_unref (v_dict); + } else { + nm_log_warn (LOGD_BT, "bluez[%s] GetProperties returns unexpected result of type %s", priv->path, g_variant_get_type_string (v_properties)); + } + g_variant_type_free (v_type); + + g_variant_unref (v_properties); + + /* Check if any connections match this device */ + load_connections (self); + + priv->initialized = TRUE; + g_signal_emit (self, signals[INITIALIZED], 0, TRUE); + + + check_emit_usable (self); + +END: + g_object_unref (self); +} + + +static void +query_properties (NMBluezDevice *self) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + GVariant *v; + + switch (priv->bluez_version) { + case 4: + g_dbus_proxy_call (priv->proxy, "GetProperties", NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START, 3000, + NULL, get_properties_cb_4, g_object_ref (self)); + break; + case 5: + g_object_freeze_notify (G_OBJECT (self)); + _take_variant_property_address (self, g_dbus_proxy_get_cached_property (priv->proxy, "Address")); + _take_variant_property_connected (self, g_dbus_proxy_get_cached_property (priv->proxy, "Connected")); + _take_variant_property_name (self, g_dbus_proxy_get_cached_property (priv->proxy, "Name")); + _take_variant_property_uuids (self, g_dbus_proxy_get_cached_property (priv->proxy, "UUIDs")); + g_object_thaw_notify (G_OBJECT (self)); + + v = g_dbus_proxy_get_cached_property (priv->proxy, "Adapter"); + if (VARIANT_IS_OF_TYPE_OBJECT_PATH (v)) { + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + BLUEZ_SERVICE, + g_variant_get_string (v, NULL), + BLUEZ5_ADAPTER_INTERFACE, + NULL, + (GAsyncReadyCallback) adapter5_on_acquired, + g_object_ref (self)); + g_variant_unref (v); + } else { + /* If the Adapter property is unset at this point, we won't try to acquire the adapter later on + * and the device stays unusable. This should not happen, but if it does, log a debug message. */ + nm_log_dbg (LOGD_BT, "bluez[%s] device has no adapter property and cannot be used.", priv->path); + } + + /* Check if any connections match this device */ + load_connections (self); + + break; + } +} + +static void +on_proxy_acquired (GObject *object, GAsyncResult *res, NMBluezDevice *self) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + GError *error = NULL; + + priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + + if (!priv->proxy) { + nm_log_warn (LOGD_BT, "bluez[%s] failed to acquire device proxy: %s.", priv->path, error->message); + g_clear_error (&error); + g_signal_emit (self, signals[INITIALIZED], 0, FALSE); + } else { + g_signal_connect (priv->proxy, "g-properties-changed", + G_CALLBACK (properties_changed), self); + + query_properties (self); + } + g_object_unref (self); +} + +static void +on_bus_acquired (GObject *object, GAsyncResult *res, NMBluezDevice *self) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + GError *error = NULL; + + priv->dbus_connection = g_bus_get_finish (res, &error); + + if (!priv->dbus_connection) { + nm_log_warn (LOGD_BT, "bluez[%s] failed to acquire bus connection: %s.", priv->path, error->message); + g_clear_error (&error); + g_signal_emit (self, signals[INITIALIZED], 0, FALSE); + } else + check_emit_usable (self); + + g_object_unref (self); +} + +/********************************************************************/ + +NMBluezDevice * +nm_bluez_device_new (const char *path, NMConnectionProvider *provider, int bluez_version) +{ + NMBluezDevice *self; + NMBluezDevicePrivate *priv; + const char *interface_name = NULL; + + g_return_val_if_fail (path != NULL, NULL); + g_return_val_if_fail (provider != NULL, NULL); + g_return_val_if_fail (bluez_version == 4 || bluez_version == 5, NULL); + + self = (NMBluezDevice *) g_object_new (NM_TYPE_BLUEZ_DEVICE, + NM_BLUEZ_DEVICE_PATH, path, + NULL); + if (!self) + return NULL; + + nm_log_dbg (LOGD_BT, "bluez[%s] create NMBluezDevice", path); + + priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + + priv->bluez_version = bluez_version; + + priv->provider = provider; + + g_signal_connect (priv->provider, + NM_CP_SIGNAL_CONNECTION_ADDED, + G_CALLBACK (cp_connection_added), + self); + + g_signal_connect (priv->provider, + NM_CP_SIGNAL_CONNECTION_REMOVED, + G_CALLBACK (cp_connection_removed), + self); + + g_signal_connect (priv->provider, + NM_CP_SIGNAL_CONNECTION_UPDATED, + G_CALLBACK (cp_connection_updated), + self); + + g_bus_get (G_BUS_TYPE_SYSTEM, + NULL, + (GAsyncReadyCallback) on_bus_acquired, + g_object_ref (self)); + + switch (priv->bluez_version) { + case 4: + interface_name = BLUEZ4_DEVICE_INTERFACE; + break; + case 5: + interface_name = BLUEZ5_DEVICE_INTERFACE; + break; + } + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + BLUEZ_SERVICE, + priv->path, + interface_name, + NULL, + (GAsyncReadyCallback) on_proxy_acquired, + g_object_ref (self)); + return self; +} + +static void +nm_bluez_device_init (NMBluezDevice *self) +{ +} + +static void +dispose (GObject *object) +{ + NMBluezDevice *self = NM_BLUEZ_DEVICE (object); + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + NMConnection *to_delete = NULL; + + if (priv->pan_connection) { + /* Check whether we want to remove the created connection. If so, we take a reference + * and delete it at the end of dispose(). */ + if ( nm_settings_connection_get_unsaved (NM_SETTINGS_CONNECTION (priv->pan_connection)) + && nm_connection_compare (priv->pan_connection, priv->pan_connection_original, NM_SETTING_COMPARE_FLAG_EXACT)) + to_delete = g_object_ref (priv->pan_connection); + + priv->pan_connection = NULL; + g_clear_object (&priv->pan_connection_original); + } + + g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_added, self); + g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_removed, self); + g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_updated, self); + + g_slist_free_full (priv->connections, g_object_unref); + priv->connections = NULL; + + g_clear_object (&priv->adapter5); + g_clear_object (&priv->dbus_connection); + + G_OBJECT_CLASS (nm_bluez_device_parent_class)->dispose (object); + + if (to_delete) { + nm_log_dbg (LOGD_BT, "bluez[%s] removing Bluetooth connection for NAP device: '%s' (%s)", priv->path, + nm_connection_get_id (to_delete), nm_connection_get_uuid (to_delete)); + nm_settings_connection_delete (NM_SETTINGS_CONNECTION (to_delete), NULL, NULL); + g_object_unref (to_delete); + } +} + +static void +finalize (GObject *object) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (object); + + nm_log_dbg (LOGD_BT, "bluez[%s]: finalize NMBluezDevice", priv->path); + + g_free (priv->path); + g_free (priv->address); + g_free (priv->name); + g_free (priv->bt_iface); + + g_clear_object (&priv->proxy); + + G_OBJECT_CLASS (nm_bluez_device_parent_class)->finalize (object); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_PATH: + g_value_set_string (value, priv->path); + break; + case PROP_ADDRESS: + g_value_set_string (value, priv->address); + break; + case PROP_NAME: + g_value_set_string (value, priv->name); + break; + case PROP_CAPABILITIES: + g_value_set_uint (value, priv->capabilities); + break; + case PROP_USABLE: + g_value_set_boolean (value, priv->usable); + break; + case PROP_CONNECTED: + g_value_set_boolean (value, priv->connected); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_PATH: + /* construct only */ + priv->path = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_bluez_device_class_init (NMBluezDeviceClass *config_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (config_class); + + g_type_class_add_private (config_class, sizeof (NMBluezDevicePrivate)); + + /* virtual methods */ + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->dispose = dispose; + object_class->finalize = finalize; + + /* Properties */ + g_object_class_install_property + (object_class, PROP_PATH, + g_param_spec_string (NM_BLUEZ_DEVICE_PATH, + "DBus Path", + "DBus Path", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, PROP_ADDRESS, + g_param_spec_string (NM_BLUEZ_DEVICE_ADDRESS, + "Address", + "Address", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_NAME, + g_param_spec_string (NM_BLUEZ_DEVICE_NAME, + "Name", + "Name", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_CAPABILITIES, + g_param_spec_uint (NM_BLUEZ_DEVICE_CAPABILITIES, + "Capabilities", + "Capabilities", + 0, G_MAXUINT, 0, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_USABLE, + g_param_spec_boolean (NM_BLUEZ_DEVICE_USABLE, + "Usable", + "Usable", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_CONNECTED, + g_param_spec_boolean (NM_BLUEZ_DEVICE_CONNECTED, + "Connected", + "Connected", + FALSE, + G_PARAM_READABLE)); + + /* Signals */ + signals[INITIALIZED] = g_signal_new ("initialized", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMBluezDeviceClass, initialized), + NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + + signals[REMOVED] = g_signal_new (NM_BLUEZ_DEVICE_REMOVED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMBluezDeviceClass, removed), + NULL, NULL, NULL, + G_TYPE_NONE, 0); +} + diff --git a/src/devices/bluetooth/nm-bluez-device.h b/src/devices/bluetooth/nm-bluez-device.h new file mode 100644 index 0000000000..0bf7d898b0 --- /dev/null +++ b/src/devices/bluetooth/nm-bluez-device.h @@ -0,0 +1,98 @@ +/* -*- 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 - 2014 Red Hat, Inc. + */ + +#ifndef NM_BLUEZ_DEVICE_H +#define NM_BLUEZ_DEVICE_H + +#include +#include +#include + +#include +#include "nm-connection.h" +#include "nm-connection-provider.h" + +#define NM_TYPE_BLUEZ_DEVICE (nm_bluez_device_get_type ()) +#define NM_BLUEZ_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ_DEVICE, NMBluezDevice)) +#define NM_BLUEZ_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ_DEVICE, NMBluezDeviceClass)) +#define NM_IS_BLUEZ_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ_DEVICE)) +#define NM_IS_BLUEZ_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_BLUEZ_DEVICE)) +#define NM_BLUEZ_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ_DEVICE, NMBluezDeviceClass)) + +/* Properties */ +#define NM_BLUEZ_DEVICE_PATH "path" +#define NM_BLUEZ_DEVICE_ADDRESS "address" +#define NM_BLUEZ_DEVICE_NAME "name" +#define NM_BLUEZ_DEVICE_CAPABILITIES "capabilities" +#define NM_BLUEZ_DEVICE_USABLE "usable" +#define NM_BLUEZ_DEVICE_CONNECTED "connected" + +/* Signals */ +#define NM_BLUEZ_DEVICE_REMOVED "removed" + +typedef struct { + GObject parent; +} NMBluezDevice; + +typedef struct { + GObjectClass parent; + + /* virtual functions */ + void (*initialized) (NMBluezDevice *self, gboolean success); + + void (*removed) (NMBluezDevice *self); +} NMBluezDeviceClass; + +GType nm_bluez_device_get_type (void); + +NMBluezDevice *nm_bluez_device_new (const char *path, NMConnectionProvider *provider, int bluez_version); + +const char *nm_bluez_device_get_path (NMBluezDevice *self); + +gboolean nm_bluez_device_get_initialized (NMBluezDevice *self); + +gboolean nm_bluez_device_get_usable (NMBluezDevice *self); + +const char *nm_bluez_device_get_address (NMBluezDevice *self); + +const char *nm_bluez_device_get_name (NMBluezDevice *self); + +guint32 nm_bluez_device_get_class (NMBluezDevice *self); + +guint32 nm_bluez_device_get_capabilities (NMBluezDevice *self); + +gboolean nm_bluez_device_get_connected (NMBluezDevice *self); + +void +nm_bluez_device_connect_async (NMBluezDevice *self, + NMBluetoothCapabilities connection_bt_type, + GAsyncReadyCallback callback, + gpointer user_data); + +const char * +nm_bluez_device_connect_finish (NMBluezDevice *self, + GAsyncResult *result, + GError **error); + +void +nm_bluez_device_disconnect (NMBluezDevice *self); + +#endif /* NM_BLUEZ_DEVICE_H */ + diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c new file mode 100644 index 0000000000..26ccb70c1a --- /dev/null +++ b/src/devices/bluetooth/nm-bluez-manager.c @@ -0,0 +1,452 @@ +/* -*- 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) 2013 - 2014 Red Hat, Inc. + */ + +#include +#include +#include +#include + +#include "nm-logging.h" +#include "nm-bluez-manager.h" +#include "nm-device-factory.h" +#include "nm-bluez4-manager.h" +#include "nm-bluez5-manager.h" +#include "nm-bluez-device.h" +#include "nm-bluez-common.h" +#include "nm-connection-provider.h" +#include "nm-device-bt.h" + +#include "nm-dbus-manager.h" + +typedef struct { + int bluez_version; + + NMConnectionProvider *provider; + NMBluez4Manager *manager4; + NMBluez5Manager *manager5; + + guint watch_name_id; + + GDBusProxy *introspect_proxy; + GCancellable *async_cancellable; +} NMBluezManagerPrivate; + +#define NM_BLUEZ_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerPrivate)) + +static GType nm_bluez_manager_get_type (void); + +static void device_factory_interface_init (NMDeviceFactory *factory_iface); + +G_DEFINE_TYPE_EXTENDED (NMBluezManager, nm_bluez_manager, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_FACTORY, device_factory_interface_init)) + +enum { + PROP_0, + PROP_DEVICE_TYPE, + LAST_PROP +}; + +static void check_bluez_and_try_setup (NMBluezManager *self); + +/**************************************************************************/ + +#define PLUGIN_TYPE NM_DEVICE_TYPE_BT + +G_MODULE_EXPORT NMDeviceFactory * +nm_device_factory_create (GError **error) +{ + return (NMDeviceFactory *) g_object_new (NM_TYPE_BLUEZ_MANAGER, NULL); +} + +G_MODULE_EXPORT NMDeviceType +nm_device_factory_get_device_type (void) +{ + return PLUGIN_TYPE; +} + +/************************************************************************/ + +struct AsyncData { + NMBluezManager *self; + GCancellable *async_cancellable; +}; + +static struct AsyncData * +async_data_pack (NMBluezManager *self) +{ + struct AsyncData *data = g_new (struct AsyncData, 1); + + data->self = self; + data->async_cancellable = g_object_ref (NM_BLUEZ_MANAGER_GET_PRIVATE (self)->async_cancellable); + return data; +} + +static NMBluezManager * +async_data_unpack (struct AsyncData *async_data) +{ + NMBluezManager *self = g_cancellable_is_cancelled (async_data->async_cancellable) + ? NULL : async_data->self; + + g_object_unref (async_data->async_cancellable); + g_free (async_data); + return self; +} + + +/** + * Cancel any current attempt to detect the version and cleanup + * the related fields. + **/ +static void +cleanup_checking (NMBluezManager *self, gboolean do_unwatch_name) +{ + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + + if (priv->async_cancellable) { + g_cancellable_cancel (priv->async_cancellable); + g_clear_object (&priv->async_cancellable); + } + + g_clear_object (&priv->introspect_proxy); + + if (do_unwatch_name && priv->watch_name_id) { + g_bus_unwatch_name (priv->watch_name_id); + priv->watch_name_id = 0; + } +} + + +static void +manager_bdaddr_added_cb (NMBluez4Manager *bluez_mgr, + NMBluezDevice *bt_device, + const char *bdaddr, + const char *name, + const char *object_path, + guint32 capabilities, + gpointer user_data) +{ + NMBluezManager *self = NM_BLUEZ_MANAGER (user_data); + NMDevice *device; + gboolean has_dun = (capabilities & NM_BT_CAPABILITY_DUN); + gboolean has_nap = (capabilities & NM_BT_CAPABILITY_NAP); + + g_return_if_fail (bdaddr != NULL); + g_return_if_fail (name != NULL); + g_return_if_fail (object_path != NULL); + g_return_if_fail (capabilities != NM_BT_CAPABILITY_NONE); + g_return_if_fail (NM_IS_BLUEZ_DEVICE (bt_device)); + + device = nm_device_bt_new (bt_device, object_path, bdaddr, name, capabilities); + if (!device) + return; + + nm_log_info (LOGD_BT, "BT device %s (%s) added (%s%s%s)", + name, + bdaddr, + has_dun ? "DUN" : "", + has_dun && has_nap ? " " : "", + has_nap ? "NAP" : ""); + g_signal_emit_by_name (self, NM_DEVICE_FACTORY_DEVICE_ADDED, device); + g_object_unref (device); +} + +static void +setup_version_number (NMBluezManager *self, int bluez_version) +{ + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + + g_return_if_fail (!priv->bluez_version); + + nm_log_info (LOGD_BT, "use BlueZ version %d", bluez_version); + + priv->bluez_version = bluez_version; + + /* Just detected the version. Cleanup the ongoing checking/detection. */ + cleanup_checking (self, TRUE); +} + +static void +setup_bluez4 (NMBluezManager *self) +{ + NMBluez4Manager *manager; + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + + g_return_if_fail (!priv->manager4 && !priv->manager5 && !priv->bluez_version); + + setup_version_number (self, 4); + priv->manager4 = manager = nm_bluez4_manager_new (priv->provider); + + g_signal_connect (manager, + NM_BLUEZ_MANAGER_BDADDR_ADDED, + G_CALLBACK (manager_bdaddr_added_cb), + self); + + nm_bluez4_manager_query_devices (manager); +} + +static void +setup_bluez5 (NMBluezManager *self) +{ + NMBluez5Manager *manager; + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + + g_return_if_fail (!priv->manager4 && !priv->manager5 && !priv->bluez_version); + + setup_version_number (self, 5); + priv->manager5 = manager = nm_bluez5_manager_new (priv->provider); + + g_signal_connect (manager, + NM_BLUEZ_MANAGER_BDADDR_ADDED, + G_CALLBACK (manager_bdaddr_added_cb), + self); + + nm_bluez5_manager_query_devices (manager); +} + + +static void +watch_name_on_appeared (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer user_data) +{ + check_bluez_and_try_setup (NM_BLUEZ_MANAGER (user_data)); +} + + +static void +check_bluez_and_try_setup_final_step (NMBluezManager *self, int bluez_version, const char *reason) +{ + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + + g_return_if_fail (!priv->bluez_version); + + switch (bluez_version) { + case 4: + setup_bluez4 (self); + break; + case 5: + setup_bluez5 (self); + break; + default: + nm_log_dbg (LOGD_BT, "detecting BlueZ version failed: %s", reason); + + /* cancel current attempts to detect the version. */ + cleanup_checking (self, FALSE); + if (!priv->watch_name_id) { + priv->watch_name_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM, + BLUEZ_SERVICE, + G_BUS_NAME_WATCHER_FLAGS_NONE, + watch_name_on_appeared, + NULL, + self, + NULL); + } + break; + } +} + +static void +check_bluez_and_try_setup_do_introspect (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + NMBluezManager *self = async_data_unpack (user_data); + NMBluezManagerPrivate *priv; + GError *error = NULL; + GVariant *result; + const char *xml_data; + int bluez_version = 0; + const char *reason = NULL; + + if (!self) + return; + + priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + + g_return_if_fail (priv->introspect_proxy); + g_return_if_fail (!g_cancellable_is_cancelled (priv->async_cancellable)); + g_return_if_fail (!priv->bluez_version); + + g_clear_object (&priv->async_cancellable); + + result = g_dbus_proxy_call_finish (priv->introspect_proxy, res, &error); + + if (!result) { + char *reason2 = g_strdup_printf ("introspect failed with %s", error->message); + check_bluez_and_try_setup_final_step (self, 0, reason2); + g_error_free (error); + g_free (reason2); + return; + } + + g_variant_get (result, "(&s)", &xml_data); + + /* might not be the best approach to detect the version, but it's good enough in practice. */ + if (strstr (xml_data, "org.freedesktop.DBus.ObjectManager")) + bluez_version = 5; + else if (strstr (xml_data, BLUEZ4_MANAGER_INTERFACE)) + bluez_version = 4; + else + reason = "unexpected introspect result"; + + g_variant_unref (result); + + check_bluez_and_try_setup_final_step (self, bluez_version, reason); +} + +static void +check_bluez_and_try_setup_on_new_proxy (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + NMBluezManager *self = async_data_unpack (user_data); + NMBluezManagerPrivate *priv; + GError *error = NULL; + + if (!self) + return; + + priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + + g_return_if_fail (!priv->introspect_proxy); + g_return_if_fail (!g_cancellable_is_cancelled (priv->async_cancellable)); + g_return_if_fail (!priv->bluez_version); + + priv->introspect_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + + if (!priv->introspect_proxy) { + char *reason = g_strdup_printf ("bluez error creating dbus proxy: %s", error->message); + check_bluez_and_try_setup_final_step (self, 0, reason); + g_error_free (error); + g_free (reason); + return; + } + + g_dbus_proxy_call (priv->introspect_proxy, + "Introspect", + NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 3000, + priv->async_cancellable, + check_bluez_and_try_setup_do_introspect, + async_data_pack (self)); +} + +static void +check_bluez_and_try_setup (NMBluezManager *self) +{ + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + + g_return_if_fail (!priv->bluez_version); + + /* there should be no ongoing detection. Anyway, cleanup_checking. */ + cleanup_checking (self, FALSE); + + priv->async_cancellable = g_cancellable_new (); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + BLUEZ_SERVICE, + "/", + DBUS_INTERFACE_INTROSPECTABLE, + priv->async_cancellable, + check_bluez_and_try_setup_on_new_proxy, + async_data_pack (self)); +} + +/*********************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_DEVICE_TYPE: + g_value_set_uint (value, PLUGIN_TYPE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + NMBluezManager *self = NM_BLUEZ_MANAGER (object); + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + + if (priv->manager4) { + g_signal_handlers_disconnect_by_func (priv->manager4, manager_bdaddr_added_cb, self); + g_clear_object (&priv->manager4); + } + if (priv->manager5) { + g_signal_handlers_disconnect_by_func (priv->manager5, manager_bdaddr_added_cb, self); + g_clear_object (&priv->manager5); + } + + cleanup_checking (self, TRUE); + + priv->bluez_version = 0; +} + +static void +constructed (GObject *object) +{ + NMBluezManager *self = NM_BLUEZ_MANAGER (object); + + G_OBJECT_CLASS (nm_bluez_manager_parent_class)->constructed (object); + + check_bluez_and_try_setup (self); +} + +static void +nm_bluez_manager_init (NMBluezManager *self) +{ + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + + priv->provider = nm_connection_provider_get (); + g_assert (priv->provider); +} + +static void +device_factory_interface_init (NMDeviceFactory *factory_iface) +{ +} + +static void +nm_bluez_manager_class_init (NMBluezManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (NMBluezManagerPrivate)); + + /* virtual methods */ + object_class->dispose = dispose; + object_class->get_property = get_property; + object_class->constructed = constructed; + + g_object_class_override_property (object_class, + PROP_DEVICE_TYPE, + NM_DEVICE_FACTORY_DEVICE_TYPE); +} + diff --git a/src/devices/bluetooth/nm-bluez-manager.h b/src/devices/bluetooth/nm-bluez-manager.h new file mode 100644 index 0000000000..68d6dbe5e8 --- /dev/null +++ b/src/devices/bluetooth/nm-bluez-manager.h @@ -0,0 +1,44 @@ +/* -*- 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) 2007 - 2008 Novell, Inc. + * Copyright (C) 2007 - 2014 Red Hat, Inc. + */ + +#ifndef NM_BLUEZ_MANAGER_H +#define NM_BLUEZ_MANAGER_H + +#include +#include + +G_BEGIN_DECLS + +#define NM_TYPE_BLUEZ_MANAGER (nm_bluez_manager_get_type ()) +#define NM_BLUEZ_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ_MANAGER, NMBluezManager)) + +#define NM_BLUEZ_MANAGER_BDADDR_ADDED "bdaddr-added" + +typedef struct { + GObject parent; +} NMBluezManager; + +typedef struct { + GObjectClass parent; +} NMBluezManagerClass; + +#endif /* NM_BLUEZ_MANAGER_H */ + diff --git a/src/devices/bluetooth/nm-bluez4-adapter.c b/src/devices/bluetooth/nm-bluez4-adapter.c new file mode 100644 index 0000000000..ad1786f02a --- /dev/null +++ b/src/devices/bluetooth/nm-bluez4-adapter.c @@ -0,0 +1,413 @@ +/* -*- 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 - 2012 Red Hat, Inc. + */ + +#include +#include + +#include "NetworkManager.h" +#include "nm-dbus-manager.h" +#include "nm-bluez4-adapter.h" +#include "nm-bluez-device.h" +#include "nm-bluez-common.h" +#include "nm-dbus-glib-types.h" +#include "nm-logging.h" + + +G_DEFINE_TYPE (NMBluez4Adapter, nm_bluez4_adapter, G_TYPE_OBJECT) + +#define NM_BLUEZ4_ADAPTER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ4_ADAPTER, NMBluez4AdapterPrivate)) + +typedef struct { + char *path; + DBusGProxy *proxy; + gboolean initialized; + + char *address; + GHashTable *devices; + + /* Cached for devices */ + NMConnectionProvider *provider; +} NMBluez4AdapterPrivate; + + +enum { + PROP_0, + PROP_PATH, + PROP_ADDRESS, + + LAST_PROP +}; + +/* Signals */ +enum { + INITIALIZED, + DEVICE_ADDED, + DEVICE_REMOVED, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +static void device_do_remove (NMBluez4Adapter *self, NMBluezDevice *device); + +const char * +nm_bluez4_adapter_get_path (NMBluez4Adapter *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ4_ADAPTER (self), NULL); + + return NM_BLUEZ4_ADAPTER_GET_PRIVATE (self)->path; +} + +const char * +nm_bluez4_adapter_get_address (NMBluez4Adapter *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ4_ADAPTER (self), NULL); + + return NM_BLUEZ4_ADAPTER_GET_PRIVATE (self)->address; +} + +gboolean +nm_bluez4_adapter_get_initialized (NMBluez4Adapter *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ4_ADAPTER (self), FALSE); + + return NM_BLUEZ4_ADAPTER_GET_PRIVATE (self)->initialized; +} + +GSList * +nm_bluez4_adapter_get_devices (NMBluez4Adapter *self) +{ + GSList *devices = NULL; + GHashTableIter iter; + NMBluezDevice *device; + + g_hash_table_iter_init (&iter, NM_BLUEZ4_ADAPTER_GET_PRIVATE (self)->devices); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) { + if (nm_bluez_device_get_usable (device)) + devices = g_slist_append (devices, device); + } + return devices; +} + +static void +emit_device_removed (NMBluez4Adapter *self, NMBluezDevice *device) +{ + nm_log_dbg (LOGD_BT, "(%s): bluez device now unusable", + nm_bluez_device_get_path (device)); + g_signal_emit (self, signals[DEVICE_REMOVED], 0, device); +} + +static void +device_usable (NMBluezDevice *device, GParamSpec *pspec, gpointer user_data) +{ + NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); + + if (nm_bluez_device_get_usable (device)) { + nm_log_dbg (LOGD_BT, "(%s): bluez device now usable (device address is %s)", + nm_bluez_device_get_path (device), + nm_bluez_device_get_address (device)); + g_signal_emit (self, signals[DEVICE_ADDED], 0, device); + } else + emit_device_removed (self, device); +} + +static void +device_initialized (NMBluezDevice *device, gboolean success, gpointer user_data) +{ + NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); + + nm_log_dbg (LOGD_BT, "(%s): bluez device %s", + nm_bluez_device_get_path (device), + success ? "initialized" : "failed to initialize"); + if (!success) + device_do_remove (self, device); +} + +static void +device_do_remove (NMBluez4Adapter *self, NMBluezDevice *device) +{ + NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); + + if (g_hash_table_remove (priv->devices, nm_bluez_device_get_path (device))) { + g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_initialized), self); + g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_usable), self); + + if (nm_bluez_device_get_usable (device)) + emit_device_removed (self, device); + + g_object_unref (device); + } +} + +static void +device_created (DBusGProxy *proxy, const char *path, gpointer user_data) +{ + NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); + NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); + NMBluezDevice *device; + + device = nm_bluez_device_new (path, priv->provider, 4); + g_signal_connect (device, "initialized", G_CALLBACK (device_initialized), self); + g_signal_connect (device, "notify::usable", G_CALLBACK (device_usable), self); + g_hash_table_insert (priv->devices, (gpointer) nm_bluez_device_get_path (device), device); + + nm_log_dbg (LOGD_BT, "(%s): new bluez device found", path); +} + +static void +device_removed (DBusGProxy *proxy, const char *path, gpointer user_data) +{ + NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); + NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); + NMBluezDevice *device; + + nm_log_dbg (LOGD_BT, "(%s): bluez device removed", path); + + device = g_hash_table_lookup (priv->devices, path); + if (device) + device_do_remove (self, device); +} + + +static void +get_properties_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +{ + NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); + NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); + GHashTable *properties = NULL; + GError *err = NULL; + GValue *value; + GPtrArray *devices; + int i; + + if (!dbus_g_proxy_end_call (proxy, call, &err, + DBUS_TYPE_G_MAP_OF_VARIANT, &properties, + G_TYPE_INVALID)) { + nm_log_warn (LOGD_BT, "bluez error getting adapter properties: %s", + err && err->message ? err->message : "(unknown)"); + g_error_free (err); + goto done; + } + + value = g_hash_table_lookup (properties, "Address"); + priv->address = value ? g_value_dup_string (value) : NULL; + + value = g_hash_table_lookup (properties, "Devices"); + devices = value ? g_value_get_boxed (value) : NULL; + + for (i = 0; devices && i < devices->len; i++) + device_created (priv->proxy, g_ptr_array_index (devices, i), self); + + g_hash_table_unref (properties); + + priv->initialized = TRUE; + +done: + g_signal_emit (self, signals[INITIALIZED], 0, priv->initialized); +} + +static void +query_properties (NMBluez4Adapter *self) +{ + NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); + DBusGProxyCall *call; + + call = dbus_g_proxy_begin_call (priv->proxy, "GetProperties", + get_properties_cb, + self, + NULL, G_TYPE_INVALID); + if (!call) { + nm_log_warn (LOGD_BT, "failed to request Bluetooth adapter properties for %s.", + priv->path); + } +} + +/***********************************************************/ + +NMBluez4Adapter * +nm_bluez4_adapter_new (const char *path, NMConnectionProvider *provider) +{ + NMBluez4Adapter *self; + NMBluez4AdapterPrivate *priv; + DBusGConnection *connection; + + self = (NMBluez4Adapter *) g_object_new (NM_TYPE_BLUEZ4_ADAPTER, + NM_BLUEZ4_ADAPTER_PATH, path, + NULL); + if (!self) + return NULL; + + priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); + + priv->provider = provider; + + connection = nm_dbus_manager_get_connection (nm_dbus_manager_get ()); + + priv->proxy = dbus_g_proxy_new_for_name (connection, + BLUEZ_SERVICE, + priv->path, + BLUEZ4_ADAPTER_INTERFACE); + + dbus_g_proxy_add_signal (priv->proxy, "DeviceCreated", + DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "DeviceCreated", + G_CALLBACK (device_created), self, NULL); + + dbus_g_proxy_add_signal (priv->proxy, "DeviceRemoved", + DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "DeviceRemoved", + G_CALLBACK (device_removed), self, NULL); + + query_properties (self); + return self; +} + +static void +nm_bluez4_adapter_init (NMBluez4Adapter *self) +{ + NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); + + priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, NULL); +} + +static gboolean +_find_all (gpointer key, gpointer value, gpointer user_data) +{ + return TRUE; +} + +static void +dispose (GObject *object) +{ + NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (object); + NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); + NMBluezDevice *device; + + while ((device = g_hash_table_find (priv->devices, _find_all, NULL))) + device_do_remove (self, device); + + G_OBJECT_CLASS (nm_bluez4_adapter_parent_class)->dispose (object); +} + +static void +finalize (GObject *object) +{ + NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (object); + + g_hash_table_destroy (priv->devices); + g_free (priv->address); + g_free (priv->path); + g_object_unref (priv->proxy); + + G_OBJECT_CLASS (nm_bluez4_adapter_parent_class)->finalize (object); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_PATH: + g_value_set_string (value, priv->path); + break; + case PROP_ADDRESS: + g_value_set_string (value, priv->address); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_PATH: + /* construct only */ + priv->path = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_bluez4_adapter_class_init (NMBluez4AdapterClass *config_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (config_class); + + g_type_class_add_private (config_class, sizeof (NMBluez4AdapterPrivate)); + + /* virtual methods */ + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->dispose = dispose; + object_class->finalize = finalize; + + /* Properties */ + g_object_class_install_property + (object_class, PROP_PATH, + g_param_spec_string (NM_BLUEZ4_ADAPTER_PATH, + "DBus Path", + "DBus Path", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, PROP_ADDRESS, + g_param_spec_string (NM_BLUEZ4_ADAPTER_ADDRESS, + "Address", + "Address", + NULL, + G_PARAM_READABLE)); + + /* Signals */ + signals[INITIALIZED] = g_signal_new ("initialized", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMBluez4AdapterClass, initialized), + NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + + signals[DEVICE_ADDED] = g_signal_new ("device-added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMBluez4AdapterClass, device_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[DEVICE_REMOVED] = g_signal_new ("device-removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMBluez4AdapterClass, device_removed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); +} + diff --git a/src/devices/bluetooth/nm-bluez4-adapter.h b/src/devices/bluetooth/nm-bluez4-adapter.h new file mode 100644 index 0000000000..454ca557eb --- /dev/null +++ b/src/devices/bluetooth/nm-bluez4-adapter.h @@ -0,0 +1,69 @@ +/* -*- 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 - 2012 Red Hat, Inc. + */ + +#ifndef NM_BLUEZ4_ADAPTER_H +#define NM_BLUEZ4_ADAPTER_H + +#include +#include + +#include "nm-bluez-device.h" +#include "nm-connection-provider.h" + +#define NM_TYPE_BLUEZ4_ADAPTER (nm_bluez4_adapter_get_type ()) +#define NM_BLUEZ4_ADAPTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ4_ADAPTER, NMBluez4Adapter)) +#define NM_BLUEZ4_ADAPTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ4_ADAPTER, NMBluez4AdapterClass)) +#define NM_IS_BLUEZ4_ADAPTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ4_ADAPTER)) +#define NM_IS_BLUEZ4_ADAPTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_BLUEZ4_ADAPTER)) +#define NM_BLUEZ4_ADAPTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ4_ADAPTER, NMBluez4AdapterClass)) + +#define NM_BLUEZ4_ADAPTER_PATH "path" +#define NM_BLUEZ4_ADAPTER_ADDRESS "address" + +typedef struct { + GObject parent; +} NMBluez4Adapter; + +typedef struct { + GObjectClass parent; + + /* virtual functions */ + void (*initialized) (NMBluez4Adapter *self, gboolean success); + + void (*device_added) (NMBluez4Adapter *self, NMBluezDevice *device); + + void (*device_removed) (NMBluez4Adapter *self, NMBluezDevice *device); +} NMBluez4AdapterClass; + +GType nm_bluez4_adapter_get_type (void); + +NMBluez4Adapter *nm_bluez4_adapter_new (const char *path, + NMConnectionProvider *provider); + +const char *nm_bluez4_adapter_get_path (NMBluez4Adapter *self); + +const char *nm_bluez4_adapter_get_address (NMBluez4Adapter *self); + +gboolean nm_bluez4_adapter_get_initialized (NMBluez4Adapter *self); + +GSList *nm_bluez4_adapter_get_devices (NMBluez4Adapter *self); + +#endif /* NM_BLUEZ4_ADAPTER_H */ + diff --git a/src/devices/bluetooth/nm-bluez4-manager.c b/src/devices/bluetooth/nm-bluez4-manager.c new file mode 100644 index 0000000000..2660cbd924 --- /dev/null +++ b/src/devices/bluetooth/nm-bluez4-manager.c @@ -0,0 +1,361 @@ +/* -*- 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) 2007 - 2008 Novell, Inc. + * Copyright (C) 2007 - 2013 Red Hat, Inc. + */ + +#include +#include +#include +#include + +#include "nm-logging.h" +#include "nm-dbus-glib-types.h" +#include "nm-bluez-manager.h" +#include "nm-bluez4-manager.h" +#include "nm-bluez4-adapter.h" +#include "nm-dbus-manager.h" +#include "nm-bluez-common.h" + + +typedef struct { + NMDBusManager *dbus_mgr; + gulong name_owner_changed_id; + + NMConnectionProvider *provider; + + DBusGProxy *proxy; + + NMBluez4Adapter *adapter; +} NMBluez4ManagerPrivate; + +#define NM_BLUEZ4_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ4_MANAGER, NMBluez4ManagerPrivate)) + +G_DEFINE_TYPE (NMBluez4Manager, nm_bluez4_manager, G_TYPE_OBJECT) + +enum { + BDADDR_ADDED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void + +emit_bdaddr_added (NMBluez4Manager *self, NMBluezDevice *device) +{ + g_signal_emit (self, signals[BDADDR_ADDED], 0, + device, + nm_bluez_device_get_address (device), + nm_bluez_device_get_name (device), + nm_bluez_device_get_path (device), + nm_bluez_device_get_capabilities (device)); +} + +void +nm_bluez4_manager_query_devices (NMBluez4Manager *self) +{ + NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + GSList *devices, *iter; + + if (!priv->adapter) + return; + + devices = nm_bluez4_adapter_get_devices (priv->adapter); + for (iter = devices; iter; iter = g_slist_next (iter)) + emit_bdaddr_added (self, NM_BLUEZ_DEVICE (iter->data)); + g_slist_free (devices); +} + +static void +device_added (NMBluez4Adapter *adapter, NMBluezDevice *device, gpointer user_data) +{ + emit_bdaddr_added (NM_BLUEZ4_MANAGER (user_data), device); +} + +static void +device_removed (NMBluez4Adapter *adapter, NMBluezDevice *device, gpointer user_data) +{ + /* Re-emit the signal on the device for now; flatten this later */ + g_signal_emit_by_name (device, NM_BLUEZ_DEVICE_REMOVED); +} + +static void +adapter_initialized (NMBluez4Adapter *adapter, gboolean success, gpointer user_data) +{ + NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data); + NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + + if (success) { + GSList *devices, *iter; + + devices = nm_bluez4_adapter_get_devices (adapter); + for (iter = devices; iter; iter = g_slist_next (iter)) + emit_bdaddr_added (self, NM_BLUEZ_DEVICE (iter->data)); + g_slist_free (devices); + + g_signal_connect (adapter, "device-added", G_CALLBACK (device_added), self); + g_signal_connect (adapter, "device-removed", G_CALLBACK (device_removed), self); + } else { + g_object_unref (priv->adapter); + priv->adapter = NULL; + } +} + +static void +adapter_removed (DBusGProxy *proxy, const char *path, NMBluez4Manager *self) +{ + NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + + if (priv->adapter && !strcmp (path, nm_bluez4_adapter_get_path (priv->adapter))) { + if (nm_bluez4_adapter_get_initialized (priv->adapter)) { + GSList *devices, *iter; + + devices = nm_bluez4_adapter_get_devices (priv->adapter); + for (iter = devices; iter; iter = g_slist_next (iter)) + g_signal_emit_by_name (NM_BLUEZ_DEVICE (iter->data), NM_BLUEZ_DEVICE_REMOVED); + g_slist_free (devices); + } + + g_object_unref (priv->adapter); + priv->adapter = NULL; + } +} + +static void +default_adapter_changed (DBusGProxy *proxy, const char *path, NMBluez4Manager *self) +{ + NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + const char *cur_path = NULL; + + if (priv->adapter) + cur_path = nm_bluez4_adapter_get_path (priv->adapter); + + if (cur_path) { + if (!path || strcmp (path, cur_path)) { + /* Default adapter changed */ + adapter_removed (priv->proxy, cur_path, self); + } else { + /* This adapter is already the default */ + return; + } + } + + /* Add the new default adapter */ + if (path) { + priv->adapter = nm_bluez4_adapter_new (path, priv->provider); + g_signal_connect (priv->adapter, "initialized", G_CALLBACK (adapter_initialized), self); + } +} + +static void +default_adapter_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +{ + NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data); + NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + const char *default_adapter = NULL; + GError *err = NULL; + + if (!dbus_g_proxy_end_call (proxy, call, &err, + DBUS_TYPE_G_OBJECT_PATH, &default_adapter, + G_TYPE_INVALID)) { + /* Ignore "No such adapter" errors; just means bluetooth isn't active */ + if ( !dbus_g_error_has_name (err, "org.bluez.Error.NoSuchAdapter") + && !dbus_g_error_has_name (err, "org.freedesktop.systemd1.LoadFailed") + && !g_error_matches (err, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN)) { + nm_log_warn (LOGD_BT, "bluez error getting default adapter: %s", + err && err->message ? err->message : "(unknown)"); + } + g_error_free (err); + return; + } + + default_adapter_changed (priv->proxy, default_adapter, self); +} + +static void +query_default_adapter (NMBluez4Manager *self) +{ + NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + DBusGProxyCall *call; + + call = dbus_g_proxy_begin_call (priv->proxy, "DefaultAdapter", + default_adapter_cb, + self, + NULL, G_TYPE_INVALID); + if (!call) + nm_log_warn (LOGD_BT, "failed to request default Bluetooth adapter."); +} + +static void +bluez_connect (NMBluez4Manager *self) +{ + NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + DBusGConnection *connection; + + g_return_if_fail (priv->proxy == NULL); + + connection = nm_dbus_manager_get_connection (priv->dbus_mgr); + if (!connection) + return; + + priv->proxy = dbus_g_proxy_new_for_name (connection, + BLUEZ_SERVICE, + BLUEZ_MANAGER_PATH, + BLUEZ4_MANAGER_INTERFACE); + + dbus_g_proxy_add_signal (priv->proxy, "AdapterRemoved", + DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "AdapterRemoved", + G_CALLBACK (adapter_removed), self, NULL); + + dbus_g_proxy_add_signal (priv->proxy, "DefaultAdapterChanged", + DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "DefaultAdapterChanged", + G_CALLBACK (default_adapter_changed), self, NULL); + + query_default_adapter (self); +} + +static void +name_owner_changed_cb (NMDBusManager *dbus_mgr, + const char *name, + const char *old_owner, + const char *new_owner, + gpointer user_data) +{ + NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data); + NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + gboolean old_owner_good = (old_owner && strlen (old_owner)); + gboolean new_owner_good = (new_owner && strlen (new_owner)); + + /* Can't handle the signal if its not from the Bluez */ + if (strcmp (BLUEZ_SERVICE, name)) + return; + + if (!old_owner_good && new_owner_good) + query_default_adapter (self); + else if (old_owner_good && !new_owner_good) { + /* Throwing away the adapter removes all devices too */ + if (priv->adapter) { + g_object_unref (priv->adapter); + priv->adapter = NULL; + } + } +} + +static void +bluez_cleanup (NMBluez4Manager *self, gboolean do_signal) +{ + NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + + if (priv->proxy) { + g_object_unref (priv->proxy); + priv->proxy = NULL; + } + + if (priv->adapter) { + g_object_unref (priv->adapter); + priv->adapter = NULL; + } +} + +static void +dbus_connection_changed_cb (NMDBusManager *dbus_mgr, + DBusGConnection *connection, + gpointer user_data) +{ + NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data); + + if (!connection) + bluez_cleanup (self, TRUE); + else + bluez_connect (self); +} + +/****************************************************************/ + +NMBluez4Manager * +nm_bluez4_manager_new (NMConnectionProvider *provider) +{ + NMBluez4Manager *instance; + + instance = g_object_new (NM_TYPE_BLUEZ4_MANAGER, NULL); + NM_BLUEZ4_MANAGER_GET_PRIVATE (instance)->provider = provider; + return instance; +} + +static void +nm_bluez4_manager_init (NMBluez4Manager *self) +{ + NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + + priv->dbus_mgr = nm_dbus_manager_get (); + g_assert (priv->dbus_mgr); + + g_signal_connect (priv->dbus_mgr, + NM_DBUS_MANAGER_NAME_OWNER_CHANGED, + G_CALLBACK (name_owner_changed_cb), + self); + + g_signal_connect (priv->dbus_mgr, + NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED, + G_CALLBACK (dbus_connection_changed_cb), + self); + + bluez_connect (self); +} + +static void +dispose (GObject *object) +{ + NMBluez4Manager *self = NM_BLUEZ4_MANAGER (object); + NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + + bluez_cleanup (self, FALSE); + + if (priv->dbus_mgr) { + g_signal_handlers_disconnect_by_func (priv->dbus_mgr, name_owner_changed_cb, self); + g_signal_handlers_disconnect_by_func (priv->dbus_mgr, dbus_connection_changed_cb, self); + priv->dbus_mgr = NULL; + } + + G_OBJECT_CLASS (nm_bluez4_manager_parent_class)->dispose (object); +} + +static void +nm_bluez4_manager_class_init (NMBluez4ManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (NMBluez4ManagerPrivate)); + + /* virtual methods */ + object_class->dispose = dispose; + + /* Signals */ + signals[BDADDR_ADDED] = + g_signal_new (NM_BLUEZ_MANAGER_BDADDR_ADDED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMBluez4ManagerClass, bdaddr_added), + NULL, NULL, NULL, + G_TYPE_NONE, 5, G_TYPE_OBJECT, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT); +} + diff --git a/src/devices/bluetooth/nm-bluez4-manager.h b/src/devices/bluetooth/nm-bluez4-manager.h new file mode 100644 index 0000000000..19b1c65a1b --- /dev/null +++ b/src/devices/bluetooth/nm-bluez4-manager.h @@ -0,0 +1,62 @@ +/* -*- 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) 2007 - 2008 Novell, Inc. + * Copyright (C) 2007 - 2013 Red Hat, Inc. + */ + +#ifndef NM_BLUEZ4_MANAGER_H +#define NM_BLUEZ4_MANAGER_H + +#include +#include + +#include +#include "nm-connection-provider.h" + +G_BEGIN_DECLS + +#define NM_TYPE_BLUEZ4_MANAGER (nm_bluez4_manager_get_type ()) +#define NM_BLUEZ4_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ4_MANAGER, NMBluez4Manager)) +#define NM_BLUEZ4_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ4_MANAGER, NMBluez4ManagerClass)) +#define NM_IS_BLUEZ4_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ4_MANAGER)) +#define NM_IS_BLUEZ4_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_BLUEZ4_MANAGER)) +#define NM_BLUEZ4_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ4_MANAGER, NMBluez4ManagerClass)) + +typedef struct { + GObject parent; +} NMBluez4Manager; + +typedef struct { + GObjectClass parent; + + /* Signals */ + void (*bdaddr_added) (NMBluez4Manager *manager, + const char *bdaddr, + const char *name, + const char *object_path, + guint uuids); +} NMBluez4ManagerClass; + +GType nm_bluez4_manager_get_type (void); + +NMBluez4Manager *nm_bluez4_manager_new (NMConnectionProvider *provider); + +void nm_bluez4_manager_query_devices (NMBluez4Manager *manager); + +#endif /* NM_BLUEZ4_MANAGER_H */ + diff --git a/src/devices/bluetooth/nm-bluez5-manager.c b/src/devices/bluetooth/nm-bluez5-manager.c new file mode 100644 index 0000000000..63006b3ab8 --- /dev/null +++ b/src/devices/bluetooth/nm-bluez5-manager.c @@ -0,0 +1,421 @@ +/* -*- 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) 2007 - 2008 Novell, Inc. + * Copyright (C) 2007 - 2013 Red Hat, Inc. + * Copyright (C) 2013 Intel Corporation. + */ + +#include +#include +#include +#include + +#include "nm-logging.h" +#include "nm-bluez-manager.h" +#include "nm-bluez5-manager.h" +#include "nm-bluez-device.h" +#include "nm-bluez-common.h" + +#include "nm-dbus-manager.h" + +typedef struct { + NMDBusManager *dbus_mgr; + gulong name_owner_changed_id; + + NMConnectionProvider *provider; + + GDBusProxy *proxy; + + GHashTable *devices; +} NMBluez5ManagerPrivate; + +#define NM_BLUEZ5_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ5_MANAGER, NMBluez5ManagerPrivate)) + +G_DEFINE_TYPE (NMBluez5Manager, nm_bluez5_manager, G_TYPE_OBJECT) + +enum { + BDADDR_ADDED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void device_initialized (NMBluezDevice *device, gboolean success, NMBluez5Manager *self); +static void device_usable (NMBluezDevice *device, GParamSpec *pspec, NMBluez5Manager *self); + +static void +emit_bdaddr_added (NMBluez5Manager *self, NMBluezDevice *device) +{ + g_signal_emit (self, signals[BDADDR_ADDED], 0, + device, + nm_bluez_device_get_address (device), + nm_bluez_device_get_name (device), + nm_bluez_device_get_path (device), + nm_bluez_device_get_capabilities (device)); +} + +void +nm_bluez5_manager_query_devices (NMBluez5Manager *self) +{ + NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); + NMBluezDevice *device; + GHashTableIter iter; + + g_hash_table_iter_init (&iter, priv->devices); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) { + if (nm_bluez_device_get_usable (device)) + emit_bdaddr_added (self, device); + } +} + +static void +remove_device (NMBluez5Manager *self, NMBluezDevice *device) +{ + g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_initialized), self); + g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_usable), self); + if (nm_bluez_device_get_usable (device)) + g_signal_emit_by_name (device, NM_BLUEZ_DEVICE_REMOVED); +} + +static void +remove_all_devices (NMBluez5Manager *self) +{ + GHashTableIter iter; + NMBluezDevice *device; + NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); + + g_hash_table_iter_init (&iter, priv->devices); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) { + g_hash_table_iter_steal (&iter); + remove_device (self, device); + g_object_unref (device); + } +} + +static void +device_usable (NMBluezDevice *device, GParamSpec *pspec, NMBluez5Manager *self) +{ + gboolean usable = nm_bluez_device_get_usable (device); + + nm_log_dbg (LOGD_BT, "(%s): bluez device now %s", + nm_bluez_device_get_path (device), + usable ? "usable" : "unusable"); + + if (usable) { + nm_log_dbg (LOGD_BT, "(%s): bluez device address %s", + nm_bluez_device_get_path (device), + nm_bluez_device_get_address (device)); + emit_bdaddr_added (self, device); + } else + g_signal_emit_by_name (device, NM_BLUEZ_DEVICE_REMOVED); +} + +static void +device_initialized (NMBluezDevice *device, gboolean success, NMBluez5Manager *self) +{ + NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); + + nm_log_dbg (LOGD_BT, "(%s): bluez device %s", + nm_bluez_device_get_path (device), + success ? "initialized" : "failed to initialize"); + if (!success) + g_hash_table_remove (priv->devices, nm_bluez_device_get_path (device)); +} + +static void +device_added (GDBusProxy *proxy, const gchar *path, NMBluez5Manager *self) +{ + NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); + NMBluezDevice *device; + + device = nm_bluez_device_new (path, priv->provider, 5); + g_signal_connect (device, "initialized", G_CALLBACK (device_initialized), self); + g_signal_connect (device, "notify::usable", G_CALLBACK (device_usable), self); + g_hash_table_insert (priv->devices, (gpointer) nm_bluez_device_get_path (device), device); + + nm_log_dbg (LOGD_BT, "(%s): new bluez device found", path); +} + +static void +device_removed (GDBusProxy *proxy, const gchar *path, NMBluez5Manager *self) +{ + NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); + NMBluezDevice *device; + + nm_log_dbg (LOGD_BT, "(%s): bluez device removed", path); + + device = g_hash_table_lookup (priv->devices, path); + if (device) { + g_hash_table_steal (priv->devices, nm_bluez_device_get_path (device)); + remove_device (NM_BLUEZ5_MANAGER (self), device); + g_object_unref (device); + } +} + +static void +object_manager_g_signal (GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + NMBluez5Manager *self) +{ + GVariant *variant; + const gchar *path; + + if (!strcmp (signal_name, "InterfacesRemoved")) { + const gchar **ifaces; + gsize i, length; + + g_variant_get (parameters, "(&o*)", &path, &variant); + + ifaces = g_variant_get_strv (variant, &length); + + for (i = 0; i < length; i++) { + if (!strcmp (ifaces[i], BLUEZ5_DEVICE_INTERFACE)) { + device_removed (proxy, path, self); + break; + } + } + + g_free (ifaces); + + } else if (!strcmp (signal_name, "InterfacesAdded")) { + g_variant_get (parameters, "(&o*)", &path, &variant); + + if (g_variant_lookup_value (variant, BLUEZ5_DEVICE_INTERFACE, + G_VARIANT_TYPE_DICTIONARY)) + device_added (proxy, path, self); + } +} + +static void +get_managed_objects_cb (GDBusProxy *proxy, + GAsyncResult *res, + NMBluez5Manager *self) +{ + GVariant *variant, *ifaces; + GVariantIter i; + GError *error = NULL; + const char *path; + + variant = g_dbus_proxy_call_finish (proxy, res, &error); + + if (!variant) { + if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) + nm_log_warn (LOGD_BT, "Couldn't get managed objects: not running Bluez5?"); + else { + nm_log_warn (LOGD_BT, "Couldn't get managed objects: %s", + error && error->message ? error->message : "(unknown)"); + } + g_clear_error (&error); + return; + } + g_variant_iter_init (&i, g_variant_get_child_value (variant, 0)); + while ((g_variant_iter_next (&i, "{&o*}", &path, &ifaces))) { + if (g_variant_lookup_value (ifaces, BLUEZ5_DEVICE_INTERFACE, + G_VARIANT_TYPE_DICTIONARY)) { + device_added (proxy, path, self); + } + } + + g_variant_unref (variant); +} + +static void +on_proxy_acquired (GObject *object, + GAsyncResult *res, + NMBluez5Manager *self) +{ + NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); + GError *error = NULL; + + priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + + if (!priv->proxy) { + nm_log_warn (LOGD_BT, "Couldn't acquire object manager proxy: %s", + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + return; + } + + /* Get already managed devices. */ + g_dbus_proxy_call (priv->proxy, "GetManagedObjects", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback) get_managed_objects_cb, + self); + + g_signal_connect (priv->proxy, "g-signal", + G_CALLBACK (object_manager_g_signal), self); +} + +static void +bluez_connect (NMBluez5Manager *self) +{ + NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); + + g_return_if_fail (priv->proxy == NULL); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + BLUEZ_SERVICE, + BLUEZ_MANAGER_PATH, + OBJECT_MANAGER_INTERFACE, + NULL, + (GAsyncReadyCallback) on_proxy_acquired, + self); +} + +static void +name_owner_changed_cb (NMDBusManager *dbus_mgr, + const char *name, + const char *old_owner, + const char *new_owner, + gpointer user_data) +{ + NMBluez5Manager *self = NM_BLUEZ5_MANAGER (user_data); + NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); + gboolean old_owner_good = (old_owner && strlen (old_owner)); + gboolean new_owner_good = (new_owner && strlen (new_owner)); + + /* Can't handle the signal if its not from the Bluez */ + if (strcmp (BLUEZ_SERVICE, name)) + return; + + if (old_owner_good && !new_owner_good) { + if (priv->devices) + remove_all_devices (self); + } +} + +static void +bluez_cleanup (NMBluez5Manager *self, gboolean do_signal) +{ + NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); + + if (priv->proxy) { + g_object_unref (priv->proxy); + priv->proxy = NULL; + } + + if (do_signal) + remove_all_devices (self); + else + g_hash_table_remove_all (priv->devices); +} + +static void +dbus_connection_changed_cb (NMDBusManager *dbus_mgr, + DBusGConnection *connection, + gpointer user_data) +{ + NMBluez5Manager *self = NM_BLUEZ5_MANAGER (user_data); + + if (!connection) + bluez_cleanup (self, TRUE); + else + bluez_connect (self); +} + +/****************************************************************/ + +NMBluez5Manager * +nm_bluez5_manager_new (NMConnectionProvider *provider) +{ + NMBluez5Manager *instance = NULL; + + instance = g_object_new (NM_TYPE_BLUEZ5_MANAGER, NULL); + NM_BLUEZ5_MANAGER_GET_PRIVATE (instance)->provider = provider; + return instance; +} + +static void +nm_bluez5_manager_init (NMBluez5Manager *self) +{ + NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); + + priv->dbus_mgr = nm_dbus_manager_get (); + g_assert (priv->dbus_mgr); + + g_signal_connect (priv->dbus_mgr, + NM_DBUS_MANAGER_NAME_OWNER_CHANGED, + G_CALLBACK (name_owner_changed_cb), + self); + + g_signal_connect (priv->dbus_mgr, + NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED, + G_CALLBACK (dbus_connection_changed_cb), + self); + + bluez_connect (self); + + priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, g_object_unref); +} + +static void +dispose (GObject *object) +{ + NMBluez5Manager *self = NM_BLUEZ5_MANAGER (object); + NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); + + bluez_cleanup (self, FALSE); + + if (priv->dbus_mgr) { + g_signal_handlers_disconnect_by_func (priv->dbus_mgr, name_owner_changed_cb, self); + g_signal_handlers_disconnect_by_func (priv->dbus_mgr, dbus_connection_changed_cb, self); + priv->dbus_mgr = NULL; + } + + G_OBJECT_CLASS (nm_bluez5_manager_parent_class)->dispose (object); +} + +static void +finalize (GObject *object) +{ + NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (object); + + g_hash_table_destroy (priv->devices); + + G_OBJECT_CLASS (nm_bluez5_manager_parent_class)->finalize (object); +} + +static void +nm_bluez5_manager_class_init (NMBluez5ManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (NMBluez5ManagerPrivate)); + + /* virtual methods */ + object_class->dispose = dispose; + object_class->finalize = finalize; + + /* Signals */ + signals[BDADDR_ADDED] = + g_signal_new (NM_BLUEZ_MANAGER_BDADDR_ADDED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMBluez5ManagerClass, bdaddr_added), + NULL, NULL, NULL, + G_TYPE_NONE, 5, G_TYPE_OBJECT, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT); +} diff --git a/src/devices/bluetooth/nm-bluez5-manager.h b/src/devices/bluetooth/nm-bluez5-manager.h new file mode 100644 index 0000000000..79f347bcef --- /dev/null +++ b/src/devices/bluetooth/nm-bluez5-manager.h @@ -0,0 +1,62 @@ +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ +/* 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) 2007 - 2008 Novell, Inc. + * Copyright (C) 2007 - 2013 Red Hat, Inc. + */ + +#ifndef NM_BLUEZ5_MANAGER_H +#define NM_BLUEZ5_MANAGER_H + +#include +#include + +#include +#include "nm-connection-provider.h" + +G_BEGIN_DECLS + +#define NM_TYPE_BLUEZ5_MANAGER (nm_bluez5_manager_get_type ()) +#define NM_BLUEZ5_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ5_MANAGER, NMBluez5Manager)) +#define NM_BLUEZ5_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ5_MANAGER, NMBluez5ManagerClass)) +#define NM_IS_BLUEZ5_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ5_MANAGER)) +#define NM_IS_BLUEZ5_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_BLUEZ5_MANAGER)) +#define NM_BLUEZ5_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ5_MANAGER, NMBluez5ManagerClass)) + +typedef struct { + GObject parent; +} NMBluez5Manager; + +typedef struct { + GObjectClass parent; + + /* Signals */ + void (*bdaddr_added) (NMBluez5Manager *manager, + const char *bdaddr, + const char *name, + const char *object_path, + guint uuids); +} NMBluez5ManagerClass; + +GType nm_bluez5_manager_get_type (void); + +NMBluez5Manager *nm_bluez5_manager_new (NMConnectionProvider *provider); + +void nm_bluez5_manager_query_devices (NMBluez5Manager *manager); + +#endif /* NM_BLUEZ5_MANAGER_H */ + diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c new file mode 100644 index 0000000000..6998bb1e20 --- /dev/null +++ b/src/devices/bluetooth/nm-device-bt.c @@ -0,0 +1,1259 @@ +/* -*- 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 - 2011 Red Hat, Inc. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include + +#include "nm-glib-compat.h" +#include "nm-bluez-common.h" +#include "nm-bluez-device.h" +#include "nm-dbus-manager.h" +#include "nm-device-bt.h" +#include "nm-device-private.h" +#include "nm-logging.h" +#include "ppp-manager/nm-ppp-manager.h" +#include "nm-setting-connection.h" +#include "nm-setting-bluetooth.h" +#include "nm-setting-cdma.h" +#include "nm-setting-gsm.h" +#include "nm-setting-serial.h" +#include "nm-setting-ppp.h" +#include "nm-device-bt-glue.h" +#include "NetworkManagerUtils.h" +#include "nm-bt-enum-types.h" +#include "nm-utils.h" + +#define MM_OLD_DBUS_SERVICE "org.freedesktop.ModemManager" +#define MM_NEW_DBUS_SERVICE "org.freedesktop.ModemManager1" + +G_DEFINE_TYPE (NMDeviceBt, nm_device_bt, NM_TYPE_DEVICE) + +#define NM_DEVICE_BT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_BT, NMDeviceBtPrivate)) + +static gboolean modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *reason); + +typedef struct { + NMDBusManager *dbus_mgr; + guint mm_watch_id; + gboolean mm_running; + + NMBluezDevice *bt_device; + + char *bdaddr; + char *name; + guint32 capabilities; + + gboolean connected; + gboolean have_iface; + + char *rfcomm_iface; + NMModem *modem; + guint32 timeout_id; + + guint32 bt_type; /* BT type of the current connection */ +} NMDeviceBtPrivate; + +enum { + PROP_0, + PROP_BT_NAME, + PROP_BT_CAPABILITIES, + PROP_BT_DEVICE, + + LAST_PROP +}; + +enum { + PPP_STATS, + + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + + +#define NM_BT_ERROR (nm_bt_error_quark ()) + +static GQuark +nm_bt_error_quark (void) +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string ("nm-bt-error"); + return quark; +} + +guint32 nm_device_bt_get_capabilities (NMDeviceBt *self) +{ + g_return_val_if_fail (NM_IS_DEVICE_BT (self), NM_BT_CAPABILITY_NONE); + + return NM_DEVICE_BT_GET_PRIVATE (self)->capabilities; +} + +static guint +get_hw_address_length (NMDevice *device, gboolean *out_permanent) +{ + /* HW address is the Bluetooth HW address of the remote device */ + if (out_permanent) + *out_permanent = TRUE; /* the bdaddr of the remote device will never change */ + return ETH_ALEN; +} + +static guint32 +get_connection_bt_type (NMConnection *connection) +{ + NMSettingBluetooth *s_bt; + const char *bt_type; + + s_bt = nm_connection_get_setting_bluetooth (connection); + if (!s_bt) + return NM_BT_CAPABILITY_NONE; + + bt_type = nm_setting_bluetooth_get_connection_type (s_bt); + g_assert (bt_type); + + if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN)) + return NM_BT_CAPABILITY_DUN; + else if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU)) + return NM_BT_CAPABILITY_NAP; + + return NM_BT_CAPABILITY_NONE; +} + +static gboolean +can_auto_connect (NMDevice *device, + NMConnection *connection, + char **specific_object) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); + guint32 bt_type; + + if (!NM_DEVICE_CLASS (nm_device_bt_parent_class)->can_auto_connect (device, connection, specific_object)) + return FALSE; + + /* Can't auto-activate a DUN connection without ModemManager */ + bt_type = get_connection_bt_type (connection); + if (bt_type == NM_BT_CAPABILITY_DUN && priv->mm_running == FALSE) + return FALSE; + + return TRUE; +} + +static gboolean +check_connection_compatible (NMDevice *device, + NMConnection *connection, + GError **error) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); + NMSettingConnection *s_con; + NMSettingBluetooth *s_bt; + const GByteArray *array; + char *str; + int addr_match = FALSE; + guint32 bt_type; + + if (!NM_DEVICE_CLASS (nm_device_bt_parent_class)->check_connection_compatible (device, connection, error)) + return FALSE; + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + + if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_BLUETOOTH_SETTING_NAME)) { + g_set_error (error, + NM_BT_ERROR, NM_BT_ERROR_CONNECTION_NOT_BT, + "The connection was not a Bluetooth connection."); + return FALSE; + } + + s_bt = nm_connection_get_setting_bluetooth (connection); + if (!s_bt) { + g_set_error (error, + NM_BT_ERROR, NM_BT_ERROR_CONNECTION_INVALID, + "The connection was not a valid Bluetooth connection."); + return FALSE; + } + + array = nm_setting_bluetooth_get_bdaddr (s_bt); + if (!array || (array->len != ETH_ALEN)) { + g_set_error (error, + NM_BT_ERROR, NM_BT_ERROR_CONNECTION_INVALID, + "The connection did not contain a valid Bluetooth address."); + return FALSE; + } + + bt_type = get_connection_bt_type (connection); + if (!(bt_type & priv->capabilities)) { + g_set_error (error, + NM_BT_ERROR, NM_BT_ERROR_CONNECTION_INCOMPATIBLE, + "The connection was not compatible with the device's capabilities."); + return FALSE; + } + + str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", + array->data[0], array->data[1], array->data[2], + array->data[3], array->data[4], array->data[5]); + addr_match = !strcmp (priv->bdaddr, str); + g_free (str); + + return addr_match; +} + +static gboolean +check_connection_available (NMDevice *device, + NMConnection *connection, + const char *specific_object) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); + guint32 bt_type; + + bt_type = get_connection_bt_type (connection); + if (!(bt_type & priv->capabilities)) + return FALSE; + + /* DUN connections aren't available without ModemManager */ + if (bt_type == NM_BT_CAPABILITY_DUN && priv->mm_running == FALSE) + return FALSE; + + return TRUE; +} + +static gboolean +complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); + NMSettingBluetooth *s_bt; + const GByteArray *setting_bdaddr; + struct ether_addr *devaddr = ether_aton (priv->bdaddr); + const char *ctype; + gboolean is_dun = FALSE, is_pan = FALSE; + NMSettingGsm *s_gsm; + NMSettingCdma *s_cdma; + NMSettingSerial *s_serial; + NMSettingPPP *s_ppp; + const char *format = NULL, *preferred = NULL; + + s_gsm = nm_connection_get_setting_gsm (connection); + s_cdma = nm_connection_get_setting_cdma (connection); + s_serial = nm_connection_get_setting_serial (connection); + s_ppp = nm_connection_get_setting_ppp (connection); + + s_bt = nm_connection_get_setting_bluetooth (connection); + if (!s_bt) { + s_bt = (NMSettingBluetooth *) nm_setting_bluetooth_new (); + nm_connection_add_setting (connection, NM_SETTING (s_bt)); + } + + ctype = nm_setting_bluetooth_get_connection_type (s_bt); + if (ctype) { + if (!strcmp (ctype, NM_SETTING_BLUETOOTH_TYPE_DUN)) + is_dun = TRUE; + else if (!strcmp (ctype, NM_SETTING_BLUETOOTH_TYPE_PANU)) + is_pan = TRUE; + } else { + if (s_gsm || s_cdma) + is_dun = TRUE; + else if (priv->capabilities & NM_BT_CAPABILITY_NAP) + is_pan = TRUE; + } + + if (is_pan) { + /* Make sure the device supports PAN */ + if (!(priv->capabilities & NM_BT_CAPABILITY_NAP)) { + g_set_error_literal (error, + NM_SETTING_BLUETOOTH_ERROR, + NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, + "PAN required but Bluetooth device does not support NAP"); + return FALSE; + } + + /* PAN can't use any DUN-related settings */ + if (s_gsm || s_cdma || s_serial || s_ppp) { + g_set_error_literal (error, + NM_SETTING_BLUETOOTH_ERROR, + NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, + "PAN incompatible with GSM, CDMA, or serial settings"); + return FALSE; + } + + g_object_set (G_OBJECT (s_bt), + NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU, + NULL); + + format = _("PAN connection %d"); + } else if (is_dun) { + /* Make sure the device supports PAN */ + if (!(priv->capabilities & NM_BT_CAPABILITY_DUN)) { + g_set_error_literal (error, + NM_SETTING_BLUETOOTH_ERROR, + NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, + "DUN required but Bluetooth device does not support DUN"); + return FALSE; + } + + /* Need at least a GSM or a CDMA setting */ + if (!s_gsm && !s_cdma) { + g_set_error_literal (error, + NM_SETTING_BLUETOOTH_ERROR, + NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, + "Setting requires DUN but no GSM or CDMA setting is present"); + return FALSE; + } + + g_object_set (G_OBJECT (s_bt), + NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_DUN, + NULL); + + if (s_gsm) { + format = _("GSM connection %d"); + if (!nm_setting_gsm_get_number (s_gsm)) + g_object_set (G_OBJECT (s_gsm), NM_SETTING_GSM_NUMBER, "*99#", NULL); + } else if (s_cdma) { + format = _("CDMA connection %d"); + if (!nm_setting_cdma_get_number (s_cdma)) + g_object_set (G_OBJECT (s_cdma), NM_SETTING_GSM_NUMBER, "#777", NULL); + } else + format = _("DUN connection %d"); + } else { + g_set_error_literal (error, + NM_SETTING_BLUETOOTH_ERROR, + NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, + "Unknown/unhandled Bluetooth connection type"); + return FALSE; + } + + nm_utils_complete_generic (connection, + NM_SETTING_BLUETOOTH_SETTING_NAME, + existing_connections, + format, + preferred, + is_dun ? FALSE : TRUE); /* No IPv6 yet for DUN */ + + setting_bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt); + if (setting_bdaddr) { + /* Make sure the setting BT Address (if any) matches the device's */ + if (memcmp (setting_bdaddr->data, devaddr->ether_addr_octet, ETH_ALEN)) { + g_set_error_literal (error, + NM_SETTING_BLUETOOTH_ERROR, + NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, + NM_SETTING_BLUETOOTH_BDADDR); + return FALSE; + } + } else { + GByteArray *bdaddr; + const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + + /* Lock the connection to this device by default */ + if (memcmp (devaddr->ether_addr_octet, null_mac, ETH_ALEN)) { + bdaddr = g_byte_array_sized_new (ETH_ALEN); + g_byte_array_append (bdaddr, devaddr->ether_addr_octet, ETH_ALEN); + g_object_set (G_OBJECT (s_bt), NM_SETTING_BLUETOOTH_BDADDR, bdaddr, NULL); + g_byte_array_free (bdaddr, TRUE); + } + } + + return TRUE; +} + +/*****************************************************************************/ +/* IP method PPP */ + +static void +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 (nm_device_get_state (device)) { + case NM_DEVICE_STATE_PREPARE: + case NM_DEVICE_STATE_CONFIG: + case NM_DEVICE_STATE_NEED_AUTH: + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); + break; + case NM_DEVICE_STATE_IP_CONFIG: + case NM_DEVICE_STATE_IP_CHECK: + case NM_DEVICE_STATE_SECONDARIES: + case NM_DEVICE_STATE_ACTIVATED: + if (nm_device_activate_ip4_state_in_conf (device)) + nm_device_activate_schedule_ip4_config_timeout (device); + else { + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + } + break; + default: + break; + } +} + +static void +modem_auth_requested (NMModem *modem, gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + + /* Auth requests (PIN, PAP/CHAP passwords, etc) only get handled + * during activation. + */ + if (!nm_device_is_activating (device)) + return; + + nm_device_state_changed (device, + NM_DEVICE_STATE_NEED_AUTH, + NM_DEVICE_STATE_REASON_NONE); +} + +static void +modem_auth_result (NMModem *modem, GError *error, gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); + NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + + if (error) { + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_NO_SECRETS); + } else { + /* 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 (NM_DEVICE_BT (device), priv->modem, &reason)) + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); + } +} + +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_get_state (device); + g_return_if_fail (state == NM_DEVICE_STATE_CONFIG || state == NM_DEVICE_STATE_NEED_AUTH); + + 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) +{ + 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, + NMIP4Config *config, + GError *error, + gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + + g_return_if_fail (nm_device_activate_ip4_state_in_conf (device) == TRUE); + + if (error) { + nm_log_warn (LOGD_MB | LOGD_IP4 | LOGD_BT, + "(%s): retrieving IP4 configuration failed: (%d) %s", + nm_device_get_ip_iface (device), + 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 + nm_device_activate_schedule_ip4_config_result (device, config); +} + +static void +data_port_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) +{ + NMDevice *self = NM_DEVICE (user_data); + + nm_device_set_ip_iface (self, nm_modem_get_data_port (modem)); +} + +static gboolean +modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *reason) +{ + NMActRequest *req; + NMActStageReturn ret; + + 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 FALSE; +} + +/*****************************************************************************/ + +static void +modem_cleanup (NMDeviceBt *self) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + + if (priv->modem) { + g_signal_handlers_disconnect_matched (priv->modem, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self); + g_clear_object (&priv->modem); + } +} + +static void +modem_removed_cb (NMModem *modem, gpointer user_data) +{ + NMDeviceBt *self = NM_DEVICE_BT (user_data); + NMDeviceState state; + + /* Fail the device if the modem was removed while active */ + state = nm_device_get_state (NM_DEVICE (self)); + if ( state == NM_DEVICE_STATE_ACTIVATED + || nm_device_is_activating (NM_DEVICE (self))) { + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_BT_FAILED); + } else + modem_cleanup (self); +} + +static gboolean +component_added (NMDevice *device, GObject *component) +{ + NMDeviceBt *self = NM_DEVICE_BT (device); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + NMModem *modem; + const gchar *modem_data_port; + const gchar *modem_control_port; + char *base; + NMDeviceState state; + NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + + if (!NM_IS_MODEM (component)) + return FALSE; + modem = NM_MODEM (component); + + modem_data_port = nm_modem_get_data_port (modem); + modem_control_port = nm_modem_get_control_port (modem); + g_return_val_if_fail (modem_data_port != NULL || modem_control_port != NULL, FALSE); + + if (!priv->rfcomm_iface) + return FALSE; + + base = g_path_get_basename (priv->rfcomm_iface); + if (g_strcmp0 (base, modem_data_port) && g_strcmp0 (base, modem_control_port)) { + 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_get_state (NM_DEVICE (self)); + if (state != NM_DEVICE_STATE_CONFIG) { + nm_log_warn (LOGD_BT | LOGD_MB, + "(%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_log_info (LOGD_BT | LOGD_MB, + "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 (); + modem_cleanup (self); + } + + 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_AUTH_REQUESTED, G_CALLBACK (modem_auth_requested), self); + g_signal_connect (modem, NM_MODEM_AUTH_RESULT, G_CALLBACK (modem_auth_result), self); + g_signal_connect (modem, NM_MODEM_REMOVED, G_CALLBACK (modem_removed_cb), self); + + /* In the old ModemManager the data port is known from the very beginning; + * while in the new ModemManager the data port is set afterwards when the bearer gets + * created */ + if (modem_data_port) + nm_device_set_ip_iface (NM_DEVICE (self), modem_data_port); + g_signal_connect (modem, "notify::" NM_MODEM_DATA_PORT, G_CALLBACK (data_port_changed_cb), 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; +} + +static gboolean +modem_find_timeout (gpointer user_data) +{ + NMDeviceBt *self = NM_DEVICE_BT (user_data); + + NM_DEVICE_BT_GET_PRIVATE (self)->timeout_id = 0; + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND); + return FALSE; +} + +static void +check_connect_continue (NMDeviceBt *self) +{ + NMDevice *device = NM_DEVICE (self); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + gboolean pan = (priv->bt_type == NM_BT_CAPABILITY_NAP); + gboolean dun = (priv->bt_type == NM_BT_CAPABILITY_DUN); + + if (!priv->connected || !priv->have_iface) + return; + + nm_log_info (LOGD_BT, "Activation (%s %s/bluetooth) Stage 2 of 5 (Device Configure) " + "successful. Will connect via %s.", + nm_device_get_iface (device), + nm_device_get_ip_iface (device), + dun ? "DUN" : (pan ? "PAN" : "unknown")); + + /* Kill the connect timeout since we're connected now */ + if (priv->timeout_id) { + g_source_remove (priv->timeout_id); + priv->timeout_id = 0; + } + + 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 */ + priv->timeout_id = g_timeout_add_seconds (30, modem_find_timeout, self); + + nm_log_info (LOGD_BT | LOGD_MB, "Activation (%s/bluetooth) Stage 2 of 5 (Device Configure) " + "waiting for modem to appear.", + nm_device_get_iface (device)); + } else + g_assert_not_reached (); +} + +static void +bluez_connect_cb (GObject *object, + GAsyncResult *res, + void *user_data) +{ + NMDeviceBt *self = NM_DEVICE_BT (user_data); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + GError *error = NULL; + const char *device; + + device = nm_bluez_device_connect_finish (NM_BLUEZ_DEVICE (object), + res, &error); + + if (!device) { + nm_log_warn (LOGD_BT, "Error connecting with bluez: %s", + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_BT_FAILED); + return; + } + + if (priv->bt_type == NM_BT_CAPABILITY_DUN) { + g_free (priv->rfcomm_iface); + priv->rfcomm_iface = g_strdup (device); + } else if (priv->bt_type == NM_BT_CAPABILITY_NAP) { + nm_device_set_ip_iface (NM_DEVICE (self), device); + } + + nm_log_dbg (LOGD_BT, "(%s): connect request successful", + nm_device_get_iface (NM_DEVICE (self))); + + /* Stage 3 gets scheduled when Bluez says we're connected */ + priv->have_iface = TRUE; + check_connect_continue (self); +} + +static void +bluez_connected_changed (NMBluezDevice *bt_device, + GParamSpec *pspec, + NMDevice *device) +{ + NMDeviceBt *self = NM_DEVICE_BT (device); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + gboolean connected; + NMDeviceState state; + + state = nm_device_get_state (device); + connected = nm_bluez_device_get_connected (bt_device); + if (connected) { + if (state == NM_DEVICE_STATE_CONFIG) { + nm_log_dbg (LOGD_BT, "(%s): connected to the device", + nm_device_get_iface (device)); + + priv->connected = TRUE; + check_connect_continue (self); + } + } else { + gboolean fail = FALSE; + + /* Bluez says we're disconnected from the device. Suck. */ + + if (nm_device_is_activating (device)) { + nm_log_info (LOGD_BT, + "Activation (%s/bluetooth): bluetooth link disconnected.", + nm_device_get_iface (device)); + fail = TRUE; + } else if (state == NM_DEVICE_STATE_ACTIVATED) { + nm_log_info (LOGD_BT, "(%s): bluetooth link disconnected.", + nm_device_get_iface (device)); + fail = TRUE; + } + + if (fail) { + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CARRIER); + priv->connected = FALSE; + } + } +} + +static gboolean +bt_connect_timeout (gpointer user_data) +{ + NMDeviceBt *self = NM_DEVICE_BT (user_data); + + nm_log_dbg (LOGD_BT, "(%s): initial connection timed out", + nm_device_get_iface (NM_DEVICE (self))); + + NM_DEVICE_BT_GET_PRIVATE (self)->timeout_id = 0; + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_BT_FAILED); + return FALSE; +} + +static NMActStageReturn +act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); + NMConnection *connection; + + connection = nm_device_get_connection (device); + g_assert (connection); + priv->bt_type = get_connection_bt_type (connection); + if (priv->bt_type == NM_BT_CAPABILITY_NONE) { + // FIXME: set a reason code + return NM_ACT_STAGE_RETURN_FAILURE; + } + + if (priv->bt_type == NM_BT_CAPABILITY_DUN && !priv->mm_running) { + *reason = NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE; + return NM_ACT_STAGE_RETURN_FAILURE; + } + + nm_log_dbg (LOGD_BT, "(%s): requesting connection to the device", + nm_device_get_iface (device)); + + /* Connect to the BT device */ + nm_bluez_device_connect_async (priv->bt_device, + priv->bt_type & (NM_BT_CAPABILITY_DUN | NM_BT_CAPABILITY_NAP), + bluez_connect_cb, device); + + if (priv->timeout_id) + g_source_remove (priv->timeout_id); + priv->timeout_id = g_timeout_add_seconds (30, bt_connect_timeout, device); + + return NM_ACT_STAGE_RETURN_POSTPONE; +} + +static NMActStageReturn +act_stage3_ip4_config_start (NMDevice *device, + NMIP4Config **out_config, + NMDeviceStateReason *reason) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); + NMActStageReturn ret; + + 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, out_config, reason); + + return ret; +} + +static NMActStageReturn +act_stage3_ip6_config_start (NMDevice *device, + NMIP6Config **out_config, + NMDeviceStateReason *reason) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); + NMActStageReturn ret; + + if (priv->bt_type == NM_BT_CAPABILITY_DUN) { + ret = nm_modem_stage3_ip6_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_ip6_config_start (device, out_config, reason); + + return ret; +} + +static void +deactivate (NMDevice *device) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); + + priv->have_iface = FALSE; + priv->connected = FALSE; + + if (priv->bt_type == NM_BT_CAPABILITY_DUN) { + if (priv->modem) { + nm_modem_deactivate (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); + modem_cleanup (NM_DEVICE_BT (device)); + } + } + + if (priv->bt_type != NM_BT_CAPABILITY_NONE) + nm_bluez_device_disconnect (priv->bt_device); + + 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); + priv->rfcomm_iface = NULL; + + if (NM_DEVICE_CLASS (nm_device_bt_parent_class)->deactivate) + NM_DEVICE_CLASS (nm_device_bt_parent_class)->deactivate (device); +} + +static void +bluez_device_removed (NMBluezDevice *bdev, gpointer user_data) +{ + g_signal_emit_by_name (NM_DEVICE_BT (user_data), NM_DEVICE_REMOVED); +} + +/*****************************************************************************/ + +static gboolean +is_available (NMDevice *dev) +{ + NMDeviceBt *self = NM_DEVICE_BT (dev); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + + /* PAN doesn't need ModemManager, so devices that support it are always available */ + if (priv->capabilities & NM_BT_CAPABILITY_NAP) + return TRUE; + + /* DUN requires ModemManager */ + return priv->mm_running; +} + +static void +handle_availability_change (NMDeviceBt *self, + gboolean old_available, + NMDeviceStateReason unavailable_reason) +{ + NMDevice *device = NM_DEVICE (self); + NMDeviceState state; + gboolean available; + + state = nm_device_get_state (device); + if (state < NM_DEVICE_STATE_UNAVAILABLE) { + nm_log_dbg (LOGD_BT, "(%s): availability blocked by UNMANAGED state", + nm_device_get_iface (device)); + return; + } + + available = nm_device_is_available (device); + if (available == old_available) + return; + + if (available) { + if (state != NM_DEVICE_STATE_UNAVAILABLE) + nm_log_warn (LOGD_CORE | LOGD_BT, "not in expected unavailable state!"); + + nm_device_state_changed (device, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_NONE); + } else { + nm_device_state_changed (device, + NM_DEVICE_STATE_UNAVAILABLE, + unavailable_reason); + } +} + +static void +set_mm_running (NMDeviceBt *self, gboolean running) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + gboolean old_available; + + if (priv->mm_running == running) + return; + + nm_log_dbg (LOGD_BT, "(%s): ModemManager now %s", + nm_device_get_iface (NM_DEVICE (self)), + running ? "available" : "unavailable"); + + old_available = nm_device_is_available (NM_DEVICE (self)); + priv->mm_running = running; + handle_availability_change (self, old_available, NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE); + + /* Need to recheck available connections whenever MM appears or disappears, + * since the device could be both DUN and NAP capable and thus may not + * change state (which rechecks available connections) when MM comes and goes. + */ + if (priv->capabilities & NM_BT_CAPABILITY_DUN) + nm_device_recheck_available_connections (NM_DEVICE (self)); +} + +static void +mm_name_owner_changed (NMDBusManager *dbus_mgr, + const char *name, + const char *old_owner, + const char *new_owner, + NMDeviceBt *self) +{ + gboolean old_owner_good; + gboolean new_owner_good; + + /* Can't handle the signal if its not from the modem service */ + if ( strcmp (MM_OLD_DBUS_SERVICE, name) != 0 +#if WITH_MODEM_MANAGER_1 + && strcmp (MM_NEW_DBUS_SERVICE, name) != 0 +#endif + ) + return; + + old_owner_good = (old_owner && strlen (old_owner)); + new_owner_good = (new_owner && strlen (new_owner)); + + if (!old_owner_good && new_owner_good) + set_mm_running (self, TRUE); + else if (old_owner_good && !new_owner_good) + set_mm_running (self, FALSE); +} + +/*****************************************************************************/ + +NMDevice * +nm_device_bt_new (NMBluezDevice *bt_device, + const char *udi, + const char *bdaddr, + const char *name, + guint32 capabilities) +{ + 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); + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (bt_device), NULL); + + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BT, + NM_DEVICE_UDI, udi, + NM_DEVICE_IFACE, bdaddr, + NM_DEVICE_DRIVER, "bluez", + NM_DEVICE_HW_ADDRESS, bdaddr, + NM_DEVICE_BT_DEVICE, bt_device, + NM_DEVICE_BT_NAME, name, + NM_DEVICE_BT_CAPABILITIES, capabilities, + NM_DEVICE_TYPE_DESC, "Bluetooth", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BT, + NULL); +} + +static void +nm_device_bt_init (NMDeviceBt *self) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + gboolean mm_running; + + priv->dbus_mgr = nm_dbus_manager_get (); + + priv->mm_watch_id = g_signal_connect (priv->dbus_mgr, + NM_DBUS_MANAGER_NAME_OWNER_CHANGED, + G_CALLBACK (mm_name_owner_changed), + self); + + /* Initial check to see if ModemManager is running */ + mm_running = nm_dbus_manager_name_has_owner (priv->dbus_mgr, MM_OLD_DBUS_SERVICE); +#if WITH_MODEM_MANAGER_1 + if (!mm_running) + mm_running = nm_dbus_manager_name_has_owner (priv->dbus_mgr, MM_NEW_DBUS_SERVICE); +#endif + set_mm_running (self, mm_running); +} + +static void +constructed (GObject *object) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); + const guint8 *my_hwaddr; + guint my_hwaddr_len = 0; + + G_OBJECT_CLASS (nm_device_bt_parent_class)->constructed (object); + + my_hwaddr = nm_device_get_hw_address (NM_DEVICE (object), &my_hwaddr_len); + g_assert (my_hwaddr); + g_assert_cmpint (my_hwaddr_len, ==, ETH_ALEN); + priv->bdaddr = nm_utils_hwaddr_ntoa (my_hwaddr, ARPHRD_ETHER); + + /* Watch for BT device property changes */ + g_signal_connect (priv->bt_device, "notify::" NM_BLUEZ_DEVICE_CONNECTED, + G_CALLBACK (bluez_connected_changed), + object); +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_BT_NAME: + /* Construct only */ + priv->name = g_value_dup_string (value); + break; + case PROP_BT_CAPABILITIES: + /* Construct only */ + priv->capabilities = g_value_get_uint (value); + break; + case PROP_BT_DEVICE: + /* Construct only */ + priv->bt_device = g_value_dup_object (value); + g_signal_connect (priv->bt_device, "removed", G_CALLBACK (bluez_device_removed), object); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_BT_NAME: + g_value_set_string (value, priv->name); + break; + case PROP_BT_CAPABILITIES: + g_value_set_uint (value, priv->capabilities); + break; + case PROP_BT_DEVICE: + g_value_set_object (value, priv->bt_device); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); + + if (priv->timeout_id) { + g_source_remove (priv->timeout_id); + priv->timeout_id = 0; + } + + g_signal_handlers_disconnect_matched (priv->bt_device, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object); + + if (priv->dbus_mgr && priv->mm_watch_id) { + g_signal_handler_disconnect (priv->dbus_mgr, priv->mm_watch_id); + priv->mm_watch_id = 0; + } + priv->dbus_mgr = NULL; + + modem_cleanup (NM_DEVICE_BT (object)); + g_clear_object (&priv->bt_device); + + G_OBJECT_CLASS (nm_device_bt_parent_class)->dispose (object); +} + +static void +finalize (GObject *object) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); + + g_free (priv->rfcomm_iface); + g_free (priv->bdaddr); + g_free (priv->name); + + G_OBJECT_CLASS (nm_device_bt_parent_class)->finalize (object); +} + +static void +nm_device_bt_class_init (NMDeviceBtClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMDeviceBtPrivate)); + + object_class->constructed = constructed; + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->dispose = dispose; + object_class->finalize = finalize; + + device_class->get_hw_address_length = get_hw_address_length; + device_class->can_auto_connect = can_auto_connect; + device_class->deactivate = deactivate; + device_class->act_stage2_config = act_stage2_config; + device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; + device_class->check_connection_compatible = check_connection_compatible; + device_class->check_connection_available = check_connection_available; + device_class->complete_connection = complete_connection; + device_class->is_available = is_available; + device_class->component_added = component_added; + + device_class->state_changed = device_state_changed; + + /* Properties */ + g_object_class_install_property + (object_class, PROP_BT_NAME, + g_param_spec_string (NM_DEVICE_BT_NAME, + "Bluetooth device name", + "Bluetooth device name", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, PROP_BT_CAPABILITIES, + g_param_spec_uint (NM_DEVICE_BT_CAPABILITIES, + "Bluetooth device capabilities", + "Bluetooth device capabilities", + NM_BT_CAPABILITY_NONE, G_MAXUINT, NM_BT_CAPABILITY_NONE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, PROP_BT_DEVICE, + g_param_spec_object (NM_DEVICE_BT_DEVICE, + "NMBluezDevice object for the Device", + "NMBluezDevice object for the Device", + NM_TYPE_BLUEZ_DEVICE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + /* Signals */ + signals[PPP_STATS] = + g_signal_new ("ppp-stats", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMDeviceBtClass, ppp_stats), + NULL, NULL, NULL, + G_TYPE_NONE, 2, + G_TYPE_UINT, G_TYPE_UINT); + + nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), + G_TYPE_FROM_CLASS (klass), + &dbus_glib_nm_device_bt_object_info); + + dbus_g_error_domain_register (NM_BT_ERROR, NULL, NM_TYPE_BT_ERROR); +} diff --git a/src/devices/bluetooth/nm-device-bt.h b/src/devices/bluetooth/nm-device-bt.h new file mode 100644 index 0000000000..83732bc09e --- /dev/null +++ b/src/devices/bluetooth/nm-device-bt.h @@ -0,0 +1,74 @@ +/* -*- 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_BT_H +#define NM_DEVICE_BT_H + +#include +#include "nm-bluez-device.h" +#include "nm-modem.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_BT (nm_device_bt_get_type ()) +#define NM_DEVICE_BT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_BT, NMDeviceBt)) +#define NM_DEVICE_BT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_BT, NMDeviceBtClass)) +#define NM_IS_DEVICE_BT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_BT)) +#define NM_IS_DEVICE_BT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_BT)) +#define NM_DEVICE_BT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_BT, NMDeviceBtClass)) + +typedef enum { + NM_BT_ERROR_CONNECTION_NOT_BT = 0, /*< nick=ConnectionNotBt >*/ + NM_BT_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/ + NM_BT_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ +} NMBtError; + +#define NM_DEVICE_BT_NAME "name" +#define NM_DEVICE_BT_CAPABILITIES "bt-capabilities" +#define NM_DEVICE_BT_DEVICE "bt-device" + +typedef struct { + NMDevice parent; +} NMDeviceBt; + +typedef struct { + NMDeviceClass parent; + + /* Signals */ + void (*ppp_stats) (NMDeviceBt *device, guint32 in_bytes, guint32 out_bytes); +} NMDeviceBtClass; + +GType nm_device_bt_get_type (void); + +NMDevice *nm_device_bt_new (NMBluezDevice *bt_device, + const char *udi, + const char *bdaddr, + const char *name, + guint32 capabilities); + +guint32 nm_device_bt_get_capabilities (NMDeviceBt *device); + +gboolean nm_device_bt_modem_added (NMDeviceBt *device, + NMModem *modem, + const char *driver); + +G_END_DECLS + +#endif /* NM_DEVICE_BT_H */ diff --git a/src/devices/nm-device-bt.c b/src/devices/nm-device-bt.c deleted file mode 100644 index ecb015b03c..0000000000 --- a/src/devices/nm-device-bt.c +++ /dev/null @@ -1,1254 +0,0 @@ -/* -*- 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 - 2011 Red Hat, Inc. - */ - -#include "config.h" - -#include -#include -#include -#include - -#include -#include - -#include "nm-glib-compat.h" -#include "nm-bluez-common.h" -#include "nm-bluez-device.h" -#include "nm-dbus-manager.h" -#include "nm-device-bt.h" -#include "nm-device-private.h" -#include "nm-logging.h" -#include "ppp-manager/nm-ppp-manager.h" -#include "nm-setting-connection.h" -#include "nm-setting-bluetooth.h" -#include "nm-setting-cdma.h" -#include "nm-setting-gsm.h" -#include "nm-setting-serial.h" -#include "nm-setting-ppp.h" -#include "nm-device-bt-glue.h" -#include "NetworkManagerUtils.h" -#include "nm-enum-types.h" -#include "nm-utils.h" - -#define MM_OLD_DBUS_SERVICE "org.freedesktop.ModemManager" -#define MM_NEW_DBUS_SERVICE "org.freedesktop.ModemManager1" - -G_DEFINE_TYPE (NMDeviceBt, nm_device_bt, NM_TYPE_DEVICE) - -#define NM_DEVICE_BT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_BT, NMDeviceBtPrivate)) - -static gboolean modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *reason); - -typedef struct { - NMDBusManager *dbus_mgr; - guint mm_watch_id; - gboolean mm_running; - - NMBluezDevice *bt_device; - - char *bdaddr; - char *name; - guint32 capabilities; - - gboolean connected; - gboolean have_iface; - - char *rfcomm_iface; - NMModem *modem; - guint32 timeout_id; - - guint32 bt_type; /* BT type of the current connection */ -} NMDeviceBtPrivate; - -enum { - PROP_0, - PROP_BT_NAME, - PROP_BT_CAPABILITIES, - PROP_BT_DEVICE, - - LAST_PROP -}; - -enum { - PPP_STATS, - - LAST_SIGNAL -}; -static guint signals[LAST_SIGNAL] = { 0 }; - - -#define NM_BT_ERROR (nm_bt_error_quark ()) - -static GQuark -nm_bt_error_quark (void) -{ - static GQuark quark = 0; - if (!quark) - quark = g_quark_from_static_string ("nm-bt-error"); - return quark; -} - -guint32 nm_device_bt_get_capabilities (NMDeviceBt *self) -{ - g_return_val_if_fail (NM_IS_DEVICE_BT (self), NM_BT_CAPABILITY_NONE); - - return NM_DEVICE_BT_GET_PRIVATE (self)->capabilities; -} - -static guint -get_hw_address_length (NMDevice *device, gboolean *out_permanent) -{ - /* HW address is the Bluetooth HW address of the remote device */ - if (out_permanent) - *out_permanent = TRUE; /* the bdaddr of the remote device will never change */ - return ETH_ALEN; -} - -static guint32 -get_connection_bt_type (NMConnection *connection) -{ - NMSettingBluetooth *s_bt; - const char *bt_type; - - s_bt = nm_connection_get_setting_bluetooth (connection); - if (!s_bt) - return NM_BT_CAPABILITY_NONE; - - bt_type = nm_setting_bluetooth_get_connection_type (s_bt); - g_assert (bt_type); - - if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN)) - return NM_BT_CAPABILITY_DUN; - else if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU)) - return NM_BT_CAPABILITY_NAP; - - return NM_BT_CAPABILITY_NONE; -} - -static gboolean -can_auto_connect (NMDevice *device, - NMConnection *connection, - char **specific_object) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); - guint32 bt_type; - - if (!NM_DEVICE_CLASS (nm_device_bt_parent_class)->can_auto_connect (device, connection, specific_object)) - return FALSE; - - /* Can't auto-activate a DUN connection without ModemManager */ - bt_type = get_connection_bt_type (connection); - if (bt_type == NM_BT_CAPABILITY_DUN && priv->mm_running == FALSE) - return FALSE; - - return TRUE; -} - -static gboolean -check_connection_compatible (NMDevice *device, - NMConnection *connection, - GError **error) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); - NMSettingConnection *s_con; - NMSettingBluetooth *s_bt; - const GByteArray *array; - char *str; - int addr_match = FALSE; - guint32 bt_type; - - if (!NM_DEVICE_CLASS (nm_device_bt_parent_class)->check_connection_compatible (device, connection, error)) - return FALSE; - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_BLUETOOTH_SETTING_NAME)) { - g_set_error (error, - NM_BT_ERROR, NM_BT_ERROR_CONNECTION_NOT_BT, - "The connection was not a Bluetooth connection."); - return FALSE; - } - - s_bt = nm_connection_get_setting_bluetooth (connection); - if (!s_bt) { - g_set_error (error, - NM_BT_ERROR, NM_BT_ERROR_CONNECTION_INVALID, - "The connection was not a valid Bluetooth connection."); - return FALSE; - } - - array = nm_setting_bluetooth_get_bdaddr (s_bt); - if (!array || (array->len != ETH_ALEN)) { - g_set_error (error, - NM_BT_ERROR, NM_BT_ERROR_CONNECTION_INVALID, - "The connection did not contain a valid Bluetooth address."); - return FALSE; - } - - bt_type = get_connection_bt_type (connection); - if (!(bt_type & priv->capabilities)) { - g_set_error (error, - NM_BT_ERROR, NM_BT_ERROR_CONNECTION_INCOMPATIBLE, - "The connection was not compatible with the device's capabilities."); - return FALSE; - } - - str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", - array->data[0], array->data[1], array->data[2], - array->data[3], array->data[4], array->data[5]); - addr_match = !strcmp (priv->bdaddr, str); - g_free (str); - - return addr_match; -} - -static gboolean -check_connection_available (NMDevice *device, - NMConnection *connection, - const char *specific_object) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); - guint32 bt_type; - - bt_type = get_connection_bt_type (connection); - if (!(bt_type & priv->capabilities)) - return FALSE; - - /* DUN connections aren't available without ModemManager */ - if (bt_type == NM_BT_CAPABILITY_DUN && priv->mm_running == FALSE) - return FALSE; - - return TRUE; -} - -static gboolean -complete_connection (NMDevice *device, - NMConnection *connection, - const char *specific_object, - const GSList *existing_connections, - GError **error) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); - NMSettingBluetooth *s_bt; - const GByteArray *setting_bdaddr; - struct ether_addr *devaddr = ether_aton (priv->bdaddr); - const char *ctype; - gboolean is_dun = FALSE, is_pan = FALSE; - NMSettingGsm *s_gsm; - NMSettingCdma *s_cdma; - NMSettingSerial *s_serial; - NMSettingPPP *s_ppp; - const char *format = NULL, *preferred = NULL; - - s_gsm = nm_connection_get_setting_gsm (connection); - s_cdma = nm_connection_get_setting_cdma (connection); - s_serial = nm_connection_get_setting_serial (connection); - s_ppp = nm_connection_get_setting_ppp (connection); - - s_bt = nm_connection_get_setting_bluetooth (connection); - if (!s_bt) { - s_bt = (NMSettingBluetooth *) nm_setting_bluetooth_new (); - nm_connection_add_setting (connection, NM_SETTING (s_bt)); - } - - ctype = nm_setting_bluetooth_get_connection_type (s_bt); - if (ctype) { - if (!strcmp (ctype, NM_SETTING_BLUETOOTH_TYPE_DUN)) - is_dun = TRUE; - else if (!strcmp (ctype, NM_SETTING_BLUETOOTH_TYPE_PANU)) - is_pan = TRUE; - } else { - if (s_gsm || s_cdma) - is_dun = TRUE; - else if (priv->capabilities & NM_BT_CAPABILITY_NAP) - is_pan = TRUE; - } - - if (is_pan) { - /* Make sure the device supports PAN */ - if (!(priv->capabilities & NM_BT_CAPABILITY_NAP)) { - g_set_error_literal (error, - NM_SETTING_BLUETOOTH_ERROR, - NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, - "PAN required but Bluetooth device does not support NAP"); - return FALSE; - } - - /* PAN can't use any DUN-related settings */ - if (s_gsm || s_cdma || s_serial || s_ppp) { - g_set_error_literal (error, - NM_SETTING_BLUETOOTH_ERROR, - NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, - "PAN incompatible with GSM, CDMA, or serial settings"); - return FALSE; - } - - g_object_set (G_OBJECT (s_bt), - NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU, - NULL); - - format = _("PAN connection %d"); - } else if (is_dun) { - /* Make sure the device supports PAN */ - if (!(priv->capabilities & NM_BT_CAPABILITY_DUN)) { - g_set_error_literal (error, - NM_SETTING_BLUETOOTH_ERROR, - NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, - "DUN required but Bluetooth device does not support DUN"); - return FALSE; - } - - /* Need at least a GSM or a CDMA setting */ - if (!s_gsm && !s_cdma) { - g_set_error_literal (error, - NM_SETTING_BLUETOOTH_ERROR, - NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, - "Setting requires DUN but no GSM or CDMA setting is present"); - return FALSE; - } - - g_object_set (G_OBJECT (s_bt), - NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_DUN, - NULL); - - if (s_gsm) { - format = _("GSM connection %d"); - if (!nm_setting_gsm_get_number (s_gsm)) - g_object_set (G_OBJECT (s_gsm), NM_SETTING_GSM_NUMBER, "*99#", NULL); - } else if (s_cdma) { - format = _("CDMA connection %d"); - if (!nm_setting_cdma_get_number (s_cdma)) - g_object_set (G_OBJECT (s_cdma), NM_SETTING_GSM_NUMBER, "#777", NULL); - } else - format = _("DUN connection %d"); - } else { - g_set_error_literal (error, - NM_SETTING_BLUETOOTH_ERROR, - NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, - "Unknown/unhandled Bluetooth connection type"); - return FALSE; - } - - nm_utils_complete_generic (connection, - NM_SETTING_BLUETOOTH_SETTING_NAME, - existing_connections, - format, - preferred, - is_dun ? FALSE : TRUE); /* No IPv6 yet for DUN */ - - setting_bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt); - if (setting_bdaddr) { - /* Make sure the setting BT Address (if any) matches the device's */ - if (memcmp (setting_bdaddr->data, devaddr->ether_addr_octet, ETH_ALEN)) { - g_set_error_literal (error, - NM_SETTING_BLUETOOTH_ERROR, - NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY, - NM_SETTING_BLUETOOTH_BDADDR); - return FALSE; - } - } else { - GByteArray *bdaddr; - const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; - - /* Lock the connection to this device by default */ - if (memcmp (devaddr->ether_addr_octet, null_mac, ETH_ALEN)) { - bdaddr = g_byte_array_sized_new (ETH_ALEN); - g_byte_array_append (bdaddr, devaddr->ether_addr_octet, ETH_ALEN); - g_object_set (G_OBJECT (s_bt), NM_SETTING_BLUETOOTH_BDADDR, bdaddr, NULL); - g_byte_array_free (bdaddr, TRUE); - } - } - - return TRUE; -} - -/*****************************************************************************/ -/* IP method PPP */ - -static void -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 (nm_device_get_state (device)) { - case NM_DEVICE_STATE_PREPARE: - case NM_DEVICE_STATE_CONFIG: - case NM_DEVICE_STATE_NEED_AUTH: - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); - break; - case NM_DEVICE_STATE_IP_CONFIG: - case NM_DEVICE_STATE_IP_CHECK: - case NM_DEVICE_STATE_SECONDARIES: - case NM_DEVICE_STATE_ACTIVATED: - if (nm_device_activate_ip4_state_in_conf (device)) - nm_device_activate_schedule_ip4_config_timeout (device); - else { - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } - break; - default: - break; - } -} - -static void -modem_auth_requested (NMModem *modem, gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - - /* Auth requests (PIN, PAP/CHAP passwords, etc) only get handled - * during activation. - */ - if (!nm_device_is_activating (device)) - return; - - nm_device_state_changed (device, - NM_DEVICE_STATE_NEED_AUTH, - NM_DEVICE_STATE_REASON_NONE); -} - -static void -modem_auth_result (NMModem *modem, GError *error, gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; - - if (error) { - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - } else { - /* 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 (NM_DEVICE_BT (device), priv->modem, &reason)) - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); - } -} - -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_get_state (device); - g_return_if_fail (state == NM_DEVICE_STATE_CONFIG || state == NM_DEVICE_STATE_NEED_AUTH); - - 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) -{ - 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, - NMIP4Config *config, - GError *error, - gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - - g_return_if_fail (nm_device_activate_ip4_state_in_conf (device) == TRUE); - - if (error) { - nm_log_warn (LOGD_MB | LOGD_IP4 | LOGD_BT, - "(%s): retrieving IP4 configuration failed: (%d) %s", - nm_device_get_ip_iface (device), - 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 - nm_device_activate_schedule_ip4_config_result (device, config); -} - -static void -data_port_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMDevice *self = NM_DEVICE (user_data); - - nm_device_set_ip_iface (self, nm_modem_get_data_port (modem)); -} - -static gboolean -modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *reason) -{ - NMActRequest *req; - NMActStageReturn ret; - - 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 FALSE; -} - -/*****************************************************************************/ - -static void -modem_cleanup (NMDeviceBt *self) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - - if (priv->modem) { - g_signal_handlers_disconnect_matched (priv->modem, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self); - g_clear_object (&priv->modem); - } -} - -static void -modem_removed_cb (NMModem *modem, gpointer user_data) -{ - NMDeviceBt *self = NM_DEVICE_BT (user_data); - NMDeviceState state; - - /* Fail the device if the modem was removed while active */ - state = nm_device_get_state (NM_DEVICE (self)); - if ( state == NM_DEVICE_STATE_ACTIVATED - || nm_device_is_activating (NM_DEVICE (self))) { - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BT_FAILED); - } else - modem_cleanup (self); -} - -static gboolean -component_added (NMDevice *device, GObject *component) -{ - NMDeviceBt *self = NM_DEVICE_BT (device); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - NMModem *modem; - const gchar *modem_data_port; - const gchar *modem_control_port; - char *base; - NMDeviceState state; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; - - if (!NM_IS_MODEM (component)) - return FALSE; - modem = NM_MODEM (component); - - modem_data_port = nm_modem_get_data_port (modem); - modem_control_port = nm_modem_get_control_port (modem); - g_return_val_if_fail (modem_data_port != NULL || modem_control_port != NULL, FALSE); - - if (!priv->rfcomm_iface) - return FALSE; - - base = g_path_get_basename (priv->rfcomm_iface); - if (g_strcmp0 (base, modem_data_port) && g_strcmp0 (base, modem_control_port)) { - 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_get_state (NM_DEVICE (self)); - if (state != NM_DEVICE_STATE_CONFIG) { - nm_log_warn (LOGD_BT | LOGD_MB, - "(%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_log_info (LOGD_BT | LOGD_MB, - "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 (); - modem_cleanup (self); - } - - 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_AUTH_REQUESTED, G_CALLBACK (modem_auth_requested), self); - g_signal_connect (modem, NM_MODEM_AUTH_RESULT, G_CALLBACK (modem_auth_result), self); - g_signal_connect (modem, NM_MODEM_REMOVED, G_CALLBACK (modem_removed_cb), self); - - /* In the old ModemManager the data port is known from the very beginning; - * while in the new ModemManager the data port is set afterwards when the bearer gets - * created */ - if (modem_data_port) - nm_device_set_ip_iface (NM_DEVICE (self), modem_data_port); - g_signal_connect (modem, "notify::" NM_MODEM_DATA_PORT, G_CALLBACK (data_port_changed_cb), 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; -} - -static gboolean -modem_find_timeout (gpointer user_data) -{ - NMDeviceBt *self = NM_DEVICE_BT (user_data); - - NM_DEVICE_BT_GET_PRIVATE (self)->timeout_id = 0; - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND); - return FALSE; -} - -static void -check_connect_continue (NMDeviceBt *self) -{ - NMDevice *device = NM_DEVICE (self); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - gboolean pan = (priv->bt_type == NM_BT_CAPABILITY_NAP); - gboolean dun = (priv->bt_type == NM_BT_CAPABILITY_DUN); - - if (!priv->connected || !priv->have_iface) - return; - - nm_log_info (LOGD_BT, "Activation (%s %s/bluetooth) Stage 2 of 5 (Device Configure) " - "successful. Will connect via %s.", - nm_device_get_iface (device), - nm_device_get_ip_iface (device), - dun ? "DUN" : (pan ? "PAN" : "unknown")); - - /* Kill the connect timeout since we're connected now */ - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } - - 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 */ - priv->timeout_id = g_timeout_add_seconds (30, modem_find_timeout, self); - - nm_log_info (LOGD_BT | LOGD_MB, "Activation (%s/bluetooth) Stage 2 of 5 (Device Configure) " - "waiting for modem to appear.", - nm_device_get_iface (device)); - } else - g_assert_not_reached (); -} - -static void -bluez_connect_cb (GObject *object, - GAsyncResult *res, - void *user_data) -{ - NMDeviceBt *self = NM_DEVICE_BT (user_data); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - GError *error = NULL; - const char *device; - - device = nm_bluez_device_connect_finish (NM_BLUEZ_DEVICE (object), - res, &error); - - if (!device) { - nm_log_warn (LOGD_BT, "Error connecting with bluez: %s", - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BT_FAILED); - return; - } - - if (priv->bt_type == NM_BT_CAPABILITY_DUN) { - g_free (priv->rfcomm_iface); - priv->rfcomm_iface = g_strdup (device); - } else if (priv->bt_type == NM_BT_CAPABILITY_NAP) { - nm_device_set_ip_iface (NM_DEVICE (self), device); - } - - nm_log_dbg (LOGD_BT, "(%s): connect request successful", - nm_device_get_iface (NM_DEVICE (self))); - - /* Stage 3 gets scheduled when Bluez says we're connected */ - priv->have_iface = TRUE; - check_connect_continue (self); -} - -static void -bluez_connected_changed (NMBluezDevice *bt_device, - GParamSpec *pspec, - NMDevice *device) -{ - NMDeviceBt *self = NM_DEVICE_BT (device); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - gboolean connected; - NMDeviceState state; - - state = nm_device_get_state (device); - connected = nm_bluez_device_get_connected (bt_device); - if (connected) { - if (state == NM_DEVICE_STATE_CONFIG) { - nm_log_dbg (LOGD_BT, "(%s): connected to the device", - nm_device_get_iface (device)); - - priv->connected = TRUE; - check_connect_continue (self); - } - } else { - gboolean fail = FALSE; - - /* Bluez says we're disconnected from the device. Suck. */ - - if (nm_device_is_activating (device)) { - nm_log_info (LOGD_BT, - "Activation (%s/bluetooth): bluetooth link disconnected.", - nm_device_get_iface (device)); - fail = TRUE; - } else if (state == NM_DEVICE_STATE_ACTIVATED) { - nm_log_info (LOGD_BT, "(%s): bluetooth link disconnected.", - nm_device_get_iface (device)); - fail = TRUE; - } - - if (fail) { - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CARRIER); - priv->connected = FALSE; - } - } -} - -static gboolean -bt_connect_timeout (gpointer user_data) -{ - NMDeviceBt *self = NM_DEVICE_BT (user_data); - - nm_log_dbg (LOGD_BT, "(%s): initial connection timed out", - nm_device_get_iface (NM_DEVICE (self))); - - NM_DEVICE_BT_GET_PRIVATE (self)->timeout_id = 0; - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BT_FAILED); - return FALSE; -} - -static NMActStageReturn -act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); - NMConnection *connection; - - connection = nm_device_get_connection (device); - g_assert (connection); - priv->bt_type = get_connection_bt_type (connection); - if (priv->bt_type == NM_BT_CAPABILITY_NONE) { - // FIXME: set a reason code - return NM_ACT_STAGE_RETURN_FAILURE; - } - - if (priv->bt_type == NM_BT_CAPABILITY_DUN && !priv->mm_running) { - *reason = NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE; - return NM_ACT_STAGE_RETURN_FAILURE; - } - - nm_log_dbg (LOGD_BT, "(%s): requesting connection to the device", - nm_device_get_iface (device)); - - /* Connect to the BT device */ - nm_bluez_device_connect_async (priv->bt_device, - priv->bt_type & (NM_BT_CAPABILITY_DUN | NM_BT_CAPABILITY_NAP), - bluez_connect_cb, device); - - if (priv->timeout_id) - g_source_remove (priv->timeout_id); - priv->timeout_id = g_timeout_add_seconds (30, bt_connect_timeout, device); - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *device, - NMIP4Config **out_config, - NMDeviceStateReason *reason) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); - NMActStageReturn ret; - - 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, out_config, reason); - - return ret; -} - -static NMActStageReturn -act_stage3_ip6_config_start (NMDevice *device, - NMIP6Config **out_config, - NMDeviceStateReason *reason) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); - NMActStageReturn ret; - - if (priv->bt_type == NM_BT_CAPABILITY_DUN) { - ret = nm_modem_stage3_ip6_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_ip6_config_start (device, out_config, reason); - - return ret; -} - -static void -deactivate (NMDevice *device) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); - - priv->have_iface = FALSE; - priv->connected = FALSE; - - if (priv->bt_type == NM_BT_CAPABILITY_DUN) { - if (priv->modem) { - nm_modem_deactivate (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); - modem_cleanup (NM_DEVICE_BT (device)); - } - } - - if (priv->bt_type != NM_BT_CAPABILITY_NONE) - nm_bluez_device_disconnect (priv->bt_device); - - 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); - priv->rfcomm_iface = NULL; - - if (NM_DEVICE_CLASS (nm_device_bt_parent_class)->deactivate) - NM_DEVICE_CLASS (nm_device_bt_parent_class)->deactivate (device); -} - -/*****************************************************************************/ - -static gboolean -is_available (NMDevice *dev) -{ - NMDeviceBt *self = NM_DEVICE_BT (dev); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - - /* PAN doesn't need ModemManager, so devices that support it are always available */ - if (priv->capabilities & NM_BT_CAPABILITY_NAP) - return TRUE; - - /* DUN requires ModemManager */ - return priv->mm_running; -} - -static void -handle_availability_change (NMDeviceBt *self, - gboolean old_available, - NMDeviceStateReason unavailable_reason) -{ - NMDevice *device = NM_DEVICE (self); - NMDeviceState state; - gboolean available; - - state = nm_device_get_state (device); - if (state < NM_DEVICE_STATE_UNAVAILABLE) { - nm_log_dbg (LOGD_BT, "(%s): availability blocked by UNMANAGED state", - nm_device_get_iface (device)); - return; - } - - available = nm_device_is_available (device); - if (available == old_available) - return; - - if (available) { - if (state != NM_DEVICE_STATE_UNAVAILABLE) - nm_log_warn (LOGD_CORE | LOGD_BT, "not in expected unavailable state!"); - - nm_device_state_changed (device, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_NONE); - } else { - nm_device_state_changed (device, - NM_DEVICE_STATE_UNAVAILABLE, - unavailable_reason); - } -} - -static void -set_mm_running (NMDeviceBt *self, gboolean running) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - gboolean old_available; - - if (priv->mm_running == running) - return; - - nm_log_dbg (LOGD_BT, "(%s): ModemManager now %s", - nm_device_get_iface (NM_DEVICE (self)), - running ? "available" : "unavailable"); - - old_available = nm_device_is_available (NM_DEVICE (self)); - priv->mm_running = running; - handle_availability_change (self, old_available, NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE); - - /* Need to recheck available connections whenever MM appears or disappears, - * since the device could be both DUN and NAP capable and thus may not - * change state (which rechecks available connections) when MM comes and goes. - */ - if (priv->capabilities & NM_BT_CAPABILITY_DUN) - nm_device_recheck_available_connections (NM_DEVICE (self)); -} - -static void -mm_name_owner_changed (NMDBusManager *dbus_mgr, - const char *name, - const char *old_owner, - const char *new_owner, - NMDeviceBt *self) -{ - gboolean old_owner_good; - gboolean new_owner_good; - - /* Can't handle the signal if its not from the modem service */ - if ( strcmp (MM_OLD_DBUS_SERVICE, name) != 0 -#if WITH_MODEM_MANAGER_1 - && strcmp (MM_NEW_DBUS_SERVICE, name) != 0 -#endif - ) - return; - - old_owner_good = (old_owner && strlen (old_owner)); - new_owner_good = (new_owner && strlen (new_owner)); - - if (!old_owner_good && new_owner_good) - set_mm_running (self, TRUE); - else if (old_owner_good && !new_owner_good) - set_mm_running (self, FALSE); -} - -/*****************************************************************************/ - -NMDevice * -nm_device_bt_new (NMBluezDevice *bt_device, - const char *udi, - const char *bdaddr, - const char *name, - guint32 capabilities) -{ - 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); - g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (bt_device), NULL); - - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BT, - NM_DEVICE_UDI, udi, - NM_DEVICE_IFACE, bdaddr, - NM_DEVICE_DRIVER, "bluez", - NM_DEVICE_HW_ADDRESS, bdaddr, - NM_DEVICE_BT_DEVICE, bt_device, - NM_DEVICE_BT_NAME, name, - NM_DEVICE_BT_CAPABILITIES, capabilities, - NM_DEVICE_TYPE_DESC, "Bluetooth", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BT, - NULL); -} - -static void -nm_device_bt_init (NMDeviceBt *self) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - gboolean mm_running; - - priv->dbus_mgr = nm_dbus_manager_get (); - - priv->mm_watch_id = g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_NAME_OWNER_CHANGED, - G_CALLBACK (mm_name_owner_changed), - self); - - /* Initial check to see if ModemManager is running */ - mm_running = nm_dbus_manager_name_has_owner (priv->dbus_mgr, MM_OLD_DBUS_SERVICE); -#if WITH_MODEM_MANAGER_1 - if (!mm_running) - mm_running = nm_dbus_manager_name_has_owner (priv->dbus_mgr, MM_NEW_DBUS_SERVICE); -#endif - set_mm_running (self, mm_running); -} - -static void -constructed (GObject *object) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); - const guint8 *my_hwaddr; - guint my_hwaddr_len = 0; - - G_OBJECT_CLASS (nm_device_bt_parent_class)->constructed (object); - - my_hwaddr = nm_device_get_hw_address (NM_DEVICE (object), &my_hwaddr_len); - g_assert (my_hwaddr); - g_assert_cmpint (my_hwaddr_len, ==, ETH_ALEN); - priv->bdaddr = nm_utils_hwaddr_ntoa (my_hwaddr, ARPHRD_ETHER); - - /* Watch for BT device property changes */ - g_signal_connect (priv->bt_device, "notify::" NM_BLUEZ_DEVICE_CONNECTED, - G_CALLBACK (bluez_connected_changed), - object); -} - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_BT_NAME: - /* Construct only */ - priv->name = g_value_dup_string (value); - break; - case PROP_BT_CAPABILITIES: - /* Construct only */ - priv->capabilities = g_value_get_uint (value); - break; - case PROP_BT_DEVICE: - /* Construct only */ - priv->bt_device = g_value_dup_object (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_BT_NAME: - g_value_set_string (value, priv->name); - break; - case PROP_BT_CAPABILITIES: - g_value_set_uint (value, priv->capabilities); - break; - case PROP_BT_DEVICE: - g_value_set_object (value, priv->bt_device); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -dispose (GObject *object) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); - - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } - - g_signal_handlers_disconnect_by_func (priv->bt_device, - G_CALLBACK (bluez_connected_changed), - object); - - if (priv->dbus_mgr && priv->mm_watch_id) { - g_signal_handler_disconnect (priv->dbus_mgr, priv->mm_watch_id); - priv->mm_watch_id = 0; - } - priv->dbus_mgr = NULL; - - modem_cleanup (NM_DEVICE_BT (object)); - g_clear_object (&priv->bt_device); - - G_OBJECT_CLASS (nm_device_bt_parent_class)->dispose (object); -} - -static void -finalize (GObject *object) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); - - g_free (priv->rfcomm_iface); - g_free (priv->bdaddr); - g_free (priv->name); - - G_OBJECT_CLASS (nm_device_bt_parent_class)->finalize (object); -} - -static void -nm_device_bt_class_init (NMDeviceBtClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - - g_type_class_add_private (object_class, sizeof (NMDeviceBtPrivate)); - - object_class->constructed = constructed; - object_class->get_property = get_property; - object_class->set_property = set_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - device_class->get_hw_address_length = get_hw_address_length; - device_class->can_auto_connect = can_auto_connect; - device_class->deactivate = deactivate; - device_class->act_stage2_config = act_stage2_config; - device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; - device_class->check_connection_compatible = check_connection_compatible; - device_class->check_connection_available = check_connection_available; - device_class->complete_connection = complete_connection; - device_class->is_available = is_available; - device_class->component_added = component_added; - - device_class->state_changed = device_state_changed; - - /* Properties */ - g_object_class_install_property - (object_class, PROP_BT_NAME, - g_param_spec_string (NM_DEVICE_BT_NAME, - "Bluetooth device name", - "Bluetooth device name", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property - (object_class, PROP_BT_CAPABILITIES, - g_param_spec_uint (NM_DEVICE_BT_CAPABILITIES, - "Bluetooth device capabilities", - "Bluetooth device capabilities", - NM_BT_CAPABILITY_NONE, G_MAXUINT, NM_BT_CAPABILITY_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property - (object_class, PROP_BT_DEVICE, - g_param_spec_object (NM_DEVICE_BT_DEVICE, - "NMBluezDevice object for the Device", - "NMBluezDevice object for the Device", - NM_TYPE_BLUEZ_DEVICE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - /* Signals */ - signals[PPP_STATS] = - g_signal_new ("ppp-stats", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMDeviceBtClass, ppp_stats), - NULL, NULL, NULL, - G_TYPE_NONE, 2, - G_TYPE_UINT, G_TYPE_UINT); - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_bt_object_info); - - dbus_g_error_domain_register (NM_BT_ERROR, NULL, NM_TYPE_BT_ERROR); -} diff --git a/src/devices/nm-device-bt.h b/src/devices/nm-device-bt.h deleted file mode 100644 index 83732bc09e..0000000000 --- a/src/devices/nm-device-bt.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -*- 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_BT_H -#define NM_DEVICE_BT_H - -#include -#include "nm-bluez-device.h" -#include "nm-modem.h" - -G_BEGIN_DECLS - -#define NM_TYPE_DEVICE_BT (nm_device_bt_get_type ()) -#define NM_DEVICE_BT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_BT, NMDeviceBt)) -#define NM_DEVICE_BT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_BT, NMDeviceBtClass)) -#define NM_IS_DEVICE_BT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_BT)) -#define NM_IS_DEVICE_BT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_BT)) -#define NM_DEVICE_BT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_BT, NMDeviceBtClass)) - -typedef enum { - NM_BT_ERROR_CONNECTION_NOT_BT = 0, /*< nick=ConnectionNotBt >*/ - NM_BT_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/ - NM_BT_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ -} NMBtError; - -#define NM_DEVICE_BT_NAME "name" -#define NM_DEVICE_BT_CAPABILITIES "bt-capabilities" -#define NM_DEVICE_BT_DEVICE "bt-device" - -typedef struct { - NMDevice parent; -} NMDeviceBt; - -typedef struct { - NMDeviceClass parent; - - /* Signals */ - void (*ppp_stats) (NMDeviceBt *device, guint32 in_bytes, guint32 out_bytes); -} NMDeviceBtClass; - -GType nm_device_bt_get_type (void); - -NMDevice *nm_device_bt_new (NMBluezDevice *bt_device, - const char *udi, - const char *bdaddr, - const char *name, - guint32 capabilities); - -guint32 nm_device_bt_get_capabilities (NMDeviceBt *device); - -gboolean nm_device_bt_modem_added (NMDeviceBt *device, - NMModem *modem, - const char *driver); - -G_END_DECLS - -#endif /* NM_DEVICE_BT_H */ diff --git a/src/nm-manager.c b/src/nm-manager.c index fa76575cf0..2d6c0f1121 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -40,7 +40,6 @@ #include "nm-dbus-manager.h" #include "nm-vpn-manager.h" #include "nm-modem-manager.h" -#include "nm-device-bt.h" #include "nm-device.h" #include "nm-device-ethernet.h" #include "nm-device-wifi.h" @@ -56,7 +55,6 @@ #include "nm-device-tun.h" #include "nm-device-macvlan.h" #include "nm-device-gre.h" -#include "nm-setting-bluetooth.h" #include "nm-setting-connection.h" #include "nm-setting-wireless.h" #include "nm-setting-vpn.h" @@ -64,8 +62,6 @@ #include "nm-platform.h" #include "nm-rfkill-manager.h" #include "nm-hostname-provider.h" -#include "nm-bluez-manager.h" -#include "nm-bluez-common.h" #include "nm-settings.h" #include "nm-settings-connection.h" #include "nm-manager-auth.h" @@ -135,19 +131,6 @@ static void impl_manager_check_connectivity (NMManager *manager, #include "nm-manager-glue.h" -static void bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr, - NMBluezDevice *bt_device, - const char *bdaddr, - const char *name, - const char *object_path, - guint32 uuids, - NMManager *manager); - -static void bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr, - const char *bdaddr, - const char *object_path, - gpointer user_data); - static void add_device (NMManager *self, NMDevice *device, gboolean generate_con); static void remove_device (NMManager *self, NMDevice *device, gboolean quitting); @@ -217,7 +200,6 @@ typedef struct { NMDBusManager *dbus_mgr; gboolean prop_filter_added; NMRfkillManager *rfkill_mgr; - NMBluezManager *bluez_mgr; /* List of NMDeviceFactoryFunc pointers sorted in priority order */ GSList *factories; @@ -1951,62 +1933,6 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con) } } -static void -bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr, - NMBluezDevice *bt_device, - const char *bdaddr, - const char *name, - const char *object_path, - guint32 capabilities, - NMManager *manager) -{ - NMDevice *device; - gboolean has_dun = (capabilities & NM_BT_CAPABILITY_DUN); - gboolean has_nap = (capabilities & NM_BT_CAPABILITY_NAP); - - g_return_if_fail (bdaddr != NULL); - g_return_if_fail (name != NULL); - g_return_if_fail (object_path != NULL); - g_return_if_fail (capabilities != NM_BT_CAPABILITY_NONE); - g_return_if_fail (NM_IS_BLUEZ_DEVICE (bt_device)); - - /* Make sure the device is not already in the device list */ - if (nm_manager_get_device_by_udi (manager, object_path)) - return; - - device = nm_device_bt_new (bt_device, object_path, bdaddr, name, capabilities); - if (device) { - nm_log_info (LOGD_HW, "BT device %s (%s) added (%s%s%s)", - name, - bdaddr, - has_dun ? "DUN" : "", - has_dun && has_nap ? " " : "", - has_nap ? "NAP" : ""); - - add_device (manager, device, FALSE); - g_object_unref (device); - } -} - -static void -bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr, - const char *bdaddr, - const char *object_path, - gpointer user_data) -{ - NMManager *self = NM_MANAGER (user_data); - NMDevice *device; - - g_return_if_fail (bdaddr != NULL); - g_return_if_fail (object_path != NULL); - - device = nm_manager_get_device_by_udi (self, object_path); - if (device) { - nm_log_info (LOGD_HW, "BT device %s removed", bdaddr); - remove_device (self, device, FALSE); - } -} - static NMDevice * find_device_by_ip_iface (NMManager *self, const gchar *iface) { @@ -4168,7 +4094,6 @@ nm_manager_start (NMManager *self) system_hostname_changed_cb (priv->settings, NULL, self); nm_platform_query_devices (); - nm_bluez_manager_query_devices (priv->bluez_mgr); /* * Connections added before the manager is started do not emit @@ -4732,18 +4657,6 @@ nm_manager_new (NMSettings *settings, G_CALLBACK (rfkill_manager_rfkill_changed_cb), singleton); - priv->bluez_mgr = nm_bluez_manager_new (NM_CONNECTION_PROVIDER (priv->settings)); - - g_signal_connect (priv->bluez_mgr, - NM_BLUEZ_MANAGER_BDADDR_ADDED, - G_CALLBACK (bluez_manager_bdaddr_added_cb), - singleton); - - g_signal_connect (priv->bluez_mgr, - NM_BLUEZ_MANAGER_BDADDR_REMOVED, - G_CALLBACK (bluez_manager_bdaddr_removed_cb), - singleton); - /* Force kernel WiFi rfkill state to follow NM saved wifi state in case * the BIOS doesn't save rfkill state, and to be consistent with user * changes to the WirelessEnabled property which toggles kernel rfkill. @@ -5044,7 +4957,6 @@ dispose (GObject *object) priv->dbus_mgr = NULL; } - g_clear_object (&priv->bluez_mgr); g_clear_object (&priv->aipd_proxy); g_clear_object (&priv->sleep_monitor); -- cgit v1.2.1 From aeb1e103d809210c4fffb719e72f3b9fb1c8fb90 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 10 Feb 2014 18:57:09 -0600 Subject: mobile: make WWAN support a plugin Make WWAN support a plugin using the new device factory interface. Provides a 5% size reduction in the core NM binary. Before After NM: 1187224 1125208 (-5%) MM: 0 100576 (all results from stripped files) --- configure.ac | 1 + po/POTFILES.in | 4 +- src/Makefile.am | 20 +- src/devices/bluetooth/Makefile.am | 7 +- src/devices/nm-device-modem.c | 543 --------------- src/devices/nm-device-modem.h | 59 -- src/devices/wwan/Makefile.am | 75 +++ src/devices/wwan/README | 45 ++ src/devices/wwan/nm-device-modem.c | 543 +++++++++++++++ src/devices/wwan/nm-device-modem.h | 59 ++ src/devices/wwan/nm-modem-broadband.c | 963 +++++++++++++++++++++++++++ src/devices/wwan/nm-modem-broadband.h | 58 ++ src/devices/wwan/nm-modem-manager.c | 757 +++++++++++++++++++++ src/devices/wwan/nm-modem-manager.h | 49 ++ src/devices/wwan/nm-modem-old-types.h | 69 ++ src/devices/wwan/nm-modem-old.c | 1141 ++++++++++++++++++++++++++++++++ src/devices/wwan/nm-modem-old.h | 56 ++ src/devices/wwan/nm-modem.c | 1009 ++++++++++++++++++++++++++++ src/devices/wwan/nm-modem.h | 193 ++++++ src/devices/wwan/nm-wwan-factory.c | 160 +++++ src/devices/wwan/nm-wwan-factory.h | 37 ++ src/modem-manager/README | 45 -- src/modem-manager/nm-modem-broadband.c | 954 -------------------------- src/modem-manager/nm-modem-broadband.h | 58 -- src/modem-manager/nm-modem-manager.c | 760 --------------------- src/modem-manager/nm-modem-manager.h | 58 -- src/modem-manager/nm-modem-old-types.h | 69 -- src/modem-manager/nm-modem-old.c | 1141 -------------------------------- src/modem-manager/nm-modem-old.h | 56 -- src/modem-manager/nm-modem.c | 1009 ---------------------------- src/modem-manager/nm-modem.h | 193 ------ src/nm-manager.c | 56 +- 32 files changed, 5224 insertions(+), 5023 deletions(-) delete mode 100644 src/devices/nm-device-modem.c delete mode 100644 src/devices/nm-device-modem.h create mode 100644 src/devices/wwan/Makefile.am create mode 100644 src/devices/wwan/README create mode 100644 src/devices/wwan/nm-device-modem.c create mode 100644 src/devices/wwan/nm-device-modem.h create mode 100644 src/devices/wwan/nm-modem-broadband.c create mode 100644 src/devices/wwan/nm-modem-broadband.h create mode 100644 src/devices/wwan/nm-modem-manager.c create mode 100644 src/devices/wwan/nm-modem-manager.h create mode 100644 src/devices/wwan/nm-modem-old-types.h create mode 100644 src/devices/wwan/nm-modem-old.c create mode 100644 src/devices/wwan/nm-modem-old.h create mode 100644 src/devices/wwan/nm-modem.c create mode 100644 src/devices/wwan/nm-modem.h create mode 100644 src/devices/wwan/nm-wwan-factory.c create mode 100644 src/devices/wwan/nm-wwan-factory.h delete mode 100644 src/modem-manager/README delete mode 100644 src/modem-manager/nm-modem-broadband.c delete mode 100644 src/modem-manager/nm-modem-broadband.h delete mode 100644 src/modem-manager/nm-modem-manager.c delete mode 100644 src/modem-manager/nm-modem-manager.h delete mode 100644 src/modem-manager/nm-modem-old-types.h delete mode 100644 src/modem-manager/nm-modem-old.c delete mode 100644 src/modem-manager/nm-modem-old.h delete mode 100644 src/modem-manager/nm-modem.c delete mode 100644 src/modem-manager/nm-modem.h diff --git a/configure.ac b/configure.ac index 79aa225fd5..a7f60ff616 100644 --- a/configure.ac +++ b/configure.ac @@ -765,6 +765,7 @@ src/rdisc/tests/Makefile src/devices/atm/Makefile src/devices/wimax/Makefile src/devices/bluetooth/Makefile +src/devices/wwan/Makefile libnm-util/libnm-util.pc libnm-util/Makefile libnm-util/tests/Makefile diff --git a/po/POTFILES.in b/po/POTFILES.in index fa7806f3f4..d03f5aa8fa 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -47,8 +47,6 @@ src/dns-manager/nm-dns-manager.c src/logging/nm-logging.c src/config/nm-config.c src/devices/atm/nm-device-adsl.c -src/modem-manager/nm-modem-broadband.c -src/modem-manager/nm-modem-old.c src/devices/bluetooth/nm-bluez-device.c src/devices/bluetooth/nm-device-bt.c src/devices/nm-device-bond.c @@ -58,6 +56,8 @@ src/devices/nm-device-infiniband.c src/devices/nm-device-olpc-mesh.c src/devices/nm-device-team.c src/devices/nm-device-vlan.c +src/devices/wwan/nm-modem-broadband.c +src/devices/wwan/nm-modem-old.c src/nm-manager.c src/nm-sleep-monitor-systemd.c src/settings/plugins/ifcfg-rh/reader.c diff --git a/src/Makefile.am b/src/Makefile.am index a50932ed20..fd0bb6964c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,6 +5,7 @@ include $(GLIB_MAKEFILE) SUBDIRS = \ . \ devices/atm \ + devices/wwan \ devices/bluetooth \ dhcp-manager \ ppp-manager \ @@ -76,8 +77,6 @@ nm_sources = \ devices/nm-device-infiniband.h \ devices/nm-device-macvlan.c \ devices/nm-device-macvlan.h \ - devices/nm-device-modem.c \ - devices/nm-device-modem.h \ devices/nm-device-olpc-mesh.c \ devices/nm-device-olpc-mesh.h \ devices/nm-device-private.h \ @@ -123,14 +122,6 @@ nm_sources = \ logging/nm-logging.c \ logging/nm-logging.h \ \ - modem-manager/nm-modem-old.c \ - modem-manager/nm-modem-old.h \ - modem-manager/nm-modem-old-types.h \ - modem-manager/nm-modem-manager.c \ - modem-manager/nm-modem-manager.h \ - modem-manager/nm-modem.c \ - modem-manager/nm-modem.h \ - \ platform/nm-fake-platform.c \ platform/nm-fake-platform.h \ platform/nm-linux-platform.c \ @@ -259,12 +250,6 @@ nm_sources = \ NetworkManagerUtils.c \ NetworkManagerUtils.h -if WITH_MODEM_MANAGER_1 -nm_sources += \ - modem-manager/nm-modem-broadband.c \ - modem-manager/nm-modem-broadband.h -endif - if SESSION_TRACKING_SYSTEMD nm_sources += nm-session-monitor-systemd.c else @@ -312,7 +297,6 @@ glue_sources = \ nm-device-gre-glue.h \ nm-device-infiniband-glue.h \ nm-device-macvlan-glue.h \ - nm-device-modem-glue.h \ nm-device-olpc-mesh-glue.h \ nm-device-team-glue.h \ nm-device-tun-glue.h \ @@ -342,7 +326,6 @@ AM_CPPFLAGS += \ $(LIBNL_CFLAGS) \ $(LIBNDP_CFLAGS) \ $(LIBSOUP_CFLAGS) \ - $(MM_GLIB_CFLAGS) \ $(POLKIT_CFLAGS) \ $(SYSTEMD_LOGIN_CFLAGS) \ \ @@ -385,7 +368,6 @@ libNetworkManager_la_LIBADD = \ $(GLIB_LIBS) \ $(GUDEV_LIBS) \ $(LIBNL_LIBS) \ - $(MM_GLIB_LIBS) \ $(POLKIT_LIBS) \ $(SYSTEMD_LOGIN_LIBS) \ $(LIBDL) \ diff --git a/src/devices/bluetooth/Makefile.am b/src/devices/bluetooth/Makefile.am index 7713fc9124..5e716af25f 100644 --- a/src/devices/bluetooth/Makefile.am +++ b/src/devices/bluetooth/Makefile.am @@ -9,7 +9,7 @@ AM_CPPFLAGS = \ -I${top_srcdir}/src/devices \ -I${top_srcdir}/src/settings \ -I${top_srcdir}/src/platform \ - -I${top_srcdir}/src/modem-manager \ + -I${top_srcdir}/src/devices/wwan \ -I${top_builddir}/include \ -I${top_srcdir}/include \ -I${top_builddir}/libnm-util \ @@ -50,7 +50,10 @@ libnm_device_plugin_bt_la_SOURCES = \ $(BUILT_SOURCES) libnm_device_plugin_bt_la_LDFLAGS = -module -avoid-version -libnm_device_plugin_bt_la_LIBADD = $(DBUS_LIBS) $(GUDEV_LIBS) +libnm_device_plugin_bt_la_LIBADD = \ + $(top_builddir)/src/devices/wwan/libnm-wwan.la \ + $(DBUS_LIBS) \ + $(GUDEV_LIBS) CLEANFILES = $(BUILT_SOURCES) diff --git a/src/devices/nm-device-modem.c b/src/devices/nm-device-modem.c deleted file mode 100644 index 6a3656c4e9..0000000000 --- a/src/devices/nm-device-modem.c +++ /dev/null @@ -1,543 +0,0 @@ -/* -*- 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 - 2011 Red Hat, Inc. - */ - -#include "config.h" - -#include - -#include "nm-device-modem.h" -#include "nm-modem.h" -#include "nm-modem-old.h" -#include "nm-device-private.h" -#include "nm-rfkill-manager.h" -#include "nm-logging.h" -#include "nm-dbus-manager.h" - -#if WITH_MODEM_MANAGER_1 -#include "nm-modem-broadband.h" -#endif - -G_DEFINE_TYPE (NMDeviceModem, nm_device_modem, NM_TYPE_DEVICE) - -#define NM_DEVICE_MODEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_MODEM, NMDeviceModemPrivate)) - -#include "nm-device-modem-glue.h" - -typedef struct { - NMModem *modem; - NMDeviceModemCapabilities caps; - NMDeviceModemCapabilities current_caps; -} NMDeviceModemPrivate; - -enum { - PROP_0, - PROP_MODEM, - PROP_CAPABILITIES, - PROP_CURRENT_CAPABILITIES, -}; - -enum { - ENABLE_CHANGED, - - LAST_SIGNAL -}; -static guint signals[LAST_SIGNAL] = { 0 }; - -static void set_enabled (NMDevice *device, gboolean enabled); - -/*****************************************************************************/ - -static void -ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - - switch (nm_device_get_state (device)) { - case NM_DEVICE_STATE_PREPARE: - case NM_DEVICE_STATE_CONFIG: - case NM_DEVICE_STATE_NEED_AUTH: - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); - break; - case NM_DEVICE_STATE_IP_CONFIG: - case NM_DEVICE_STATE_IP_CHECK: - case NM_DEVICE_STATE_SECONDARIES: - case NM_DEVICE_STATE_ACTIVATED: - if (nm_device_activate_ip4_state_in_conf (device)) - nm_device_activate_schedule_ip4_config_timeout (device); - else { - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } - break; - default: - break; - } -} - -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_get_state (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 void -modem_auth_requested (NMModem *modem, gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - - /* Auth requests (PIN, PAP/CHAP passwords, etc) only get handled - * during activation. - */ - if (!nm_device_is_activating (device)) - return; - - nm_device_state_changed (device, - NM_DEVICE_STATE_NEED_AUTH, - NM_DEVICE_STATE_REASON_NONE); -} - -static void -modem_auth_result (NMModem *modem, GError *error, gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - - if (error) { - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - } else { - /* Otherwise, on success for modem 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 void -modem_ip4_config_result (NMModem *self, - NMIP4Config *config, - GError *error, - gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - - g_return_if_fail (nm_device_activate_ip4_state_in_conf (device) == TRUE); - - if (error) { - nm_log_warn (LOGD_MB | LOGD_IP4, "retrieving IP4 configuration failed: (%d) %s", - 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 - nm_device_activate_schedule_ip4_config_result (device, config); -} - -static void -data_port_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMDevice *self = NM_DEVICE (user_data); - - /* We set the IP iface in the device as soon as we know it, so that we - * properly ifup it if needed */ - nm_device_set_ip_iface (self, nm_modem_get_data_port (modem)); -} - -static void -modem_enabled_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMDeviceModem *self = NM_DEVICE_MODEM (user_data); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); - - set_enabled (NM_DEVICE (self), nm_modem_get_mm_enabled (priv->modem)); - - g_signal_emit (G_OBJECT (self), signals[ENABLE_CHANGED], 0); -} - -static void -modem_connected_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMDeviceModem *self = NM_DEVICE_MODEM (user_data); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); - - if ( nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_ACTIVATED - && !nm_modem_get_mm_connected (priv->modem)) { - /* Fail the device if the modem disconnects unexpectedly */ - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); - } -} - -static void -modem_removed_cb (NMModem *modem, gpointer user_data) -{ - g_signal_emit_by_name (NM_DEVICE (user_data), NM_DEVICE_REMOVED); -} - -/*****************************************************************************/ - -NMModem * -nm_device_modem_get_modem (NMDeviceModem *self) -{ - g_return_val_if_fail (NM_IS_DEVICE_MODEM (self), NULL); - - return NM_DEVICE_MODEM_GET_PRIVATE (self)->modem; -} - -static gboolean -owns_iface (NMDevice *device, const char *iface) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); - - g_assert (priv->modem); - return nm_modem_owns_port (priv->modem, iface); -} - -/*****************************************************************************/ - -static void -device_state_changed (NMDevice *device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - nm_modem_device_state_changed (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, - new_state, - old_state, - reason); -} - -static guint -get_hw_address_length (NMDevice *device, gboolean *out_permanent) -{ - return 0; -} - -static gboolean -check_connection_compatible (NMDevice *device, - NMConnection *connection, - GError **error) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); - - if (!NM_DEVICE_CLASS (nm_device_modem_parent_class)->check_connection_compatible (device, connection, error)) - return FALSE; - - return nm_modem_check_connection_compatible (priv->modem, connection, error); -} - -static gboolean -complete_connection (NMDevice *device, - NMConnection *connection, - const char *specific_object, - const GSList *existing_connections, - GError **error) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); - - return nm_modem_complete_connection (priv->modem, connection, existing_connections, error); -} - -static void -deactivate (NMDevice *device) -{ - nm_modem_deactivate (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, device); -} - -static NMActStageReturn -act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) -{ - NMActStageReturn ret; - NMActRequest *req; - - ret = NM_DEVICE_CLASS (nm_device_modem_parent_class)->act_stage1_prepare (device, reason); - if (ret != NM_ACT_STAGE_RETURN_SUCCESS) - return ret; - - req = nm_device_get_act_request (device); - g_assert (req); - - return nm_modem_act_stage1_prepare (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, req, reason); -} - -static NMActStageReturn -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_MODEM_GET_PRIVATE (device)->modem, req, reason); -} - -static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *device, - NMIP4Config **out_config, - NMDeviceStateReason *reason) -{ - return nm_modem_stage3_ip4_config_start (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, - device, - NM_DEVICE_CLASS (nm_device_modem_parent_class), - reason); -} - -static void -ip4_config_pre_commit (NMDevice *device, NMIP4Config *config) -{ - nm_modem_ip4_pre_commit (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, device, config); -} - -static NMActStageReturn -act_stage3_ip6_config_start (NMDevice *device, - NMIP6Config **out_config, - NMDeviceStateReason *reason) -{ - return nm_modem_stage3_ip6_config_start (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, - device, - NM_DEVICE_CLASS (nm_device_modem_parent_class), - reason); -} - -/*****************************************************************************/ - -static gboolean -get_enabled (NMDevice *device) -{ - return nm_modem_get_mm_enabled (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem); -} - -static void -set_enabled (NMDevice *device, gboolean enabled) -{ - NMDeviceModem *self = NM_DEVICE_MODEM (device); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); - NMDeviceState state; - - if (priv->modem) { - nm_modem_set_mm_enabled (priv->modem, enabled); - - if (enabled == FALSE) { - state = nm_device_get_state (device); - if (nm_device_is_activating (device) || state == NM_DEVICE_STATE_ACTIVATED) { - /* user-initiated action, hence DISCONNECTED not FAILED */ - nm_device_state_changed (device, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_USER_REQUESTED); - } - } - } -} - -/*****************************************************************************/ - -NMDevice * -nm_device_modem_new (NMModem *modem, const char *driver) -{ - NMDeviceModemCapabilities caps = NM_DEVICE_MODEM_CAPABILITY_NONE; - NMDeviceModemCapabilities current_caps = NM_DEVICE_MODEM_CAPABILITY_NONE; - NMDevice *device; - - g_return_val_if_fail (NM_IS_MODEM (modem), NULL); - g_return_val_if_fail (driver != NULL, NULL); - - /* Load capabilities */ - nm_modem_get_capabilities (modem, &caps, ¤t_caps); - - device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_MODEM, - NM_DEVICE_UDI, nm_modem_get_path (modem), - NM_DEVICE_IFACE, nm_modem_get_uid (modem), - NM_DEVICE_DRIVER, driver, - NM_DEVICE_TYPE_DESC, "Broadband", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_MODEM, - NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WWAN, - NM_DEVICE_MODEM_MODEM, modem, - NM_DEVICE_MODEM_CAPABILITIES, caps, - NM_DEVICE_MODEM_CURRENT_CAPABILITIES, current_caps, - NULL); - - /* In old MM modems, data port is known right away (may be changed - * afterwards during a PPP session setup) */ - if (NM_IS_MODEM_OLD (modem)) - nm_device_set_ip_iface (device, nm_modem_get_data_port (modem)); - - return device; -} - -static void -nm_device_modem_init (NMDeviceModem *self) -{ -} - -static void -set_modem (NMDeviceModem *self, NMModem *modem) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); - - g_return_if_fail (modem != NULL); - - priv->modem = g_object_ref (modem); - - 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_AUTH_REQUESTED, G_CALLBACK (modem_auth_requested), self); - g_signal_connect (modem, NM_MODEM_AUTH_RESULT, G_CALLBACK (modem_auth_result), self); - g_signal_connect (modem, "notify::" NM_MODEM_ENABLED, G_CALLBACK (modem_enabled_cb), self); - g_signal_connect (modem, "notify::" NM_MODEM_CONNECTED, G_CALLBACK (modem_connected_cb), self); - g_signal_connect (modem, NM_MODEM_REMOVED, G_CALLBACK (modem_removed_cb), self); - - /* In the old ModemManager the data port is known from the very beginning; - * while in the new ModemManager the data port is set afterwards when the bearer gets - * created */ - g_signal_connect (modem, "notify::" NM_MODEM_DATA_PORT, G_CALLBACK (data_port_changed_cb), self); -} - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_MODEM: - /* construct-only */ - set_modem (NM_DEVICE_MODEM (object), g_value_get_object (value)); - break; - case PROP_CAPABILITIES: - priv->caps = g_value_get_uint (value); - break; - case PROP_CURRENT_CAPABILITIES: - priv->current_caps = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_MODEM: - g_value_set_object (value, priv->modem); - break; - case PROP_CAPABILITIES: - g_value_set_uint (value, priv->caps); - break; - case PROP_CURRENT_CAPABILITIES: - g_value_set_uint (value, priv->current_caps); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -finalize (GObject *object) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object); - - g_object_unref (priv->modem); - priv->modem = NULL; - - G_OBJECT_CLASS (nm_device_modem_parent_class)->finalize (object); -} - -static void -nm_device_modem_class_init (NMDeviceModemClass *mclass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (mclass); - NMDeviceClass *device_class = NM_DEVICE_CLASS (mclass); - - g_type_class_add_private (object_class, sizeof (NMDeviceModemPrivate)); - - /* Virtual methods */ - object_class->finalize = finalize; - object_class->get_property = get_property; - object_class->set_property = set_property; - - device_class->get_hw_address_length = get_hw_address_length; - device_class->check_connection_compatible = check_connection_compatible; - device_class->complete_connection = complete_connection; - device_class->deactivate = deactivate; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->act_stage2_config = act_stage2_config; - device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; - device_class->ip4_config_pre_commit = ip4_config_pre_commit; - device_class->get_enabled = get_enabled; - device_class->set_enabled = set_enabled; - device_class->owns_iface = owns_iface; - - device_class->state_changed = device_state_changed; - - /* Properties */ - g_object_class_install_property - (object_class, PROP_MODEM, - g_param_spec_object (NM_DEVICE_MODEM_MODEM, - "Modem", - "Modem", - NM_TYPE_MODEM, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (object_class, PROP_CAPABILITIES, - g_param_spec_uint (NM_DEVICE_MODEM_CAPABILITIES, - "Modem Capabilities", - "Modem Capabilities", - 0, G_MAXUINT32, NM_DEVICE_MODEM_CAPABILITY_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (object_class, PROP_CURRENT_CAPABILITIES, - g_param_spec_uint (NM_DEVICE_MODEM_CURRENT_CAPABILITIES, - "Current modem Capabilities", - "Current modem Capabilities", - 0, G_MAXUINT32, NM_DEVICE_MODEM_CAPABILITY_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - /* Signals */ - signals[ENABLE_CHANGED] = - g_signal_new (NM_DEVICE_MODEM_ENABLE_CHANGED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (mclass), - &dbus_glib_nm_device_modem_object_info); -} diff --git a/src/devices/nm-device-modem.h b/src/devices/nm-device-modem.h deleted file mode 100644 index aa0c7c351b..0000000000 --- a/src/devices/nm-device-modem.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- 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) 2011 Red Hat, Inc. - */ - -#ifndef NM_DEVICE_MODEM_H -#define NM_DEVICE_MODEM_H - -#include -#include - -#include "nm-device.h" -#include "nm-modem.h" - -#define NM_TYPE_DEVICE_MODEM (nm_device_modem_get_type ()) -#define NM_DEVICE_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_MODEM, NMDeviceModem)) -#define NM_DEVICE_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_MODEM, NMDeviceModemClass)) -#define NM_IS_DEVICE_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_MODEM)) -#define NM_IS_DEVICE_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_MODEM)) -#define NM_DEVICE_MODEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_MODEM, NMDeviceModemClass)) - -#define NM_DEVICE_MODEM_MODEM "modem" -#define NM_DEVICE_MODEM_CAPABILITIES "modem-capabilities" -#define NM_DEVICE_MODEM_CURRENT_CAPABILITIES "current-capabilities" - -#define NM_DEVICE_MODEM_ENABLE_CHANGED "enable-changed" - -typedef struct { - NMDevice parent; -} NMDeviceModem; - -typedef struct { - NMDeviceClass parent; - -} NMDeviceModemClass; - -GType nm_device_modem_get_type (void); - -NMDevice *nm_device_modem_new (NMModem *modem, const char *driver); - -/* Private for subclases */ -NMModem *nm_device_modem_get_modem (NMDeviceModem *self); - -#endif /* NM_DEVICE_MODEM_H */ diff --git a/src/devices/wwan/Makefile.am b/src/devices/wwan/Makefile.am new file mode 100644 index 0000000000..46ae255ea0 --- /dev/null +++ b/src/devices/wwan/Makefile.am @@ -0,0 +1,75 @@ +include $(GLIB_MAKEFILE) + +@GNOME_CODE_COVERAGE_RULES@ + +AM_CPPFLAGS = \ + -I${top_srcdir}/src \ + -I${top_builddir}/src \ + -I${top_srcdir}/src/logging \ + -I${top_srcdir}/src/devices \ + -I${top_srcdir}/src/settings \ + -I${top_srcdir}/src/platform \ + -I${top_builddir}/include \ + -I${top_srcdir}/include \ + -I${top_builddir}/libnm-util \ + -I${top_srcdir}/libnm-util \ + $(DBUS_CFLAGS) \ + $(POLKIT_CFLAGS) \ + $(MM_GLIB_CFLAGS) + +BUILT_SOURCES = $(null) + +pkglib_LTLIBRARIES = libnm-wwan.la libnm-device-plugin-wwan.la + +########################################################### + +GLIB_GENERATED = nm-modem-enum-types.h nm-modem-enum-types.c +GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM +GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM +nm_modem_enum_types_sources = $(srcdir)/nm-modem.h + +BUILT_SOURCES += $(GLIB_GENERATED) + +libnm_wwan_la_SOURCES = \ + nm-modem-old.c \ + nm-modem-old.h \ + nm-modem-old-types.h \ + nm-modem-manager.c \ + nm-modem-manager.h \ + nm-modem.c \ + nm-modem.h \ + \ + $(GLIB_GENERATED) + +if WITH_MODEM_MANAGER_1 +libnm_wwan_la_SOURCES += \ + nm-modem-broadband.c \ + nm-modem-broadband.h +endif + +libnm_wwan_la_LDFLAGS = -avoid-version +libnm_wwan_la_LIBADD = $(DBUS_LIBS) $(MM_GLIB_LIBS) + +########################################################### + +nm-device-modem-glue.h: $(top_srcdir)/introspection/nm-device-modem.xml + dbus-binding-tool --prefix=nm_device_modem --mode=glib-server --output=$@ $< + +BUILT_SOURCES += nm-device-modem-glue.h + +libnm_device_plugin_wwan_la_SOURCES = \ + nm-wwan-factory.c \ + nm-wwan-factory.h \ + nm-device-modem.c \ + nm-device-modem.h \ + nm-device-modem-glue.h + +libnm_device_plugin_wwan_la_LDFLAGS = -module -avoid-version +libnm_device_plugin_wwan_la_LIBADD = \ + libnm-wwan.la \ + $(DBUS_LIBS) + +########################################################### + +CLEANFILES = $(BUILT_SOURCES) + diff --git a/src/devices/wwan/README b/src/devices/wwan/README new file mode 100644 index 0000000000..4661c04287 --- /dev/null +++ b/src/devices/wwan/README @@ -0,0 +1,45 @@ + +ModemManager integration is organized as follows: + + +Common source +******************************************************************************** + + * nm-modem.[h|c]: + Defines the basic `NMModem' object. The core NetworkManager implementation + will use this interface exclusively, regardless of the real final type of + the modem object. + + * nm-modem-manager.[h|c]: + Defines the `NMModemManager' object, which takes care of listening to + signals from the DBus interface notifying about added or removed modems. + It also takes care of creating proper `NMModem' objects from the + information retrieved from the DBus interface. + + +ModemManager 0.7 integration +******************************************************************************** + + * nm-modem-broadband.[h|c]: + Defines the `NMModemBroadband' object, which is a subclass of `NMModem'. + This object handles both 3GPP and 3GPP2 modems exposed in the new + `ModemManager1' interface. + + +ModemManager 0.4/0.5/0.6 integration +******************************************************************************** + + * nm-modem-old-types.h: + Defines helper types to use with the (old) ModemManager DBus API. + + * nm-modem-old.[h|c]: + Defines the `NMModemGeneric' object. All modem objects based on the old + ModemManager interface are subclasses of this one. + + * nm-modem-gsm.[h|c]: + Defines the `NMModemGsm' object, which is a subclass of `NMModemGeneric'. + This object handles 3GPP-specific (GSM, UMTS, HSPA, LTE) modems. + + * nm-modem-cdma.[h|c]: + Defines the `NMModemCdma' object, which is a subclass of `NMModemGeneric'. + This object handles 3GPP2-specific modems (CDMA, EV-DO). diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c new file mode 100644 index 0000000000..723f86e4dd --- /dev/null +++ b/src/devices/wwan/nm-device-modem.c @@ -0,0 +1,543 @@ +/* -*- 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 - 2011 Red Hat, Inc. + */ + +#include "config.h" + +#include + +#include "nm-device-modem.h" +#include "nm-modem.h" +#include "nm-modem-old.h" +#include "nm-device-private.h" +#include "nm-rfkill-manager.h" +#include "nm-logging.h" +#include "nm-dbus-manager.h" + +#if WITH_MODEM_MANAGER_1 +#include "nm-modem-broadband.h" +#endif + +G_DEFINE_TYPE (NMDeviceModem, nm_device_modem, NM_TYPE_DEVICE) + +#define NM_DEVICE_MODEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_MODEM, NMDeviceModemPrivate)) + +#include "nm-device-modem-glue.h" + +typedef struct { + NMModem *modem; + NMDeviceModemCapabilities caps; + NMDeviceModemCapabilities current_caps; +} NMDeviceModemPrivate; + +enum { + PROP_0, + PROP_MODEM, + PROP_CAPABILITIES, + PROP_CURRENT_CAPABILITIES, +}; + +enum { + ENABLE_CHANGED, + + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +static void set_enabled (NMDevice *device, gboolean enabled); + +/*****************************************************************************/ + +static void +ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + + switch (nm_device_get_state (device)) { + case NM_DEVICE_STATE_PREPARE: + case NM_DEVICE_STATE_CONFIG: + case NM_DEVICE_STATE_NEED_AUTH: + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); + break; + case NM_DEVICE_STATE_IP_CONFIG: + case NM_DEVICE_STATE_IP_CHECK: + case NM_DEVICE_STATE_SECONDARIES: + case NM_DEVICE_STATE_ACTIVATED: + if (nm_device_activate_ip4_state_in_conf (device)) + nm_device_activate_schedule_ip4_config_timeout (device); + else { + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + } + break; + default: + break; + } +} + +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_get_state (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 void +modem_auth_requested (NMModem *modem, gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + + /* Auth requests (PIN, PAP/CHAP passwords, etc) only get handled + * during activation. + */ + if (!nm_device_is_activating (device)) + return; + + nm_device_state_changed (device, + NM_DEVICE_STATE_NEED_AUTH, + NM_DEVICE_STATE_REASON_NONE); +} + +static void +modem_auth_result (NMModem *modem, GError *error, gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + + if (error) { + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_NO_SECRETS); + } else { + /* Otherwise, on success for modem 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 void +modem_ip4_config_result (NMModem *self, + NMIP4Config *config, + GError *error, + gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + + g_return_if_fail (nm_device_activate_ip4_state_in_conf (device) == TRUE); + + if (error) { + nm_log_warn (LOGD_MB | LOGD_IP4, "retrieving IP4 configuration failed: (%d) %s", + 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 + nm_device_activate_schedule_ip4_config_result (device, config); +} + +static void +data_port_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) +{ + NMDevice *self = NM_DEVICE (user_data); + + /* We set the IP iface in the device as soon as we know it, so that we + * properly ifup it if needed */ + nm_device_set_ip_iface (self, nm_modem_get_data_port (modem)); +} + +static void +modem_enabled_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) +{ + NMDeviceModem *self = NM_DEVICE_MODEM (user_data); + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); + + set_enabled (NM_DEVICE (self), nm_modem_get_mm_enabled (priv->modem)); + + g_signal_emit (G_OBJECT (self), signals[ENABLE_CHANGED], 0); +} + +static void +modem_connected_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) +{ + NMDeviceModem *self = NM_DEVICE_MODEM (user_data); + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); + + if ( nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_ACTIVATED + && !nm_modem_get_mm_connected (priv->modem)) { + /* Fail the device if the modem disconnects unexpectedly */ + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); + } +} + +static void +modem_removed_cb (NMModem *modem, gpointer user_data) +{ + g_signal_emit_by_name (NM_DEVICE (user_data), NM_DEVICE_REMOVED); +} + +/*****************************************************************************/ + +NMModem * +nm_device_modem_get_modem (NMDeviceModem *self) +{ + g_return_val_if_fail (NM_IS_DEVICE_MODEM (self), NULL); + + return NM_DEVICE_MODEM_GET_PRIVATE (self)->modem; +} + +static gboolean +owns_iface (NMDevice *device, const char *iface) +{ + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); + + g_assert (priv->modem); + return nm_modem_owns_port (priv->modem, iface); +} + +/*****************************************************************************/ + +static void +device_state_changed (NMDevice *device, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason) +{ + nm_modem_device_state_changed (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, + new_state, + old_state, + reason); +} + +static guint +get_hw_address_length (NMDevice *device, gboolean *out_permanent) +{ + return 0; +} + +static gboolean +check_connection_compatible (NMDevice *device, + NMConnection *connection, + GError **error) +{ + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); + + if (!NM_DEVICE_CLASS (nm_device_modem_parent_class)->check_connection_compatible (device, connection, error)) + return FALSE; + + return nm_modem_check_connection_compatible (priv->modem, connection, error); +} + +static gboolean +complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); + + return nm_modem_complete_connection (priv->modem, connection, existing_connections, error); +} + +static void +deactivate (NMDevice *device) +{ + nm_modem_deactivate (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, device); +} + +static NMActStageReturn +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) +{ + NMActStageReturn ret; + NMActRequest *req; + + ret = NM_DEVICE_CLASS (nm_device_modem_parent_class)->act_stage1_prepare (device, reason); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + + req = nm_device_get_act_request (device); + g_assert (req); + + return nm_modem_act_stage1_prepare (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, req, reason); +} + +static NMActStageReturn +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_MODEM_GET_PRIVATE (device)->modem, req, reason); +} + +static NMActStageReturn +act_stage3_ip4_config_start (NMDevice *device, + NMIP4Config **out_config, + NMDeviceStateReason *reason) +{ + return nm_modem_stage3_ip4_config_start (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, + device, + NM_DEVICE_CLASS (nm_device_modem_parent_class), + reason); +} + +static void +ip4_config_pre_commit (NMDevice *device, NMIP4Config *config) +{ + nm_modem_ip4_pre_commit (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, device, config); +} + +static NMActStageReturn +act_stage3_ip6_config_start (NMDevice *device, + NMIP6Config **out_config, + NMDeviceStateReason *reason) +{ + return nm_modem_stage3_ip6_config_start (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, + device, + NM_DEVICE_CLASS (nm_device_modem_parent_class), + reason); +} + +/*****************************************************************************/ + +static gboolean +get_enabled (NMDevice *device) +{ + return nm_modem_get_mm_enabled (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem); +} + +static void +set_enabled (NMDevice *device, gboolean enabled) +{ + NMDeviceModem *self = NM_DEVICE_MODEM (device); + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); + NMDeviceState state; + + if (priv->modem) { + nm_modem_set_mm_enabled (priv->modem, enabled); + + if (enabled == FALSE) { + state = nm_device_get_state (device); + if (nm_device_is_activating (device) || state == NM_DEVICE_STATE_ACTIVATED) { + /* user-initiated action, hence DISCONNECTED not FAILED */ + nm_device_state_changed (device, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_USER_REQUESTED); + } + } + } +} + +/*****************************************************************************/ + +NMDevice * +nm_device_modem_new (NMModem *modem) +{ + NMDeviceModemCapabilities caps = NM_DEVICE_MODEM_CAPABILITY_NONE; + NMDeviceModemCapabilities current_caps = NM_DEVICE_MODEM_CAPABILITY_NONE; + NMDevice *device; + const char *data_port; + + g_return_val_if_fail (NM_IS_MODEM (modem), NULL); + + /* Load capabilities */ + nm_modem_get_capabilities (modem, &caps, ¤t_caps); + + device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_MODEM, + NM_DEVICE_UDI, nm_modem_get_path (modem), + NM_DEVICE_IFACE, nm_modem_get_uid (modem), + NM_DEVICE_DRIVER, nm_modem_get_driver (modem), + NM_DEVICE_TYPE_DESC, "Broadband", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_MODEM, + NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WWAN, + NM_DEVICE_MODEM_MODEM, modem, + NM_DEVICE_MODEM_CAPABILITIES, caps, + NM_DEVICE_MODEM_CURRENT_CAPABILITIES, current_caps, + NULL); + + /* If the data port is known, set it as the IP interface immediately */ + data_port = nm_modem_get_data_port (modem); + if (data_port) + nm_device_set_ip_iface (device, data_port); + + return device; +} + +static void +nm_device_modem_init (NMDeviceModem *self) +{ +} + +static void +set_modem (NMDeviceModem *self, NMModem *modem) +{ + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); + + g_return_if_fail (modem != NULL); + + priv->modem = g_object_ref (modem); + + 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_AUTH_REQUESTED, G_CALLBACK (modem_auth_requested), self); + g_signal_connect (modem, NM_MODEM_AUTH_RESULT, G_CALLBACK (modem_auth_result), self); + g_signal_connect (modem, "notify::" NM_MODEM_ENABLED, G_CALLBACK (modem_enabled_cb), self); + g_signal_connect (modem, "notify::" NM_MODEM_CONNECTED, G_CALLBACK (modem_connected_cb), self); + g_signal_connect (modem, NM_MODEM_REMOVED, G_CALLBACK (modem_removed_cb), self); + + /* In the old ModemManager the data port is known from the very beginning; + * while in the new ModemManager the data port is set afterwards when the bearer gets + * created */ + g_signal_connect (modem, "notify::" NM_MODEM_DATA_PORT, G_CALLBACK (data_port_changed_cb), self); +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_MODEM: + /* construct-only */ + set_modem (NM_DEVICE_MODEM (object), g_value_get_object (value)); + break; + case PROP_CAPABILITIES: + priv->caps = g_value_get_uint (value); + break; + case PROP_CURRENT_CAPABILITIES: + priv->current_caps = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_MODEM: + g_value_set_object (value, priv->modem); + break; + case PROP_CAPABILITIES: + g_value_set_uint (value, priv->caps); + break; + case PROP_CURRENT_CAPABILITIES: + g_value_set_uint (value, priv->current_caps); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +finalize (GObject *object) +{ + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object); + + g_object_unref (priv->modem); + priv->modem = NULL; + + G_OBJECT_CLASS (nm_device_modem_parent_class)->finalize (object); +} + +static void +nm_device_modem_class_init (NMDeviceModemClass *mclass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (mclass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (mclass); + + g_type_class_add_private (object_class, sizeof (NMDeviceModemPrivate)); + + /* Virtual methods */ + object_class->finalize = finalize; + object_class->get_property = get_property; + object_class->set_property = set_property; + + device_class->get_hw_address_length = get_hw_address_length; + device_class->check_connection_compatible = check_connection_compatible; + device_class->complete_connection = complete_connection; + device_class->deactivate = deactivate; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; + device_class->ip4_config_pre_commit = ip4_config_pre_commit; + device_class->get_enabled = get_enabled; + device_class->set_enabled = set_enabled; + device_class->owns_iface = owns_iface; + + device_class->state_changed = device_state_changed; + + /* Properties */ + g_object_class_install_property + (object_class, PROP_MODEM, + g_param_spec_object (NM_DEVICE_MODEM_MODEM, + "Modem", + "Modem", + NM_TYPE_MODEM, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, PROP_CAPABILITIES, + g_param_spec_uint (NM_DEVICE_MODEM_CAPABILITIES, + "Modem Capabilities", + "Modem Capabilities", + 0, G_MAXUINT32, NM_DEVICE_MODEM_CAPABILITY_NONE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, PROP_CURRENT_CAPABILITIES, + g_param_spec_uint (NM_DEVICE_MODEM_CURRENT_CAPABILITIES, + "Current modem Capabilities", + "Current modem Capabilities", + 0, G_MAXUINT32, NM_DEVICE_MODEM_CAPABILITY_NONE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + /* Signals */ + signals[ENABLE_CHANGED] = + g_signal_new (NM_DEVICE_MODEM_ENABLE_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), + G_TYPE_FROM_CLASS (mclass), + &dbus_glib_nm_device_modem_object_info); +} diff --git a/src/devices/wwan/nm-device-modem.h b/src/devices/wwan/nm-device-modem.h new file mode 100644 index 0000000000..1147b57be3 --- /dev/null +++ b/src/devices/wwan/nm-device-modem.h @@ -0,0 +1,59 @@ +/* -*- 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) 2011 Red Hat, Inc. + */ + +#ifndef NM_DEVICE_MODEM_H +#define NM_DEVICE_MODEM_H + +#include +#include + +#include "nm-device.h" +#include "nm-modem.h" + +#define NM_TYPE_DEVICE_MODEM (nm_device_modem_get_type ()) +#define NM_DEVICE_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_MODEM, NMDeviceModem)) +#define NM_DEVICE_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_MODEM, NMDeviceModemClass)) +#define NM_IS_DEVICE_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_MODEM)) +#define NM_IS_DEVICE_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_MODEM)) +#define NM_DEVICE_MODEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_MODEM, NMDeviceModemClass)) + +#define NM_DEVICE_MODEM_MODEM "modem" +#define NM_DEVICE_MODEM_CAPABILITIES "modem-capabilities" +#define NM_DEVICE_MODEM_CURRENT_CAPABILITIES "current-capabilities" + +#define NM_DEVICE_MODEM_ENABLE_CHANGED "enable-changed" + +typedef struct { + NMDevice parent; +} NMDeviceModem; + +typedef struct { + NMDeviceClass parent; + +} NMDeviceModemClass; + +GType nm_device_modem_get_type (void); + +NMDevice *nm_device_modem_new (NMModem *modem); + +/* Private for subclases */ +NMModem *nm_device_modem_get_modem (NMDeviceModem *self); + +#endif /* NM_DEVICE_MODEM_H */ diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c new file mode 100644 index 0000000000..3fd94586a9 --- /dev/null +++ b/src/devices/wwan/nm-modem-broadband.c @@ -0,0 +1,963 @@ +/* -*- 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) 2012 Aleksander Morgado + */ + +#include +#include +#include +#include "nm-modem-broadband.h" +#include "nm-setting-connection.h" +#include "nm-logging.h" +#include "NetworkManagerUtils.h" +#include "nm-device-private.h" + +G_DEFINE_TYPE (NMModemBroadband, nm_modem_broadband, NM_TYPE_MODEM) + +struct _NMModemBroadbandPrivate { + /* The modem object from dbus */ + MMObject *modem_object; + /* Per-interface objects */ + MMModem *modem_iface; + MMModemSimple *simple_iface; + + /* Connection setup */ + MMSimpleConnectProperties *connect_properties; + MMBearer *bearer; + MMBearerIpConfig *ipv4_config; + MMBearerIpConfig *ipv6_config; + + guint32 pin_tries; +}; + +enum { + PROP_0, + PROP_MODEM, +}; + +#define MODEM_CAPS_3GPP(caps) (caps & (MM_MODEM_CAPABILITY_GSM_UMTS | \ + MM_MODEM_CAPABILITY_LTE | \ + MM_MODEM_CAPABILITY_LTE_ADVANCED)) + +#define MODEM_CAPS_3GPP2(caps) (caps & (MM_MODEM_CAPABILITY_CDMA_EVDO)) + +/* Maximum time to keep the DBus call waiting for a connection result */ +#define MODEM_CONNECT_TIMEOUT_SECS 120 + +/*****************************************************************************/ + +static NMDeviceStateReason +translate_mm_error (GError *error) +{ + NMDeviceStateReason reason; + + if (g_error_matches (error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_CARRIER)) + reason = NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER; + else if (g_error_matches (error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_DIALTONE)) + reason = NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE; + else if (g_error_matches (error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_BUSY)) + reason = NM_DEVICE_STATE_REASON_MODEM_BUSY; + else if (g_error_matches (error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_ANSWER)) + reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT; + else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NETWORK_NOT_ALLOWED)) + reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED; + else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT)) + reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT; + else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NO_NETWORK)) + reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING; + else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED)) + reason = NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED; + else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN)) + reason = NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED; + else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK)) + reason = NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED; + else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) + reason = NM_DEVICE_STATE_REASON_GSM_SIM_WRONG; + else { + /* unable to map the ModemManager error to a NM_DEVICE_STATE_REASON */ + nm_log_dbg (LOGD_MB, "unmapped error detected: '%s'", error->message); + reason = NM_DEVICE_STATE_REASON_UNKNOWN; + } + + return reason; +} + +/*****************************************************************************/ + +static void +get_capabilities (NMModem *_self, + NMDeviceModemCapabilities *modem_caps, + NMDeviceModemCapabilities *current_caps) +{ + NMModemBroadband *self = NM_MODEM_BROADBAND (_self); + MMModemCapability all_supported = MM_MODEM_CAPABILITY_NONE; + MMModemCapability *supported; + guint n_supported; + + /* For now, we don't care about the capability combinations, just merge all + * combinations in a single mask */ + if (mm_modem_get_supported_capabilities (self->priv->modem_iface, &supported, &n_supported)) { + guint i; + + for (i = 0; i < n_supported; i++) + all_supported |= supported[i]; + + g_free (supported); + } + + *modem_caps = (NMDeviceModemCapabilities) all_supported; + *current_caps = (NMDeviceModemCapabilities) mm_modem_get_current_capabilities (self->priv->modem_iface); +} + +static gboolean +owns_port (NMModem *_self, const char *iface) +{ + NMModemBroadband *self = NM_MODEM_BROADBAND (_self); + const MMModemPortInfo *ports = NULL; + guint n_ports = 0, i; + gboolean owns = FALSE; + + mm_modem_peek_ports (self->priv->modem_iface, &ports, &n_ports); + for (i = 0; i < n_ports && !owns; i++) + owns = (g_strcmp0 (iface, ports[i].name) == 0); + return owns; +} + +/*****************************************************************************/ + +static void +ask_for_pin (NMModemBroadband *self) +{ + guint32 tries; + + tries = self->priv->pin_tries++; + nm_modem_get_secrets (NM_MODEM (self), + NM_SETTING_GSM_SETTING_NAME, + tries ? TRUE : FALSE, + NM_SETTING_GSM_PIN); +} + +static void +connect_ready (MMModemSimple *simple_iface, + GAsyncResult *res, + NMModemBroadband *self) +{ + GError *error = NULL; + guint ip_method; + + g_clear_object (&self->priv->connect_properties); + + self->priv->bearer = mm_modem_simple_connect_finish (simple_iface, res, &error); + if (!self->priv->bearer) { + if (g_error_matches (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) || + (g_error_matches (error, + MM_CORE_ERROR, + MM_CORE_ERROR_UNAUTHORIZED) && + mm_modem_get_unlock_required (self->priv->modem_iface) == MM_MODEM_LOCK_SIM_PIN)) { + /* Request PIN */ + ask_for_pin (self); + } else { + /* Strip remote error info before logging it */ + if (g_dbus_error_is_remote_error (error)) + g_dbus_error_strip_remote_error (error); + + nm_log_warn (LOGD_MB, "(%s) failed to connect modem: %s", + nm_modem_get_uid (NM_MODEM (self)), + error && error->message ? error->message : "(unknown)"); + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (error)); + } + + g_clear_error (&error); + g_object_unref (self); + return; + } + + /* Grab IP configurations */ + self->priv->ipv4_config = mm_bearer_get_ipv4_config (self->priv->bearer); + self->priv->ipv6_config = mm_bearer_get_ipv6_config (self->priv->bearer); + + switch (mm_bearer_ip_config_get_method (self->priv->ipv4_config)) { + case MM_BEARER_IP_METHOD_PPP: + ip_method = MM_MODEM_IP_METHOD_PPP; + break; + case MM_BEARER_IP_METHOD_STATIC: + ip_method = MM_MODEM_IP_METHOD_STATIC; + break; + case MM_BEARER_IP_METHOD_DHCP: + ip_method = MM_MODEM_IP_METHOD_DHCP; + break; + default: + error = g_error_new (NM_MODEM_ERROR, + NM_MODEM_ERROR_CONNECTION_INVALID, + "invalid IP config"); + nm_log_warn (LOGD_MB, "(%s) failed to connect modem: %s", + nm_modem_get_uid (NM_MODEM (self)), + error->message); + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (error)); + g_error_free (error); + g_object_unref (self); + return; + } + + /* IPv4 for now only */ + g_object_set (self, + NM_MODEM_DATA_PORT, mm_bearer_get_interface (self->priv->bearer), + NM_MODEM_IP_METHOD, ip_method, + NM_MODEM_IP_TIMEOUT, mm_bearer_get_ip_timeout (self->priv->bearer), + NULL); + + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, TRUE, NM_DEVICE_STATE_REASON_NONE); + g_object_unref (self); +} + +static MMSimpleConnectProperties * +create_cdma_connect_properties (NMConnection *connection) +{ + NMSettingCdma *setting; + MMSimpleConnectProperties *properties; + const gchar *str; + + setting = nm_connection_get_setting_cdma (connection); + properties = mm_simple_connect_properties_new (); + + str = nm_setting_cdma_get_number (setting); + if (str) + mm_simple_connect_properties_set_number (properties, str); + + return properties; +} + +static MMSimpleConnectProperties * +create_gsm_connect_properties (NMConnection *connection) +{ + NMSettingGsm *setting; + NMSettingPPP *s_ppp; + MMSimpleConnectProperties *properties; + const gchar *str; + + setting = nm_connection_get_setting_gsm (connection); + properties = mm_simple_connect_properties_new (); + + /* TODO: not needed */ + str = nm_setting_gsm_get_number (setting); + if (str) + mm_simple_connect_properties_set_number (properties, str); + + str = nm_setting_gsm_get_apn (setting); + if (str) + mm_simple_connect_properties_set_apn (properties, str); + + str = nm_setting_gsm_get_network_id (setting); + if (str) + mm_simple_connect_properties_set_operator_id (properties, str); + + str = nm_setting_gsm_get_pin (setting); + if (str) + mm_simple_connect_properties_set_pin (properties, str); + + str = nm_setting_gsm_get_username (setting); + if (str) + mm_simple_connect_properties_set_user (properties, str); + + str = nm_setting_gsm_get_password (setting); + if (str) + mm_simple_connect_properties_set_password (properties, str); + + /* Roaming */ + if (nm_setting_gsm_get_home_only (setting)) + mm_simple_connect_properties_set_allow_roaming (properties, FALSE); + + /* For IpMethod == STATIC or DHCP */ + s_ppp = nm_connection_get_setting_ppp (connection); + if (s_ppp) { + MMBearerAllowedAuth allowed_auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN; + + if (nm_setting_ppp_get_noauth (s_ppp)) + allowed_auth = MM_BEARER_ALLOWED_AUTH_NONE; + if (!nm_setting_ppp_get_refuse_pap (s_ppp)) + allowed_auth |= MM_BEARER_ALLOWED_AUTH_PAP; + if (!nm_setting_ppp_get_refuse_chap (s_ppp)) + allowed_auth |= MM_BEARER_ALLOWED_AUTH_CHAP; + if (!nm_setting_ppp_get_refuse_mschap (s_ppp)) + allowed_auth |= MM_BEARER_ALLOWED_AUTH_MSCHAP; + if (!nm_setting_ppp_get_refuse_mschapv2 (s_ppp)) + allowed_auth |= MM_BEARER_ALLOWED_AUTH_MSCHAPV2; + if (!nm_setting_ppp_get_refuse_eap (s_ppp)) + allowed_auth |= MM_BEARER_ALLOWED_AUTH_EAP; + + mm_simple_connect_properties_set_allowed_auth (properties, allowed_auth); + } + + return properties; +} + +static NMActStageReturn +act_stage1_prepare (NMModem *_self, + NMConnection *connection, + NMDeviceStateReason *reason) +{ + NMModemBroadband *self = NM_MODEM_BROADBAND (_self); + MMModemCapability caps; + + g_clear_object (&self->priv->connect_properties); + + caps = mm_modem_get_current_capabilities (self->priv->modem_iface); + if (MODEM_CAPS_3GPP (caps)) + self->priv->connect_properties = create_gsm_connect_properties (connection); + else if (MODEM_CAPS_3GPP2 (caps)) + self->priv->connect_properties = create_cdma_connect_properties (connection); + else { + nm_log_warn (LOGD_MB, "(%s) not a mobile broadband modem", + nm_modem_get_uid (NM_MODEM (self))); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + if (!self->priv->simple_iface) + self->priv->simple_iface = mm_object_get_modem_simple (self->priv->modem_object); + + g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (self->priv->simple_iface), MODEM_CONNECT_TIMEOUT_SECS * 1000); + mm_modem_simple_connect (self->priv->simple_iface, + self->priv->connect_properties, + NULL, + (GAsyncReadyCallback)connect_ready, + g_object_ref (self)); + + return NM_ACT_STAGE_RETURN_POSTPONE; +} + +/*****************************************************************************/ + +static gboolean +check_connection_compatible (NMModem *_self, + NMConnection *connection, + GError **error) +{ + NMModemBroadband *self = NM_MODEM_BROADBAND (_self); + MMModemCapability modem_caps; + NMSettingConnection *s_con; + + modem_caps = mm_modem_get_current_capabilities (self->priv->modem_iface); + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + + if (MODEM_CAPS_3GPP (modem_caps)) { + NMSettingGsm *s_gsm; + + if (!g_str_equal (nm_setting_connection_get_connection_type (s_con), + NM_SETTING_GSM_SETTING_NAME)) { + g_set_error (error, + NM_MODEM_ERROR, + NM_MODEM_ERROR_CONNECTION_NOT_GSM, + "The connection was not a 3GPP connection."); + return FALSE; + } + + s_gsm = nm_connection_get_setting_gsm (connection); + if (!s_gsm) { + g_set_error (error, + NM_MODEM_ERROR, + NM_MODEM_ERROR_CONNECTION_INVALID, + "The connection was not a valid 3GPP connection."); + return FALSE; + } + + return TRUE; + } + + if (MODEM_CAPS_3GPP2 (modem_caps)) { + NMSettingCdma *s_cdma; + + if (!g_str_equal (nm_setting_connection_get_connection_type (s_con), + NM_SETTING_CDMA_SETTING_NAME)) { + g_set_error (error, + NM_MODEM_ERROR, + NM_MODEM_ERROR_CONNECTION_NOT_CDMA, + "The connection was not a 3GPP2 connection."); + return FALSE; + } + + s_cdma = nm_connection_get_setting_cdma (connection); + if (!s_cdma) { + g_set_error (error, + NM_MODEM_ERROR, + NM_MODEM_ERROR_CONNECTION_INVALID, + "The connection was not a valid 3GPP2 connection."); + return FALSE; + } + + return TRUE; + } + + g_set_error (error, + NM_MODEM_ERROR, + NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE, + "Device is not a mobile broadband modem"); + return FALSE; +} + +/*****************************************************************************/ + +static gboolean +complete_connection (NMModem *_self, + NMConnection *connection, + const GSList *existing_connections, + GError **error) +{ + NMModemBroadband *self = NM_MODEM_BROADBAND (_self); + MMModemCapability modem_caps; + NMSettingPPP *s_ppp; + + modem_caps = mm_modem_get_current_capabilities (self->priv->modem_iface); + + /* PPP settings common to 3GPP and 3GPP2 */ + s_ppp = nm_connection_get_setting_ppp (connection); + if (!s_ppp) { + s_ppp = (NMSettingPPP *) nm_setting_ppp_new (); + g_object_set (G_OBJECT (s_ppp), + NM_SETTING_PPP_LCP_ECHO_FAILURE, 5, + NM_SETTING_PPP_LCP_ECHO_INTERVAL, 30, + NULL); + nm_connection_add_setting (connection, NM_SETTING (s_ppp)); + } + + if (MODEM_CAPS_3GPP (modem_caps)) { + NMSettingGsm *s_gsm; + + s_gsm = nm_connection_get_setting_gsm (connection); + if (!s_gsm || !nm_setting_gsm_get_apn (s_gsm)) { + /* Need an APN at least */ + g_set_error_literal (error, + NM_SETTING_GSM_ERROR, + NM_SETTING_GSM_ERROR_MISSING_PROPERTY, + NM_SETTING_GSM_APN); + return FALSE; + } + + /* TODO: This is not needed */ + if (!nm_setting_gsm_get_number (s_gsm)) + g_object_set (G_OBJECT (s_gsm), NM_SETTING_GSM_NUMBER, "*99#", NULL); + + nm_utils_complete_generic (connection, + NM_SETTING_GSM_SETTING_NAME, + existing_connections, + _("GSM connection %d"), + NULL, + FALSE); /* No IPv6 yet by default */ + + return TRUE; + } + + if (MODEM_CAPS_3GPP2 (modem_caps)) { + NMSettingCdma *s_cdma; + + s_cdma = nm_connection_get_setting_cdma (connection); + if (!s_cdma) { + s_cdma = (NMSettingCdma *) nm_setting_cdma_new (); + nm_connection_add_setting (connection, NM_SETTING (s_cdma)); + } + + if (!nm_setting_cdma_get_number (s_cdma)) + g_object_set (G_OBJECT (s_cdma), NM_SETTING_CDMA_NUMBER, "#777", NULL); + + nm_utils_complete_generic (connection, + NM_SETTING_CDMA_SETTING_NAME, + existing_connections, + _("CDMA connection %d"), + NULL, + FALSE); /* No IPv6 yet by default */ + + return TRUE; + } + + g_set_error (error, + NM_MODEM_ERROR, + NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE, + "Device is not a mobile broadband modem"); + return FALSE; +} + +/*****************************************************************************/ + +static gboolean +get_user_pass (NMModem *modem, + NMConnection *connection, + const char **user, + const char **pass) +{ + NMSettingGsm *s_gsm; + NMSettingCdma *s_cdma; + + s_gsm = nm_connection_get_setting_gsm (connection); + s_cdma = nm_connection_get_setting_cdma (connection); + if (!s_gsm && !s_cdma) + return FALSE; + + if (user) { + if (s_gsm) + *user = nm_setting_gsm_get_username (s_gsm); + else if (s_cdma) + *user = nm_setting_cdma_get_username (s_cdma); + } + if (pass) { + if (s_gsm) + *pass = nm_setting_gsm_get_password (s_gsm); + else if (s_cdma) + *pass = nm_setting_cdma_get_password (s_cdma); + } + + return TRUE; +} + +/*****************************************************************************/ +/* Query/Update enabled state */ + +static void +update_mm_enabled (NMModem *self, + gboolean new_enabled) +{ + if (nm_modem_get_mm_enabled (self) != new_enabled) { + g_object_set (self, + NM_MODEM_ENABLED, new_enabled, + NULL); + } +} + +static void +modem_disable_ready (MMModem *modem_iface, + GAsyncResult *res, + NMModemBroadband *self) +{ + GError *error = NULL; + + if (!mm_modem_disable_finish (modem_iface, res, &error)) { + nm_log_warn (LOGD_MB, "(%s) failed to disable modem: %s", + nm_modem_get_uid (NM_MODEM (self)), + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } else + /* Update enabled/disabled state again */ + update_mm_enabled (NM_MODEM (self), FALSE); + + /* Balance refcount */ + g_object_unref (self); +} + +static void +modem_enable_ready (MMModem *modem_iface, + GAsyncResult *res, + NMModemBroadband *self) +{ + GError *error = NULL; + + if (!mm_modem_enable_finish (modem_iface, res, &error)) { + nm_log_warn (LOGD_MB, "(%s) failed to enable modem: %s", + nm_modem_get_uid (NM_MODEM (self)), + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } else + update_mm_enabled (NM_MODEM (self), TRUE); + + /* Balance refcount */ + g_object_unref (self); +} + +static void +set_mm_enabled (NMModem *_self, + gboolean enabled) +{ + NMModemBroadband *self = NM_MODEM_BROADBAND (_self); + + if (enabled) { + /* Don't even try to enable if we're known to be already locked */ + if (mm_modem_get_state (self->priv->modem_iface) == MM_MODEM_STATE_LOCKED) { + nm_log_warn (LOGD_MB, "(%s) cannot enable modem: locked", + nm_modem_get_uid (NM_MODEM (self))); + g_signal_emit_by_name (self, NM_MODEM_AUTH_REQUESTED, 0); + return; + } + + mm_modem_enable (self->priv->modem_iface, + NULL, /* cancellable */ + (GAsyncReadyCallback)modem_enable_ready, + g_object_ref (self)); + } else { + mm_modem_disable (self->priv->modem_iface, + NULL, /* cancellable */ + (GAsyncReadyCallback)modem_disable_ready, + g_object_ref (self)); + + /* When disabling don't say we're enabled */ + update_mm_enabled (NM_MODEM (self), enabled); + } +} + +/*****************************************************************************/ +/* IP method static */ + +static gboolean +ip_string_to_network_address (const gchar *str, + guint32 *out) +{ + guint32 addr = 0; + gboolean success = FALSE; + + if (!str || inet_pton (AF_INET, str, &addr) != 1) + addr = 0; + else + success = TRUE; + + *out = (guint32)addr; + return success; +} + +static gboolean +static_stage3_done (NMModemBroadband *self) +{ + GError *error = NULL; + NMIP4Config *config = NULL; + const gchar *address_string; + const gchar *gw_string; + guint32 address_network; + guint32 gw; + NMPlatformIP4Address address; + const gchar **dns; + guint i; + + g_assert (self->priv->ipv4_config); + + nm_log_info (LOGD_MB, "(%s): IPv4 static configuration:", + nm_modem_get_uid (NM_MODEM (self))); + + /* Fully fail if invalid IP address retrieved */ + address_string = mm_bearer_ip_config_get_address (self->priv->ipv4_config); + if (!ip_string_to_network_address (address_string, &address_network)) { + error = g_error_new (NM_MODEM_ERROR, + NM_MODEM_ERROR_CONNECTION_INVALID, + "(%s) retrieving IP4 configuration failed: invalid address given '%s'", + nm_modem_get_uid (NM_MODEM (self)), + address_string); + goto out; + } + + /* Missing gateway not a hard failure */ + gw_string = mm_bearer_ip_config_get_gateway (self->priv->ipv4_config); + ip_string_to_network_address (gw_string, &gw); + + config = nm_ip4_config_new (); + + memset (&address, 0, sizeof (address)); + address.address = address_network; + address.plen = mm_bearer_ip_config_get_prefix (self->priv->ipv4_config); + address.source = NM_PLATFORM_SOURCE_WWAN; + nm_ip4_config_add_address (config, &address); + + nm_log_info (LOGD_MB, " address %s/%d", address_string, address.plen); + + if (gw) { + nm_ip4_config_set_gateway (config, gw); + nm_log_info (LOGD_MB, " gateway %s", gw_string); + } + + /* DNS servers */ + dns = mm_bearer_ip_config_get_dns (self->priv->ipv4_config); + for (i = 0; dns[i]; i++) { + if ( ip_string_to_network_address (dns[i], &address_network) + && address_network > 0) { + nm_ip4_config_add_nameserver (config, address_network); + nm_log_info (LOGD_MB, " DNS %s", dns[i]); + } + } + +out: + g_signal_emit_by_name (self, NM_MODEM_IP4_CONFIG_RESULT, config, error); + g_clear_error (&error); + return FALSE; +} + +static NMActStageReturn +static_stage3_ip4_config_start (NMModem *_self, + NMActRequest *req, + NMDeviceStateReason *reason) +{ + NMModemBroadband *self = NM_MODEM_BROADBAND (_self); + + /* We schedule it in an idle just to follow the same logic as in the + * generic modem implementation. */ + g_idle_add ((GSourceFunc)static_stage3_done, self); + + return NM_ACT_STAGE_RETURN_POSTPONE; +} + +/*****************************************************************************/ +/* Disconnect */ + +typedef struct { + NMModemBroadband *self; + gboolean warn; +} SimpleDisconnectContext; + +static void +simple_disconnect_context_free (SimpleDisconnectContext *ctx) +{ + g_object_unref (ctx->self); + g_slice_free (SimpleDisconnectContext, ctx); +} + +static void +simple_disconnect_ready (MMModemSimple *modem_iface, + GAsyncResult *res, + SimpleDisconnectContext *ctx) +{ + GError *error = NULL; + + if (!mm_modem_simple_disconnect_finish (modem_iface, res, &error)) { + if (ctx->warn) + nm_log_warn (LOGD_MB, "(%s) failed to disconnect modem: %s", + nm_modem_get_uid (NM_MODEM (ctx->self)), + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } + + simple_disconnect_context_free (ctx); +} + +static void +disconnect (NMModem *self, + gboolean warn) +{ + SimpleDisconnectContext *ctx; + + ctx = g_slice_new (SimpleDisconnectContext); + ctx->self = g_object_ref (self); + + /* Don't bother warning on FAILED since the modem is already gone */ + ctx->warn = warn; + + mm_modem_simple_disconnect ( + ctx->self->priv->simple_iface, + NULL, /* bearer path; if NULL given ALL get disconnected */ + NULL, /* cancellable */ + (GAsyncReadyCallback)simple_disconnect_ready, + ctx); +} + +/*****************************************************************************/ + +static void +deactivate (NMModem *_self, NMDevice *device) +{ + NMModemBroadband *self = NM_MODEM_BROADBAND (_self); + + /* TODO: cancel SimpleConnect() if any */ + + /* Cleanup IPv4 addresses and routes */ + g_clear_object (&self->priv->ipv4_config); + g_clear_object (&self->priv->ipv6_config); + g_clear_object (&self->priv->bearer); + + self->priv->pin_tries = 0; + + /* Chain up parent's */ + NM_MODEM_CLASS (nm_modem_broadband_parent_class)->deactivate (_self, device); +} + +/*****************************************************************************/ + +static void +modem_state_changed (MMModem *modem, + MMModemState old_state, + MMModemState new_state, + MMModemStateChangeReason reason, + NMModemBroadband *self) +{ + gboolean old; + gboolean new; + + nm_log_info (LOGD_MB, "(%s) modem state changed, '%s' --> '%s' (reason: %s)\n", + nm_modem_get_uid (NM_MODEM (self)), + mm_modem_state_get_string (old_state), + mm_modem_state_get_string (new_state), + mm_modem_state_change_reason_get_string (reason)); + + old = nm_modem_get_mm_enabled (NM_MODEM (self)); + new = (mm_modem_get_state (self->priv->modem_iface) >= MM_MODEM_STATE_ENABLED); + if (old != new) + g_object_set (self, + NM_MODEM_ENABLED, new, + NULL); + + old = nm_modem_get_mm_connected (NM_MODEM (self)); + new = (mm_modem_get_state (self->priv->modem_iface) >= MM_MODEM_STATE_CONNECTED); + if (old != new) + g_object_set (self, + NM_MODEM_CONNECTED, new, + NULL); +} + +/*****************************************************************************/ + +NMModem * +nm_modem_broadband_new (GObject *object, GError **error) +{ + NMModem *modem; + MMObject *modem_object; + MMModem *modem_iface; + gchar *drivers; + + g_return_val_if_fail (MM_IS_OBJECT (object), NULL); + modem_object = MM_OBJECT (object); + + /* Ensure we have the 'Modem' interface and the primary port at least */ + modem_iface = mm_object_peek_modem (modem_object); + g_return_val_if_fail (!!modem_iface, NULL); + g_return_val_if_fail (!!mm_modem_get_primary_port (modem_iface), NULL); + + /* If the modem is in 'FAILED' state we cannot do anything with it. + * This happens when a severe error happened when trying to initialize it, + * like missing SIM. */ + if (mm_modem_get_state (modem_iface) == MM_MODEM_STATE_FAILED) { + g_set_error (error, NM_MODEM_ERROR, NM_MODEM_ERROR_INITIALIZATION_FAILED, + "(%s): unusable modem detected", + mm_modem_get_primary_port (modem_iface)); + return NULL; + } + + /* Build a single string with all drivers listed */ + drivers = g_strjoinv (", ", (gchar **)mm_modem_get_drivers (modem_iface)); + + modem = g_object_new (NM_TYPE_MODEM_BROADBAND, + NM_MODEM_PATH, mm_object_get_path (modem_object), + NM_MODEM_UID, mm_modem_get_primary_port (modem_iface), + NM_MODEM_CONTROL_PORT, mm_modem_get_primary_port (modem_iface), + NM_MODEM_DATA_PORT, NULL, /* We don't know it until bearer created */ + NM_MODEM_BROADBAND_MODEM, modem_object, + NM_MODEM_DRIVER, drivers, + NULL); + g_free (drivers); + return modem; +} + +static void +nm_modem_broadband_init (NMModemBroadband *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + NM_TYPE_MODEM_BROADBAND, + NMModemBroadbandPrivate); +} + +static void +set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NMModemBroadband *self = NM_MODEM_BROADBAND (object); + + switch (prop_id) { + case PROP_MODEM: + /* construct-only */ + self->priv->modem_object = g_value_dup_object (value); + self->priv->modem_iface = mm_object_get_modem (self->priv->modem_object); + g_assert (self->priv->modem_iface != NULL); + g_signal_connect (self->priv->modem_iface, + "state-changed", + G_CALLBACK (modem_state_changed), + self); + + g_object_set (object, + NM_MODEM_ENABLED, (mm_modem_get_state (self->priv->modem_iface) >= MM_MODEM_STATE_ENABLED), + NM_MODEM_CONNECTED, (mm_modem_get_state (self->priv->modem_iface) >= MM_MODEM_STATE_CONNECTED), + NULL); + + /* Note: don't grab the Simple iface here; the Modem interface is the + * only one assumed to be always valid and available */ + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NMModemBroadband *self = NM_MODEM_BROADBAND (object); + + switch (prop_id) { + case PROP_MODEM: + g_value_set_object (value, self->priv->modem_object); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + NMModemBroadband *self = NM_MODEM_BROADBAND (object); + + g_clear_object (&self->priv->ipv4_config); + g_clear_object (&self->priv->ipv6_config); + g_clear_object (&self->priv->bearer); + g_clear_object (&self->priv->modem_iface); + g_clear_object (&self->priv->simple_iface); + g_clear_object (&self->priv->modem_object); + + G_OBJECT_CLASS (nm_modem_broadband_parent_class)->dispose (object); +} + +static void +nm_modem_broadband_class_init (NMModemBroadbandClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMModemClass *modem_class = NM_MODEM_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMModemBroadbandPrivate)); + + /* Virtual methods */ + object_class->dispose = dispose; + object_class->get_property = get_property; + object_class->set_property = set_property; + + modem_class->get_capabilities = get_capabilities; + modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start; + modem_class->disconnect = disconnect; + modem_class->deactivate = deactivate; + modem_class->set_mm_enabled = set_mm_enabled; + modem_class->get_user_pass = get_user_pass; + modem_class->check_connection_compatible = check_connection_compatible; + modem_class->complete_connection = complete_connection; + modem_class->act_stage1_prepare = act_stage1_prepare; + modem_class->owns_port = owns_port; + + /* Properties */ + g_object_class_install_property + (object_class, PROP_MODEM, + g_param_spec_object (NM_MODEM_BROADBAND_MODEM, + "Modem", + "Broadband modem object", + MM_GDBUS_TYPE_OBJECT, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} diff --git a/src/devices/wwan/nm-modem-broadband.h b/src/devices/wwan/nm-modem-broadband.h new file mode 100644 index 0000000000..e12ca68caf --- /dev/null +++ b/src/devices/wwan/nm-modem-broadband.h @@ -0,0 +1,58 @@ +/* -*- 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) 2012 - Aleksander Morgado + */ + +#ifndef NM_MODEM_BROADBAND_H +#define NM_MODEM_BROADBAND_H + +#include +#include +#include "nm-modem.h" + +G_BEGIN_DECLS + +#define NM_TYPE_MODEM_BROADBAND (nm_modem_broadband_get_type ()) +#define NM_MODEM_BROADBAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadband)) +#define NM_MODEM_BROADBAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_MODEM_BROADBAND, NMModemBroadbandClass)) +#define NM_IS_MODEM_BROADBAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_BROADBAND)) +#define NM_IS_MODEM_BROADBAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_MODEM_BROADBAND)) +#define NM_MODEM_BROADBAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadbandClass)) + +#define NM_MODEM_BROADBAND_MODEM "modem" + +typedef struct _NMModemBroadband NMModemBroadband; +typedef struct _NMModemBroadbandClass NMModemBroadbandClass; +typedef struct _NMModemBroadbandPrivate NMModemBroadbandPrivate; + +struct _NMModemBroadband { + NMModem parent; + NMModemBroadbandPrivate *priv; +}; + +struct _NMModemBroadbandClass { + NMModemClass parent; +}; + +GType nm_modem_broadband_get_type (void); + +NMModem *nm_modem_broadband_new (GObject *object, GError **error); + +G_END_DECLS + +#endif /* NM_MODEM_BROADBAND_H */ diff --git a/src/devices/wwan/nm-modem-manager.c b/src/devices/wwan/nm-modem-manager.c new file mode 100644 index 0000000000..c48117004e --- /dev/null +++ b/src/devices/wwan/nm-modem-manager.c @@ -0,0 +1,757 @@ +/* -*- 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 - 2014 Red Hat, Inc. + * Copyright (C) 2009 Novell, Inc. + * Copyright (C) 2009 Canonical Ltd. + */ + +#include +#include "config.h" +#include "nm-modem-manager.h" +#include "nm-logging.h" +#include "nm-modem.h" +#include "nm-modem-old.h" +#include "nm-dbus-manager.h" +#include "nm-modem-old-types.h" +#include "nm-dbus-glib-types.h" + +#if WITH_MODEM_MANAGER_1 +#include +#include "nm-modem-broadband.h" +#endif + +#define MODEM_POKE_INTERVAL 120 + +G_DEFINE_TYPE (NMModemManager, nm_modem_manager, G_TYPE_OBJECT) + +struct _NMModemManagerPrivate { + /* ModemManager < 0.7 */ + NMDBusManager *dbus_mgr; + DBusGProxy *proxy; + guint poke_id; + +#if WITH_MODEM_MANAGER_1 + /* ModemManager >= 0.7 */ + GDBusConnection *dbus_connection; + MMManager *modem_manager_1; + guint modem_manager_1_launch_id; + gboolean old_modem_manager_found; + gboolean new_modem_manager_found; + guint modem_manager_1_name_owner_changed_id; + guint modem_manager_1_object_added_id; + guint modem_manager_1_object_removed_id; +#endif + + /* Common */ + GHashTable *modems; +}; + +enum { + MODEM_ADDED, + LAST_SIGNAL, +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +/************************************************************************/ + +static void +handle_new_modem (NMModemManager *self, NMModem *modem) +{ + const char *path; + + path = nm_modem_get_path (modem); + if (g_hash_table_lookup (self->priv->modems, path)) { + g_warn_if_reached (); + return; + } + + /* Track the new modem */ + g_hash_table_insert (self->priv->modems, g_strdup (path), modem); + g_signal_emit (self, signals[MODEM_ADDED], 0, modem); +} + +/************************************************************************/ +/* Support for ModemManager < 0.7 */ + +static void +clear_modem_manager_support (NMModemManager *self) +{ + if (self->priv->poke_id) { + g_source_remove (self->priv->poke_id); + self->priv->poke_id = 0; + } + + if (self->priv->proxy) { + g_object_unref (self->priv->proxy); + self->priv->proxy = NULL; + } +} + +static void +create_modem (NMModemManager *self, const char *path) +{ + DBusGProxy *proxy; + GError *error = NULL; + NMModem *modem = NULL; + GHashTable *properties; + + if (g_hash_table_lookup (self->priv->modems, path)) { + nm_log_warn (LOGD_MB, "modem with path %s already exists, ignoring", path); + return; + } + + proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (self->priv->dbus_mgr), + MM_OLD_DBUS_SERVICE, + path, + DBUS_INTERFACE_PROPERTIES); + g_assert (proxy); + if (dbus_g_proxy_call_with_timeout (proxy, "GetAll", 15000, &error, + G_TYPE_STRING, MM_OLD_DBUS_INTERFACE_MODEM, + G_TYPE_INVALID, + DBUS_TYPE_G_MAP_OF_VARIANT, &properties, + G_TYPE_INVALID)) { + /* Success, create the modem */ + modem = nm_modem_old_new (path, properties, &error); + if (modem) + handle_new_modem (self, modem); + else { + nm_log_warn (LOGD_MB, "failed to create modem: %s", + error ? error->message : "(unknown)"); + } + g_hash_table_destroy (properties); + } else { + nm_log_warn (LOGD_MB, "could not get modem properties: %s %s", + error ? dbus_g_error_get_name (error) : "(none)", + error ? error->message : "(unknown)"); + } + + g_object_unref (proxy); + g_clear_error (&error); +} + +static void +modem_added (DBusGProxy *proxy, const char *path, gpointer user_data) +{ + create_modem (NM_MODEM_MANAGER (user_data), path); +} + +static void +modem_removed (DBusGProxy *proxy, const char *path, gpointer user_data) +{ + NMModemManager *self = NM_MODEM_MANAGER (user_data); + NMModem *modem; + + modem = (NMModem *) g_hash_table_lookup (self->priv->modems, path); + if (modem) { + nm_modem_emit_removed (modem); + g_hash_table_remove (self->priv->modems, path); + } +} + +static void +mm_poke_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +{ + GPtrArray *modems; + int i; + + if (dbus_g_proxy_end_call (proxy, call, NULL, + DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &modems, + G_TYPE_INVALID)) { + /* Don't care about the returned value, just free it */ + for (i = 0; i < modems->len; i++) + g_free ((char *) g_ptr_array_index (modems, i)); + g_ptr_array_free (modems, TRUE); + } + g_object_unref (proxy); +} + +static gboolean +poke_modem_cb (gpointer user_data) +{ + NMModemManager *self = NM_MODEM_MANAGER (user_data); + DBusGConnection *g_connection; + DBusGProxy *proxy; + + g_connection = nm_dbus_manager_get_connection (self->priv->dbus_mgr); + proxy = dbus_g_proxy_new_for_name (g_connection, + MM_OLD_DBUS_SERVICE, + MM_OLD_DBUS_PATH, + MM_OLD_DBUS_INTERFACE); + + nm_log_dbg (LOGD_MB, "Requesting to (re)launch modem-manager..."); + + dbus_g_proxy_begin_call_with_timeout (proxy, + "EnumerateDevices", + mm_poke_cb, + NULL, + NULL, + 5000, + G_TYPE_INVALID); + return TRUE; +} + +static void +enumerate_devices_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer data) +{ + NMModemManager *manager = NM_MODEM_MANAGER (data); + GPtrArray *modems; + GError *error = NULL; + + if (!dbus_g_proxy_end_call (proxy, call_id, &error, + dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &modems, + G_TYPE_INVALID)) { + nm_log_warn (LOGD_MB, "could not get modem list: %s", error->message); + g_error_free (error); + } else { + int i; + + for (i = 0; i < modems->len; i++) { + char *path = (char *) g_ptr_array_index (modems, i); + + create_modem (manager, path); + g_free (path); + } + + g_ptr_array_free (modems, TRUE); + } +} + +#if WITH_MODEM_MANAGER_1 +static void clear_modem_manager_1_support (NMModemManager *self); +#endif + +static void +modem_manager_appeared (NMModemManager *self, gboolean enumerate_devices) +{ + if (self->priv->poke_id) { + g_source_remove (self->priv->poke_id); + self->priv->poke_id = 0; + } + + nm_log_info (LOGD_MB, "modem-manager is now available"); + +#if WITH_MODEM_MANAGER_1 + self->priv->old_modem_manager_found = TRUE; + if (self->priv->new_modem_manager_found) + nm_log_warn (LOGD_MB, "Both the old and the new ModemManager were found"); + else + clear_modem_manager_1_support (self); +#endif + + self->priv->proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (self->priv->dbus_mgr), + MM_OLD_DBUS_SERVICE, MM_OLD_DBUS_PATH, MM_OLD_DBUS_INTERFACE); + + dbus_g_proxy_add_signal (self->priv->proxy, "DeviceAdded", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (self->priv->proxy, "DeviceAdded", + G_CALLBACK (modem_added), self, + NULL); + + dbus_g_proxy_add_signal (self->priv->proxy, "DeviceRemoved", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (self->priv->proxy, "DeviceRemoved", + G_CALLBACK (modem_removed), self, + NULL); + + if (enumerate_devices) + dbus_g_proxy_begin_call (self->priv->proxy, "EnumerateDevices", enumerate_devices_done, self, NULL, G_TYPE_INVALID); +} + +static gboolean +remove_one_modem (gpointer key, gpointer value, gpointer user_data) +{ + nm_modem_emit_removed (NM_MODEM (value)); + return TRUE; +} + +static void +modem_manager_disappeared (NMModemManager *self) +{ + g_hash_table_foreach_remove (self->priv->modems, remove_one_modem, self); + + if (self->priv->proxy) { + g_object_unref (self->priv->proxy); + self->priv->proxy = NULL; + } + + /* Try to activate the modem-manager */ + nm_log_dbg (LOGD_MB, "trying to start the modem manager..."); + poke_modem_cb (self); + self->priv->poke_id = g_timeout_add_seconds (MODEM_POKE_INTERVAL, poke_modem_cb, self); +} + +static void +nm_modem_manager_name_owner_changed (NMDBusManager *dbus_mgr, + const char *name, + const char *old_owner, + const char *new_owner, + gpointer user_data) +{ + gboolean old_owner_good; + gboolean new_owner_good; + + /* Can't handle the signal if its not from the modem service */ + if (strcmp (MM_OLD_DBUS_SERVICE, name) != 0) + return; + + old_owner_good = (old_owner && strlen (old_owner)); + new_owner_good = (new_owner && strlen (new_owner)); + + if (!old_owner_good && new_owner_good) { + modem_manager_appeared (NM_MODEM_MANAGER (user_data), FALSE); + } else if (old_owner_good && !new_owner_good) { + nm_log_info (LOGD_MB, "the modem manager disappeared"); + modem_manager_disappeared (NM_MODEM_MANAGER (user_data)); + } +} + +/************************************************************************/ +/* Support for ModemManager >= 0.7 */ + +#if WITH_MODEM_MANAGER_1 + +static void +modem_manager_1_clear_signals (NMModemManager *self) +{ + if (!self->priv->modem_manager_1) + return; + + if (self->priv->modem_manager_1_name_owner_changed_id) { + if (g_signal_handler_is_connected (self->priv->modem_manager_1, + self->priv->modem_manager_1_name_owner_changed_id)) + g_signal_handler_disconnect (self->priv->modem_manager_1, + self->priv->modem_manager_1_name_owner_changed_id); + self->priv->modem_manager_1_name_owner_changed_id = 0; + } + + if (self->priv->modem_manager_1_object_added_id) { + if (g_signal_handler_is_connected (self->priv->modem_manager_1, + self->priv->modem_manager_1_object_added_id)) + g_signal_handler_disconnect (self->priv->modem_manager_1, + self->priv->modem_manager_1_object_added_id); + self->priv->modem_manager_1_object_added_id = 0; + } + + if (self->priv->modem_manager_1_object_removed_id) { + if (g_signal_handler_is_connected (self->priv->modem_manager_1, + self->priv->modem_manager_1_object_removed_id)) + g_signal_handler_disconnect (self->priv->modem_manager_1, + self->priv->modem_manager_1_object_removed_id); + self->priv->modem_manager_1_object_removed_id = 0; + } +} + +static void +clear_modem_manager_1_support (NMModemManager *self) +{ + if (self->priv->modem_manager_1_launch_id) { + g_source_remove (self->priv->modem_manager_1_launch_id); + self->priv->modem_manager_1_launch_id = 0; + } + + modem_manager_1_clear_signals (self); + g_clear_object (&self->priv->modem_manager_1); + g_clear_object (&self->priv->dbus_connection); +} + +static void +modem_object_added (MMManager *modem_manager, + MMObject *modem_object, + NMModemManager *self) +{ + const gchar *path; + MMModem *modem_iface; + NMModem *modem; + GError *error = NULL; + + /* Ensure we don't have the same modem already */ + path = mm_object_get_path (modem_object); + if (g_hash_table_lookup (self->priv->modems, path)) { + nm_log_warn (LOGD_MB, "modem with path %s already exists, ignoring", path); + return; + } + + /* Ensure we have the 'Modem' interface at least */ + modem_iface = mm_object_peek_modem (modem_object); + if (!modem_iface) { + nm_log_warn (LOGD_MB, "modem with path %s doesn't have the Modem interface, ignoring", path); + return; + } + + /* Ensure we have a primary port reported */ + if (!mm_modem_get_primary_port (modem_iface)) { + nm_log_warn (LOGD_MB, "modem with path %s has unknown primary port, ignoring", path); + return; + } + + /* Create a new modem object */ + modem = nm_modem_broadband_new (G_OBJECT (modem_object), &error); + if (modem) + handle_new_modem (self, modem); + else { + nm_log_warn (LOGD_MB, "failed to create modem: %s", + error ? error->message : "(unknown)"); + } + g_clear_error (&error); +} + +static void +modem_object_removed (MMManager *manager, + MMObject *modem_object, + NMModemManager *self) +{ + NMModem *modem; + const gchar *path; + + path = mm_object_get_path (modem_object); + modem = (NMModem *) g_hash_table_lookup (self->priv->modems, path); + if (!modem) + return; + + nm_modem_emit_removed (modem); + g_hash_table_remove (self->priv->modems, path); +} + +static void +modem_manager_1_available (NMModemManager *self) +{ + GList *modems, *l; + + nm_log_info (LOGD_MB, "ModemManager available in the bus"); + + self->priv->new_modem_manager_found = TRUE; + if (self->priv->old_modem_manager_found) + nm_log_warn (LOGD_MB, "Both the old and the new ModemManager were found"); + else + clear_modem_manager_support (self); + + /* Update initial modems list */ + modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->priv->modem_manager_1)); + for (l = modems; l; l = g_list_next (l)) + modem_object_added (self->priv->modem_manager_1, MM_OBJECT (l->data), self); + g_list_free_full (modems, (GDestroyNotify) g_object_unref); +} + +static void schedule_modem_manager_1_relaunch (NMModemManager *self, + guint n_seconds); +static void ensure_client (NMModemManager *self); + +static void +modem_manager_1_name_owner_changed (MMManager *modem_manager_1, + GParamSpec *pspec, + NMModemManager *self) +{ + gchar *name_owner; + + /* Quit poking, if any */ + if (self->priv->modem_manager_1_launch_id) { + g_source_remove (self->priv->modem_manager_1_launch_id); + self->priv->modem_manager_1_launch_id = 0; + } + + name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (modem_manager_1)); + if (!name_owner) { + nm_log_info (LOGD_MB, "ModemManager disappeared from bus"); + +#if !HAVE_SYSTEMD + /* If not managed by systemd, schedule relaunch */ + schedule_modem_manager_1_relaunch (self, 0); +#endif + + return; + } + + /* Available! */ + g_free (name_owner); + + /* Hack alert: GDBusObjectManagerClient won't signal neither 'object-added' + * nor 'object-removed' if it was created while there was no ModemManager in + * the bus. This hack avoids this issue until we get a GIO with the fix + * included... */ + modem_manager_1_clear_signals (self); + g_clear_object (&self->priv->modem_manager_1); + ensure_client (self); + + /* Whenever GDBusObjectManagerClient is fixed, we can just do the following: + * modem_manager_1_available (self); + */ +} + +#if !HAVE_SYSTEMD + +static void +modem_manager_1_poke_cb (GDBusConnection *connection, + GAsyncResult *res, + NMModemManager *self) +{ + GError *error = NULL; + GVariant *result; + + result = g_dbus_connection_call_finish (connection, res, &error); + if (error) { + /* Ignore common errors when MM is not installed and such */ + if ( !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN) + && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_EXEC_FAILED) + && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FORK_FAILED) + && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FAILED) + && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_TIMEOUT) + && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) { + nm_log_dbg (LOGD_MB, "error poking ModemManager: %s", error->message); + } + g_error_free (error); + + /* Setup timeout to relaunch */ + schedule_modem_manager_1_relaunch (self, MODEM_POKE_INTERVAL); + } else + g_variant_unref (result); + + /* Balance refcount */ + g_object_unref (self); +} + +static void +modem_manager_1_poke (NMModemManager *self) +{ + /* If there is no current owner right away, ensure we poke to get one */ + g_dbus_connection_call (self->priv->dbus_connection, + "org.freedesktop.ModemManager1", + "/org/freedesktop/ModemManager1", + "org.freedesktop.DBus.Peer", + "Ping", + NULL, /* inputs */ + NULL, /* outputs */ + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, /* cancellable */ + (GAsyncReadyCallback)modem_manager_1_poke_cb, /* callback */ + g_object_ref (self)); /* user_data */ +} + +#endif /* HAVE_SYSTEMD */ + +static void +modem_manager_1_check_name_owner (NMModemManager *self) +{ + gchar *name_owner; + + name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (self->priv->modem_manager_1)); + if (name_owner) { + /* Available! */ + modem_manager_1_available (self); + g_free (name_owner); + return; + } + +#if !HAVE_SYSTEMD + /* If the lifecycle is not managed by systemd, poke */ + modem_manager_1_poke (self); +#endif +} + +static void +manager_new_ready (GObject *source, + GAsyncResult *res, + NMModemManager *self) +{ + /* Note we always get an extra reference to self here */ + + GError *error = NULL; + + g_assert (!self->priv->modem_manager_1); + self->priv->modem_manager_1 = mm_manager_new_finish (res, &error); + if (!self->priv->modem_manager_1) { + /* We're not really supposed to get any error here. If we do get one, + * though, just re-schedule the MMManager creation after some time. + * During this period, name-owner changes won't be followed. */ + nm_log_warn (LOGD_MB, "error creating ModemManager client: %s", error->message); + g_error_free (error); + /* Setup timeout to relaunch */ + schedule_modem_manager_1_relaunch (self, MODEM_POKE_INTERVAL); + } else if (self->priv->old_modem_manager_found) { + /* If we found the old MM, abort */ + clear_modem_manager_1_support (self); + } else { + /* Setup signals in the GDBusObjectManagerClient */ + self->priv->modem_manager_1_name_owner_changed_id = + g_signal_connect (self->priv->modem_manager_1, + "notify::name-owner", + G_CALLBACK (modem_manager_1_name_owner_changed), + self); + self->priv->modem_manager_1_object_added_id = + g_signal_connect (self->priv->modem_manager_1, + "object-added", + G_CALLBACK (modem_object_added), + self); + self->priv->modem_manager_1_object_removed_id = + g_signal_connect (self->priv->modem_manager_1, + "object-removed", + G_CALLBACK (modem_object_removed), + self); + + modem_manager_1_check_name_owner (self); + } + + /* Balance refcount */ + g_object_unref (self); +} + +static void +ensure_client (NMModemManager *self) +{ + g_assert (self->priv->dbus_connection); + + /* Create the GDBusObjectManagerClient. We do not request to autostart, as + * we don't really want the MMManager creation to fail. We can always poke + * later on if we want to request the autostart */ + if (!self->priv->modem_manager_1) { + mm_manager_new (self->priv->dbus_connection, + G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, + NULL, + (GAsyncReadyCallback)manager_new_ready, + g_object_ref (self)); + return; + } + + /* If already available, recheck name owner! */ + modem_manager_1_check_name_owner (self); +} + +static void +bus_get_ready (GObject *source, + GAsyncResult *res, + NMModemManager *self) +{ + /* Note we always get an extra reference to self here */ + + GError *error = NULL; + + self->priv->dbus_connection = g_bus_get_finish (res, &error); + if (!self->priv->dbus_connection) { + nm_log_warn (LOGD_CORE, "error getting bus connection: %s", error->message); + g_error_free (error); + /* Setup timeout to relaunch */ + schedule_modem_manager_1_relaunch (self, MODEM_POKE_INTERVAL); + } else if (self->priv->old_modem_manager_found) { + /* If we found the old MM, abort */ + clear_modem_manager_1_support (self); + } else { + /* Got the bus, ensure client */ + ensure_client (self); + } + + /* Balance refcount */ + g_object_unref (self); +} + +static gboolean +ensure_bus (NMModemManager *self) +{ + /* Clear launch ID */ + self->priv->modem_manager_1_launch_id = 0; + + if (!self->priv->dbus_connection) + g_bus_get (G_BUS_TYPE_SYSTEM, + NULL, + (GAsyncReadyCallback)bus_get_ready, + g_object_ref (self)); + else + /* If bus is already available, ensure client */ + ensure_client (self); + + return FALSE; +} + +static void +schedule_modem_manager_1_relaunch (NMModemManager *self, + guint n_seconds) +{ + /* No need to pass an extra reference to self; timeout/idle will be + * cancelled if the object gets disposed. */ + + if (n_seconds) + self->priv->modem_manager_1_launch_id = g_timeout_add_seconds (n_seconds, (GSourceFunc)ensure_bus, self); + else + self->priv->modem_manager_1_launch_id = g_idle_add ((GSourceFunc)ensure_bus, self); +} + +#endif /* WITH_MODEM_MANAGER_1 */ + +/************************************************************************/ + +static void +nm_modem_manager_init (NMModemManager *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_MODEM_MANAGER, NMModemManagerPrivate); + + self->priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + + /* ModemManager < 0.7 */ + self->priv->dbus_mgr = nm_dbus_manager_get (); + g_signal_connect (self->priv->dbus_mgr, NM_DBUS_MANAGER_NAME_OWNER_CHANGED, + G_CALLBACK (nm_modem_manager_name_owner_changed), + self); + if (nm_dbus_manager_name_has_owner (self->priv->dbus_mgr, MM_OLD_DBUS_SERVICE)) + modem_manager_appeared (self, TRUE); + else + modem_manager_disappeared (self); + +#if WITH_MODEM_MANAGER_1 + /* ModemManager >= 0.7 */ + schedule_modem_manager_1_relaunch (self, 0); +#endif +} + +static void +dispose (GObject *object) +{ + NMModemManager *self = NM_MODEM_MANAGER (object); + + /* ModemManager < 0.7 */ + clear_modem_manager_support (self); + +#if WITH_MODEM_MANAGER_1 + /* ModemManager >= 0.7 */ + clear_modem_manager_1_support (self); +#endif + + if (self->priv->modems) { + g_hash_table_foreach_remove (self->priv->modems, remove_one_modem, object); + g_hash_table_destroy (self->priv->modems); + } + + self->priv->dbus_mgr = NULL; + + /* Chain up to the parent class */ + G_OBJECT_CLASS (nm_modem_manager_parent_class)->dispose (object); +} + +static void +nm_modem_manager_class_init (NMModemManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMModemManagerPrivate)); + + object_class->dispose = dispose; + + signals[MODEM_ADDED] = + g_signal_new (NM_MODEM_MANAGER_MODEM_ADDED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMModemManagerClass, modem_added), + NULL, NULL, NULL, + G_TYPE_NONE, 1, NM_TYPE_MODEM); +} diff --git a/src/devices/wwan/nm-modem-manager.h b/src/devices/wwan/nm-modem-manager.h new file mode 100644 index 0000000000..3082bdb39f --- /dev/null +++ b/src/devices/wwan/nm-modem-manager.h @@ -0,0 +1,49 @@ +/* -*- 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 - 2014 Red Hat, Inc. + * Copyright (C) 2009 Novell, Inc. + * Copyright (C) 2009 Canonical Ltd. + */ + +#ifndef NM_MODEM_MANAGER_H +#define NM_MODEM_MANAGER_H + +#include +#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)) + +#define NM_MODEM_MANAGER_MODEM_ADDED "modem-added" + +typedef struct _NMModemManagerPrivate NMModemManagerPrivate; + +typedef struct { + GObject parent; + NMModemManagerPrivate *priv; +} NMModemManager; + +typedef struct { + GObjectClass parent; + + void (*modem_added) (NMModemManager *self, NMModem *modem); +} NMModemManagerClass; + +GType nm_modem_manager_get_type (void); + +#endif /* NM_MODEM_MANAGER_H */ diff --git a/src/devices/wwan/nm-modem-old-types.h b/src/devices/wwan/nm-modem-old-types.h new file mode 100644 index 0000000000..976605db2b --- /dev/null +++ b/src/devices/wwan/nm-modem-old-types.h @@ -0,0 +1,69 @@ +/* -*- 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 Novell, Inc. + */ + +#ifndef NM_MODEM_OLD_TYPES_H +#define NM_MODEM_OLD_TYPES_H + +#define MM_OLD_DBUS_SERVICE "org.freedesktop.ModemManager" +#define MM_OLD_DBUS_PATH "/org/freedesktop/ModemManager" +#define MM_OLD_DBUS_INTERFACE "org.freedesktop.ModemManager" +#define MM_OLD_DBUS_INTERFACE_MODEM "org.freedesktop.ModemManager.Modem" +#define MM_OLD_DBUS_INTERFACE_MODEM_SIMPLE "org.freedesktop.ModemManager.Modem.Simple" +#define MM_OLD_DBUS_INTERFACE_MODEM_CDMA "org.freedesktop.ModemManager.Modem.Cdma" +#define MM_OLD_DBUS_INTERFACE_MODEM_GSM_CARD "org.freedesktop.ModemManager.Modem.Gsm.Card" +#define MM_OLD_DBUS_INTERFACE_MODEM_GSM_NETWORK "org.freedesktop.ModemManager.Modem.Gsm.Network" + +#define MM_OLD_MODEM_TYPE_UNKNOWN 0 +#define MM_OLD_MODEM_TYPE_GSM 1 +#define MM_OLD_MODEM_TYPE_CDMA 2 + +/* Errors */ + +#define MM_OLD_MODEM_CONNECT_ERROR_NO_CARRIER MM_OLD_DBUS_INTERFACE_MODEM ".NoCarrier" +#define MM_OLD_MODEM_CONNECT_ERROR_NO_DIALTONE MM_OLD_DBUS_INTERFACE_MODEM ".NoDialtone" +#define MM_OLD_MODEM_CONNECT_ERROR_BUSY MM_OLD_DBUS_INTERFACE_MODEM ".Busy" +#define MM_OLD_MODEM_CONNECT_ERROR_NO_ANSWER MM_OLD_DBUS_INTERFACE_MODEM ".NoAnswer" + +#define MM_OLD_MODEM_ERROR "org.freedesktop.ModemManager.Modem.Gsm" + +#define MM_OLD_MODEM_ERROR_NETWORK_NOT_ALLOWED MM_OLD_MODEM_ERROR ".NetworkNotAllowed" +#define MM_OLD_MODEM_ERROR_NETWORK_TIMEOUT MM_OLD_MODEM_ERROR ".NetworkTimeout" +#define MM_OLD_MODEM_ERROR_NO_NETWORK MM_OLD_MODEM_ERROR ".NoNetwork" +#define MM_OLD_MODEM_ERROR_SIM_NOT_INSERTED MM_OLD_MODEM_ERROR ".SimNotInserted" +#define MM_OLD_MODEM_ERROR_SIM_PIN MM_OLD_MODEM_ERROR ".SimPinRequired" +#define MM_OLD_MODEM_ERROR_SIM_PUK MM_OLD_MODEM_ERROR ".SimPukRequired" +#define MM_OLD_MODEM_ERROR_SIM_WRONG MM_OLD_MODEM_ERROR ".SimWrong" + +typedef enum { + MM_OLD_MODEM_STATE_UNKNOWN = 0, + MM_OLD_MODEM_STATE_DISABLED = 10, + MM_OLD_MODEM_STATE_DISABLING = 20, + MM_OLD_MODEM_STATE_ENABLING = 30, + MM_OLD_MODEM_STATE_ENABLED = 40, + MM_OLD_MODEM_STATE_SEARCHING = 50, + MM_OLD_MODEM_STATE_REGISTERED = 60, + MM_OLD_MODEM_STATE_DISCONNECTING = 70, + MM_OLD_MODEM_STATE_CONNECTING = 80, + MM_OLD_MODEM_STATE_CONNECTED = 90, + + MM_OLD_MODEM_STATE_LAST = MM_OLD_MODEM_STATE_CONNECTED +} MMOldModemState; + +#endif /* NM_MODEM_OLD_TYPES_H */ diff --git a/src/devices/wwan/nm-modem-old.c b/src/devices/wwan/nm-modem-old.c new file mode 100644 index 0000000000..f8bbcebb85 --- /dev/null +++ b/src/devices/wwan/nm-modem-old.c @@ -0,0 +1,1141 @@ +/* -*- 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 - 2013 Red Hat, Inc. + * Copyright (C) 2009 Novell, Inc. + */ + +#include +#include + +#include "nm-modem-old.h" +#include "nm-dbus-manager.h" +#include "nm-setting-connection.h" +#include "nm-properties-changed-signal.h" +#include "nm-modem-old-types.h" +#include "nm-logging.h" +#include "NetworkManagerUtils.h" +#include "nm-device-private.h" +#include "nm-dbus-glib-types.h" +#include "nm-glib-compat.h" + +G_DEFINE_TYPE (NMModemOld, nm_modem_old, NM_TYPE_MODEM) + +#define NM_MODEM_OLD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM_OLD, NMModemOldPrivate)) + +typedef struct { + DBusGProxy *proxy; + DBusGProxy *props_proxy; + + MMOldModemState state; + NMDeviceModemCapabilities caps; + + DBusGProxyCall *call; + GHashTable *connect_properties; + + guint32 pin_tries; + guint enable_delay_id; +} NMModemOldPrivate; + +#define CAPS_3GPP (NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS | NM_DEVICE_MODEM_CAPABILITY_LTE) + +/*****************************************************************************/ + +typedef enum { + MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_ANY = 0, + MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_GPRS, + MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_EDGE, + MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_UMTS, + MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_HSDPA, + MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_2G_PREFERRED, + MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_3G_PREFERRED, + MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_2G_ONLY, + MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_3G_ONLY, + MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_HSUPA, + MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_HSPA, + + MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_LAST = MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_HSPA +} MMModemDeprecatedMode; + +typedef enum { + MM_MODEM_GSM_ALLOWED_MODE_ANY = 0, + MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED = 1, + MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED = 2, + MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY = 3, + MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY = 4, + MM_MODEM_GSM_ALLOWED_MODE_4G_PREFERRED = 5, + MM_MODEM_GSM_ALLOWED_MODE_4G_ONLY = 6, + + MM_MODEM_GSM_ALLOWED_MODE_LAST = MM_MODEM_GSM_ALLOWED_MODE_4G_ONLY +} MMModemGsmAllowedMode; + +typedef enum { + MM_MODEM_GSM_ALLOWED_AUTH_UNKNOWN = 0x0000, + /* bits 0..4 order match Ericsson device bitmap */ + MM_MODEM_GSM_ALLOWED_AUTH_NONE = 0x0001, + MM_MODEM_GSM_ALLOWED_AUTH_PAP = 0x0002, + MM_MODEM_GSM_ALLOWED_AUTH_CHAP = 0x0004, + MM_MODEM_GSM_ALLOWED_AUTH_MSCHAP = 0x0008, + MM_MODEM_GSM_ALLOWED_AUTH_MSCHAPV2 = 0x0010, + MM_MODEM_GSM_ALLOWED_AUTH_EAP = 0x0020, + + MM_MODEM_GSM_ALLOWED_AUTH_LAST = MM_MODEM_GSM_ALLOWED_AUTH_EAP +} MMModemGsmAllowedAuth; + +static NMDeviceStateReason +translate_mm_error (GError *error) +{ + NMDeviceStateReason reason; + + if (dbus_g_error_has_name (error, MM_OLD_MODEM_CONNECT_ERROR_NO_CARRIER)) + reason = NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER; + else if (dbus_g_error_has_name (error, MM_OLD_MODEM_CONNECT_ERROR_NO_DIALTONE)) + reason = NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE; + else if (dbus_g_error_has_name (error, MM_OLD_MODEM_CONNECT_ERROR_BUSY)) + reason = NM_DEVICE_STATE_REASON_MODEM_BUSY; + else if (dbus_g_error_has_name (error, MM_OLD_MODEM_CONNECT_ERROR_NO_ANSWER)) + reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT; + else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_NETWORK_NOT_ALLOWED)) + reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED; + else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_NETWORK_TIMEOUT)) + reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT; + else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_NO_NETWORK)) + reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING; + else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_SIM_NOT_INSERTED)) + reason = NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED; + else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_SIM_PIN)) + reason = NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED; + else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_SIM_PUK)) + reason = NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED; + else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_SIM_WRONG)) + reason = NM_DEVICE_STATE_REASON_GSM_SIM_WRONG; + else { + /* unable to map the ModemManager error to a NM_DEVICE_STATE_REASON */ + nm_log_dbg (LOGD_MB, "unmapped dbus error detected: '%s'", dbus_g_error_get_name (error)); + reason = NM_DEVICE_STATE_REASON_UNKNOWN; + } + + /* FIXME: We have only GSM error messages here, and we have no idea which + activation state failed. Reasons like: + NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED, + NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED, + NM_DEVICE_STATE_REASON_GSM_APN_FAILED, + NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED, + NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED + are not used. + */ + return reason; +} + +/*****************************************************************************/ + +DBusGProxy * +nm_modem_old_get_proxy (NMModemOld *self, const char *interface) +{ + + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); + const char *current_iface; + + g_return_val_if_fail (NM_IS_MODEM_OLD (self), NULL); + + /* Default to the default interface. */ + if (interface == NULL) + interface = MM_OLD_DBUS_INTERFACE_MODEM; + + if (interface && !strcmp (interface, DBUS_INTERFACE_PROPERTIES)) + return priv->props_proxy; + + current_iface = dbus_g_proxy_get_interface (priv->proxy); + if (!current_iface || strcmp (current_iface, interface)) + dbus_g_proxy_set_interface (priv->proxy, interface); + + return priv->proxy; +} + +/*****************************************************************************/ +/* Query/Update enabled state */ + +static void +update_mm_enabled (NMModem *self, + gboolean new_enabled) +{ + if (nm_modem_get_mm_enabled (self) != new_enabled) { + g_object_set (self, + NM_MODEM_ENABLED, new_enabled, + NULL); + } +} + +static void +get_mm_enabled_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +{ + NMModem *self = NM_MODEM (user_data); + GError *error = NULL; + GValue value = G_VALUE_INIT; + + if (!dbus_g_proxy_end_call (proxy, call_id, &error, + G_TYPE_VALUE, &value, + G_TYPE_INVALID)) { + nm_log_warn (LOGD_MB, "failed get modem enabled state: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + return; + } + + if (G_VALUE_HOLDS_BOOLEAN (&value)) { + update_mm_enabled (self, g_value_get_boolean (&value)); + } else + nm_log_warn (LOGD_MB, "failed get modem enabled state: unexpected reply type"); + + g_value_unset (&value); +} + +static void +query_mm_enabled (NMModemOld *self) +{ + dbus_g_proxy_begin_call (NM_MODEM_OLD_GET_PRIVATE (self)->props_proxy, + "Get", get_mm_enabled_done, + self, NULL, + G_TYPE_STRING, MM_OLD_DBUS_INTERFACE_MODEM, + G_TYPE_STRING, "Enabled", + G_TYPE_INVALID); +} + +static void +set_mm_enabled_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +{ + GError *error = NULL; + + if (!dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) { + nm_log_warn (LOGD_MB, "failed to enable/disable modem: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + } + + /* Update enabled/disabled state again */ + query_mm_enabled (NM_MODEM_OLD (user_data)); +} + +static void +set_mm_enabled (NMModem *self, gboolean enabled) +{ + /* 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 + * toggle rfkill status of the WWAN modem. + */ + dbus_g_proxy_begin_call (nm_modem_old_get_proxy (NM_MODEM_OLD (self), + MM_OLD_DBUS_INTERFACE_MODEM), + "Enable", set_mm_enabled_done, + self, NULL, + G_TYPE_BOOLEAN, enabled, + G_TYPE_INVALID); + /* If we are disabling the modem, stop saying that it's enabled. */ + if (!enabled) + update_mm_enabled (self, enabled); +} + +/*****************************************************************************/ + +static void +ask_for_pin (NMModemOld *self, gboolean always_ask) +{ + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); + guint32 tries = 0; + + g_return_if_fail (NM_IS_MODEM_OLD (self)); + + if (!always_ask) + tries = priv->pin_tries++; + + nm_modem_get_secrets (NM_MODEM (self), + NM_SETTING_GSM_SETTING_NAME, + (tries || always_ask) ? TRUE : FALSE, + NM_SETTING_GSM_PIN); +} + +static void +stage1_prepare_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +{ + NMModemOld *self = NM_MODEM_OLD (user_data); + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); + GError *error = NULL; + gboolean asked = FALSE; + + 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 { + if (priv->caps & CAPS_3GPP) { + if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_SIM_PIN)) { + ask_for_pin (self, FALSE); + asked = TRUE; + } else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_SIM_WRONG)) { + ask_for_pin (self, TRUE); + asked = TRUE; + } + } + + if (!asked) { + nm_log_warn (LOGD_MB, "Mobile connection failed: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (error)); + } + g_error_free (error); + } +} + +static void +do_connect (NMModemOld *self) +{ + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); + DBusGProxy *proxy; + + proxy = nm_modem_old_get_proxy (NM_MODEM_OLD (self), MM_OLD_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); + +/* do_enable() is used as a GSourceFunc, hence the gboolean return */ +static gboolean +do_enable (NMModemOld *self) +{ + DBusGProxy *proxy; + + g_return_val_if_fail (NM_IS_MODEM_OLD (self), FALSE); + + NM_MODEM_OLD_GET_PRIVATE (self)->enable_delay_id = 0; + proxy = nm_modem_old_get_proxy (NM_MODEM_OLD (self), MM_OLD_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); + return FALSE; +} + +static void +stage1_pin_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +{ + NMModemOld *self = NM_MODEM_OLD (user_data); + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); + NMDeviceStateReason reason; + GError *error = NULL; + + if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) { + /* Success; try to enable the modem again. Wait a few seconds to ensure + * that ModemManager is ready for the enable right after the unlock. + */ + if (priv->enable_delay_id == 0) + priv->enable_delay_id = g_timeout_add_seconds (4, (GSourceFunc) do_enable, self); + } else { + nm_log_warn (LOGD_MB, "GSM PIN unlock failed: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + + /* try to translate the error reason */ + reason = translate_mm_error (error); + if (reason == NM_DEVICE_STATE_REASON_UNKNOWN) + reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED; + + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, reason); + g_error_free (error); + } +} + +static void +handle_enable_pin_required (NMModemOld *self) +{ + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); + const char *pin = NULL; + GValue *value; + DBusGProxy *proxy; + + g_assert (priv->caps & CAPS_3GPP); + + /* 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_old_get_proxy (NM_MODEM_OLD (self), MM_OLD_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) +{ + NMModemOld *self = NM_MODEM_OLD (user_data); + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); + NMDeviceStateReason reason; + GError *error = NULL; + + if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) + do_connect (self); + else { + if ((priv->caps & CAPS_3GPP) && dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_SIM_PIN)) + handle_enable_pin_required (self); + else { + nm_log_warn (LOGD_MB, "Modem enable failed: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + + /* try to translate the error reason */ + reason = translate_mm_error (error); + if (reason == NM_DEVICE_STATE_REASON_UNKNOWN) + reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED; + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, reason); + } + + g_error_free (error); + } +} + +static GHashTable * +create_connect_properties (NMConnection *connection) +{ + NMSettingCdma *s_cdma; + NMSettingGsm *s_gsm; + NMSettingPPP *s_ppp; + GHashTable *properties; + const char *str; + + properties = value_hash_create (); + + s_cdma = nm_connection_get_setting_cdma (connection); + if (s_cdma) { + str = nm_setting_cdma_get_number (s_cdma); + if (str) + value_hash_add_str (properties, "number", str); + return properties; + } + + s_gsm = nm_connection_get_setting_gsm (connection); + if (s_gsm) { + str = nm_setting_gsm_get_number (s_gsm); + if (str) + value_hash_add_str (properties, "number", str); + + str = nm_setting_gsm_get_apn (s_gsm); + if (str) + value_hash_add_str (properties, "apn", str); + + str = nm_setting_gsm_get_network_id (s_gsm); + if (str) + value_hash_add_str (properties, "network_id", str); + + str = nm_setting_gsm_get_pin (s_gsm); + if (str) + value_hash_add_str (properties, "pin", str); + + str = nm_setting_gsm_get_username (s_gsm); + if (str) + value_hash_add_str (properties, "username", str); + + str = nm_setting_gsm_get_password (s_gsm); + if (str) + value_hash_add_str (properties, "password", str); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + /* Add both old and new preferred modes */ + switch (nm_setting_gsm_get_network_type (s_gsm)) { + case NM_SETTING_GSM_NETWORK_TYPE_UMTS_HSPA: + value_hash_add_uint (properties, "network_mode", MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_3G_ONLY); + value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY); + break; + case NM_SETTING_GSM_NETWORK_TYPE_GPRS_EDGE: + value_hash_add_uint (properties, "network_mode", MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_2G_ONLY); + value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY); + break; + case NM_SETTING_GSM_NETWORK_TYPE_PREFER_UMTS_HSPA: + value_hash_add_uint (properties, "network_mode", MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_3G_PREFERRED); + value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED); + break; + case NM_SETTING_GSM_NETWORK_TYPE_PREFER_GPRS_EDGE: + value_hash_add_uint (properties, "network_mode", MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_2G_PREFERRED); + value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED); + break; + case NM_SETTING_GSM_NETWORK_TYPE_PREFER_4G: + /* deprecated modes not extended for 4G, so no need to set them here */ + value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_4G_PREFERRED); + break; + case NM_SETTING_GSM_NETWORK_TYPE_4G: + /* deprecated modes not extended for 4G, so no need to set them here */ + value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_4G_ONLY); + break; + default: + value_hash_add_uint (properties, "network_mode", MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_ANY); + value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_ANY); + break; + } +G_GNUC_END_IGNORE_DEPRECATIONS + + /* Roaming */ + if (nm_setting_gsm_get_home_only (s_gsm)) + value_hash_add_bool (properties, "home_only", TRUE); + + /* For IpMethod == STATIC or DHCP */ + s_ppp = nm_connection_get_setting_ppp (connection); + if (s_ppp) { + guint32 auth = MM_MODEM_GSM_ALLOWED_AUTH_UNKNOWN; + + if (nm_setting_ppp_get_noauth (s_ppp)) + auth |= MM_MODEM_GSM_ALLOWED_AUTH_NONE; + if (!nm_setting_ppp_get_refuse_pap (s_ppp)) + auth |= MM_MODEM_GSM_ALLOWED_AUTH_PAP; + if (!nm_setting_ppp_get_refuse_chap (s_ppp)) + auth |= MM_MODEM_GSM_ALLOWED_AUTH_CHAP; + if (!nm_setting_ppp_get_refuse_mschap (s_ppp)) + auth |= MM_MODEM_GSM_ALLOWED_AUTH_MSCHAP; + if (!nm_setting_ppp_get_refuse_mschapv2 (s_ppp)) + auth |= MM_MODEM_GSM_ALLOWED_AUTH_MSCHAPV2; + if (!nm_setting_ppp_get_refuse_eap (s_ppp)) + auth |= MM_MODEM_GSM_ALLOWED_AUTH_EAP; + + if (auth != MM_MODEM_GSM_ALLOWED_AUTH_UNKNOWN) + value_hash_add_uint (properties, "allowed_auth", auth); + } + + return properties; + } + + g_hash_table_destroy (properties); + return NULL; +} + +static NMActStageReturn +act_stage1_prepare (NMModem *modem, + NMConnection *connection, + NMDeviceStateReason *reason) +{ + NMModemOld *self = NM_MODEM_OLD (modem); + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); + 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 (self); + else + do_enable (self); + + return NM_ACT_STAGE_RETURN_POSTPONE; +} + +/*****************************************************************************/ +/* IP method static */ + +static char addr_to_string_buf[INET6_ADDRSTRLEN + 1]; + +static const char * +ip_address_to_string (guint32 numeric) +{ + guint32 temp_addr; + + memset (&addr_to_string_buf, '\0', sizeof (addr_to_string_buf)); + temp_addr = numeric; + + if (inet_ntop (AF_INET, &temp_addr, addr_to_string_buf, INET_ADDRSTRLEN)) { + return addr_to_string_buf; + } else { + nm_log_warn (LOGD_VPN, "error converting IP4 address 0x%X", + ntohl (temp_addr)); + return NULL; + } +} + +static void +static_stage3_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +{ + NMModemOld *self = NM_MODEM_OLD (user_data); + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); + GValueArray *ret_array = NULL; + GError *error = NULL; + NMIP4Config *config = NULL; + + priv->call = NULL; + + /* Returned value array is (uuuu): [IP, DNS1, DNS2, DNS3], all in + * network byte order. + */ + if (dbus_g_proxy_end_call (proxy, call, &error, + G_TYPE_VALUE_ARRAY, &ret_array, + G_TYPE_INVALID)) { + NMPlatformIP4Address address; + int i; + + config = nm_ip4_config_new (); + memset (&address, 0, sizeof (address)); + + nm_log_info (LOGD_MB, "(%s): IPv4 static configuration:", + nm_modem_get_uid (NM_MODEM (self))); + + /* IP address */ + address.address = g_value_get_uint (g_value_array_get_nth (ret_array, 0)); + address.plen = 32; + address.source = NM_PLATFORM_SOURCE_WWAN; + nm_ip4_config_add_address (config, &address); + + nm_log_info (LOGD_MB, " address %s/%d", + ip_address_to_string (address.address), + address.plen); + + /* DNS servers */ + for (i = 1; i < ret_array->n_values; i++) { + GValue *value = g_value_array_get_nth (ret_array, i); + guint32 tmp = g_value_get_uint (value); + + if (tmp > 0) { + nm_ip4_config_add_nameserver (config, tmp); + nm_log_info (LOGD_MB, " DNS %s", ip_address_to_string (tmp)); + } + } + g_value_array_free (ret_array); + } + + g_signal_emit_by_name (self, NM_MODEM_IP4_CONFIG_RESULT, config, error); + g_clear_error (&error); +} + +static NMActStageReturn +static_stage3_ip4_config_start (NMModem *self, + NMActRequest *req, + NMDeviceStateReason *reason) +{ + NMModemOldPrivate *priv; + + g_return_val_if_fail (NM_IS_MODEM (self), 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_OLD_GET_PRIVATE (self); + + priv->call = dbus_g_proxy_begin_call (nm_modem_old_get_proxy (NM_MODEM_OLD (self), + MM_OLD_DBUS_INTERFACE_MODEM), + "GetIP4Config", static_stage3_done, + self, NULL, + G_TYPE_INVALID); + + return NM_ACT_STAGE_RETURN_POSTPONE; +} + +/*****************************************************************************/ + +static void +disconnect_done (DBusGProxy *proxy, + DBusGProxyCall *call_id, + gpointer user_data) +{ + GError *error = NULL; + gboolean warn = GPOINTER_TO_UINT (user_data); + + if (!dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID) && warn) { + nm_log_info (LOGD_MB, "disconnect failed: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + } +} + +static void +disconnect (NMModem *self, + gboolean warn) +{ + dbus_g_proxy_begin_call (nm_modem_old_get_proxy (NM_MODEM_OLD (self), + MM_OLD_DBUS_INTERFACE_MODEM), + "Disconnect", + disconnect_done, + GUINT_TO_POINTER (warn), + NULL, + G_TYPE_INVALID); +} + +/*****************************************************************************/ + +static void +deactivate (NMModem *self, NMDevice *device) +{ + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); + + priv->pin_tries = 0; + + if (priv->call) { + dbus_g_proxy_cancel_call (priv->proxy, priv->call); + priv->call = NULL; + } + + if (priv->enable_delay_id) { + g_source_remove (priv->enable_delay_id); + priv->enable_delay_id = 0; + } + + /* Chain up parent */ + NM_MODEM_CLASS (nm_modem_old_parent_class)->deactivate (self, device); +} + +/*****************************************************************************/ + +static void +modem_properties_changed (DBusGProxy *proxy, + const char *interface, + GHashTable *props, + gpointer user_data) +{ + NMModemOld *self = NM_MODEM_OLD (user_data); + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); + GValue *value; + MMOldModemState new_state; + + if (strcmp (interface, MM_OLD_DBUS_INTERFACE_MODEM)) + return; + + value = g_hash_table_lookup (props, "Enabled"); + if (value && G_VALUE_HOLDS_BOOLEAN (value)) { + g_object_set (self, + NM_MODEM_ENABLED, g_value_get_boolean (value), + NULL); + } + + value = g_hash_table_lookup (props, "IpMethod"); + if (value && G_VALUE_HOLDS_UINT (value)) { + g_object_set (self, + NM_MODEM_IP_METHOD, g_value_get_uint (value), + NULL); + } + + value = g_hash_table_lookup (props, "State"); + if (value && G_VALUE_HOLDS_UINT (value)) { + new_state = g_value_get_uint (value); + if (new_state != priv->state) { + if (new_state == MM_OLD_MODEM_STATE_CONNECTED) + g_object_set (self, + NM_MODEM_CONNECTED, TRUE, + NULL); + else if (priv->state == MM_OLD_MODEM_STATE_CONNECTED) + g_object_set (self, + NM_MODEM_CONNECTED, FALSE, + NULL); + priv->state = new_state; + } + } +} + +/*****************************************************************************/ + +static gboolean +check_connection_compatible (NMModem *modem, + NMConnection *connection, + GError **error) +{ + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (modem); + NMSettingConnection *s_con; + gboolean valid_cdma = FALSE, valid_gsm = FALSE; + const char *ctype; + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + ctype = nm_setting_connection_get_connection_type (s_con); + g_assert (ctype); + + /* Check for valid CDMA first */ + if (strcmp (ctype, NM_SETTING_CDMA_SETTING_NAME) == 0) + valid_cdma = !!nm_connection_get_setting_cdma (connection); + + if (strcmp (ctype, NM_SETTING_GSM_SETTING_NAME) == 0) + valid_gsm = !!nm_connection_get_setting_gsm (connection); + + /* Validate CDMA */ + if (priv->caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO) { + if (valid_cdma) + return TRUE; + + /* If the modem is only CDMA and the connection is not CDMA, error */ + if ((priv->caps ^ NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO) == 0) { + g_set_error (error, NM_MODEM_ERROR, NM_MODEM_ERROR_CONNECTION_NOT_CDMA, + "The connection was not a CDMA connection."); + return FALSE; + } + } + + /* Validate 3GPP */ + if (priv->caps & CAPS_3GPP) { + if (valid_gsm) + return TRUE; + + g_set_error (error, NM_MODEM_ERROR, NM_MODEM_ERROR_CONNECTION_NOT_GSM, + "The connection was not a GSM/UMTS/LTE connection."); + return FALSE; + } + + g_set_error (error, NM_MODEM_ERROR, NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE, + "The connection was not not compatible with this modem (caps 0x%X)", + priv->caps); + return FALSE; +} + +/*****************************************************************************/ + +static void +complete_ppp_setting (NMConnection *connection) +{ + NMSettingPPP *s_ppp; + + s_ppp = nm_connection_get_setting_ppp (connection); + if (!s_ppp) { + s_ppp = (NMSettingPPP *) nm_setting_ppp_new (); + g_object_set (G_OBJECT (s_ppp), + NM_SETTING_PPP_LCP_ECHO_FAILURE, 5, + NM_SETTING_PPP_LCP_ECHO_INTERVAL, 30, + NULL); + nm_connection_add_setting (connection, NM_SETTING (s_ppp)); + } +} + +static gboolean +complete_connection_3gpp (NMConnection *connection, + const GSList *existing_connections, + GError **error) +{ + NMSettingGsm *s_gsm; + + s_gsm = nm_connection_get_setting_gsm (connection); + if (!s_gsm || !nm_setting_gsm_get_apn (s_gsm)) { + /* Need an APN at least */ + g_set_error_literal (error, + NM_SETTING_GSM_ERROR, + NM_SETTING_GSM_ERROR_MISSING_PROPERTY, + NM_SETTING_GSM_APN); + return FALSE; + } + + if (!nm_setting_gsm_get_number (s_gsm)) + g_object_set (G_OBJECT (s_gsm), NM_SETTING_GSM_NUMBER, "*99#", NULL); + + complete_ppp_setting (connection); + + nm_utils_complete_generic (connection, + NM_SETTING_GSM_SETTING_NAME, + existing_connections, + _("GSM connection %d"), + NULL, + FALSE); /* No IPv6 yet by default */ + return TRUE; +} + +static gboolean +complete_connection_cdma (NMConnection *connection, + const GSList *existing_connections, + GError **error) +{ + NMSettingCdma *s_cdma; + + s_cdma = nm_connection_get_setting_cdma (connection); + if (!s_cdma) { + s_cdma = (NMSettingCdma *) nm_setting_cdma_new (); + nm_connection_add_setting (connection, NM_SETTING (s_cdma)); + } + + if (!nm_setting_cdma_get_number (s_cdma)) + g_object_set (G_OBJECT (s_cdma), NM_SETTING_CDMA_NUMBER, "#777", NULL); + + complete_ppp_setting (connection); + + nm_utils_complete_generic (connection, + NM_SETTING_CDMA_SETTING_NAME, + existing_connections, + _("CDMA connection %d"), + NULL, + FALSE); /* No IPv6 yet by default */ + return TRUE; +} + +static gboolean +complete_connection (NMModem *modem, + NMConnection *connection, + const GSList *existing_connections, + GError **error) +{ + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (modem); + + /* If the modem has LTE, complete as 3GPP */ + if (priv->caps & NM_DEVICE_MODEM_CAPABILITY_LTE) + return complete_connection_3gpp (connection, existing_connections, error); + + /* Otherwise, prefer CDMA on the theory that if the modem has CDMA/EVDO + * that's most likely what the user will be using. + */ + if (priv->caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO) + return complete_connection_cdma (connection, existing_connections, error); + + if (priv->caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS) + return complete_connection_3gpp (connection, existing_connections, error); + + g_set_error_literal (error, NM_MODEM_ERROR, NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE, + "Modem had no WWAN capabilities."); + return FALSE; +} + +/*****************************************************************************/ + +static gboolean +get_user_pass (NMModem *modem, + NMConnection *connection, + const char **user, + const char **pass) +{ + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (modem); + NMSettingCdma *s_cdma; + NMSettingGsm *s_gsm; + + if (priv->caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO) { + s_cdma = nm_connection_get_setting_cdma (connection); + if (s_cdma) { + if (user) + *user = nm_setting_cdma_get_username (s_cdma); + if (pass) + *pass = nm_setting_cdma_get_password (s_cdma); + return TRUE; + } + } + + /* Fall back to GSM; will be used for CDMA devices on LTE networks too */ + s_gsm = nm_connection_get_setting_gsm (connection); + if (s_gsm) { + if (user) + *user = nm_setting_gsm_get_username (s_gsm); + if (pass) + *pass = nm_setting_gsm_get_password (s_gsm); + return TRUE; + } + + return FALSE; +} + +/*****************************************************************************/ + +static void +get_capabilities (NMModem *_self, + NMDeviceModemCapabilities *modem_caps, + NMDeviceModemCapabilities *current_caps) +{ + NMModemOld *self = NM_MODEM_OLD (_self); + + *current_caps = *modem_caps = NM_MODEM_OLD_GET_PRIVATE (self)->caps; +} + +/*****************************************************************************/ + +NMModem * +nm_modem_old_new (const char *path, GHashTable *properties, GError **error) +{ + NMDeviceModemCapabilities caps = NM_DEVICE_MODEM_CAPABILITY_NONE; + NMModemOld *self; + GHashTableIter iter; + const char *prop; + GValue *value; + const char *data_device = NULL; + const char *driver = NULL; + const char *master_device = NULL; + guint32 modem_type = MM_OLD_MODEM_TYPE_UNKNOWN; + guint32 ip_method = MM_MODEM_IP_METHOD_PPP; + guint32 ip_timeout = 0; + MMOldModemState state = MM_OLD_MODEM_STATE_UNKNOWN; + + g_return_val_if_fail (path != NULL, NULL); + g_return_val_if_fail (properties != NULL, NULL); + + g_hash_table_iter_init (&iter, properties); + while (g_hash_table_iter_next (&iter, (gpointer) &prop, (gpointer) &value)) { + if (g_strcmp0 (prop, "Type") == 0) + modem_type = g_value_get_uint (value); + else if (g_strcmp0 (prop, "MasterDevice") == 0) + master_device = g_value_get_string (value); + else if (g_strcmp0 (prop, "IpMethod") == 0) + ip_method = g_value_get_uint (value); + else if (g_strcmp0 (prop, "Device") == 0) + data_device = g_value_get_string (value); + else if (g_strcmp0 (prop, "Driver") == 0) + driver = g_value_get_string (value); + else if (g_strcmp0 (prop, "IpTimeout") == 0) + ip_timeout = g_value_get_uint (value); + else if (g_strcmp0 (prop, "State") == 0) + state = g_value_get_uint (value); + } + + if (modem_type == MM_OLD_MODEM_TYPE_UNKNOWN) { + g_set_error (error, NM_MODEM_ERROR, NM_MODEM_ERROR_INITIALIZATION_FAILED, + "Unhandled modem type %d", modem_type); + return NULL; + } + + if (!master_device || !strlen (master_device)) { + g_set_error_literal (error, NM_MODEM_ERROR, NM_MODEM_ERROR_INITIALIZATION_FAILED, + "Failed to retrieve modem master device."); + return NULL; + } + + if (!driver || !strlen (driver)) { + g_set_error_literal (error, NM_MODEM_ERROR, NM_MODEM_ERROR_INITIALIZATION_FAILED, + "Failed to retrieve modem driver."); + return NULL; + } + + if (!data_device || !strlen (data_device)) { + g_set_error_literal (error, NM_MODEM_ERROR, NM_MODEM_ERROR_INITIALIZATION_FAILED, + "Failed to retrieve modem data device."); + return NULL; + } + + self = (NMModemOld *) g_object_new (NM_TYPE_MODEM_OLD, + NM_MODEM_PATH, path, + NM_MODEM_DRIVER, driver, + NM_MODEM_UID, data_device, + NM_MODEM_CONTROL_PORT, NULL, + NM_MODEM_DATA_PORT, data_device, + NM_MODEM_IP_METHOD, ip_method, + NM_MODEM_IP_TIMEOUT, ip_timeout, + NM_MODEM_CONNECTED, (state == MM_OLD_MODEM_STATE_CONNECTED), + NULL); + if (self) { + if (modem_type == MM_OLD_MODEM_TYPE_CDMA) + caps |= NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO; + if (modem_type == MM_OLD_MODEM_TYPE_GSM) + caps |= NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS; + + NM_MODEM_OLD_GET_PRIVATE (self)->caps = caps; + } + + return (NMModem *) self; +} + +static void +nm_modem_old_init (NMModemOld *self) +{ +} + +static GObject* +constructor (GType type, + guint n_construct_params, + GObjectConstructParam *construct_params) +{ + GObject *object; + NMModemOldPrivate *priv; + DBusGConnection *bus; + + object = G_OBJECT_CLASS (nm_modem_old_parent_class)->constructor (type, n_construct_params, construct_params); + if (!object) + return NULL; + + priv = NM_MODEM_OLD_GET_PRIVATE (object); + + bus = nm_dbus_manager_get_connection (nm_dbus_manager_get ()); + priv->proxy = dbus_g_proxy_new_for_name (bus, + MM_OLD_DBUS_SERVICE, + nm_modem_get_path (NM_MODEM (object)), + MM_OLD_DBUS_INTERFACE_MODEM); + + priv->props_proxy = dbus_g_proxy_new_for_name (bus, + MM_OLD_DBUS_SERVICE, + nm_modem_get_path (NM_MODEM (object)), + DBUS_INTERFACE_PROPERTIES); + dbus_g_object_register_marshaller (g_cclosure_marshal_generic, + G_TYPE_NONE, + G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (priv->props_proxy, "MmPropertiesChanged", + G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->props_proxy, "MmPropertiesChanged", + G_CALLBACK (modem_properties_changed), + object, + NULL); + + query_mm_enabled (NM_MODEM_OLD (object)); + + return object; +} + +static void +dispose (GObject *object) +{ + NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (object); + + if (priv->proxy) { + g_object_unref (priv->proxy); + priv->proxy = NULL; + } + + if (priv->props_proxy) { + g_object_unref (priv->props_proxy); + priv->props_proxy = NULL; + } + + if (priv->connect_properties) { + g_hash_table_destroy (priv->connect_properties); + priv->connect_properties = NULL; + } + + if (priv->enable_delay_id) { + g_source_remove (priv->enable_delay_id); + priv->enable_delay_id = 0; + } + + G_OBJECT_CLASS (nm_modem_old_parent_class)->dispose (object); +} + +static void +nm_modem_old_class_init (NMModemOldClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMModemClass *modem_class = NM_MODEM_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMModemOldPrivate)); + + /* Virtual methods */ + object_class->constructor = constructor; + object_class->dispose = dispose; + + modem_class->get_capabilities = get_capabilities; + modem_class->get_user_pass = get_user_pass; + modem_class->complete_connection = complete_connection; + modem_class->check_connection_compatible = check_connection_compatible; + modem_class->act_stage1_prepare = act_stage1_prepare; + modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start; + modem_class->disconnect = disconnect; + modem_class->deactivate = deactivate; + modem_class->set_mm_enabled = set_mm_enabled; +} diff --git a/src/devices/wwan/nm-modem-old.h b/src/devices/wwan/nm-modem-old.h new file mode 100644 index 0000000000..828da6a6d4 --- /dev/null +++ b/src/devices/wwan/nm-modem-old.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 - 2011 Red Hat, Inc. + * Copyright (C) 2009 Novell, Inc. + */ + +#ifndef NM_MODEM_OLD_H +#define NM_MODEM_OLD_H + +#include +#include +#include "nm-modem.h" +#include "nm-modem-old-types.h" + +G_BEGIN_DECLS + +#define NM_TYPE_MODEM_OLD (nm_modem_old_get_type ()) +#define NM_MODEM_OLD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_OLD, NMModemOld)) +#define NM_MODEM_OLD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_MODEM_OLD, NMModemOldClass)) +#define NM_IS_MODEM_OLD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_OLD)) +#define NM_IS_MODEM_OLD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_MODEM_OLD)) +#define NM_MODEM_OLD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MODEM_OLD, NMModemOldClass)) + +typedef struct { + NMModem parent; +} NMModemOld; + +typedef struct { + NMModemClass parent; +} NMModemOldClass; + +GType nm_modem_old_get_type (void); + +NMModem *nm_modem_old_new (const char *path, GHashTable *properties, GError **error); + +/* Protected */ +DBusGProxy *nm_modem_old_get_proxy (NMModemOld *modem, const gchar *interface); + +G_END_DECLS + +#endif /* NM_MODEM_OLD_H */ diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c new file mode 100644 index 0000000000..2ff0200894 --- /dev/null +++ b/src/devices/wwan/nm-modem.c @@ -0,0 +1,1009 @@ +/* -*- 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 - 2011 Red Hat, Inc. + * Copyright (C) 2009 Novell, Inc. + */ + +#include +#include "nm-modem.h" +#include "nm-platform.h" +#include "nm-dbus-manager.h" +#include "nm-setting-connection.h" +#include "nm-properties-changed-signal.h" +#include "nm-logging.h" +#include "NetworkManagerUtils.h" +#include "nm-device-private.h" +#include "nm-dbus-glib-types.h" +#include "nm-modem-enum-types.h" + +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_CONTROL_PORT, + PROP_DATA_PORT, + PROP_PATH, + PROP_UID, + PROP_DRIVER, + PROP_IP_METHOD, + PROP_IP_TIMEOUT, + PROP_ENABLED, + PROP_CONNECTED, + + LAST_PROP +}; + +typedef struct { + char *uid; + char *path; + char *driver; + char *control_port; + char *data_port; + char *ppp_iface; + guint32 ip_method; + + NMPPPManager *ppp_manager; + + NMActRequest *act_request; + guint32 secrets_tries; + guint32 secrets_id; + + gboolean mm_enabled; + guint32 mm_ip_timeout; + gboolean mm_connected; + + /* PPP stats */ + guint32 in_bytes; + guint32 out_bytes; +} NMModemPrivate; + +enum { + PPP_STATS, + PPP_FAILED, + PREPARE_RESULT, + IP4_CONFIG_RESULT, + AUTH_REQUESTED, + AUTH_RESULT, + REMOVED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + + +/*****************************************************************************/ + +GQuark +nm_modem_error_quark (void) +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string ("nm-modem-error"); + return quark; +} + +/*****************************************************************************/ +/* Get/Set enabled/connected */ + +gboolean +nm_modem_get_mm_enabled (NMModem *self) +{ + return NM_MODEM_GET_PRIVATE (self)->mm_enabled; +} + +void +nm_modem_set_mm_enabled (NMModem *self, + gboolean enabled) +{ + NMModemPrivate *priv; + + priv = NM_MODEM_GET_PRIVATE (self); + + if (priv->mm_enabled != enabled) + NM_MODEM_GET_CLASS (self)->set_mm_enabled (self, enabled); +} + +gboolean +nm_modem_get_mm_connected (NMModem *self) +{ + return NM_MODEM_GET_PRIVATE (self)->mm_connected; +} + +void +nm_modem_emit_removed (NMModem *self) +{ + g_signal_emit (self, signals[REMOVED], 0); +} + +/*****************************************************************************/ +/* IP method PPP */ + +static void +ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_data) +{ + switch (status) { + case NM_PPP_STATUS_DISCONNECT: + g_signal_emit (NM_MODEM (user_data), signals[PPP_FAILED], 0, NM_DEVICE_STATE_REASON_PPP_DISCONNECT); + break; + case NM_PPP_STATUS_DEAD: + g_signal_emit (NM_MODEM (user_data), signals[PPP_FAILED], 0, NM_DEVICE_STATE_REASON_PPP_FAILED); + break; + default: + break; + } +} + +static void +ppp_ip4_config (NMPPPManager *ppp_manager, + const char *iface, + NMIP4Config *config, + gpointer 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 */ + guint32 bad_dns2 = htonl (0x0A0B0C0E); + guint32 good_dns2 = htonl (0x04020202); /* GTE nameserver */ + gboolean dns_workaround = FALSE; + + /* Notify about the new data port to use */ + g_free (priv->ppp_iface); + priv->ppp_iface = g_strdup (iface); + g_object_notify (G_OBJECT (self), NM_MODEM_DATA_PORT); + + /* 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 + * not the case. + * + * http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=2e09ef6886bbf00bc5a9a641110f801e372ffde6 + * http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=f8191bf07df374f119a07910a79217c7618f113e + */ + + num = nm_ip4_config_get_num_nameservers (config); + if (num == 2) { + gboolean found1 = FALSE, found2 = FALSE; + + for (i = 0; i < num; i++) { + guint32 ns = nm_ip4_config_get_nameserver (config, i); + + if (ns == bad_dns1) + found1 = TRUE; + else if (ns == bad_dns2) + found2 = TRUE; + } + + /* Be somewhat conservative about substitutions; the "bad" nameservers + * could actually be valid in some cases, so only substitute if ppp + * returns *only* the two bad nameservers. + */ + dns_workaround = (found1 && found2); + } + + if (!num || dns_workaround) { + nm_log_warn (LOGD_PPP, "compensating for invalid PPP-provided nameservers"); + nm_ip4_config_reset_nameservers (config); + nm_ip4_config_add_nameserver (config, good_dns1); + nm_ip4_config_add_nameserver (config, good_dns2); + } + + g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, config, NULL); +} + +static void +ppp_stats (NMPPPManager *ppp_manager, + guint32 in_bytes, + guint32 out_bytes, + gpointer user_data) +{ + NMModem *self = NM_MODEM (user_data); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + + if (priv->in_bytes != in_bytes || priv->out_bytes != out_bytes) { + priv->in_bytes = in_bytes; + priv->out_bytes = out_bytes; + + g_signal_emit (self, signals[PPP_STATS], 0, in_bytes, out_bytes); + } +} + +static NMActStageReturn +ppp_stage3_ip4_config_start (NMModem *self, + NMActRequest *req, + NMDeviceStateReason *reason) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + const char *ppp_name = NULL; + GError *error = NULL; + NMActStageReturn ret; + guint ip_timeout = 20; + + g_return_val_if_fail (NM_IS_MODEM (self), 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); + + if (NM_MODEM_GET_CLASS (self)->get_user_pass) { + NMConnection *connection = nm_act_request_get_connection (req); + + g_assert (connection); + if (!NM_MODEM_GET_CLASS (self)->get_user_pass (self, connection, &ppp_name, NULL)) + return NM_ACT_STAGE_RETURN_FAILURE; + } + + /* Check if ModemManager requested a specific IP timeout to be used. If 0 reported, + * use the default one (20s) */ + if (priv->mm_ip_timeout > 0) { + nm_log_info (LOGD_PPP, "using modem-specified IP timeout: %u seconds", + priv->mm_ip_timeout); + ip_timeout = priv->mm_ip_timeout; + } + + priv->ppp_manager = nm_ppp_manager_new (priv->data_port); + if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, ip_timeout, &error)) { + g_signal_connect (priv->ppp_manager, "state-changed", + G_CALLBACK (ppp_state_changed), + self); + g_signal_connect (priv->ppp_manager, "ip4-config", + G_CALLBACK (ppp_ip4_config), + self); + g_signal_connect (priv->ppp_manager, "stats", + G_CALLBACK (ppp_stats), + self); + + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } else { + nm_log_err (LOGD_PPP, "error starting PPP: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_error_free (error); + + 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; +} + +/*****************************************************************************/ + +NMActStageReturn +nm_modem_stage3_ip4_config_start (NMModem *self, + NMDevice *device, + NMDeviceClass *device_class, + NMDeviceStateReason *reason) +{ + NMModemPrivate *priv; + NMActRequest *req; + NMActStageReturn ret; + + g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (NM_IS_DEVICE (device), 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); + + priv = NM_MODEM_GET_PRIVATE (self); + switch (priv->ip_method) { + case MM_MODEM_IP_METHOD_PPP: + ret = ppp_stage3_ip4_config_start (self, req, reason); + break; + case MM_MODEM_IP_METHOD_STATIC: + ret = NM_MODEM_GET_CLASS (self)->static_stage3_ip4_config_start (self, req, reason); + break; + case MM_MODEM_IP_METHOD_DHCP: + ret = device_class->act_stage3_ip4_config_start (device, NULL, reason); + break; + default: + nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method); + ret = NM_ACT_STAGE_RETURN_FAILURE; + break; + } + + return ret; +} + +void +nm_modem_ip4_pre_commit (NMModem *modem, + NMDevice *device, + NMIP4Config *config) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (modem); + + /* If the modem has an ethernet-type data interface (ie, not PPP and thus + * not point-to-point) and IP config has a /32 prefix, then we assume that + * ARP will be pointless and we turn it off. + */ + if ( priv->ip_method == MM_MODEM_IP_METHOD_STATIC + || priv->ip_method == MM_MODEM_IP_METHOD_DHCP) { + const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, 0); + + g_assert (address); + if (address->plen == 32) + nm_platform_link_set_noarp (nm_device_get_ip_ifindex (device)); + } +} + +/*****************************************************************************/ + +NMActStageReturn +nm_modem_stage3_ip6_config_start (NMModem *self, + NMDevice *device, + NMDeviceClass *device_class, + NMDeviceStateReason *reason) +{ + /* FIXME: We don't support IPv6 on modems quite yet... */ + nm_device_activate_schedule_ip6_config_timeout (device); + return NM_ACT_STAGE_RETURN_POSTPONE; +} + +/*****************************************************************************/ + +static void +cancel_get_secrets (NMModem *self) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + + if (priv->secrets_id) { + nm_act_request_cancel_secrets (priv->act_request, priv->secrets_id); + priv->secrets_id = 0; + } +} + +static void +modem_secrets_cb (NMActRequest *req, + guint32 call_id, + NMConnection *connection, + GError *error, + gpointer user_data) +{ + NMModem *self = NM_MODEM (user_data); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + + g_return_if_fail (call_id == priv->secrets_id); + + priv->secrets_id = 0; + + if (error) + nm_log_warn (LOGD_MB, "%s", error->message); + + g_signal_emit (self, signals[AUTH_RESULT], 0, error); +} + +gboolean +nm_modem_get_secrets (NMModem *self, + const char *setting_name, + gboolean request_new, + const char *hint) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + NMSettingsGetSecretsFlags flags = NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION; + + cancel_get_secrets (self); + + if (request_new) + flags |= NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW; + priv->secrets_id = nm_act_request_get_secrets (priv->act_request, + setting_name, + flags, + hint, + modem_secrets_cb, + self); + if (priv->secrets_id) + g_signal_emit (self, signals[AUTH_REQUESTED], 0); + + return !!(priv->secrets_id); +} + +/*****************************************************************************/ + +static NMActStageReturn +act_stage1_prepare (NMModem *modem, + NMConnection *connection, + 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; + NMSettingsGetSecretsFlags flags = NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION; + NMConnection *connection; + + if (priv->act_request) + g_object_unref (priv->act_request); + priv->act_request = g_object_ref (req); + + connection = nm_act_request_get_connection (req); + g_assert (connection); + + setting_name = nm_connection_need_secrets (connection, &hints); + if (!setting_name) { + /* Ready to connect */ + g_assert (!hints); + return NM_MODEM_GET_CLASS (self)->act_stage1_prepare (self, connection, reason); + } + + /* Secrets required... */ + if (priv->secrets_tries++) + flags |= NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW; + + priv->secrets_id = nm_act_request_get_secrets (req, + setting_name, + flags, + hints ? g_ptr_array_index (hints, 0) : NULL, + modem_secrets_cb, + self); + if (priv->secrets_id) { + g_signal_emit (self, signals[AUTH_REQUESTED], 0); + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } else { + *reason = NM_DEVICE_STATE_REASON_NO_SECRETS; + ret = NM_ACT_STAGE_RETURN_FAILURE; + } + + 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; +} + +/*****************************************************************************/ + +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; +} + +/*****************************************************************************/ + +gboolean +nm_modem_complete_connection (NMModem *self, + NMConnection *connection, + const GSList *existing_connections, + GError **error) +{ + if (NM_MODEM_GET_CLASS (self)->complete_connection) + return NM_MODEM_GET_CLASS (self)->complete_connection (self, connection, existing_connections, error); + return FALSE; +} + +/*****************************************************************************/ + +static void +deactivate (NMModem *self, NMDevice *device) +{ + NMModemPrivate *priv; + int ifindex; + + g_return_if_fail (NM_IS_MODEM (self)); + g_return_if_fail (NM_IS_DEVICE (device)); + + priv = NM_MODEM_GET_PRIVATE (self); + + priv->secrets_tries = 0; + + if (priv->act_request) { + cancel_get_secrets (self); + g_object_unref (priv->act_request); + priv->act_request = NULL; + } + + priv->in_bytes = priv->out_bytes = 0; + + if (priv->ppp_manager) { + g_object_unref (priv->ppp_manager); + priv->ppp_manager = NULL; + } + + switch (priv->ip_method) { + case MM_MODEM_IP_METHOD_PPP: + break; + case MM_MODEM_IP_METHOD_STATIC: + case MM_MODEM_IP_METHOD_DHCP: + ifindex = nm_device_get_ip_ifindex (device); + if (ifindex > 0) { + nm_platform_route_flush (ifindex); + nm_platform_address_flush (ifindex); + nm_platform_link_set_down (ifindex); + } + break; + default: + nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method); + break; + } + + g_free (priv->ppp_iface); + priv->ppp_iface = NULL; +} + +/*****************************************************************************/ + +void +nm_modem_deactivate (NMModem *self, NMDevice *device) +{ + NM_MODEM_GET_CLASS (self)->deactivate (self, device); +} + +/*****************************************************************************/ + +void +nm_modem_device_state_changed (NMModem *self, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason) +{ + gboolean was_connected = FALSE, warn = TRUE; + NMModemPrivate *priv; + + g_return_if_fail (NM_IS_MODEM (self)); + + if (old_state >= NM_DEVICE_STATE_PREPARE && old_state <= NM_DEVICE_STATE_DEACTIVATING) + was_connected = TRUE; + + priv = NM_MODEM_GET_PRIVATE (self); + + /* Make sure we don't leave the serial device open */ + switch (new_state) { + case NM_DEVICE_STATE_UNMANAGED: + case NM_DEVICE_STATE_UNAVAILABLE: + case NM_DEVICE_STATE_DISCONNECTED: + case NM_DEVICE_STATE_FAILED: + if (priv->act_request) { + cancel_get_secrets (self); + g_object_unref (priv->act_request); + priv->act_request = NULL; + } + + if (was_connected) { + /* Don't bother warning on FAILED since the modem is already gone */ + if (new_state == NM_DEVICE_STATE_FAILED) + warn = FALSE; + NM_MODEM_GET_CLASS (self)->disconnect (self, warn); + } + break; + default: + break; + } +} + +/*****************************************************************************/ + +const char * +nm_modem_get_uid (NMModem *self) +{ + g_return_val_if_fail (NM_IS_MODEM (self), NULL); + + return NM_MODEM_GET_PRIVATE (self)->uid; +} + +const char * +nm_modem_get_path (NMModem *self) +{ + g_return_val_if_fail (NM_IS_MODEM (self), NULL); + + return NM_MODEM_GET_PRIVATE (self)->path; +} + +const char * +nm_modem_get_driver (NMModem *self) +{ + g_return_val_if_fail (NM_IS_MODEM (self), NULL); + + return NM_MODEM_GET_PRIVATE (self)->driver; +} + +const char * +nm_modem_get_control_port (NMModem *self) +{ + g_return_val_if_fail (NM_IS_MODEM (self), NULL); + + return NM_MODEM_GET_PRIVATE (self)->control_port; +} + +const char * +nm_modem_get_data_port (NMModem *self) +{ + g_return_val_if_fail (NM_IS_MODEM (self), NULL); + + /* The ppp_iface takes precedence over the data interface when PPP is used, + * since data_iface is the TTY over which PPP is run, and that TTY can't + * do IP. The caller really wants the thing that's doing IP. + */ + return NM_MODEM_GET_PRIVATE (self)->ppp_iface ? + NM_MODEM_GET_PRIVATE (self)->ppp_iface : NM_MODEM_GET_PRIVATE (self)->data_port; +} + +gboolean +nm_modem_owns_port (NMModem *self, const char *iface) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + + g_return_val_if_fail (iface != NULL, FALSE); + + if (NM_MODEM_GET_CLASS (self)->owns_port) + return NM_MODEM_GET_CLASS (self)->owns_port (self, iface); + + /* Fall back to data/control ports */ + if (priv->ppp_iface && (strcmp (priv->ppp_iface, iface) == 0)) + return TRUE; + if (priv->data_port && (strcmp (priv->data_port, iface) == 0)) + return TRUE; + if (priv->control_port && (strcmp (priv->control_port, iface) == 0)) + return TRUE; + + return FALSE; +} + +/*****************************************************************************/ + +void +nm_modem_get_capabilities (NMModem *self, + NMDeviceModemCapabilities *modem_caps, + NMDeviceModemCapabilities *current_caps) +{ + g_return_if_fail (NM_IS_MODEM (self)); + + NM_MODEM_GET_CLASS (self)->get_capabilities (self, modem_caps, current_caps); +} + +/*****************************************************************************/ + +static void +nm_modem_init (NMModem *self) +{ +} + +static GObject* +constructor (GType type, + guint n_construct_params, + GObjectConstructParam *construct_params) +{ + GObject *object; + NMModemPrivate *priv; + + object = G_OBJECT_CLASS (nm_modem_parent_class)->constructor (type, + n_construct_params, + construct_params); + if (!object) + return NULL; + + priv = NM_MODEM_GET_PRIVATE (object); + + if (!priv->data_port && !priv->control_port) { + nm_log_err (LOGD_HW, "neither modem command nor data interface provided"); + goto err; + } + + if (!priv->path) { + nm_log_err (LOGD_HW, "D-Bus path not provided"); + goto err; + } + + return object; + + err: + g_object_unref (object); + return NULL; +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_PATH: + g_value_set_string (value, priv->path); + break; + case PROP_DRIVER: + g_value_set_string (value, priv->driver); + break; + case PROP_CONTROL_PORT: + g_value_set_string (value, priv->control_port); + break; + case PROP_DATA_PORT: + g_value_set_string (value, nm_modem_get_data_port (NM_MODEM (object))); + break; + case PROP_UID: + g_value_set_string (value, priv->uid); + break; + case PROP_IP_METHOD: + g_value_set_uint (value, priv->ip_method); + break; + case PROP_IP_TIMEOUT: + g_value_set_uint (value, priv->mm_ip_timeout); + break; + case PROP_ENABLED: + g_value_set_boolean (value, priv->mm_enabled); + break; + case PROP_CONNECTED: + g_value_set_boolean (value, priv->mm_connected); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_PATH: + /* Construct only */ + priv->path = g_value_dup_string (value); + break; + case PROP_DRIVER: + /* Construct only */ + priv->driver = g_value_dup_string (value); + break; + case PROP_CONTROL_PORT: + priv->control_port = g_value_dup_string (value); + break; + case PROP_DATA_PORT: + priv->data_port = g_value_dup_string (value); + break; + case PROP_UID: + /* Construct only */ + priv->uid = g_value_dup_string (value); + break; + case PROP_IP_METHOD: + priv->ip_method = g_value_get_uint (value); + break; + case PROP_IP_TIMEOUT: + priv->mm_ip_timeout = g_value_get_uint (value); + break; + case PROP_ENABLED: + priv->mm_enabled = g_value_get_boolean (value); + break; + case PROP_CONNECTED: + priv->mm_connected = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object); + + if (priv->act_request) { + g_object_unref (priv->act_request); + priv->act_request = NULL; + } + + G_OBJECT_CLASS (nm_modem_parent_class)->dispose (object); +} + +static void +finalize (GObject *object) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object); + + g_free (priv->uid); + g_free (priv->path); + g_free (priv->driver); + g_free (priv->control_port); + g_free (priv->data_port); + + G_OBJECT_CLASS (nm_modem_parent_class)->finalize (object); +} + +static void +nm_modem_class_init (NMModemClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMModemPrivate)); + + /* Virtual methods */ + object_class->constructor = constructor; + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->dispose = dispose; + object_class->finalize = finalize; + + klass->act_stage1_prepare = act_stage1_prepare; + klass->deactivate = deactivate; + + /* Properties */ + + g_object_class_install_property + (object_class, PROP_UID, + g_param_spec_string (NM_MODEM_UID, + "UID", + "Modem unique ID", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, PROP_PATH, + g_param_spec_string (NM_MODEM_PATH, + "DBus path", + "DBus path", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, PROP_DRIVER, + g_param_spec_string (NM_MODEM_DRIVER, + "Driver", + "Driver", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, PROP_CONTROL_PORT, + g_param_spec_string (NM_MODEM_CONTROL_PORT, + "Control port", + "The port controlling the modem", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, PROP_DATA_PORT, + g_param_spec_string (NM_MODEM_DATA_PORT, + "Data port", + "The port to connect to", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property + (object_class, PROP_IP_METHOD, + g_param_spec_uint (NM_MODEM_IP_METHOD, + "IP method", + "IP method", + MM_MODEM_IP_METHOD_PPP, + MM_MODEM_IP_METHOD_DHCP, + MM_MODEM_IP_METHOD_PPP, + G_PARAM_READWRITE)); + + g_object_class_install_property + (object_class, PROP_IP_TIMEOUT, + g_param_spec_uint (NM_MODEM_IP_TIMEOUT, + "IP timeout", + "IP timeout", + 0, 360, 20, + G_PARAM_READWRITE)); + + g_object_class_install_property + (object_class, PROP_ENABLED, + g_param_spec_boolean (NM_MODEM_ENABLED, + "Enabled", + "Enabled", + TRUE, + G_PARAM_READWRITE)); + + g_object_class_install_property + (object_class, PROP_CONNECTED, + g_param_spec_boolean (NM_MODEM_CONNECTED, + "Connected", + "Connected", + TRUE, + G_PARAM_READWRITE)); + + /* Signals */ + + signals[PPP_STATS] = + g_signal_new ("ppp-stats", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMModemClass, ppp_stats), + NULL, NULL, NULL, + G_TYPE_NONE, 2, + G_TYPE_UINT, G_TYPE_UINT); + + 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, NULL, + G_TYPE_NONE, 1, G_TYPE_UINT); + + 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, NULL, + G_TYPE_NONE, 2, 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, NULL, + G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_UINT); + + signals[AUTH_REQUESTED] = + g_signal_new (NM_MODEM_AUTH_REQUESTED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMModemClass, auth_requested), + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + signals[AUTH_RESULT] = + g_signal_new (NM_MODEM_AUTH_RESULT, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMModemClass, auth_result), + NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + signals[REMOVED] = + g_signal_new (NM_MODEM_REMOVED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMModemClass, removed), + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + dbus_g_error_domain_register (NM_MODEM_ERROR, + NM_DBUS_INTERFACE_DEVICE_MODEM, + NM_TYPE_MODEM_ERROR); +} diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h new file mode 100644 index 0000000000..f15be26769 --- /dev/null +++ b/src/devices/wwan/nm-modem.h @@ -0,0 +1,193 @@ +/* -*- 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 - 2011 Red Hat, Inc. + * Copyright (C) 2009 Novell, Inc. + */ + +#ifndef NM_MODEM_H +#define NM_MODEM_H + +#include +#include +#include "ppp-manager/nm-ppp-manager.h" +#include "nm-device.h" + +G_BEGIN_DECLS + +#define NM_TYPE_MODEM (nm_modem_get_type ()) +#define NM_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM, NMModem)) +#define NM_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_MODEM, NMModemClass)) +#define NM_IS_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM)) +#define NM_IS_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_MODEM)) +#define NM_MODEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MODEM, NMModemClass)) + +#define NM_MODEM_UID "uid" +#define NM_MODEM_PATH "path" +#define NM_MODEM_DRIVER "driver" +#define NM_MODEM_CONTROL_PORT "control-port" +#define NM_MODEM_DATA_PORT "data-port" +#define NM_MODEM_IP_METHOD "ip-method" +#define NM_MODEM_IP_TIMEOUT "ip-timeout" +#define NM_MODEM_ENABLED "enabled" +#define NM_MODEM_CONNECTED "connected" + +#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_AUTH_REQUESTED "auth-requested" +#define NM_MODEM_AUTH_RESULT "auth-result" +#define NM_MODEM_REMOVED "removed" + +#define MM_MODEM_IP_METHOD_PPP 0 +#define MM_MODEM_IP_METHOD_STATIC 1 +#define MM_MODEM_IP_METHOD_DHCP 2 + +typedef enum { + NM_MODEM_ERROR_CONNECTION_NOT_GSM, /*< nick=ConnectionNotGsm >*/ + NM_MODEM_ERROR_CONNECTION_NOT_CDMA, /*< nick=ConnectionNotCdma >*/ + NM_MODEM_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/ + NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ + NM_MODEM_ERROR_INITIALIZATION_FAILED, /*< nick=InitializationFailed >*/ +} NMModemError; + +#define NM_MODEM_ERROR (nm_modem_error_quark ()) +GQuark nm_modem_error_quark (void); + + +typedef struct { + GObject parent; +} NMModem; + +typedef struct { + GObjectClass parent; + + void (*get_capabilities) (NMModem *self, + NMDeviceModemCapabilities *modem_caps, + NMDeviceModemCapabilities *current_caps); + + gboolean (*get_user_pass) (NMModem *modem, + NMConnection *connection, + const char **user, + const char **pass); + + gboolean (*check_connection_compatible) (NMModem *modem, + NMConnection *connection, + GError **error); + + gboolean (*complete_connection) (NMModem *modem, + NMConnection *connection, + const GSList *existing_connections, + GError **error); + + NMActStageReturn (*act_stage1_prepare) (NMModem *modem, + NMConnection *connection, + NMDeviceStateReason *reason); + + NMActStageReturn (*static_stage3_ip4_config_start) (NMModem *self, + NMActRequest *req, + NMDeviceStateReason *reason); + + void (*set_mm_enabled) (NMModem *self, gboolean enabled); + + void (*disconnect) (NMModem *self, gboolean warn); + + void (*deactivate) (NMModem *self, NMDevice *device); + + gboolean (*owns_port) (NMModem *self, const char *iface); + + /* Signals */ + 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, NMIP4Config *config, GError *error); + + void (*auth_requested) (NMModem *self); + void (*auth_result) (NMModem *self, GError *error); + + void (*removed) (NMModem *self); +} NMModemClass; + +GType nm_modem_get_type (void); + +const char *nm_modem_get_path (NMModem *modem); +const char *nm_modem_get_uid (NMModem *modem); +const char *nm_modem_get_control_port (NMModem *modem); +const char *nm_modem_get_data_port (NMModem *modem); +const char *nm_modem_get_driver (NMModem *modem); + +gboolean nm_modem_owns_port (NMModem *modem, const char *iface); + +void nm_modem_get_capabilities (NMModem *self, + NMDeviceModemCapabilities *modem_caps, + NMDeviceModemCapabilities *current_caps); + +gboolean nm_modem_check_connection_compatible (NMModem *self, + NMConnection *connection, + GError **error); + +gboolean nm_modem_complete_connection (NMModem *self, + NMConnection *connection, + const GSList *existing_connections, + 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_stage3_ip6_config_start (NMModem *modem, + NMDevice *device, + NMDeviceClass *device_class, + NMDeviceStateReason *reason); + +void nm_modem_ip4_pre_commit (NMModem *modem, NMDevice *device, NMIP4Config *config); + +gboolean nm_modem_get_secrets (NMModem *modem, + const char *setting_name, + gboolean request_new, + const char *hint); + +void nm_modem_deactivate (NMModem *modem, NMDevice *device); + +void nm_modem_device_state_changed (NMModem *modem, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason); + +gboolean nm_modem_get_mm_enabled (NMModem *self); + +void nm_modem_set_mm_enabled (NMModem *self, gboolean enabled); + +gboolean nm_modem_get_mm_connected (NMModem *self); + +/* For the modem-manager only */ +void nm_modem_emit_removed (NMModem *self); + +G_END_DECLS + +#endif /* NM_MODEM_H */ diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c new file mode 100644 index 0000000000..3a02fb1913 --- /dev/null +++ b/src/devices/wwan/nm-wwan-factory.c @@ -0,0 +1,160 @@ +/* -*- 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) 2014 Red Hat, Inc. + */ + +#include +#include "config.h" +#include "nm-device-factory.h" +#include "nm-wwan-factory.h" +#include "nm-modem-manager.h" +#include "nm-device-modem.h" +#include "nm-logging.h" + +static GType nm_wwan_factory_get_type (void); + +static void device_factory_interface_init (NMDeviceFactory *factory_iface); + +G_DEFINE_TYPE_EXTENDED (NMWwanFactory, nm_wwan_factory, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_FACTORY, device_factory_interface_init)) + +#define NM_WWAN_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_WWAN_FACTORY, NMWwanFactoryPrivate)) + +typedef struct { + NMModemManager *mm; +} NMWwanFactoryPrivate; + +enum { + PROP_0, + PROP_DEVICE_TYPE, + + LAST_PROP +}; + +/************************************************************************/ + +#define PLUGIN_TYPE NM_DEVICE_TYPE_MODEM + +G_MODULE_EXPORT NMDeviceFactory * +nm_device_factory_create (GError **error) +{ + return (NMDeviceFactory *) g_object_new (NM_TYPE_WWAN_FACTORY, NULL); +} + +G_MODULE_EXPORT NMDeviceType +nm_device_factory_get_device_type (void) +{ + return PLUGIN_TYPE; +} + +/************************************************************************/ + +static void +modem_added_cb (NMModemManager *manager, + NMModem *modem, + gpointer user_data) +{ + NMWwanFactory *self = NM_WWAN_FACTORY (user_data); + NMDevice *device; + const char *driver, *port; + + /* Do nothing if the modem was consumed by some other plugin */ + if (nm_device_factory_emit_component_added (NM_DEVICE_FACTORY (self), G_OBJECT (modem))) + return; + + driver = nm_modem_get_driver (modem); + + /* 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 && strstr (driver, "bluetooth")) { + port = nm_modem_get_data_port (modem); + if (!port) + port = nm_modem_get_control_port (modem); + nm_log_info (LOGD_MB, "ignoring modem '%s' (no associated Bluetooth device)", port); + return; + } + + /* Make the new modem device */ + device = nm_device_modem_new (modem); + g_assert (device); + g_signal_emit_by_name (self, NM_DEVICE_FACTORY_DEVICE_ADDED, device); + g_object_unref (device); +} + +static void +nm_wwan_factory_init (NMWwanFactory *self) +{ + NMWwanFactoryPrivate *priv = NM_WWAN_FACTORY_GET_PRIVATE (self); + + priv->mm = g_object_new (NM_TYPE_MODEM_MANAGER, NULL); + g_assert (priv->mm); + g_signal_connect (priv->mm, + NM_MODEM_MANAGER_MODEM_ADDED, + G_CALLBACK (modem_added_cb), + self); +} + +static void +device_factory_interface_init (NMDeviceFactory *factory_iface) +{ +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_DEVICE_TYPE: + g_value_set_uint (value, PLUGIN_TYPE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + NMWwanFactory *self = NM_WWAN_FACTORY (object); + NMWwanFactoryPrivate *priv = NM_WWAN_FACTORY_GET_PRIVATE (self); + + if (priv->mm) + g_signal_handlers_disconnect_by_func (priv->mm, modem_added_cb, self); + g_clear_object (&priv->mm); + + /* Chain up to the parent class */ + G_OBJECT_CLASS (nm_wwan_factory_parent_class)->dispose (object); +} + +static void +nm_wwan_factory_class_init (NMWwanFactoryClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMWwanFactoryPrivate)); + + object_class->dispose = dispose; + object_class->get_property = get_property; + + g_object_class_override_property (object_class, + PROP_DEVICE_TYPE, + NM_DEVICE_FACTORY_DEVICE_TYPE); +} diff --git a/src/devices/wwan/nm-wwan-factory.h b/src/devices/wwan/nm-wwan-factory.h new file mode 100644 index 0000000000..b7aee01f15 --- /dev/null +++ b/src/devices/wwan/nm-wwan-factory.h @@ -0,0 +1,37 @@ +/* -*- 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) 2014 Red Hat, Inc. + */ + +#ifndef NM_WWAN_FACTORY_H +#define NM_WWAN_FACTORY_H + +#include + +#define NM_TYPE_WWAN_FACTORY (nm_wwan_factory_get_type ()) +#define NM_WWAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WWAN_FACTORY, NMWwanFactory)) + +typedef struct { + GObject parent; +} NMWwanFactory; + +typedef struct { + GObjectClass parent; +} NMWwanFactoryClass; + +#endif /* NM_WWAN_FACTORY_H */ diff --git a/src/modem-manager/README b/src/modem-manager/README deleted file mode 100644 index 4661c04287..0000000000 --- a/src/modem-manager/README +++ /dev/null @@ -1,45 +0,0 @@ - -ModemManager integration is organized as follows: - - -Common source -******************************************************************************** - - * nm-modem.[h|c]: - Defines the basic `NMModem' object. The core NetworkManager implementation - will use this interface exclusively, regardless of the real final type of - the modem object. - - * nm-modem-manager.[h|c]: - Defines the `NMModemManager' object, which takes care of listening to - signals from the DBus interface notifying about added or removed modems. - It also takes care of creating proper `NMModem' objects from the - information retrieved from the DBus interface. - - -ModemManager 0.7 integration -******************************************************************************** - - * nm-modem-broadband.[h|c]: - Defines the `NMModemBroadband' object, which is a subclass of `NMModem'. - This object handles both 3GPP and 3GPP2 modems exposed in the new - `ModemManager1' interface. - - -ModemManager 0.4/0.5/0.6 integration -******************************************************************************** - - * nm-modem-old-types.h: - Defines helper types to use with the (old) ModemManager DBus API. - - * nm-modem-old.[h|c]: - Defines the `NMModemGeneric' object. All modem objects based on the old - ModemManager interface are subclasses of this one. - - * nm-modem-gsm.[h|c]: - Defines the `NMModemGsm' object, which is a subclass of `NMModemGeneric'. - This object handles 3GPP-specific (GSM, UMTS, HSPA, LTE) modems. - - * nm-modem-cdma.[h|c]: - Defines the `NMModemCdma' object, which is a subclass of `NMModemGeneric'. - This object handles 3GPP2-specific modems (CDMA, EV-DO). diff --git a/src/modem-manager/nm-modem-broadband.c b/src/modem-manager/nm-modem-broadband.c deleted file mode 100644 index f368c2e0ac..0000000000 --- a/src/modem-manager/nm-modem-broadband.c +++ /dev/null @@ -1,954 +0,0 @@ -/* -*- 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) 2012 Aleksander Morgado - */ - -#include -#include -#include -#include "nm-modem-broadband.h" -#include "nm-setting-connection.h" -#include "nm-logging.h" -#include "NetworkManagerUtils.h" -#include "nm-device-private.h" - -G_DEFINE_TYPE (NMModemBroadband, nm_modem_broadband, NM_TYPE_MODEM) - -struct _NMModemBroadbandPrivate { - /* The modem object from dbus */ - MMObject *modem_object; - /* Per-interface objects */ - MMModem *modem_iface; - MMModemSimple *simple_iface; - - /* Connection setup */ - MMSimpleConnectProperties *connect_properties; - MMBearer *bearer; - MMBearerIpConfig *ipv4_config; - MMBearerIpConfig *ipv6_config; - - guint32 pin_tries; -}; - -enum { - PROP_0, - PROP_MODEM, -}; - -#define MODEM_CAPS_3GPP(caps) (caps & (MM_MODEM_CAPABILITY_GSM_UMTS | \ - MM_MODEM_CAPABILITY_LTE | \ - MM_MODEM_CAPABILITY_LTE_ADVANCED)) - -#define MODEM_CAPS_3GPP2(caps) (caps & (MM_MODEM_CAPABILITY_CDMA_EVDO)) - -/* Maximum time to keep the DBus call waiting for a connection result */ -#define MODEM_CONNECT_TIMEOUT_SECS 120 - -/*****************************************************************************/ - -static NMDeviceStateReason -translate_mm_error (GError *error) -{ - NMDeviceStateReason reason; - - if (g_error_matches (error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_CARRIER)) - reason = NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER; - else if (g_error_matches (error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_DIALTONE)) - reason = NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE; - else if (g_error_matches (error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_BUSY)) - reason = NM_DEVICE_STATE_REASON_MODEM_BUSY; - else if (g_error_matches (error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_ANSWER)) - reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT; - else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NETWORK_NOT_ALLOWED)) - reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED; - else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT)) - reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT; - else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NO_NETWORK)) - reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING; - else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED; - else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED; - else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED; - else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_WRONG; - else { - /* unable to map the ModemManager error to a NM_DEVICE_STATE_REASON */ - nm_log_dbg (LOGD_MB, "unmapped error detected: '%s'", error->message); - reason = NM_DEVICE_STATE_REASON_UNKNOWN; - } - - return reason; -} - -/*****************************************************************************/ - -static void -get_capabilities (NMModem *_self, - NMDeviceModemCapabilities *modem_caps, - NMDeviceModemCapabilities *current_caps) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND (_self); - MMModemCapability all_supported = MM_MODEM_CAPABILITY_NONE; - MMModemCapability *supported; - guint n_supported; - - /* For now, we don't care about the capability combinations, just merge all - * combinations in a single mask */ - if (mm_modem_get_supported_capabilities (self->priv->modem_iface, &supported, &n_supported)) { - guint i; - - for (i = 0; i < n_supported; i++) - all_supported |= supported[i]; - - g_free (supported); - } - - *modem_caps = (NMDeviceModemCapabilities) all_supported; - *current_caps = (NMDeviceModemCapabilities) mm_modem_get_current_capabilities (self->priv->modem_iface); -} - -static gboolean -owns_port (NMModem *_self, const char *iface) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND (_self); - const MMModemPortInfo *ports = NULL; - guint n_ports = 0, i; - gboolean owns = FALSE; - - mm_modem_peek_ports (self->priv->modem_iface, &ports, &n_ports); - for (i = 0; i < n_ports && !owns; i++) - owns = (g_strcmp0 (iface, ports[i].name) == 0); - return owns; -} - -/*****************************************************************************/ - -static void -ask_for_pin (NMModemBroadband *self) -{ - guint32 tries; - - tries = self->priv->pin_tries++; - nm_modem_get_secrets (NM_MODEM (self), - NM_SETTING_GSM_SETTING_NAME, - tries ? TRUE : FALSE, - NM_SETTING_GSM_PIN); -} - -static void -connect_ready (MMModemSimple *simple_iface, - GAsyncResult *res, - NMModemBroadband *self) -{ - GError *error = NULL; - guint ip_method; - - g_clear_object (&self->priv->connect_properties); - - self->priv->bearer = mm_modem_simple_connect_finish (simple_iface, res, &error); - if (!self->priv->bearer) { - if (g_error_matches (error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) || - (g_error_matches (error, - MM_CORE_ERROR, - MM_CORE_ERROR_UNAUTHORIZED) && - mm_modem_get_unlock_required (self->priv->modem_iface) == MM_MODEM_LOCK_SIM_PIN)) { - /* Request PIN */ - ask_for_pin (self); - } else { - /* Strip remote error info before logging it */ - if (g_dbus_error_is_remote_error (error)) - g_dbus_error_strip_remote_error (error); - - nm_log_warn (LOGD_MB, "(%s) failed to connect modem: %s", - nm_modem_get_uid (NM_MODEM (self)), - error && error->message ? error->message : "(unknown)"); - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (error)); - } - - g_clear_error (&error); - g_object_unref (self); - return; - } - - /* Grab IP configurations */ - self->priv->ipv4_config = mm_bearer_get_ipv4_config (self->priv->bearer); - self->priv->ipv6_config = mm_bearer_get_ipv6_config (self->priv->bearer); - - switch (mm_bearer_ip_config_get_method (self->priv->ipv4_config)) { - case MM_BEARER_IP_METHOD_PPP: - ip_method = MM_MODEM_IP_METHOD_PPP; - break; - case MM_BEARER_IP_METHOD_STATIC: - ip_method = MM_MODEM_IP_METHOD_STATIC; - break; - case MM_BEARER_IP_METHOD_DHCP: - ip_method = MM_MODEM_IP_METHOD_DHCP; - break; - default: - error = g_error_new (NM_MODEM_ERROR, - NM_MODEM_ERROR_CONNECTION_INVALID, - "invalid IP config"); - nm_log_warn (LOGD_MB, "(%s) failed to connect modem: %s", - nm_modem_get_uid (NM_MODEM (self)), - error->message); - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (error)); - g_error_free (error); - g_object_unref (self); - return; - } - - /* IPv4 for now only */ - g_object_set (self, - NM_MODEM_DATA_PORT, mm_bearer_get_interface (self->priv->bearer), - NM_MODEM_IP_METHOD, ip_method, - NM_MODEM_IP_TIMEOUT, mm_bearer_get_ip_timeout (self->priv->bearer), - NULL); - - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, TRUE, NM_DEVICE_STATE_REASON_NONE); - g_object_unref (self); -} - -static MMSimpleConnectProperties * -create_cdma_connect_properties (NMConnection *connection) -{ - NMSettingCdma *setting; - MMSimpleConnectProperties *properties; - const gchar *str; - - setting = nm_connection_get_setting_cdma (connection); - properties = mm_simple_connect_properties_new (); - - str = nm_setting_cdma_get_number (setting); - if (str) - mm_simple_connect_properties_set_number (properties, str); - - return properties; -} - -static MMSimpleConnectProperties * -create_gsm_connect_properties (NMConnection *connection) -{ - NMSettingGsm *setting; - NMSettingPPP *s_ppp; - MMSimpleConnectProperties *properties; - const gchar *str; - - setting = nm_connection_get_setting_gsm (connection); - properties = mm_simple_connect_properties_new (); - - /* TODO: not needed */ - str = nm_setting_gsm_get_number (setting); - if (str) - mm_simple_connect_properties_set_number (properties, str); - - str = nm_setting_gsm_get_apn (setting); - if (str) - mm_simple_connect_properties_set_apn (properties, str); - - str = nm_setting_gsm_get_network_id (setting); - if (str) - mm_simple_connect_properties_set_operator_id (properties, str); - - str = nm_setting_gsm_get_pin (setting); - if (str) - mm_simple_connect_properties_set_pin (properties, str); - - str = nm_setting_gsm_get_username (setting); - if (str) - mm_simple_connect_properties_set_user (properties, str); - - str = nm_setting_gsm_get_password (setting); - if (str) - mm_simple_connect_properties_set_password (properties, str); - - /* Roaming */ - if (nm_setting_gsm_get_home_only (setting)) - mm_simple_connect_properties_set_allow_roaming (properties, FALSE); - - /* For IpMethod == STATIC or DHCP */ - s_ppp = nm_connection_get_setting_ppp (connection); - if (s_ppp) { - MMBearerAllowedAuth allowed_auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN; - - if (nm_setting_ppp_get_noauth (s_ppp)) - allowed_auth = MM_BEARER_ALLOWED_AUTH_NONE; - if (!nm_setting_ppp_get_refuse_pap (s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_PAP; - if (!nm_setting_ppp_get_refuse_chap (s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_CHAP; - if (!nm_setting_ppp_get_refuse_mschap (s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_MSCHAP; - if (!nm_setting_ppp_get_refuse_mschapv2 (s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_MSCHAPV2; - if (!nm_setting_ppp_get_refuse_eap (s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_EAP; - - mm_simple_connect_properties_set_allowed_auth (properties, allowed_auth); - } - - return properties; -} - -static NMActStageReturn -act_stage1_prepare (NMModem *_self, - NMConnection *connection, - NMDeviceStateReason *reason) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND (_self); - MMModemCapability caps; - - g_clear_object (&self->priv->connect_properties); - - caps = mm_modem_get_current_capabilities (self->priv->modem_iface); - if (MODEM_CAPS_3GPP (caps)) - self->priv->connect_properties = create_gsm_connect_properties (connection); - else if (MODEM_CAPS_3GPP2 (caps)) - self->priv->connect_properties = create_cdma_connect_properties (connection); - else { - nm_log_warn (LOGD_MB, "(%s) not a mobile broadband modem", - nm_modem_get_uid (NM_MODEM (self))); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - if (!self->priv->simple_iface) - self->priv->simple_iface = mm_object_get_modem_simple (self->priv->modem_object); - - g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (self->priv->simple_iface), MODEM_CONNECT_TIMEOUT_SECS * 1000); - mm_modem_simple_connect (self->priv->simple_iface, - self->priv->connect_properties, - NULL, - (GAsyncReadyCallback)connect_ready, - g_object_ref (self)); - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ - -static gboolean -check_connection_compatible (NMModem *_self, - NMConnection *connection, - GError **error) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND (_self); - MMModemCapability modem_caps; - NMSettingConnection *s_con; - - modem_caps = mm_modem_get_current_capabilities (self->priv->modem_iface); - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (MODEM_CAPS_3GPP (modem_caps)) { - NMSettingGsm *s_gsm; - - if (!g_str_equal (nm_setting_connection_get_connection_type (s_con), - NM_SETTING_GSM_SETTING_NAME)) { - g_set_error (error, - NM_MODEM_ERROR, - NM_MODEM_ERROR_CONNECTION_NOT_GSM, - "The connection was not a 3GPP connection."); - return FALSE; - } - - s_gsm = nm_connection_get_setting_gsm (connection); - if (!s_gsm) { - g_set_error (error, - NM_MODEM_ERROR, - NM_MODEM_ERROR_CONNECTION_INVALID, - "The connection was not a valid 3GPP connection."); - return FALSE; - } - - return TRUE; - } - - if (MODEM_CAPS_3GPP2 (modem_caps)) { - NMSettingCdma *s_cdma; - - if (!g_str_equal (nm_setting_connection_get_connection_type (s_con), - NM_SETTING_CDMA_SETTING_NAME)) { - g_set_error (error, - NM_MODEM_ERROR, - NM_MODEM_ERROR_CONNECTION_NOT_CDMA, - "The connection was not a 3GPP2 connection."); - return FALSE; - } - - s_cdma = nm_connection_get_setting_cdma (connection); - if (!s_cdma) { - g_set_error (error, - NM_MODEM_ERROR, - NM_MODEM_ERROR_CONNECTION_INVALID, - "The connection was not a valid 3GPP2 connection."); - return FALSE; - } - - return TRUE; - } - - g_set_error (error, - NM_MODEM_ERROR, - NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE, - "Device is not a mobile broadband modem"); - return FALSE; -} - -/*****************************************************************************/ - -static gboolean -complete_connection (NMModem *_self, - NMConnection *connection, - const GSList *existing_connections, - GError **error) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND (_self); - MMModemCapability modem_caps; - NMSettingPPP *s_ppp; - - modem_caps = mm_modem_get_current_capabilities (self->priv->modem_iface); - - /* PPP settings common to 3GPP and 3GPP2 */ - s_ppp = nm_connection_get_setting_ppp (connection); - if (!s_ppp) { - s_ppp = (NMSettingPPP *) nm_setting_ppp_new (); - g_object_set (G_OBJECT (s_ppp), - NM_SETTING_PPP_LCP_ECHO_FAILURE, 5, - NM_SETTING_PPP_LCP_ECHO_INTERVAL, 30, - NULL); - nm_connection_add_setting (connection, NM_SETTING (s_ppp)); - } - - if (MODEM_CAPS_3GPP (modem_caps)) { - NMSettingGsm *s_gsm; - - s_gsm = nm_connection_get_setting_gsm (connection); - if (!s_gsm || !nm_setting_gsm_get_apn (s_gsm)) { - /* Need an APN at least */ - g_set_error_literal (error, - NM_SETTING_GSM_ERROR, - NM_SETTING_GSM_ERROR_MISSING_PROPERTY, - NM_SETTING_GSM_APN); - return FALSE; - } - - /* TODO: This is not needed */ - if (!nm_setting_gsm_get_number (s_gsm)) - g_object_set (G_OBJECT (s_gsm), NM_SETTING_GSM_NUMBER, "*99#", NULL); - - nm_utils_complete_generic (connection, - NM_SETTING_GSM_SETTING_NAME, - existing_connections, - _("GSM connection %d"), - NULL, - FALSE); /* No IPv6 yet by default */ - - return TRUE; - } - - if (MODEM_CAPS_3GPP2 (modem_caps)) { - NMSettingCdma *s_cdma; - - s_cdma = nm_connection_get_setting_cdma (connection); - if (!s_cdma) { - s_cdma = (NMSettingCdma *) nm_setting_cdma_new (); - nm_connection_add_setting (connection, NM_SETTING (s_cdma)); - } - - if (!nm_setting_cdma_get_number (s_cdma)) - g_object_set (G_OBJECT (s_cdma), NM_SETTING_CDMA_NUMBER, "#777", NULL); - - nm_utils_complete_generic (connection, - NM_SETTING_CDMA_SETTING_NAME, - existing_connections, - _("CDMA connection %d"), - NULL, - FALSE); /* No IPv6 yet by default */ - - return TRUE; - } - - g_set_error (error, - NM_MODEM_ERROR, - NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE, - "Device is not a mobile broadband modem"); - return FALSE; -} - -/*****************************************************************************/ - -static gboolean -get_user_pass (NMModem *modem, - NMConnection *connection, - const char **user, - const char **pass) -{ - NMSettingGsm *s_gsm; - NMSettingCdma *s_cdma; - - s_gsm = nm_connection_get_setting_gsm (connection); - s_cdma = nm_connection_get_setting_cdma (connection); - if (!s_gsm && !s_cdma) - return FALSE; - - if (user) { - if (s_gsm) - *user = nm_setting_gsm_get_username (s_gsm); - else if (s_cdma) - *user = nm_setting_cdma_get_username (s_cdma); - } - if (pass) { - if (s_gsm) - *pass = nm_setting_gsm_get_password (s_gsm); - else if (s_cdma) - *pass = nm_setting_cdma_get_password (s_cdma); - } - - return TRUE; -} - -/*****************************************************************************/ -/* Query/Update enabled state */ - -static void -update_mm_enabled (NMModem *self, - gboolean new_enabled) -{ - if (nm_modem_get_mm_enabled (self) != new_enabled) { - g_object_set (self, - NM_MODEM_ENABLED, new_enabled, - NULL); - } -} - -static void -modem_disable_ready (MMModem *modem_iface, - GAsyncResult *res, - NMModemBroadband *self) -{ - GError *error = NULL; - - if (!mm_modem_disable_finish (modem_iface, res, &error)) { - nm_log_warn (LOGD_MB, "(%s) failed to disable modem: %s", - nm_modem_get_uid (NM_MODEM (self)), - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - } else - /* Update enabled/disabled state again */ - update_mm_enabled (NM_MODEM (self), FALSE); - - /* Balance refcount */ - g_object_unref (self); -} - -static void -modem_enable_ready (MMModem *modem_iface, - GAsyncResult *res, - NMModemBroadband *self) -{ - GError *error = NULL; - - if (!mm_modem_enable_finish (modem_iface, res, &error)) { - nm_log_warn (LOGD_MB, "(%s) failed to enable modem: %s", - nm_modem_get_uid (NM_MODEM (self)), - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - } else - update_mm_enabled (NM_MODEM (self), TRUE); - - /* Balance refcount */ - g_object_unref (self); -} - -static void -set_mm_enabled (NMModem *_self, - gboolean enabled) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND (_self); - - if (enabled) { - /* Don't even try to enable if we're known to be already locked */ - if (mm_modem_get_state (self->priv->modem_iface) == MM_MODEM_STATE_LOCKED) { - nm_log_warn (LOGD_MB, "(%s) cannot enable modem: locked", - nm_modem_get_uid (NM_MODEM (self))); - g_signal_emit_by_name (self, NM_MODEM_AUTH_REQUESTED, 0); - return; - } - - mm_modem_enable (self->priv->modem_iface, - NULL, /* cancellable */ - (GAsyncReadyCallback)modem_enable_ready, - g_object_ref (self)); - } else { - mm_modem_disable (self->priv->modem_iface, - NULL, /* cancellable */ - (GAsyncReadyCallback)modem_disable_ready, - g_object_ref (self)); - - /* When disabling don't say we're enabled */ - update_mm_enabled (NM_MODEM (self), enabled); - } -} - -/*****************************************************************************/ -/* IP method static */ - -static gboolean -ip_string_to_network_address (const gchar *str, - guint32 *out) -{ - guint32 addr = 0; - gboolean success = FALSE; - - if (!str || inet_pton (AF_INET, str, &addr) != 1) - addr = 0; - else - success = TRUE; - - *out = (guint32)addr; - return success; -} - -static gboolean -static_stage3_done (NMModemBroadband *self) -{ - GError *error = NULL; - NMIP4Config *config = NULL; - const gchar *address_string; - const gchar *gw_string; - guint32 address_network; - guint32 gw; - NMPlatformIP4Address address; - const gchar **dns; - guint i; - - g_assert (self->priv->ipv4_config); - - nm_log_info (LOGD_MB, "(%s): IPv4 static configuration:", - nm_modem_get_uid (NM_MODEM (self))); - - /* Fully fail if invalid IP address retrieved */ - address_string = mm_bearer_ip_config_get_address (self->priv->ipv4_config); - if (!ip_string_to_network_address (address_string, &address_network)) { - error = g_error_new (NM_MODEM_ERROR, - NM_MODEM_ERROR_CONNECTION_INVALID, - "(%s) retrieving IP4 configuration failed: invalid address given '%s'", - nm_modem_get_uid (NM_MODEM (self)), - address_string); - goto out; - } - - /* Missing gateway not a hard failure */ - gw_string = mm_bearer_ip_config_get_gateway (self->priv->ipv4_config); - ip_string_to_network_address (gw_string, &gw); - - config = nm_ip4_config_new (); - - memset (&address, 0, sizeof (address)); - address.address = address_network; - address.plen = mm_bearer_ip_config_get_prefix (self->priv->ipv4_config); - address.source = NM_PLATFORM_SOURCE_WWAN; - nm_ip4_config_add_address (config, &address); - - nm_log_info (LOGD_MB, " address %s/%d", address_string, address.plen); - - if (gw) { - nm_ip4_config_set_gateway (config, gw); - nm_log_info (LOGD_MB, " gateway %s", gw_string); - } - - /* DNS servers */ - dns = mm_bearer_ip_config_get_dns (self->priv->ipv4_config); - for (i = 0; dns[i]; i++) { - if ( ip_string_to_network_address (dns[i], &address_network) - && address_network > 0) { - nm_ip4_config_add_nameserver (config, address_network); - nm_log_info (LOGD_MB, " DNS %s", dns[i]); - } - } - -out: - g_signal_emit_by_name (self, NM_MODEM_IP4_CONFIG_RESULT, config, error); - g_clear_error (&error); - return FALSE; -} - -static NMActStageReturn -static_stage3_ip4_config_start (NMModem *_self, - NMActRequest *req, - NMDeviceStateReason *reason) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND (_self); - - /* We schedule it in an idle just to follow the same logic as in the - * generic modem implementation. */ - g_idle_add ((GSourceFunc)static_stage3_done, self); - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ -/* Disconnect */ - -typedef struct { - NMModemBroadband *self; - gboolean warn; -} SimpleDisconnectContext; - -static void -simple_disconnect_context_free (SimpleDisconnectContext *ctx) -{ - g_object_unref (ctx->self); - g_slice_free (SimpleDisconnectContext, ctx); -} - -static void -simple_disconnect_ready (MMModemSimple *modem_iface, - GAsyncResult *res, - SimpleDisconnectContext *ctx) -{ - GError *error = NULL; - - if (!mm_modem_simple_disconnect_finish (modem_iface, res, &error)) { - if (ctx->warn) - nm_log_warn (LOGD_MB, "(%s) failed to disconnect modem: %s", - nm_modem_get_uid (NM_MODEM (ctx->self)), - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - } - - simple_disconnect_context_free (ctx); -} - -static void -disconnect (NMModem *self, - gboolean warn) -{ - SimpleDisconnectContext *ctx; - - ctx = g_slice_new (SimpleDisconnectContext); - ctx->self = g_object_ref (self); - - /* Don't bother warning on FAILED since the modem is already gone */ - ctx->warn = warn; - - mm_modem_simple_disconnect ( - ctx->self->priv->simple_iface, - NULL, /* bearer path; if NULL given ALL get disconnected */ - NULL, /* cancellable */ - (GAsyncReadyCallback)simple_disconnect_ready, - ctx); -} - -/*****************************************************************************/ - -static void -deactivate (NMModem *_self, NMDevice *device) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND (_self); - - /* TODO: cancel SimpleConnect() if any */ - - /* Cleanup IPv4 addresses and routes */ - g_clear_object (&self->priv->ipv4_config); - g_clear_object (&self->priv->ipv6_config); - g_clear_object (&self->priv->bearer); - - self->priv->pin_tries = 0; - - /* Chain up parent's */ - NM_MODEM_CLASS (nm_modem_broadband_parent_class)->deactivate (_self, device); -} - -/*****************************************************************************/ - -static void -modem_state_changed (MMModem *modem, - MMModemState old_state, - MMModemState new_state, - MMModemStateChangeReason reason, - NMModemBroadband *self) -{ - gboolean old; - gboolean new; - - nm_log_info (LOGD_MB, "(%s) modem state changed, '%s' --> '%s' (reason: %s)\n", - nm_modem_get_uid (NM_MODEM (self)), - mm_modem_state_get_string (old_state), - mm_modem_state_get_string (new_state), - mm_modem_state_change_reason_get_string (reason)); - - old = nm_modem_get_mm_enabled (NM_MODEM (self)); - new = (mm_modem_get_state (self->priv->modem_iface) >= MM_MODEM_STATE_ENABLED); - if (old != new) - g_object_set (self, - NM_MODEM_ENABLED, new, - NULL); - - old = nm_modem_get_mm_connected (NM_MODEM (self)); - new = (mm_modem_get_state (self->priv->modem_iface) >= MM_MODEM_STATE_CONNECTED); - if (old != new) - g_object_set (self, - NM_MODEM_CONNECTED, new, - NULL); -} - -/*****************************************************************************/ - -NMModem * -nm_modem_broadband_new (GObject *object) -{ - MMObject *modem_object; - MMModem *modem_iface; - - g_return_val_if_fail (MM_IS_OBJECT (object), NULL); - modem_object = MM_OBJECT (object); - - /* Ensure we have the 'Modem' interface and the primary port at least */ - modem_iface = mm_object_peek_modem (modem_object); - g_return_val_if_fail (!!modem_iface, NULL); - g_return_val_if_fail (!!mm_modem_get_primary_port (modem_iface), NULL); - - /* If the modem is in 'FAILED' state we cannot do anything with it. - * This happens when a severe error happened when trying to initialize it, - * like missing SIM. */ - if (mm_modem_get_state (modem_iface) == MM_MODEM_STATE_FAILED) { - nm_log_warn (LOGD_MB, "(%s): unusable modem detected", - mm_modem_get_primary_port (modem_iface)); - return NULL; - } - - return (NMModem *) g_object_new (NM_TYPE_MODEM_BROADBAND, - NM_MODEM_PATH, mm_object_get_path (modem_object), - NM_MODEM_UID, mm_modem_get_primary_port (modem_iface), - NM_MODEM_CONTROL_PORT, mm_modem_get_primary_port (modem_iface), - NM_MODEM_DATA_PORT, NULL, /* We don't know it until bearer created */ - NM_MODEM_BROADBAND_MODEM, modem_object, - NULL); -} - -static void -nm_modem_broadband_init (NMModemBroadband *self) -{ - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - NM_TYPE_MODEM_BROADBAND, - NMModemBroadbandPrivate); -} - -static void -set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND (object); - - switch (prop_id) { - case PROP_MODEM: - /* construct-only */ - self->priv->modem_object = g_value_dup_object (value); - self->priv->modem_iface = mm_object_get_modem (self->priv->modem_object); - g_assert (self->priv->modem_iface != NULL); - g_signal_connect (self->priv->modem_iface, - "state-changed", - G_CALLBACK (modem_state_changed), - self); - - g_object_set (object, - NM_MODEM_ENABLED, (mm_modem_get_state (self->priv->modem_iface) >= MM_MODEM_STATE_ENABLED), - NM_MODEM_CONNECTED, (mm_modem_get_state (self->priv->modem_iface) >= MM_MODEM_STATE_CONNECTED), - NULL); - - /* Note: don't grab the Simple iface here; the Modem interface is the - * only one assumed to be always valid and available */ - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND (object); - - switch (prop_id) { - case PROP_MODEM: - g_value_set_object (value, self->priv->modem_object); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -dispose (GObject *object) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND (object); - - g_clear_object (&self->priv->ipv4_config); - g_clear_object (&self->priv->ipv6_config); - g_clear_object (&self->priv->bearer); - g_clear_object (&self->priv->modem_iface); - g_clear_object (&self->priv->simple_iface); - g_clear_object (&self->priv->modem_object); - - G_OBJECT_CLASS (nm_modem_broadband_parent_class)->dispose (object); -} - -static void -nm_modem_broadband_class_init (NMModemBroadbandClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMModemClass *modem_class = NM_MODEM_CLASS (klass); - - g_type_class_add_private (object_class, sizeof (NMModemBroadbandPrivate)); - - /* Virtual methods */ - object_class->dispose = dispose; - object_class->get_property = get_property; - object_class->set_property = set_property; - - modem_class->get_capabilities = get_capabilities; - modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start; - modem_class->disconnect = disconnect; - modem_class->deactivate = deactivate; - modem_class->set_mm_enabled = set_mm_enabled; - modem_class->get_user_pass = get_user_pass; - modem_class->check_connection_compatible = check_connection_compatible; - modem_class->complete_connection = complete_connection; - modem_class->act_stage1_prepare = act_stage1_prepare; - modem_class->owns_port = owns_port; - - /* Properties */ - g_object_class_install_property - (object_class, PROP_MODEM, - g_param_spec_object (NM_MODEM_BROADBAND_MODEM, - "Modem", - "Broadband modem object", - MM_GDBUS_TYPE_OBJECT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -} diff --git a/src/modem-manager/nm-modem-broadband.h b/src/modem-manager/nm-modem-broadband.h deleted file mode 100644 index 635c619a4f..0000000000 --- a/src/modem-manager/nm-modem-broadband.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- 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) 2012 - Aleksander Morgado - */ - -#ifndef NM_MODEM_BROADBAND_H -#define NM_MODEM_BROADBAND_H - -#include -#include -#include "nm-modem.h" - -G_BEGIN_DECLS - -#define NM_TYPE_MODEM_BROADBAND (nm_modem_broadband_get_type ()) -#define NM_MODEM_BROADBAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadband)) -#define NM_MODEM_BROADBAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_MODEM_BROADBAND, NMModemBroadbandClass)) -#define NM_IS_MODEM_BROADBAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_BROADBAND)) -#define NM_IS_MODEM_BROADBAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_MODEM_BROADBAND)) -#define NM_MODEM_BROADBAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadbandClass)) - -#define NM_MODEM_BROADBAND_MODEM "modem" - -typedef struct _NMModemBroadband NMModemBroadband; -typedef struct _NMModemBroadbandClass NMModemBroadbandClass; -typedef struct _NMModemBroadbandPrivate NMModemBroadbandPrivate; - -struct _NMModemBroadband { - NMModem parent; - NMModemBroadbandPrivate *priv; -}; - -struct _NMModemBroadbandClass { - NMModemClass parent; -}; - -GType nm_modem_broadband_get_type (void); - -NMModem *nm_modem_broadband_new (GObject *object); - -G_END_DECLS - -#endif /* NM_MODEM_BROADBAND_H */ diff --git a/src/modem-manager/nm-modem-manager.c b/src/modem-manager/nm-modem-manager.c deleted file mode 100644 index f68a569666..0000000000 --- a/src/modem-manager/nm-modem-manager.c +++ /dev/null @@ -1,760 +0,0 @@ -/* -*- 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. - * Copyright (C) 2009 Novell, Inc. - * Copyright (C) 2009 Canonical Ltd. - */ - -#include -#include "config.h" -#include "nm-modem-manager.h" -#include "nm-logging.h" -#include "nm-modem.h" -#include "nm-modem-old.h" -#include "nm-dbus-manager.h" -#include "nm-modem-old-types.h" -#include "nm-dbus-glib-types.h" - -#if WITH_MODEM_MANAGER_1 -#include -#include "nm-modem-broadband.h" -#endif - -#define MODEM_POKE_INTERVAL 120 - -G_DEFINE_TYPE (NMModemManager, nm_modem_manager, G_TYPE_OBJECT) - -struct _NMModemManagerPrivate { - /* ModemManager < 0.7 */ - NMDBusManager *dbus_mgr; - DBusGProxy *proxy; - guint poke_id; - -#if WITH_MODEM_MANAGER_1 - /* ModemManager >= 0.7 */ - GDBusConnection *dbus_connection; - MMManager *modem_manager_1; - guint modem_manager_1_launch_id; - gboolean old_modem_manager_found; - gboolean new_modem_manager_found; - guint modem_manager_1_name_owner_changed_id; - guint modem_manager_1_object_added_id; - guint modem_manager_1_object_removed_id; -#endif - - /* Common */ - GHashTable *modems; -}; - -enum { - MODEM_ADDED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - - -NMModemManager * -nm_modem_manager_get (void) -{ - static NMModemManager *singleton = NULL; - - if (!singleton) - singleton = NM_MODEM_MANAGER (g_object_new (NM_TYPE_MODEM_MANAGER, NULL)); - else - g_object_ref (singleton); - - g_assert (singleton); - return singleton; -} - -/************************************************************************/ -/* Support for ModemManager < 0.7 */ - -static void -clear_modem_manager_support (NMModemManager *self) -{ - if (self->priv->poke_id) { - g_source_remove (self->priv->poke_id); - self->priv->poke_id = 0; - } - - if (self->priv->proxy) { - g_object_unref (self->priv->proxy); - self->priv->proxy = NULL; - } -} - -static void -create_modem (NMModemManager *self, const char *path) -{ - DBusGProxy *proxy; - GError *error = NULL; - NMModem *modem = NULL; - GHashTable *properties; - - if (g_hash_table_lookup (self->priv->modems, path)) { - nm_log_warn (LOGD_MB, "modem with path %s already exists, ignoring", path); - return; - } - - proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (self->priv->dbus_mgr), - MM_OLD_DBUS_SERVICE, - path, - DBUS_INTERFACE_PROPERTIES); - g_assert (proxy); - if (dbus_g_proxy_call_with_timeout (proxy, "GetAll", 15000, &error, - G_TYPE_STRING, MM_OLD_DBUS_INTERFACE_MODEM, - G_TYPE_INVALID, - DBUS_TYPE_G_MAP_OF_VARIANT, &properties, - G_TYPE_INVALID)) { - /* Success, create the modem */ - modem = nm_modem_old_new (path, properties, &error); - if (modem) { - g_hash_table_insert (self->priv->modems, g_strdup (path), modem); - g_signal_emit (self, signals[MODEM_ADDED], 0, modem, nm_modem_get_driver (modem)); - } else { - nm_log_warn (LOGD_MB, "failed to create modem: %s", - error ? error->message : "(unknown)"); - } - g_hash_table_destroy (properties); - } else { - nm_log_warn (LOGD_MB, "could not get modem properties: %s %s", - error ? dbus_g_error_get_name (error) : "(none)", - error ? error->message : "(unknown)"); - } - - g_object_unref (proxy); - g_clear_error (&error); -} - -static void -modem_added (DBusGProxy *proxy, const char *path, gpointer user_data) -{ - create_modem (NM_MODEM_MANAGER (user_data), path); -} - -static void -modem_removed (DBusGProxy *proxy, const char *path, gpointer user_data) -{ - NMModemManager *self = NM_MODEM_MANAGER (user_data); - NMModem *modem; - - modem = (NMModem *) g_hash_table_lookup (self->priv->modems, path); - if (modem) { - nm_modem_emit_removed (modem); - g_hash_table_remove (self->priv->modems, path); - } -} - -static void -mm_poke_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) -{ - GPtrArray *modems; - int i; - - if (dbus_g_proxy_end_call (proxy, call, NULL, - DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &modems, - G_TYPE_INVALID)) { - /* Don't care about the returned value, just free it */ - for (i = 0; i < modems->len; i++) - g_free ((char *) g_ptr_array_index (modems, i)); - g_ptr_array_free (modems, TRUE); - } - g_object_unref (proxy); -} - -static gboolean -poke_modem_cb (gpointer user_data) -{ - NMModemManager *self = NM_MODEM_MANAGER (user_data); - DBusGConnection *g_connection; - DBusGProxy *proxy; - - g_connection = nm_dbus_manager_get_connection (self->priv->dbus_mgr); - proxy = dbus_g_proxy_new_for_name (g_connection, - MM_OLD_DBUS_SERVICE, - MM_OLD_DBUS_PATH, - MM_OLD_DBUS_INTERFACE); - - nm_log_dbg (LOGD_MB, "Requesting to (re)launch modem-manager..."); - - dbus_g_proxy_begin_call_with_timeout (proxy, - "EnumerateDevices", - mm_poke_cb, - NULL, - NULL, - 5000, - G_TYPE_INVALID); - return TRUE; -} - -static void -enumerate_devices_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer data) -{ - NMModemManager *manager = NM_MODEM_MANAGER (data); - GPtrArray *modems; - GError *error = NULL; - - if (!dbus_g_proxy_end_call (proxy, call_id, &error, - dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &modems, - G_TYPE_INVALID)) { - nm_log_warn (LOGD_MB, "could not get modem list: %s", error->message); - g_error_free (error); - } else { - int i; - - for (i = 0; i < modems->len; i++) { - char *path = (char *) g_ptr_array_index (modems, i); - - create_modem (manager, path); - g_free (path); - } - - g_ptr_array_free (modems, TRUE); - } -} - -#if WITH_MODEM_MANAGER_1 -static void clear_modem_manager_1_support (NMModemManager *self); -#endif - -static void -modem_manager_appeared (NMModemManager *self, gboolean enumerate_devices) -{ - if (self->priv->poke_id) { - g_source_remove (self->priv->poke_id); - self->priv->poke_id = 0; - } - - nm_log_info (LOGD_MB, "modem-manager is now available"); - -#if WITH_MODEM_MANAGER_1 - self->priv->old_modem_manager_found = TRUE; - if (self->priv->new_modem_manager_found) - nm_log_warn (LOGD_MB, "Both the old and the new ModemManager were found"); - else - clear_modem_manager_1_support (self); -#endif - - self->priv->proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (self->priv->dbus_mgr), - MM_OLD_DBUS_SERVICE, MM_OLD_DBUS_PATH, MM_OLD_DBUS_INTERFACE); - - dbus_g_proxy_add_signal (self->priv->proxy, "DeviceAdded", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (self->priv->proxy, "DeviceAdded", - G_CALLBACK (modem_added), self, - NULL); - - dbus_g_proxy_add_signal (self->priv->proxy, "DeviceRemoved", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (self->priv->proxy, "DeviceRemoved", - G_CALLBACK (modem_removed), self, - NULL); - - if (enumerate_devices) - dbus_g_proxy_begin_call (self->priv->proxy, "EnumerateDevices", enumerate_devices_done, self, NULL, G_TYPE_INVALID); -} - -static gboolean -remove_one_modem (gpointer key, gpointer value, gpointer user_data) -{ - nm_modem_emit_removed (NM_MODEM (value)); - return TRUE; -} - -static void -modem_manager_disappeared (NMModemManager *self) -{ - g_hash_table_foreach_remove (self->priv->modems, remove_one_modem, self); - - if (self->priv->proxy) { - g_object_unref (self->priv->proxy); - self->priv->proxy = NULL; - } - - /* Try to activate the modem-manager */ - nm_log_dbg (LOGD_MB, "trying to start the modem manager..."); - poke_modem_cb (self); - self->priv->poke_id = g_timeout_add_seconds (MODEM_POKE_INTERVAL, poke_modem_cb, self); -} - -static void -nm_modem_manager_name_owner_changed (NMDBusManager *dbus_mgr, - const char *name, - const char *old_owner, - const char *new_owner, - gpointer user_data) -{ - gboolean old_owner_good; - gboolean new_owner_good; - - /* Can't handle the signal if its not from the modem service */ - if (strcmp (MM_OLD_DBUS_SERVICE, name) != 0) - return; - - old_owner_good = (old_owner && strlen (old_owner)); - new_owner_good = (new_owner && strlen (new_owner)); - - if (!old_owner_good && new_owner_good) { - modem_manager_appeared (NM_MODEM_MANAGER (user_data), FALSE); - } else if (old_owner_good && !new_owner_good) { - nm_log_info (LOGD_MB, "the modem manager disappeared"); - modem_manager_disappeared (NM_MODEM_MANAGER (user_data)); - } -} - -/************************************************************************/ -/* Support for ModemManager >= 0.7 */ - -#if WITH_MODEM_MANAGER_1 - -static void -modem_manager_1_clear_signals (NMModemManager *self) -{ - if (!self->priv->modem_manager_1) - return; - - if (self->priv->modem_manager_1_name_owner_changed_id) { - if (g_signal_handler_is_connected (self->priv->modem_manager_1, - self->priv->modem_manager_1_name_owner_changed_id)) - g_signal_handler_disconnect (self->priv->modem_manager_1, - self->priv->modem_manager_1_name_owner_changed_id); - self->priv->modem_manager_1_name_owner_changed_id = 0; - } - - if (self->priv->modem_manager_1_object_added_id) { - if (g_signal_handler_is_connected (self->priv->modem_manager_1, - self->priv->modem_manager_1_object_added_id)) - g_signal_handler_disconnect (self->priv->modem_manager_1, - self->priv->modem_manager_1_object_added_id); - self->priv->modem_manager_1_object_added_id = 0; - } - - if (self->priv->modem_manager_1_object_removed_id) { - if (g_signal_handler_is_connected (self->priv->modem_manager_1, - self->priv->modem_manager_1_object_removed_id)) - g_signal_handler_disconnect (self->priv->modem_manager_1, - self->priv->modem_manager_1_object_removed_id); - self->priv->modem_manager_1_object_removed_id = 0; - } -} - -static void -clear_modem_manager_1_support (NMModemManager *self) -{ - if (self->priv->modem_manager_1_launch_id) { - g_source_remove (self->priv->modem_manager_1_launch_id); - self->priv->modem_manager_1_launch_id = 0; - } - - modem_manager_1_clear_signals (self); - g_clear_object (&self->priv->modem_manager_1); - g_clear_object (&self->priv->dbus_connection); -} - -static void -modem_object_added (MMManager *modem_manager, - MMObject *modem_object, - NMModemManager *self) -{ - const gchar *path; - gchar *drivers; - MMModem *modem_iface; - NMModem *modem; - - /* Ensure we don't have the same modem already */ - path = mm_object_get_path (modem_object); - if (g_hash_table_lookup (self->priv->modems, path)) { - nm_log_warn (LOGD_MB, "modem with path %s already exists, ignoring", path); - return; - } - - /* Ensure we have the 'Modem' interface at least */ - modem_iface = mm_object_peek_modem (modem_object); - if (!modem_iface) { - nm_log_warn (LOGD_MB, "modem with path %s doesn't have the Modem interface, ignoring", path); - return; - } - - /* Ensure we have a primary port reported */ - if (!mm_modem_get_primary_port (modem_iface)) { - nm_log_warn (LOGD_MB, "modem with path %s has unknown primary port, ignoring", path); - return; - } - - /* Create a new modem object */ - modem = nm_modem_broadband_new (G_OBJECT (modem_object)); - if (!modem) - return; - - /* Build a single string with all drivers listed */ - drivers = g_strjoinv (", ", (gchar **)mm_modem_get_drivers (modem_iface)); - - /* Keep track of the new modem and notify about it */ - g_hash_table_insert (self->priv->modems, g_strdup (path), modem); - g_signal_emit (self, signals[MODEM_ADDED], 0, modem, drivers); - g_free (drivers); -} - -static void -modem_object_removed (MMManager *manager, - MMObject *modem_object, - NMModemManager *self) -{ - NMModem *modem; - const gchar *path; - - path = mm_object_get_path (modem_object); - modem = (NMModem *) g_hash_table_lookup (self->priv->modems, path); - if (!modem) - return; - - nm_modem_emit_removed (modem); - g_hash_table_remove (self->priv->modems, path); -} - -static void -modem_manager_1_available (NMModemManager *self) -{ - GList *modems, *l; - - nm_log_info (LOGD_MB, "ModemManager available in the bus"); - - self->priv->new_modem_manager_found = TRUE; - if (self->priv->old_modem_manager_found) - nm_log_warn (LOGD_MB, "Both the old and the new ModemManager were found"); - else - clear_modem_manager_support (self); - - /* Update initial modems list */ - modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->priv->modem_manager_1)); - for (l = modems; l; l = g_list_next (l)) - modem_object_added (self->priv->modem_manager_1, MM_OBJECT (l->data), self); - g_list_free_full (modems, (GDestroyNotify) g_object_unref); -} - -static void schedule_modem_manager_1_relaunch (NMModemManager *self, - guint n_seconds); -static void ensure_client (NMModemManager *self); - -static void -modem_manager_1_name_owner_changed (MMManager *modem_manager_1, - GParamSpec *pspec, - NMModemManager *self) -{ - gchar *name_owner; - - /* Quit poking, if any */ - if (self->priv->modem_manager_1_launch_id) { - g_source_remove (self->priv->modem_manager_1_launch_id); - self->priv->modem_manager_1_launch_id = 0; - } - - name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (modem_manager_1)); - if (!name_owner) { - nm_log_info (LOGD_MB, "ModemManager disappeared from bus"); - -#if !HAVE_SYSTEMD - /* If not managed by systemd, schedule relaunch */ - schedule_modem_manager_1_relaunch (self, 0); -#endif - - return; - } - - /* Available! */ - g_free (name_owner); - - /* Hack alert: GDBusObjectManagerClient won't signal neither 'object-added' - * nor 'object-removed' if it was created while there was no ModemManager in - * the bus. This hack avoids this issue until we get a GIO with the fix - * included... */ - modem_manager_1_clear_signals (self); - g_clear_object (&self->priv->modem_manager_1); - ensure_client (self); - - /* Whenever GDBusObjectManagerClient is fixed, we can just do the following: - * modem_manager_1_available (self); - */ -} - -#if !HAVE_SYSTEMD - -static void -modem_manager_1_poke_cb (GDBusConnection *connection, - GAsyncResult *res, - NMModemManager *self) -{ - GError *error = NULL; - GVariant *result; - - result = g_dbus_connection_call_finish (connection, res, &error); - if (error) { - /* Ignore common errors when MM is not installed and such */ - if ( !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN) - && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_EXEC_FAILED) - && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FORK_FAILED) - && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FAILED) - && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_TIMEOUT) - && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) { - nm_log_dbg (LOGD_MB, "error poking ModemManager: %s", error->message); - } - g_error_free (error); - - /* Setup timeout to relaunch */ - schedule_modem_manager_1_relaunch (self, MODEM_POKE_INTERVAL); - } else - g_variant_unref (result); - - /* Balance refcount */ - g_object_unref (self); -} - -static void -modem_manager_1_poke (NMModemManager *self) -{ - /* If there is no current owner right away, ensure we poke to get one */ - g_dbus_connection_call (self->priv->dbus_connection, - "org.freedesktop.ModemManager1", - "/org/freedesktop/ModemManager1", - "org.freedesktop.DBus.Peer", - "Ping", - NULL, /* inputs */ - NULL, /* outputs */ - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, /* cancellable */ - (GAsyncReadyCallback)modem_manager_1_poke_cb, /* callback */ - g_object_ref (self)); /* user_data */ -} - -#endif /* HAVE_SYSTEMD */ - -static void -modem_manager_1_check_name_owner (NMModemManager *self) -{ - gchar *name_owner; - - name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (self->priv->modem_manager_1)); - if (name_owner) { - /* Available! */ - modem_manager_1_available (self); - g_free (name_owner); - return; - } - -#if !HAVE_SYSTEMD - /* If the lifecycle is not managed by systemd, poke */ - modem_manager_1_poke (self); -#endif -} - -static void -manager_new_ready (GObject *source, - GAsyncResult *res, - NMModemManager *self) -{ - /* Note we always get an extra reference to self here */ - - GError *error = NULL; - - g_assert (!self->priv->modem_manager_1); - self->priv->modem_manager_1 = mm_manager_new_finish (res, &error); - if (!self->priv->modem_manager_1) { - /* We're not really supposed to get any error here. If we do get one, - * though, just re-schedule the MMManager creation after some time. - * During this period, name-owner changes won't be followed. */ - nm_log_warn (LOGD_MB, "error creating ModemManager client: %s", error->message); - g_error_free (error); - /* Setup timeout to relaunch */ - schedule_modem_manager_1_relaunch (self, MODEM_POKE_INTERVAL); - } else if (self->priv->old_modem_manager_found) { - /* If we found the old MM, abort */ - clear_modem_manager_1_support (self); - } else { - /* Setup signals in the GDBusObjectManagerClient */ - self->priv->modem_manager_1_name_owner_changed_id = - g_signal_connect (self->priv->modem_manager_1, - "notify::name-owner", - G_CALLBACK (modem_manager_1_name_owner_changed), - self); - self->priv->modem_manager_1_object_added_id = - g_signal_connect (self->priv->modem_manager_1, - "object-added", - G_CALLBACK (modem_object_added), - self); - self->priv->modem_manager_1_object_removed_id = - g_signal_connect (self->priv->modem_manager_1, - "object-removed", - G_CALLBACK (modem_object_removed), - self); - - modem_manager_1_check_name_owner (self); - } - - /* Balance refcount */ - g_object_unref (self); -} - -static void -ensure_client (NMModemManager *self) -{ - g_assert (self->priv->dbus_connection); - - /* Create the GDBusObjectManagerClient. We do not request to autostart, as - * we don't really want the MMManager creation to fail. We can always poke - * later on if we want to request the autostart */ - if (!self->priv->modem_manager_1) { - mm_manager_new (self->priv->dbus_connection, - G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, - NULL, - (GAsyncReadyCallback)manager_new_ready, - g_object_ref (self)); - return; - } - - /* If already available, recheck name owner! */ - modem_manager_1_check_name_owner (self); -} - -static void -bus_get_ready (GObject *source, - GAsyncResult *res, - NMModemManager *self) -{ - /* Note we always get an extra reference to self here */ - - GError *error = NULL; - - self->priv->dbus_connection = g_bus_get_finish (res, &error); - if (!self->priv->dbus_connection) { - nm_log_warn (LOGD_CORE, "error getting bus connection: %s", error->message); - g_error_free (error); - /* Setup timeout to relaunch */ - schedule_modem_manager_1_relaunch (self, MODEM_POKE_INTERVAL); - } else if (self->priv->old_modem_manager_found) { - /* If we found the old MM, abort */ - clear_modem_manager_1_support (self); - } else { - /* Got the bus, ensure client */ - ensure_client (self); - } - - /* Balance refcount */ - g_object_unref (self); -} - -static gboolean -ensure_bus (NMModemManager *self) -{ - /* Clear launch ID */ - self->priv->modem_manager_1_launch_id = 0; - - if (!self->priv->dbus_connection) - g_bus_get (G_BUS_TYPE_SYSTEM, - NULL, - (GAsyncReadyCallback)bus_get_ready, - g_object_ref (self)); - else - /* If bus is already available, ensure client */ - ensure_client (self); - - return FALSE; -} - -static void -schedule_modem_manager_1_relaunch (NMModemManager *self, - guint n_seconds) -{ - /* No need to pass an extra reference to self; timeout/idle will be - * cancelled if the object gets disposed. */ - - if (n_seconds) - self->priv->modem_manager_1_launch_id = g_timeout_add_seconds (n_seconds, (GSourceFunc)ensure_bus, self); - else - self->priv->modem_manager_1_launch_id = g_idle_add ((GSourceFunc)ensure_bus, self); -} - -#endif /* WITH_MODEM_MANAGER_1 */ - -/************************************************************************/ - -static void -nm_modem_manager_init (NMModemManager *self) -{ - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_MODEM_MANAGER, NMModemManagerPrivate); - - self->priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - - /* ModemManager < 0.7 */ - self->priv->dbus_mgr = nm_dbus_manager_get (); - g_signal_connect (self->priv->dbus_mgr, NM_DBUS_MANAGER_NAME_OWNER_CHANGED, - G_CALLBACK (nm_modem_manager_name_owner_changed), - self); - if (nm_dbus_manager_name_has_owner (self->priv->dbus_mgr, MM_OLD_DBUS_SERVICE)) - modem_manager_appeared (self, TRUE); - else - modem_manager_disappeared (self); - -#if WITH_MODEM_MANAGER_1 - /* ModemManager >= 0.7 */ - schedule_modem_manager_1_relaunch (self, 0); -#endif -} - -static void -dispose (GObject *object) -{ - NMModemManager *self = NM_MODEM_MANAGER (object); - - /* ModemManager < 0.7 */ - clear_modem_manager_support (self); - -#if WITH_MODEM_MANAGER_1 - /* ModemManager >= 0.7 */ - clear_modem_manager_1_support (self); -#endif - - if (self->priv->modems) { - g_hash_table_foreach_remove (self->priv->modems, remove_one_modem, object); - g_hash_table_destroy (self->priv->modems); - } - - self->priv->dbus_mgr = NULL; - - /* Chain up to the parent class */ - G_OBJECT_CLASS (nm_modem_manager_parent_class)->dispose (object); -} - -static void -nm_modem_manager_class_init (NMModemManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (object_class, sizeof (NMModemManagerPrivate)); - - object_class->dispose = dispose; - - /* signals */ - signals[MODEM_ADDED] = - g_signal_new ("modem-added", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMModemManagerClass, modem_added), - NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_STRING); -} diff --git a/src/modem-manager/nm-modem-manager.h b/src/modem-manager/nm-modem-manager.h deleted file mode 100644 index 0c2b243b91..0000000000 --- a/src/modem-manager/nm-modem-manager.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- 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. - * Copyright (C) 2009 Novell, Inc. - * Copyright (C) 2009 Canonical Ltd. - */ - -#ifndef NM_MODEM_MANAGER_H -#define NM_MODEM_MANAGER_H - -#include -#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)) -#define NM_MODEM_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_MODEM_MANAGER, NMModemManagerClass)) -#define NM_IS_MODEM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_MANAGER)) -#define NM_IS_MODEM_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_MODEM_MANAGER)) -#define NM_MODEM_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MODEM_MANAGER, NMModemManagerClass)) - -typedef struct _NMModemManager NMModemManager; -typedef struct _NMModemManagerClass NMModemManagerClass; -typedef struct _NMModemManagerPrivate NMModemManagerPrivate; - -struct _NMModemManager { - GObject parent; - NMModemManagerPrivate *priv; -}; - -struct _NMModemManagerClass { - GObjectClass parent; - - /* Signals */ - void (*modem_added) (NMModemManager *manager, NMModem *modem, const char *driver); - - void (*modem_removed) (NMModemManager *manager, NMModem *modem); -}; - -GType nm_modem_manager_get_type (void); - -NMModemManager *nm_modem_manager_get (void); - -#endif /* NM_MODEM_MANAGER_H */ diff --git a/src/modem-manager/nm-modem-old-types.h b/src/modem-manager/nm-modem-old-types.h deleted file mode 100644 index 976605db2b..0000000000 --- a/src/modem-manager/nm-modem-old-types.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- 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 Novell, Inc. - */ - -#ifndef NM_MODEM_OLD_TYPES_H -#define NM_MODEM_OLD_TYPES_H - -#define MM_OLD_DBUS_SERVICE "org.freedesktop.ModemManager" -#define MM_OLD_DBUS_PATH "/org/freedesktop/ModemManager" -#define MM_OLD_DBUS_INTERFACE "org.freedesktop.ModemManager" -#define MM_OLD_DBUS_INTERFACE_MODEM "org.freedesktop.ModemManager.Modem" -#define MM_OLD_DBUS_INTERFACE_MODEM_SIMPLE "org.freedesktop.ModemManager.Modem.Simple" -#define MM_OLD_DBUS_INTERFACE_MODEM_CDMA "org.freedesktop.ModemManager.Modem.Cdma" -#define MM_OLD_DBUS_INTERFACE_MODEM_GSM_CARD "org.freedesktop.ModemManager.Modem.Gsm.Card" -#define MM_OLD_DBUS_INTERFACE_MODEM_GSM_NETWORK "org.freedesktop.ModemManager.Modem.Gsm.Network" - -#define MM_OLD_MODEM_TYPE_UNKNOWN 0 -#define MM_OLD_MODEM_TYPE_GSM 1 -#define MM_OLD_MODEM_TYPE_CDMA 2 - -/* Errors */ - -#define MM_OLD_MODEM_CONNECT_ERROR_NO_CARRIER MM_OLD_DBUS_INTERFACE_MODEM ".NoCarrier" -#define MM_OLD_MODEM_CONNECT_ERROR_NO_DIALTONE MM_OLD_DBUS_INTERFACE_MODEM ".NoDialtone" -#define MM_OLD_MODEM_CONNECT_ERROR_BUSY MM_OLD_DBUS_INTERFACE_MODEM ".Busy" -#define MM_OLD_MODEM_CONNECT_ERROR_NO_ANSWER MM_OLD_DBUS_INTERFACE_MODEM ".NoAnswer" - -#define MM_OLD_MODEM_ERROR "org.freedesktop.ModemManager.Modem.Gsm" - -#define MM_OLD_MODEM_ERROR_NETWORK_NOT_ALLOWED MM_OLD_MODEM_ERROR ".NetworkNotAllowed" -#define MM_OLD_MODEM_ERROR_NETWORK_TIMEOUT MM_OLD_MODEM_ERROR ".NetworkTimeout" -#define MM_OLD_MODEM_ERROR_NO_NETWORK MM_OLD_MODEM_ERROR ".NoNetwork" -#define MM_OLD_MODEM_ERROR_SIM_NOT_INSERTED MM_OLD_MODEM_ERROR ".SimNotInserted" -#define MM_OLD_MODEM_ERROR_SIM_PIN MM_OLD_MODEM_ERROR ".SimPinRequired" -#define MM_OLD_MODEM_ERROR_SIM_PUK MM_OLD_MODEM_ERROR ".SimPukRequired" -#define MM_OLD_MODEM_ERROR_SIM_WRONG MM_OLD_MODEM_ERROR ".SimWrong" - -typedef enum { - MM_OLD_MODEM_STATE_UNKNOWN = 0, - MM_OLD_MODEM_STATE_DISABLED = 10, - MM_OLD_MODEM_STATE_DISABLING = 20, - MM_OLD_MODEM_STATE_ENABLING = 30, - MM_OLD_MODEM_STATE_ENABLED = 40, - MM_OLD_MODEM_STATE_SEARCHING = 50, - MM_OLD_MODEM_STATE_REGISTERED = 60, - MM_OLD_MODEM_STATE_DISCONNECTING = 70, - MM_OLD_MODEM_STATE_CONNECTING = 80, - MM_OLD_MODEM_STATE_CONNECTED = 90, - - MM_OLD_MODEM_STATE_LAST = MM_OLD_MODEM_STATE_CONNECTED -} MMOldModemState; - -#endif /* NM_MODEM_OLD_TYPES_H */ diff --git a/src/modem-manager/nm-modem-old.c b/src/modem-manager/nm-modem-old.c deleted file mode 100644 index f8bbcebb85..0000000000 --- a/src/modem-manager/nm-modem-old.c +++ /dev/null @@ -1,1141 +0,0 @@ -/* -*- 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 - 2013 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - */ - -#include -#include - -#include "nm-modem-old.h" -#include "nm-dbus-manager.h" -#include "nm-setting-connection.h" -#include "nm-properties-changed-signal.h" -#include "nm-modem-old-types.h" -#include "nm-logging.h" -#include "NetworkManagerUtils.h" -#include "nm-device-private.h" -#include "nm-dbus-glib-types.h" -#include "nm-glib-compat.h" - -G_DEFINE_TYPE (NMModemOld, nm_modem_old, NM_TYPE_MODEM) - -#define NM_MODEM_OLD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM_OLD, NMModemOldPrivate)) - -typedef struct { - DBusGProxy *proxy; - DBusGProxy *props_proxy; - - MMOldModemState state; - NMDeviceModemCapabilities caps; - - DBusGProxyCall *call; - GHashTable *connect_properties; - - guint32 pin_tries; - guint enable_delay_id; -} NMModemOldPrivate; - -#define CAPS_3GPP (NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS | NM_DEVICE_MODEM_CAPABILITY_LTE) - -/*****************************************************************************/ - -typedef enum { - MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_ANY = 0, - MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_GPRS, - MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_EDGE, - MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_UMTS, - MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_HSDPA, - MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_2G_PREFERRED, - MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_3G_PREFERRED, - MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_2G_ONLY, - MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_3G_ONLY, - MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_HSUPA, - MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_HSPA, - - MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_LAST = MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_HSPA -} MMModemDeprecatedMode; - -typedef enum { - MM_MODEM_GSM_ALLOWED_MODE_ANY = 0, - MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED = 1, - MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED = 2, - MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY = 3, - MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY = 4, - MM_MODEM_GSM_ALLOWED_MODE_4G_PREFERRED = 5, - MM_MODEM_GSM_ALLOWED_MODE_4G_ONLY = 6, - - MM_MODEM_GSM_ALLOWED_MODE_LAST = MM_MODEM_GSM_ALLOWED_MODE_4G_ONLY -} MMModemGsmAllowedMode; - -typedef enum { - MM_MODEM_GSM_ALLOWED_AUTH_UNKNOWN = 0x0000, - /* bits 0..4 order match Ericsson device bitmap */ - MM_MODEM_GSM_ALLOWED_AUTH_NONE = 0x0001, - MM_MODEM_GSM_ALLOWED_AUTH_PAP = 0x0002, - MM_MODEM_GSM_ALLOWED_AUTH_CHAP = 0x0004, - MM_MODEM_GSM_ALLOWED_AUTH_MSCHAP = 0x0008, - MM_MODEM_GSM_ALLOWED_AUTH_MSCHAPV2 = 0x0010, - MM_MODEM_GSM_ALLOWED_AUTH_EAP = 0x0020, - - MM_MODEM_GSM_ALLOWED_AUTH_LAST = MM_MODEM_GSM_ALLOWED_AUTH_EAP -} MMModemGsmAllowedAuth; - -static NMDeviceStateReason -translate_mm_error (GError *error) -{ - NMDeviceStateReason reason; - - if (dbus_g_error_has_name (error, MM_OLD_MODEM_CONNECT_ERROR_NO_CARRIER)) - reason = NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER; - else if (dbus_g_error_has_name (error, MM_OLD_MODEM_CONNECT_ERROR_NO_DIALTONE)) - reason = NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE; - else if (dbus_g_error_has_name (error, MM_OLD_MODEM_CONNECT_ERROR_BUSY)) - reason = NM_DEVICE_STATE_REASON_MODEM_BUSY; - else if (dbus_g_error_has_name (error, MM_OLD_MODEM_CONNECT_ERROR_NO_ANSWER)) - reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT; - else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_NETWORK_NOT_ALLOWED)) - reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED; - else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_NETWORK_TIMEOUT)) - reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT; - else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_NO_NETWORK)) - reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING; - else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_SIM_NOT_INSERTED)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED; - else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_SIM_PIN)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED; - else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_SIM_PUK)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED; - else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_SIM_WRONG)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_WRONG; - else { - /* unable to map the ModemManager error to a NM_DEVICE_STATE_REASON */ - nm_log_dbg (LOGD_MB, "unmapped dbus error detected: '%s'", dbus_g_error_get_name (error)); - reason = NM_DEVICE_STATE_REASON_UNKNOWN; - } - - /* FIXME: We have only GSM error messages here, and we have no idea which - activation state failed. Reasons like: - NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED, - NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED, - NM_DEVICE_STATE_REASON_GSM_APN_FAILED, - NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED, - NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED - are not used. - */ - return reason; -} - -/*****************************************************************************/ - -DBusGProxy * -nm_modem_old_get_proxy (NMModemOld *self, const char *interface) -{ - - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); - const char *current_iface; - - g_return_val_if_fail (NM_IS_MODEM_OLD (self), NULL); - - /* Default to the default interface. */ - if (interface == NULL) - interface = MM_OLD_DBUS_INTERFACE_MODEM; - - if (interface && !strcmp (interface, DBUS_INTERFACE_PROPERTIES)) - return priv->props_proxy; - - current_iface = dbus_g_proxy_get_interface (priv->proxy); - if (!current_iface || strcmp (current_iface, interface)) - dbus_g_proxy_set_interface (priv->proxy, interface); - - return priv->proxy; -} - -/*****************************************************************************/ -/* Query/Update enabled state */ - -static void -update_mm_enabled (NMModem *self, - gboolean new_enabled) -{ - if (nm_modem_get_mm_enabled (self) != new_enabled) { - g_object_set (self, - NM_MODEM_ENABLED, new_enabled, - NULL); - } -} - -static void -get_mm_enabled_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) -{ - NMModem *self = NM_MODEM (user_data); - GError *error = NULL; - GValue value = G_VALUE_INIT; - - if (!dbus_g_proxy_end_call (proxy, call_id, &error, - G_TYPE_VALUE, &value, - G_TYPE_INVALID)) { - nm_log_warn (LOGD_MB, "failed get modem enabled state: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - return; - } - - if (G_VALUE_HOLDS_BOOLEAN (&value)) { - update_mm_enabled (self, g_value_get_boolean (&value)); - } else - nm_log_warn (LOGD_MB, "failed get modem enabled state: unexpected reply type"); - - g_value_unset (&value); -} - -static void -query_mm_enabled (NMModemOld *self) -{ - dbus_g_proxy_begin_call (NM_MODEM_OLD_GET_PRIVATE (self)->props_proxy, - "Get", get_mm_enabled_done, - self, NULL, - G_TYPE_STRING, MM_OLD_DBUS_INTERFACE_MODEM, - G_TYPE_STRING, "Enabled", - G_TYPE_INVALID); -} - -static void -set_mm_enabled_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) -{ - GError *error = NULL; - - if (!dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) { - nm_log_warn (LOGD_MB, "failed to enable/disable modem: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - } - - /* Update enabled/disabled state again */ - query_mm_enabled (NM_MODEM_OLD (user_data)); -} - -static void -set_mm_enabled (NMModem *self, gboolean enabled) -{ - /* 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 - * toggle rfkill status of the WWAN modem. - */ - dbus_g_proxy_begin_call (nm_modem_old_get_proxy (NM_MODEM_OLD (self), - MM_OLD_DBUS_INTERFACE_MODEM), - "Enable", set_mm_enabled_done, - self, NULL, - G_TYPE_BOOLEAN, enabled, - G_TYPE_INVALID); - /* If we are disabling the modem, stop saying that it's enabled. */ - if (!enabled) - update_mm_enabled (self, enabled); -} - -/*****************************************************************************/ - -static void -ask_for_pin (NMModemOld *self, gboolean always_ask) -{ - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); - guint32 tries = 0; - - g_return_if_fail (NM_IS_MODEM_OLD (self)); - - if (!always_ask) - tries = priv->pin_tries++; - - nm_modem_get_secrets (NM_MODEM (self), - NM_SETTING_GSM_SETTING_NAME, - (tries || always_ask) ? TRUE : FALSE, - NM_SETTING_GSM_PIN); -} - -static void -stage1_prepare_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) -{ - NMModemOld *self = NM_MODEM_OLD (user_data); - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); - GError *error = NULL; - gboolean asked = FALSE; - - 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 { - if (priv->caps & CAPS_3GPP) { - if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_SIM_PIN)) { - ask_for_pin (self, FALSE); - asked = TRUE; - } else if (dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_SIM_WRONG)) { - ask_for_pin (self, TRUE); - asked = TRUE; - } - } - - if (!asked) { - nm_log_warn (LOGD_MB, "Mobile connection failed: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (error)); - } - g_error_free (error); - } -} - -static void -do_connect (NMModemOld *self) -{ - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); - DBusGProxy *proxy; - - proxy = nm_modem_old_get_proxy (NM_MODEM_OLD (self), MM_OLD_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); - -/* do_enable() is used as a GSourceFunc, hence the gboolean return */ -static gboolean -do_enable (NMModemOld *self) -{ - DBusGProxy *proxy; - - g_return_val_if_fail (NM_IS_MODEM_OLD (self), FALSE); - - NM_MODEM_OLD_GET_PRIVATE (self)->enable_delay_id = 0; - proxy = nm_modem_old_get_proxy (NM_MODEM_OLD (self), MM_OLD_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); - return FALSE; -} - -static void -stage1_pin_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) -{ - NMModemOld *self = NM_MODEM_OLD (user_data); - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); - NMDeviceStateReason reason; - GError *error = NULL; - - if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) { - /* Success; try to enable the modem again. Wait a few seconds to ensure - * that ModemManager is ready for the enable right after the unlock. - */ - if (priv->enable_delay_id == 0) - priv->enable_delay_id = g_timeout_add_seconds (4, (GSourceFunc) do_enable, self); - } else { - nm_log_warn (LOGD_MB, "GSM PIN unlock failed: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - - /* try to translate the error reason */ - reason = translate_mm_error (error); - if (reason == NM_DEVICE_STATE_REASON_UNKNOWN) - reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED; - - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, reason); - g_error_free (error); - } -} - -static void -handle_enable_pin_required (NMModemOld *self) -{ - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); - const char *pin = NULL; - GValue *value; - DBusGProxy *proxy; - - g_assert (priv->caps & CAPS_3GPP); - - /* 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_old_get_proxy (NM_MODEM_OLD (self), MM_OLD_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) -{ - NMModemOld *self = NM_MODEM_OLD (user_data); - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); - NMDeviceStateReason reason; - GError *error = NULL; - - if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) - do_connect (self); - else { - if ((priv->caps & CAPS_3GPP) && dbus_g_error_has_name (error, MM_OLD_MODEM_ERROR_SIM_PIN)) - handle_enable_pin_required (self); - else { - nm_log_warn (LOGD_MB, "Modem enable failed: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - - /* try to translate the error reason */ - reason = translate_mm_error (error); - if (reason == NM_DEVICE_STATE_REASON_UNKNOWN) - reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED; - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, reason); - } - - g_error_free (error); - } -} - -static GHashTable * -create_connect_properties (NMConnection *connection) -{ - NMSettingCdma *s_cdma; - NMSettingGsm *s_gsm; - NMSettingPPP *s_ppp; - GHashTable *properties; - const char *str; - - properties = value_hash_create (); - - s_cdma = nm_connection_get_setting_cdma (connection); - if (s_cdma) { - str = nm_setting_cdma_get_number (s_cdma); - if (str) - value_hash_add_str (properties, "number", str); - return properties; - } - - s_gsm = nm_connection_get_setting_gsm (connection); - if (s_gsm) { - str = nm_setting_gsm_get_number (s_gsm); - if (str) - value_hash_add_str (properties, "number", str); - - str = nm_setting_gsm_get_apn (s_gsm); - if (str) - value_hash_add_str (properties, "apn", str); - - str = nm_setting_gsm_get_network_id (s_gsm); - if (str) - value_hash_add_str (properties, "network_id", str); - - str = nm_setting_gsm_get_pin (s_gsm); - if (str) - value_hash_add_str (properties, "pin", str); - - str = nm_setting_gsm_get_username (s_gsm); - if (str) - value_hash_add_str (properties, "username", str); - - str = nm_setting_gsm_get_password (s_gsm); - if (str) - value_hash_add_str (properties, "password", str); - -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - /* Add both old and new preferred modes */ - switch (nm_setting_gsm_get_network_type (s_gsm)) { - case NM_SETTING_GSM_NETWORK_TYPE_UMTS_HSPA: - value_hash_add_uint (properties, "network_mode", MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_3G_ONLY); - value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY); - break; - case NM_SETTING_GSM_NETWORK_TYPE_GPRS_EDGE: - value_hash_add_uint (properties, "network_mode", MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_2G_ONLY); - value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY); - break; - case NM_SETTING_GSM_NETWORK_TYPE_PREFER_UMTS_HSPA: - value_hash_add_uint (properties, "network_mode", MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_3G_PREFERRED); - value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED); - break; - case NM_SETTING_GSM_NETWORK_TYPE_PREFER_GPRS_EDGE: - value_hash_add_uint (properties, "network_mode", MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_2G_PREFERRED); - value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED); - break; - case NM_SETTING_GSM_NETWORK_TYPE_PREFER_4G: - /* deprecated modes not extended for 4G, so no need to set them here */ - value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_4G_PREFERRED); - break; - case NM_SETTING_GSM_NETWORK_TYPE_4G: - /* deprecated modes not extended for 4G, so no need to set them here */ - value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_4G_ONLY); - break; - default: - value_hash_add_uint (properties, "network_mode", MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_ANY); - value_hash_add_uint (properties, "allowed_mode", MM_MODEM_GSM_ALLOWED_MODE_ANY); - break; - } -G_GNUC_END_IGNORE_DEPRECATIONS - - /* Roaming */ - if (nm_setting_gsm_get_home_only (s_gsm)) - value_hash_add_bool (properties, "home_only", TRUE); - - /* For IpMethod == STATIC or DHCP */ - s_ppp = nm_connection_get_setting_ppp (connection); - if (s_ppp) { - guint32 auth = MM_MODEM_GSM_ALLOWED_AUTH_UNKNOWN; - - if (nm_setting_ppp_get_noauth (s_ppp)) - auth |= MM_MODEM_GSM_ALLOWED_AUTH_NONE; - if (!nm_setting_ppp_get_refuse_pap (s_ppp)) - auth |= MM_MODEM_GSM_ALLOWED_AUTH_PAP; - if (!nm_setting_ppp_get_refuse_chap (s_ppp)) - auth |= MM_MODEM_GSM_ALLOWED_AUTH_CHAP; - if (!nm_setting_ppp_get_refuse_mschap (s_ppp)) - auth |= MM_MODEM_GSM_ALLOWED_AUTH_MSCHAP; - if (!nm_setting_ppp_get_refuse_mschapv2 (s_ppp)) - auth |= MM_MODEM_GSM_ALLOWED_AUTH_MSCHAPV2; - if (!nm_setting_ppp_get_refuse_eap (s_ppp)) - auth |= MM_MODEM_GSM_ALLOWED_AUTH_EAP; - - if (auth != MM_MODEM_GSM_ALLOWED_AUTH_UNKNOWN) - value_hash_add_uint (properties, "allowed_auth", auth); - } - - return properties; - } - - g_hash_table_destroy (properties); - return NULL; -} - -static NMActStageReturn -act_stage1_prepare (NMModem *modem, - NMConnection *connection, - NMDeviceStateReason *reason) -{ - NMModemOld *self = NM_MODEM_OLD (modem); - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); - 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 (self); - else - do_enable (self); - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ -/* IP method static */ - -static char addr_to_string_buf[INET6_ADDRSTRLEN + 1]; - -static const char * -ip_address_to_string (guint32 numeric) -{ - guint32 temp_addr; - - memset (&addr_to_string_buf, '\0', sizeof (addr_to_string_buf)); - temp_addr = numeric; - - if (inet_ntop (AF_INET, &temp_addr, addr_to_string_buf, INET_ADDRSTRLEN)) { - return addr_to_string_buf; - } else { - nm_log_warn (LOGD_VPN, "error converting IP4 address 0x%X", - ntohl (temp_addr)); - return NULL; - } -} - -static void -static_stage3_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) -{ - NMModemOld *self = NM_MODEM_OLD (user_data); - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); - GValueArray *ret_array = NULL; - GError *error = NULL; - NMIP4Config *config = NULL; - - priv->call = NULL; - - /* Returned value array is (uuuu): [IP, DNS1, DNS2, DNS3], all in - * network byte order. - */ - if (dbus_g_proxy_end_call (proxy, call, &error, - G_TYPE_VALUE_ARRAY, &ret_array, - G_TYPE_INVALID)) { - NMPlatformIP4Address address; - int i; - - config = nm_ip4_config_new (); - memset (&address, 0, sizeof (address)); - - nm_log_info (LOGD_MB, "(%s): IPv4 static configuration:", - nm_modem_get_uid (NM_MODEM (self))); - - /* IP address */ - address.address = g_value_get_uint (g_value_array_get_nth (ret_array, 0)); - address.plen = 32; - address.source = NM_PLATFORM_SOURCE_WWAN; - nm_ip4_config_add_address (config, &address); - - nm_log_info (LOGD_MB, " address %s/%d", - ip_address_to_string (address.address), - address.plen); - - /* DNS servers */ - for (i = 1; i < ret_array->n_values; i++) { - GValue *value = g_value_array_get_nth (ret_array, i); - guint32 tmp = g_value_get_uint (value); - - if (tmp > 0) { - nm_ip4_config_add_nameserver (config, tmp); - nm_log_info (LOGD_MB, " DNS %s", ip_address_to_string (tmp)); - } - } - g_value_array_free (ret_array); - } - - g_signal_emit_by_name (self, NM_MODEM_IP4_CONFIG_RESULT, config, error); - g_clear_error (&error); -} - -static NMActStageReturn -static_stage3_ip4_config_start (NMModem *self, - NMActRequest *req, - NMDeviceStateReason *reason) -{ - NMModemOldPrivate *priv; - - g_return_val_if_fail (NM_IS_MODEM (self), 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_OLD_GET_PRIVATE (self); - - priv->call = dbus_g_proxy_begin_call (nm_modem_old_get_proxy (NM_MODEM_OLD (self), - MM_OLD_DBUS_INTERFACE_MODEM), - "GetIP4Config", static_stage3_done, - self, NULL, - G_TYPE_INVALID); - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ - -static void -disconnect_done (DBusGProxy *proxy, - DBusGProxyCall *call_id, - gpointer user_data) -{ - GError *error = NULL; - gboolean warn = GPOINTER_TO_UINT (user_data); - - if (!dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID) && warn) { - nm_log_info (LOGD_MB, "disconnect failed: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - } -} - -static void -disconnect (NMModem *self, - gboolean warn) -{ - dbus_g_proxy_begin_call (nm_modem_old_get_proxy (NM_MODEM_OLD (self), - MM_OLD_DBUS_INTERFACE_MODEM), - "Disconnect", - disconnect_done, - GUINT_TO_POINTER (warn), - NULL, - G_TYPE_INVALID); -} - -/*****************************************************************************/ - -static void -deactivate (NMModem *self, NMDevice *device) -{ - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); - - priv->pin_tries = 0; - - if (priv->call) { - dbus_g_proxy_cancel_call (priv->proxy, priv->call); - priv->call = NULL; - } - - if (priv->enable_delay_id) { - g_source_remove (priv->enable_delay_id); - priv->enable_delay_id = 0; - } - - /* Chain up parent */ - NM_MODEM_CLASS (nm_modem_old_parent_class)->deactivate (self, device); -} - -/*****************************************************************************/ - -static void -modem_properties_changed (DBusGProxy *proxy, - const char *interface, - GHashTable *props, - gpointer user_data) -{ - NMModemOld *self = NM_MODEM_OLD (user_data); - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (self); - GValue *value; - MMOldModemState new_state; - - if (strcmp (interface, MM_OLD_DBUS_INTERFACE_MODEM)) - return; - - value = g_hash_table_lookup (props, "Enabled"); - if (value && G_VALUE_HOLDS_BOOLEAN (value)) { - g_object_set (self, - NM_MODEM_ENABLED, g_value_get_boolean (value), - NULL); - } - - value = g_hash_table_lookup (props, "IpMethod"); - if (value && G_VALUE_HOLDS_UINT (value)) { - g_object_set (self, - NM_MODEM_IP_METHOD, g_value_get_uint (value), - NULL); - } - - value = g_hash_table_lookup (props, "State"); - if (value && G_VALUE_HOLDS_UINT (value)) { - new_state = g_value_get_uint (value); - if (new_state != priv->state) { - if (new_state == MM_OLD_MODEM_STATE_CONNECTED) - g_object_set (self, - NM_MODEM_CONNECTED, TRUE, - NULL); - else if (priv->state == MM_OLD_MODEM_STATE_CONNECTED) - g_object_set (self, - NM_MODEM_CONNECTED, FALSE, - NULL); - priv->state = new_state; - } - } -} - -/*****************************************************************************/ - -static gboolean -check_connection_compatible (NMModem *modem, - NMConnection *connection, - GError **error) -{ - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (modem); - NMSettingConnection *s_con; - gboolean valid_cdma = FALSE, valid_gsm = FALSE; - const char *ctype; - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - ctype = nm_setting_connection_get_connection_type (s_con); - g_assert (ctype); - - /* Check for valid CDMA first */ - if (strcmp (ctype, NM_SETTING_CDMA_SETTING_NAME) == 0) - valid_cdma = !!nm_connection_get_setting_cdma (connection); - - if (strcmp (ctype, NM_SETTING_GSM_SETTING_NAME) == 0) - valid_gsm = !!nm_connection_get_setting_gsm (connection); - - /* Validate CDMA */ - if (priv->caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO) { - if (valid_cdma) - return TRUE; - - /* If the modem is only CDMA and the connection is not CDMA, error */ - if ((priv->caps ^ NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO) == 0) { - g_set_error (error, NM_MODEM_ERROR, NM_MODEM_ERROR_CONNECTION_NOT_CDMA, - "The connection was not a CDMA connection."); - return FALSE; - } - } - - /* Validate 3GPP */ - if (priv->caps & CAPS_3GPP) { - if (valid_gsm) - return TRUE; - - g_set_error (error, NM_MODEM_ERROR, NM_MODEM_ERROR_CONNECTION_NOT_GSM, - "The connection was not a GSM/UMTS/LTE connection."); - return FALSE; - } - - g_set_error (error, NM_MODEM_ERROR, NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE, - "The connection was not not compatible with this modem (caps 0x%X)", - priv->caps); - return FALSE; -} - -/*****************************************************************************/ - -static void -complete_ppp_setting (NMConnection *connection) -{ - NMSettingPPP *s_ppp; - - s_ppp = nm_connection_get_setting_ppp (connection); - if (!s_ppp) { - s_ppp = (NMSettingPPP *) nm_setting_ppp_new (); - g_object_set (G_OBJECT (s_ppp), - NM_SETTING_PPP_LCP_ECHO_FAILURE, 5, - NM_SETTING_PPP_LCP_ECHO_INTERVAL, 30, - NULL); - nm_connection_add_setting (connection, NM_SETTING (s_ppp)); - } -} - -static gboolean -complete_connection_3gpp (NMConnection *connection, - const GSList *existing_connections, - GError **error) -{ - NMSettingGsm *s_gsm; - - s_gsm = nm_connection_get_setting_gsm (connection); - if (!s_gsm || !nm_setting_gsm_get_apn (s_gsm)) { - /* Need an APN at least */ - g_set_error_literal (error, - NM_SETTING_GSM_ERROR, - NM_SETTING_GSM_ERROR_MISSING_PROPERTY, - NM_SETTING_GSM_APN); - return FALSE; - } - - if (!nm_setting_gsm_get_number (s_gsm)) - g_object_set (G_OBJECT (s_gsm), NM_SETTING_GSM_NUMBER, "*99#", NULL); - - complete_ppp_setting (connection); - - nm_utils_complete_generic (connection, - NM_SETTING_GSM_SETTING_NAME, - existing_connections, - _("GSM connection %d"), - NULL, - FALSE); /* No IPv6 yet by default */ - return TRUE; -} - -static gboolean -complete_connection_cdma (NMConnection *connection, - const GSList *existing_connections, - GError **error) -{ - NMSettingCdma *s_cdma; - - s_cdma = nm_connection_get_setting_cdma (connection); - if (!s_cdma) { - s_cdma = (NMSettingCdma *) nm_setting_cdma_new (); - nm_connection_add_setting (connection, NM_SETTING (s_cdma)); - } - - if (!nm_setting_cdma_get_number (s_cdma)) - g_object_set (G_OBJECT (s_cdma), NM_SETTING_CDMA_NUMBER, "#777", NULL); - - complete_ppp_setting (connection); - - nm_utils_complete_generic (connection, - NM_SETTING_CDMA_SETTING_NAME, - existing_connections, - _("CDMA connection %d"), - NULL, - FALSE); /* No IPv6 yet by default */ - return TRUE; -} - -static gboolean -complete_connection (NMModem *modem, - NMConnection *connection, - const GSList *existing_connections, - GError **error) -{ - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (modem); - - /* If the modem has LTE, complete as 3GPP */ - if (priv->caps & NM_DEVICE_MODEM_CAPABILITY_LTE) - return complete_connection_3gpp (connection, existing_connections, error); - - /* Otherwise, prefer CDMA on the theory that if the modem has CDMA/EVDO - * that's most likely what the user will be using. - */ - if (priv->caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO) - return complete_connection_cdma (connection, existing_connections, error); - - if (priv->caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS) - return complete_connection_3gpp (connection, existing_connections, error); - - g_set_error_literal (error, NM_MODEM_ERROR, NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE, - "Modem had no WWAN capabilities."); - return FALSE; -} - -/*****************************************************************************/ - -static gboolean -get_user_pass (NMModem *modem, - NMConnection *connection, - const char **user, - const char **pass) -{ - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (modem); - NMSettingCdma *s_cdma; - NMSettingGsm *s_gsm; - - if (priv->caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO) { - s_cdma = nm_connection_get_setting_cdma (connection); - if (s_cdma) { - if (user) - *user = nm_setting_cdma_get_username (s_cdma); - if (pass) - *pass = nm_setting_cdma_get_password (s_cdma); - return TRUE; - } - } - - /* Fall back to GSM; will be used for CDMA devices on LTE networks too */ - s_gsm = nm_connection_get_setting_gsm (connection); - if (s_gsm) { - if (user) - *user = nm_setting_gsm_get_username (s_gsm); - if (pass) - *pass = nm_setting_gsm_get_password (s_gsm); - return TRUE; - } - - return FALSE; -} - -/*****************************************************************************/ - -static void -get_capabilities (NMModem *_self, - NMDeviceModemCapabilities *modem_caps, - NMDeviceModemCapabilities *current_caps) -{ - NMModemOld *self = NM_MODEM_OLD (_self); - - *current_caps = *modem_caps = NM_MODEM_OLD_GET_PRIVATE (self)->caps; -} - -/*****************************************************************************/ - -NMModem * -nm_modem_old_new (const char *path, GHashTable *properties, GError **error) -{ - NMDeviceModemCapabilities caps = NM_DEVICE_MODEM_CAPABILITY_NONE; - NMModemOld *self; - GHashTableIter iter; - const char *prop; - GValue *value; - const char *data_device = NULL; - const char *driver = NULL; - const char *master_device = NULL; - guint32 modem_type = MM_OLD_MODEM_TYPE_UNKNOWN; - guint32 ip_method = MM_MODEM_IP_METHOD_PPP; - guint32 ip_timeout = 0; - MMOldModemState state = MM_OLD_MODEM_STATE_UNKNOWN; - - g_return_val_if_fail (path != NULL, NULL); - g_return_val_if_fail (properties != NULL, NULL); - - g_hash_table_iter_init (&iter, properties); - while (g_hash_table_iter_next (&iter, (gpointer) &prop, (gpointer) &value)) { - if (g_strcmp0 (prop, "Type") == 0) - modem_type = g_value_get_uint (value); - else if (g_strcmp0 (prop, "MasterDevice") == 0) - master_device = g_value_get_string (value); - else if (g_strcmp0 (prop, "IpMethod") == 0) - ip_method = g_value_get_uint (value); - else if (g_strcmp0 (prop, "Device") == 0) - data_device = g_value_get_string (value); - else if (g_strcmp0 (prop, "Driver") == 0) - driver = g_value_get_string (value); - else if (g_strcmp0 (prop, "IpTimeout") == 0) - ip_timeout = g_value_get_uint (value); - else if (g_strcmp0 (prop, "State") == 0) - state = g_value_get_uint (value); - } - - if (modem_type == MM_OLD_MODEM_TYPE_UNKNOWN) { - g_set_error (error, NM_MODEM_ERROR, NM_MODEM_ERROR_INITIALIZATION_FAILED, - "Unhandled modem type %d", modem_type); - return NULL; - } - - if (!master_device || !strlen (master_device)) { - g_set_error_literal (error, NM_MODEM_ERROR, NM_MODEM_ERROR_INITIALIZATION_FAILED, - "Failed to retrieve modem master device."); - return NULL; - } - - if (!driver || !strlen (driver)) { - g_set_error_literal (error, NM_MODEM_ERROR, NM_MODEM_ERROR_INITIALIZATION_FAILED, - "Failed to retrieve modem driver."); - return NULL; - } - - if (!data_device || !strlen (data_device)) { - g_set_error_literal (error, NM_MODEM_ERROR, NM_MODEM_ERROR_INITIALIZATION_FAILED, - "Failed to retrieve modem data device."); - return NULL; - } - - self = (NMModemOld *) g_object_new (NM_TYPE_MODEM_OLD, - NM_MODEM_PATH, path, - NM_MODEM_DRIVER, driver, - NM_MODEM_UID, data_device, - NM_MODEM_CONTROL_PORT, NULL, - NM_MODEM_DATA_PORT, data_device, - NM_MODEM_IP_METHOD, ip_method, - NM_MODEM_IP_TIMEOUT, ip_timeout, - NM_MODEM_CONNECTED, (state == MM_OLD_MODEM_STATE_CONNECTED), - NULL); - if (self) { - if (modem_type == MM_OLD_MODEM_TYPE_CDMA) - caps |= NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO; - if (modem_type == MM_OLD_MODEM_TYPE_GSM) - caps |= NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS; - - NM_MODEM_OLD_GET_PRIVATE (self)->caps = caps; - } - - return (NMModem *) self; -} - -static void -nm_modem_old_init (NMModemOld *self) -{ -} - -static GObject* -constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) -{ - GObject *object; - NMModemOldPrivate *priv; - DBusGConnection *bus; - - object = G_OBJECT_CLASS (nm_modem_old_parent_class)->constructor (type, n_construct_params, construct_params); - if (!object) - return NULL; - - priv = NM_MODEM_OLD_GET_PRIVATE (object); - - bus = nm_dbus_manager_get_connection (nm_dbus_manager_get ()); - priv->proxy = dbus_g_proxy_new_for_name (bus, - MM_OLD_DBUS_SERVICE, - nm_modem_get_path (NM_MODEM (object)), - MM_OLD_DBUS_INTERFACE_MODEM); - - priv->props_proxy = dbus_g_proxy_new_for_name (bus, - MM_OLD_DBUS_SERVICE, - nm_modem_get_path (NM_MODEM (object)), - DBUS_INTERFACE_PROPERTIES); - dbus_g_object_register_marshaller (g_cclosure_marshal_generic, - G_TYPE_NONE, - G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT, - G_TYPE_INVALID); - dbus_g_proxy_add_signal (priv->props_proxy, "MmPropertiesChanged", - G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT, - G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->props_proxy, "MmPropertiesChanged", - G_CALLBACK (modem_properties_changed), - object, - NULL); - - query_mm_enabled (NM_MODEM_OLD (object)); - - return object; -} - -static void -dispose (GObject *object) -{ - NMModemOldPrivate *priv = NM_MODEM_OLD_GET_PRIVATE (object); - - if (priv->proxy) { - g_object_unref (priv->proxy); - priv->proxy = NULL; - } - - if (priv->props_proxy) { - g_object_unref (priv->props_proxy); - priv->props_proxy = NULL; - } - - if (priv->connect_properties) { - g_hash_table_destroy (priv->connect_properties); - priv->connect_properties = NULL; - } - - if (priv->enable_delay_id) { - g_source_remove (priv->enable_delay_id); - priv->enable_delay_id = 0; - } - - G_OBJECT_CLASS (nm_modem_old_parent_class)->dispose (object); -} - -static void -nm_modem_old_class_init (NMModemOldClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMModemClass *modem_class = NM_MODEM_CLASS (klass); - - g_type_class_add_private (object_class, sizeof (NMModemOldPrivate)); - - /* Virtual methods */ - object_class->constructor = constructor; - object_class->dispose = dispose; - - modem_class->get_capabilities = get_capabilities; - modem_class->get_user_pass = get_user_pass; - modem_class->complete_connection = complete_connection; - modem_class->check_connection_compatible = check_connection_compatible; - modem_class->act_stage1_prepare = act_stage1_prepare; - modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start; - modem_class->disconnect = disconnect; - modem_class->deactivate = deactivate; - modem_class->set_mm_enabled = set_mm_enabled; -} diff --git a/src/modem-manager/nm-modem-old.h b/src/modem-manager/nm-modem-old.h deleted file mode 100644 index 828da6a6d4..0000000000 --- a/src/modem-manager/nm-modem-old.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- 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 - 2011 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - */ - -#ifndef NM_MODEM_OLD_H -#define NM_MODEM_OLD_H - -#include -#include -#include "nm-modem.h" -#include "nm-modem-old-types.h" - -G_BEGIN_DECLS - -#define NM_TYPE_MODEM_OLD (nm_modem_old_get_type ()) -#define NM_MODEM_OLD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_OLD, NMModemOld)) -#define NM_MODEM_OLD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_MODEM_OLD, NMModemOldClass)) -#define NM_IS_MODEM_OLD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_OLD)) -#define NM_IS_MODEM_OLD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_MODEM_OLD)) -#define NM_MODEM_OLD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MODEM_OLD, NMModemOldClass)) - -typedef struct { - NMModem parent; -} NMModemOld; - -typedef struct { - NMModemClass parent; -} NMModemOldClass; - -GType nm_modem_old_get_type (void); - -NMModem *nm_modem_old_new (const char *path, GHashTable *properties, GError **error); - -/* Protected */ -DBusGProxy *nm_modem_old_get_proxy (NMModemOld *modem, const gchar *interface); - -G_END_DECLS - -#endif /* NM_MODEM_OLD_H */ diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c deleted file mode 100644 index 8327c1c5d9..0000000000 --- a/src/modem-manager/nm-modem.c +++ /dev/null @@ -1,1009 +0,0 @@ -/* -*- 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 - 2011 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - */ - -#include -#include "nm-modem.h" -#include "nm-platform.h" -#include "nm-dbus-manager.h" -#include "nm-setting-connection.h" -#include "nm-properties-changed-signal.h" -#include "nm-logging.h" -#include "NetworkManagerUtils.h" -#include "nm-device-private.h" -#include "nm-dbus-glib-types.h" -#include "nm-enum-types.h" - -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_CONTROL_PORT, - PROP_DATA_PORT, - PROP_PATH, - PROP_UID, - PROP_DRIVER, - PROP_IP_METHOD, - PROP_IP_TIMEOUT, - PROP_ENABLED, - PROP_CONNECTED, - - LAST_PROP -}; - -typedef struct { - char *uid; - char *path; - char *driver; - char *control_port; - char *data_port; - char *ppp_iface; - guint32 ip_method; - - NMPPPManager *ppp_manager; - - NMActRequest *act_request; - guint32 secrets_tries; - guint32 secrets_id; - - gboolean mm_enabled; - guint32 mm_ip_timeout; - gboolean mm_connected; - - /* PPP stats */ - guint32 in_bytes; - guint32 out_bytes; -} NMModemPrivate; - -enum { - PPP_STATS, - PPP_FAILED, - PREPARE_RESULT, - IP4_CONFIG_RESULT, - AUTH_REQUESTED, - AUTH_RESULT, - REMOVED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - - -/*****************************************************************************/ - -GQuark -nm_modem_error_quark (void) -{ - static GQuark quark = 0; - if (!quark) - quark = g_quark_from_static_string ("nm-modem-error"); - return quark; -} - -/*****************************************************************************/ -/* Get/Set enabled/connected */ - -gboolean -nm_modem_get_mm_enabled (NMModem *self) -{ - return NM_MODEM_GET_PRIVATE (self)->mm_enabled; -} - -void -nm_modem_set_mm_enabled (NMModem *self, - gboolean enabled) -{ - NMModemPrivate *priv; - - priv = NM_MODEM_GET_PRIVATE (self); - - if (priv->mm_enabled != enabled) - NM_MODEM_GET_CLASS (self)->set_mm_enabled (self, enabled); -} - -gboolean -nm_modem_get_mm_connected (NMModem *self) -{ - return NM_MODEM_GET_PRIVATE (self)->mm_connected; -} - -void -nm_modem_emit_removed (NMModem *self) -{ - g_signal_emit (self, signals[REMOVED], 0); -} - -/*****************************************************************************/ -/* IP method PPP */ - -static void -ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_data) -{ - switch (status) { - case NM_PPP_STATUS_DISCONNECT: - g_signal_emit (NM_MODEM (user_data), signals[PPP_FAILED], 0, NM_DEVICE_STATE_REASON_PPP_DISCONNECT); - break; - case NM_PPP_STATUS_DEAD: - g_signal_emit (NM_MODEM (user_data), signals[PPP_FAILED], 0, NM_DEVICE_STATE_REASON_PPP_FAILED); - break; - default: - break; - } -} - -static void -ppp_ip4_config (NMPPPManager *ppp_manager, - const char *iface, - NMIP4Config *config, - gpointer 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 */ - guint32 bad_dns2 = htonl (0x0A0B0C0E); - guint32 good_dns2 = htonl (0x04020202); /* GTE nameserver */ - gboolean dns_workaround = FALSE; - - /* Notify about the new data port to use */ - g_free (priv->ppp_iface); - priv->ppp_iface = g_strdup (iface); - g_object_notify (G_OBJECT (self), NM_MODEM_DATA_PORT); - - /* 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 - * not the case. - * - * http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=2e09ef6886bbf00bc5a9a641110f801e372ffde6 - * http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=f8191bf07df374f119a07910a79217c7618f113e - */ - - num = nm_ip4_config_get_num_nameservers (config); - if (num == 2) { - gboolean found1 = FALSE, found2 = FALSE; - - for (i = 0; i < num; i++) { - guint32 ns = nm_ip4_config_get_nameserver (config, i); - - if (ns == bad_dns1) - found1 = TRUE; - else if (ns == bad_dns2) - found2 = TRUE; - } - - /* Be somewhat conservative about substitutions; the "bad" nameservers - * could actually be valid in some cases, so only substitute if ppp - * returns *only* the two bad nameservers. - */ - dns_workaround = (found1 && found2); - } - - if (!num || dns_workaround) { - nm_log_warn (LOGD_PPP, "compensating for invalid PPP-provided nameservers"); - nm_ip4_config_reset_nameservers (config); - nm_ip4_config_add_nameserver (config, good_dns1); - nm_ip4_config_add_nameserver (config, good_dns2); - } - - g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, config, NULL); -} - -static void -ppp_stats (NMPPPManager *ppp_manager, - guint32 in_bytes, - guint32 out_bytes, - gpointer user_data) -{ - NMModem *self = NM_MODEM (user_data); - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - - if (priv->in_bytes != in_bytes || priv->out_bytes != out_bytes) { - priv->in_bytes = in_bytes; - priv->out_bytes = out_bytes; - - g_signal_emit (self, signals[PPP_STATS], 0, in_bytes, out_bytes); - } -} - -static NMActStageReturn -ppp_stage3_ip4_config_start (NMModem *self, - NMActRequest *req, - NMDeviceStateReason *reason) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - const char *ppp_name = NULL; - GError *error = NULL; - NMActStageReturn ret; - guint ip_timeout = 20; - - g_return_val_if_fail (NM_IS_MODEM (self), 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); - - if (NM_MODEM_GET_CLASS (self)->get_user_pass) { - NMConnection *connection = nm_act_request_get_connection (req); - - g_assert (connection); - if (!NM_MODEM_GET_CLASS (self)->get_user_pass (self, connection, &ppp_name, NULL)) - return NM_ACT_STAGE_RETURN_FAILURE; - } - - /* Check if ModemManager requested a specific IP timeout to be used. If 0 reported, - * use the default one (20s) */ - if (priv->mm_ip_timeout > 0) { - nm_log_info (LOGD_PPP, "using modem-specified IP timeout: %u seconds", - priv->mm_ip_timeout); - ip_timeout = priv->mm_ip_timeout; - } - - priv->ppp_manager = nm_ppp_manager_new (priv->data_port); - if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, ip_timeout, &error)) { - g_signal_connect (priv->ppp_manager, "state-changed", - G_CALLBACK (ppp_state_changed), - self); - g_signal_connect (priv->ppp_manager, "ip4-config", - G_CALLBACK (ppp_ip4_config), - self); - g_signal_connect (priv->ppp_manager, "stats", - G_CALLBACK (ppp_stats), - self); - - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else { - nm_log_err (LOGD_PPP, "error starting PPP: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_error_free (error); - - 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; -} - -/*****************************************************************************/ - -NMActStageReturn -nm_modem_stage3_ip4_config_start (NMModem *self, - NMDevice *device, - NMDeviceClass *device_class, - NMDeviceStateReason *reason) -{ - NMModemPrivate *priv; - NMActRequest *req; - NMActStageReturn ret; - - g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE); - g_return_val_if_fail (NM_IS_DEVICE (device), 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); - - priv = NM_MODEM_GET_PRIVATE (self); - switch (priv->ip_method) { - case MM_MODEM_IP_METHOD_PPP: - ret = ppp_stage3_ip4_config_start (self, req, reason); - break; - case MM_MODEM_IP_METHOD_STATIC: - ret = NM_MODEM_GET_CLASS (self)->static_stage3_ip4_config_start (self, req, reason); - break; - case MM_MODEM_IP_METHOD_DHCP: - ret = device_class->act_stage3_ip4_config_start (device, NULL, reason); - break; - default: - nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method); - ret = NM_ACT_STAGE_RETURN_FAILURE; - break; - } - - return ret; -} - -void -nm_modem_ip4_pre_commit (NMModem *modem, - NMDevice *device, - NMIP4Config *config) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (modem); - - /* If the modem has an ethernet-type data interface (ie, not PPP and thus - * not point-to-point) and IP config has a /32 prefix, then we assume that - * ARP will be pointless and we turn it off. - */ - if ( priv->ip_method == MM_MODEM_IP_METHOD_STATIC - || priv->ip_method == MM_MODEM_IP_METHOD_DHCP) { - const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, 0); - - g_assert (address); - if (address->plen == 32) - nm_platform_link_set_noarp (nm_device_get_ip_ifindex (device)); - } -} - -/*****************************************************************************/ - -NMActStageReturn -nm_modem_stage3_ip6_config_start (NMModem *self, - NMDevice *device, - NMDeviceClass *device_class, - NMDeviceStateReason *reason) -{ - /* FIXME: We don't support IPv6 on modems quite yet... */ - nm_device_activate_schedule_ip6_config_timeout (device); - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ - -static void -cancel_get_secrets (NMModem *self) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - - if (priv->secrets_id) { - nm_act_request_cancel_secrets (priv->act_request, priv->secrets_id); - priv->secrets_id = 0; - } -} - -static void -modem_secrets_cb (NMActRequest *req, - guint32 call_id, - NMConnection *connection, - GError *error, - gpointer user_data) -{ - NMModem *self = NM_MODEM (user_data); - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - - g_return_if_fail (call_id == priv->secrets_id); - - priv->secrets_id = 0; - - if (error) - nm_log_warn (LOGD_MB, "%s", error->message); - - g_signal_emit (self, signals[AUTH_RESULT], 0, error); -} - -gboolean -nm_modem_get_secrets (NMModem *self, - const char *setting_name, - gboolean request_new, - const char *hint) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - NMSettingsGetSecretsFlags flags = NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION; - - cancel_get_secrets (self); - - if (request_new) - flags |= NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW; - priv->secrets_id = nm_act_request_get_secrets (priv->act_request, - setting_name, - flags, - hint, - modem_secrets_cb, - self); - if (priv->secrets_id) - g_signal_emit (self, signals[AUTH_REQUESTED], 0); - - return !!(priv->secrets_id); -} - -/*****************************************************************************/ - -static NMActStageReturn -act_stage1_prepare (NMModem *modem, - NMConnection *connection, - 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; - NMSettingsGetSecretsFlags flags = NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION; - NMConnection *connection; - - if (priv->act_request) - g_object_unref (priv->act_request); - priv->act_request = g_object_ref (req); - - connection = nm_act_request_get_connection (req); - g_assert (connection); - - setting_name = nm_connection_need_secrets (connection, &hints); - if (!setting_name) { - /* Ready to connect */ - g_assert (!hints); - return NM_MODEM_GET_CLASS (self)->act_stage1_prepare (self, connection, reason); - } - - /* Secrets required... */ - if (priv->secrets_tries++) - flags |= NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW; - - priv->secrets_id = nm_act_request_get_secrets (req, - setting_name, - flags, - hints ? g_ptr_array_index (hints, 0) : NULL, - modem_secrets_cb, - self); - if (priv->secrets_id) { - g_signal_emit (self, signals[AUTH_REQUESTED], 0); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else { - *reason = NM_DEVICE_STATE_REASON_NO_SECRETS; - ret = NM_ACT_STAGE_RETURN_FAILURE; - } - - 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; -} - -/*****************************************************************************/ - -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; -} - -/*****************************************************************************/ - -gboolean -nm_modem_complete_connection (NMModem *self, - NMConnection *connection, - const GSList *existing_connections, - GError **error) -{ - if (NM_MODEM_GET_CLASS (self)->complete_connection) - return NM_MODEM_GET_CLASS (self)->complete_connection (self, connection, existing_connections, error); - return FALSE; -} - -/*****************************************************************************/ - -static void -deactivate (NMModem *self, NMDevice *device) -{ - NMModemPrivate *priv; - int ifindex; - - g_return_if_fail (NM_IS_MODEM (self)); - g_return_if_fail (NM_IS_DEVICE (device)); - - priv = NM_MODEM_GET_PRIVATE (self); - - priv->secrets_tries = 0; - - if (priv->act_request) { - cancel_get_secrets (self); - g_object_unref (priv->act_request); - priv->act_request = NULL; - } - - priv->in_bytes = priv->out_bytes = 0; - - if (priv->ppp_manager) { - g_object_unref (priv->ppp_manager); - priv->ppp_manager = NULL; - } - - switch (priv->ip_method) { - case MM_MODEM_IP_METHOD_PPP: - break; - case MM_MODEM_IP_METHOD_STATIC: - case MM_MODEM_IP_METHOD_DHCP: - ifindex = nm_device_get_ip_ifindex (device); - if (ifindex > 0) { - nm_platform_route_flush (ifindex); - nm_platform_address_flush (ifindex); - nm_platform_link_set_down (ifindex); - } - break; - default: - nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method); - break; - } - - g_free (priv->ppp_iface); - priv->ppp_iface = NULL; -} - -/*****************************************************************************/ - -void -nm_modem_deactivate (NMModem *self, NMDevice *device) -{ - NM_MODEM_GET_CLASS (self)->deactivate (self, device); -} - -/*****************************************************************************/ - -void -nm_modem_device_state_changed (NMModem *self, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - gboolean was_connected = FALSE, warn = TRUE; - NMModemPrivate *priv; - - g_return_if_fail (NM_IS_MODEM (self)); - - if (old_state >= NM_DEVICE_STATE_PREPARE && old_state <= NM_DEVICE_STATE_DEACTIVATING) - was_connected = TRUE; - - priv = NM_MODEM_GET_PRIVATE (self); - - /* Make sure we don't leave the serial device open */ - switch (new_state) { - case NM_DEVICE_STATE_UNMANAGED: - case NM_DEVICE_STATE_UNAVAILABLE: - case NM_DEVICE_STATE_DISCONNECTED: - case NM_DEVICE_STATE_FAILED: - if (priv->act_request) { - cancel_get_secrets (self); - g_object_unref (priv->act_request); - priv->act_request = NULL; - } - - if (was_connected) { - /* Don't bother warning on FAILED since the modem is already gone */ - if (new_state == NM_DEVICE_STATE_FAILED) - warn = FALSE; - NM_MODEM_GET_CLASS (self)->disconnect (self, warn); - } - break; - default: - break; - } -} - -/*****************************************************************************/ - -const char * -nm_modem_get_uid (NMModem *self) -{ - g_return_val_if_fail (NM_IS_MODEM (self), NULL); - - return NM_MODEM_GET_PRIVATE (self)->uid; -} - -const char * -nm_modem_get_path (NMModem *self) -{ - g_return_val_if_fail (NM_IS_MODEM (self), NULL); - - return NM_MODEM_GET_PRIVATE (self)->path; -} - -const char * -nm_modem_get_driver (NMModem *self) -{ - g_return_val_if_fail (NM_IS_MODEM (self), NULL); - - return NM_MODEM_GET_PRIVATE (self)->driver; -} - -const char * -nm_modem_get_control_port (NMModem *self) -{ - g_return_val_if_fail (NM_IS_MODEM (self), NULL); - - return NM_MODEM_GET_PRIVATE (self)->control_port; -} - -const char * -nm_modem_get_data_port (NMModem *self) -{ - g_return_val_if_fail (NM_IS_MODEM (self), NULL); - - /* The ppp_iface takes precedence over the data interface when PPP is used, - * since data_iface is the TTY over which PPP is run, and that TTY can't - * do IP. The caller really wants the thing that's doing IP. - */ - return NM_MODEM_GET_PRIVATE (self)->ppp_iface ? - NM_MODEM_GET_PRIVATE (self)->ppp_iface : NM_MODEM_GET_PRIVATE (self)->data_port; -} - -gboolean -nm_modem_owns_port (NMModem *self, const char *iface) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - - g_return_val_if_fail (iface != NULL, FALSE); - - if (NM_MODEM_GET_CLASS (self)->owns_port) - return NM_MODEM_GET_CLASS (self)->owns_port (self, iface); - - /* Fall back to data/control ports */ - if (priv->ppp_iface && (strcmp (priv->ppp_iface, iface) == 0)) - return TRUE; - if (priv->data_port && (strcmp (priv->data_port, iface) == 0)) - return TRUE; - if (priv->control_port && (strcmp (priv->control_port, iface) == 0)) - return TRUE; - - return FALSE; -} - -/*****************************************************************************/ - -void -nm_modem_get_capabilities (NMModem *self, - NMDeviceModemCapabilities *modem_caps, - NMDeviceModemCapabilities *current_caps) -{ - g_return_if_fail (NM_IS_MODEM (self)); - - NM_MODEM_GET_CLASS (self)->get_capabilities (self, modem_caps, current_caps); -} - -/*****************************************************************************/ - -static void -nm_modem_init (NMModem *self) -{ -} - -static GObject* -constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) -{ - GObject *object; - NMModemPrivate *priv; - - object = G_OBJECT_CLASS (nm_modem_parent_class)->constructor (type, - n_construct_params, - construct_params); - if (!object) - return NULL; - - priv = NM_MODEM_GET_PRIVATE (object); - - if (!priv->data_port && !priv->control_port) { - nm_log_err (LOGD_HW, "neither modem command nor data interface provided"); - goto err; - } - - if (!priv->path) { - nm_log_err (LOGD_HW, "D-Bus path not provided"); - goto err; - } - - return object; - - err: - g_object_unref (object); - return NULL; -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_PATH: - g_value_set_string (value, priv->path); - break; - case PROP_DRIVER: - g_value_set_string (value, priv->driver); - break; - case PROP_CONTROL_PORT: - g_value_set_string (value, priv->control_port); - break; - case PROP_DATA_PORT: - g_value_set_string (value, nm_modem_get_data_port (NM_MODEM (object))); - break; - case PROP_UID: - g_value_set_string (value, priv->uid); - break; - case PROP_IP_METHOD: - g_value_set_uint (value, priv->ip_method); - break; - case PROP_IP_TIMEOUT: - g_value_set_uint (value, priv->mm_ip_timeout); - break; - case PROP_ENABLED: - g_value_set_boolean (value, priv->mm_enabled); - break; - case PROP_CONNECTED: - g_value_set_boolean (value, priv->mm_connected); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_PATH: - /* Construct only */ - priv->path = g_value_dup_string (value); - break; - case PROP_DRIVER: - /* Construct only */ - priv->driver = g_value_dup_string (value); - break; - case PROP_CONTROL_PORT: - priv->control_port = g_value_dup_string (value); - break; - case PROP_DATA_PORT: - priv->data_port = g_value_dup_string (value); - break; - case PROP_UID: - /* Construct only */ - priv->uid = g_value_dup_string (value); - break; - case PROP_IP_METHOD: - priv->ip_method = g_value_get_uint (value); - break; - case PROP_IP_TIMEOUT: - priv->mm_ip_timeout = g_value_get_uint (value); - break; - case PROP_ENABLED: - priv->mm_enabled = g_value_get_boolean (value); - break; - case PROP_CONNECTED: - priv->mm_connected = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -dispose (GObject *object) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object); - - if (priv->act_request) { - g_object_unref (priv->act_request); - priv->act_request = NULL; - } - - G_OBJECT_CLASS (nm_modem_parent_class)->dispose (object); -} - -static void -finalize (GObject *object) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object); - - g_free (priv->uid); - g_free (priv->path); - g_free (priv->driver); - g_free (priv->control_port); - g_free (priv->data_port); - - G_OBJECT_CLASS (nm_modem_parent_class)->finalize (object); -} - -static void -nm_modem_class_init (NMModemClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (object_class, sizeof (NMModemPrivate)); - - /* Virtual methods */ - object_class->constructor = constructor; - object_class->set_property = set_property; - object_class->get_property = get_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - klass->act_stage1_prepare = act_stage1_prepare; - klass->deactivate = deactivate; - - /* Properties */ - - g_object_class_install_property - (object_class, PROP_UID, - g_param_spec_string (NM_MODEM_UID, - "UID", - "Modem unique ID", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property - (object_class, PROP_PATH, - g_param_spec_string (NM_MODEM_PATH, - "DBus path", - "DBus path", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property - (object_class, PROP_DRIVER, - g_param_spec_string (NM_MODEM_DRIVER, - "Driver", - "Driver", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property - (object_class, PROP_CONTROL_PORT, - g_param_spec_string (NM_MODEM_CONTROL_PORT, - "Control port", - "The port controlling the modem", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property - (object_class, PROP_DATA_PORT, - g_param_spec_string (NM_MODEM_DATA_PORT, - "Data port", - "The port to connect to", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property - (object_class, PROP_IP_METHOD, - g_param_spec_uint (NM_MODEM_IP_METHOD, - "IP method", - "IP method", - MM_MODEM_IP_METHOD_PPP, - MM_MODEM_IP_METHOD_DHCP, - MM_MODEM_IP_METHOD_PPP, - G_PARAM_READWRITE)); - - g_object_class_install_property - (object_class, PROP_IP_TIMEOUT, - g_param_spec_uint (NM_MODEM_IP_TIMEOUT, - "IP timeout", - "IP timeout", - 0, 360, 20, - G_PARAM_READWRITE)); - - g_object_class_install_property - (object_class, PROP_ENABLED, - g_param_spec_boolean (NM_MODEM_ENABLED, - "Enabled", - "Enabled", - TRUE, - G_PARAM_READWRITE)); - - g_object_class_install_property - (object_class, PROP_CONNECTED, - g_param_spec_boolean (NM_MODEM_CONNECTED, - "Connected", - "Connected", - TRUE, - G_PARAM_READWRITE)); - - /* Signals */ - - signals[PPP_STATS] = - g_signal_new ("ppp-stats", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMModemClass, ppp_stats), - NULL, NULL, NULL, - G_TYPE_NONE, 2, - G_TYPE_UINT, G_TYPE_UINT); - - 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, NULL, - G_TYPE_NONE, 1, G_TYPE_UINT); - - 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, NULL, - G_TYPE_NONE, 2, 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, NULL, - G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_UINT); - - signals[AUTH_REQUESTED] = - g_signal_new (NM_MODEM_AUTH_REQUESTED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMModemClass, auth_requested), - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - signals[AUTH_RESULT] = - g_signal_new (NM_MODEM_AUTH_RESULT, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMModemClass, auth_result), - NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_POINTER); - - signals[REMOVED] = - g_signal_new (NM_MODEM_REMOVED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMModemClass, removed), - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - dbus_g_error_domain_register (NM_MODEM_ERROR, - NM_DBUS_INTERFACE_DEVICE_MODEM, - NM_TYPE_MODEM_ERROR); -} diff --git a/src/modem-manager/nm-modem.h b/src/modem-manager/nm-modem.h deleted file mode 100644 index f15be26769..0000000000 --- a/src/modem-manager/nm-modem.h +++ /dev/null @@ -1,193 +0,0 @@ -/* -*- 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 - 2011 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - */ - -#ifndef NM_MODEM_H -#define NM_MODEM_H - -#include -#include -#include "ppp-manager/nm-ppp-manager.h" -#include "nm-device.h" - -G_BEGIN_DECLS - -#define NM_TYPE_MODEM (nm_modem_get_type ()) -#define NM_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM, NMModem)) -#define NM_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_MODEM, NMModemClass)) -#define NM_IS_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM)) -#define NM_IS_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_MODEM)) -#define NM_MODEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MODEM, NMModemClass)) - -#define NM_MODEM_UID "uid" -#define NM_MODEM_PATH "path" -#define NM_MODEM_DRIVER "driver" -#define NM_MODEM_CONTROL_PORT "control-port" -#define NM_MODEM_DATA_PORT "data-port" -#define NM_MODEM_IP_METHOD "ip-method" -#define NM_MODEM_IP_TIMEOUT "ip-timeout" -#define NM_MODEM_ENABLED "enabled" -#define NM_MODEM_CONNECTED "connected" - -#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_AUTH_REQUESTED "auth-requested" -#define NM_MODEM_AUTH_RESULT "auth-result" -#define NM_MODEM_REMOVED "removed" - -#define MM_MODEM_IP_METHOD_PPP 0 -#define MM_MODEM_IP_METHOD_STATIC 1 -#define MM_MODEM_IP_METHOD_DHCP 2 - -typedef enum { - NM_MODEM_ERROR_CONNECTION_NOT_GSM, /*< nick=ConnectionNotGsm >*/ - NM_MODEM_ERROR_CONNECTION_NOT_CDMA, /*< nick=ConnectionNotCdma >*/ - NM_MODEM_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/ - NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ - NM_MODEM_ERROR_INITIALIZATION_FAILED, /*< nick=InitializationFailed >*/ -} NMModemError; - -#define NM_MODEM_ERROR (nm_modem_error_quark ()) -GQuark nm_modem_error_quark (void); - - -typedef struct { - GObject parent; -} NMModem; - -typedef struct { - GObjectClass parent; - - void (*get_capabilities) (NMModem *self, - NMDeviceModemCapabilities *modem_caps, - NMDeviceModemCapabilities *current_caps); - - gboolean (*get_user_pass) (NMModem *modem, - NMConnection *connection, - const char **user, - const char **pass); - - gboolean (*check_connection_compatible) (NMModem *modem, - NMConnection *connection, - GError **error); - - gboolean (*complete_connection) (NMModem *modem, - NMConnection *connection, - const GSList *existing_connections, - GError **error); - - NMActStageReturn (*act_stage1_prepare) (NMModem *modem, - NMConnection *connection, - NMDeviceStateReason *reason); - - NMActStageReturn (*static_stage3_ip4_config_start) (NMModem *self, - NMActRequest *req, - NMDeviceStateReason *reason); - - void (*set_mm_enabled) (NMModem *self, gboolean enabled); - - void (*disconnect) (NMModem *self, gboolean warn); - - void (*deactivate) (NMModem *self, NMDevice *device); - - gboolean (*owns_port) (NMModem *self, const char *iface); - - /* Signals */ - 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, NMIP4Config *config, GError *error); - - void (*auth_requested) (NMModem *self); - void (*auth_result) (NMModem *self, GError *error); - - void (*removed) (NMModem *self); -} NMModemClass; - -GType nm_modem_get_type (void); - -const char *nm_modem_get_path (NMModem *modem); -const char *nm_modem_get_uid (NMModem *modem); -const char *nm_modem_get_control_port (NMModem *modem); -const char *nm_modem_get_data_port (NMModem *modem); -const char *nm_modem_get_driver (NMModem *modem); - -gboolean nm_modem_owns_port (NMModem *modem, const char *iface); - -void nm_modem_get_capabilities (NMModem *self, - NMDeviceModemCapabilities *modem_caps, - NMDeviceModemCapabilities *current_caps); - -gboolean nm_modem_check_connection_compatible (NMModem *self, - NMConnection *connection, - GError **error); - -gboolean nm_modem_complete_connection (NMModem *self, - NMConnection *connection, - const GSList *existing_connections, - 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_stage3_ip6_config_start (NMModem *modem, - NMDevice *device, - NMDeviceClass *device_class, - NMDeviceStateReason *reason); - -void nm_modem_ip4_pre_commit (NMModem *modem, NMDevice *device, NMIP4Config *config); - -gboolean nm_modem_get_secrets (NMModem *modem, - const char *setting_name, - gboolean request_new, - const char *hint); - -void nm_modem_deactivate (NMModem *modem, NMDevice *device); - -void nm_modem_device_state_changed (NMModem *modem, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason); - -gboolean nm_modem_get_mm_enabled (NMModem *self); - -void nm_modem_set_mm_enabled (NMModem *self, gboolean enabled); - -gboolean nm_modem_get_mm_connected (NMModem *self); - -/* For the modem-manager only */ -void nm_modem_emit_removed (NMModem *self); - -G_END_DECLS - -#endif /* NM_MODEM_H */ diff --git a/src/nm-manager.c b/src/nm-manager.c index 2d6c0f1121..7e8ae75fa3 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -39,12 +39,10 @@ #include "nm-logging.h" #include "nm-dbus-manager.h" #include "nm-vpn-manager.h" -#include "nm-modem-manager.h" #include "nm-device.h" #include "nm-device-ethernet.h" #include "nm-device-wifi.h" #include "nm-device-olpc-mesh.h" -#include "nm-device-modem.h" #include "nm-device-infiniband.h" #include "nm-device-bond.h" #include "nm-device-team.h" @@ -213,9 +211,6 @@ typedef struct { NMVPNManager *vpn_manager; - NMModemManager *modem_manager; - guint modem_added_id; - DBusGProxy *aipd_proxy; NMSleepMonitor *sleep_monitor; @@ -519,45 +514,6 @@ manager_sleeping (NMManager *self) return FALSE; } -static void -modem_added (NMModemManager *modem_manager, - NMModem *modem, - const char *driver, - gpointer user_data) -{ - NMManager *self = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device = NULL; - const char *modem_iface; - GSList *iter; - - /* Give Bluetooth DUN devices first chance to claim the modem */ - for (iter = priv->devices; iter; iter = iter->next) { - if (nm_device_notify_component_added (device, G_OBJECT (modem))) - 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")) { - modem_iface = nm_modem_get_data_port (modem); - if (!modem_iface) - modem_iface = nm_modem_get_control_port (modem); - - nm_log_info (LOGD_MB, "ignoring modem '%s' (no associated Bluetooth device)", modem_iface); - return; - } - - /* Make the new modem device */ - device = nm_device_modem_new (modem, driver); - if (device) { - add_device (self, device, FALSE); - g_object_unref (device); - } -} - static void set_state (NMManager *manager, NMState state) { @@ -1838,7 +1794,7 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con) G_CALLBACK (manager_ipw_rfkill_state_changed), self); } else if (devtype == NM_DEVICE_TYPE_MODEM) { - g_signal_connect (device, NM_DEVICE_MODEM_ENABLE_CHANGED, + g_signal_connect (device, "enable-changed", G_CALLBACK (manager_modem_enabled_changed), self); } @@ -4716,10 +4672,6 @@ nm_manager_init (NMManager *manager) G_CALLBACK (dbus_connection_changed_cb), manager); - priv->modem_manager = nm_modem_manager_get (); - priv->modem_added_id = g_signal_connect (priv->modem_manager, "modem-added", - G_CALLBACK (modem_added), manager); - priv->vpn_manager = nm_vpn_manager_get (); g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr); @@ -4937,12 +4889,6 @@ dispose (GObject *object) g_clear_object (&priv->settings); g_clear_object (&priv->vpn_manager); - if (priv->modem_added_id) { - g_source_remove (priv->modem_added_id); - priv->modem_added_id = 0; - } - g_clear_object (&priv->modem_manager); - /* Unregister property filter */ if (priv->dbus_mgr) { bus = nm_dbus_manager_get_connection (priv->dbus_mgr); -- cgit v1.2.1 From 493bbbeb4a98a43c7f13cd89db4b14142fbecb7d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 24 Feb 2014 18:10:18 -0600 Subject: core: consolidate auto-activation recheck signals Add a generic signal that devices can use to indicate that something material in the network situation changed, and that auto-activation may now be possible. This reduces specific knowledge of device types in the policy. --- src/devices/nm-device-private.h | 2 ++ src/devices/nm-device-wifi.c | 28 ++++++++++++++++++---------- src/devices/nm-device.c | 14 ++++++++++++++ src/devices/nm-device.h | 9 +++++---- src/devices/wimax/nm-device-wimax.c | 22 ++++++++++++++++------ src/devices/wwan/nm-device-modem.c | 1 + src/nm-policy.c | 33 +++------------------------------ 7 files changed, 59 insertions(+), 50 deletions(-) diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index e4e5a4dbca..e5c9942b36 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -95,4 +95,6 @@ void nm_device_master_check_slave_physical_port (NMDevice *dev, NMDevice *slave, void nm_device_set_carrier (NMDevice *device, gboolean carrier); +void nm_device_emit_recheck_auto_activate (NMDevice *device); + #endif /* NM_DEVICE_PRIVATE_H */ diff --git a/src/devices/nm-device-wifi.c b/src/devices/nm-device-wifi.c index f9c77d1409..df90671ed9 100644 --- a/src/devices/nm-device-wifi.c +++ b/src/devices/nm-device-wifi.c @@ -803,19 +803,32 @@ bring_up (NMDevice *device, gboolean *no_firmware) return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->bring_up (device, no_firmware); } +static void +emit_ap_added_removed (NMDeviceWifi *self, + guint signum, + NMAccessPoint *ap, + gboolean recheck_available_connections) +{ + g_signal_emit (self, signals[signum], 0, ap); + g_object_notify (G_OBJECT (self), NM_DEVICE_WIFI_ACCESS_POINTS); + nm_device_emit_recheck_auto_activate (NM_DEVICE (self)); + if (recheck_available_connections) + nm_device_recheck_available_connections (NM_DEVICE (self)); +} + static void remove_access_point (NMDeviceWifi *device, NMAccessPoint *ap) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device); + NMDeviceWifi *self = NM_DEVICE_WIFI (device); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); g_return_if_fail (ap); g_return_if_fail (ap != priv->current_ap); g_return_if_fail (g_slist_find (priv->ap_list, ap)); priv->ap_list = g_slist_remove (priv->ap_list, ap); - g_signal_emit (device, signals[ACCESS_POINT_REMOVED], 0, ap); - g_object_notify (G_OBJECT (device), NM_DEVICE_WIFI_ACCESS_POINTS); + emit_ap_added_removed (self, ACCESS_POINT_REMOVED, ap, FALSE); g_object_unref (ap); } @@ -1788,7 +1801,6 @@ supplicant_iface_scan_done_cb (NMSupplicantInterface *iface, } } - /**************************************************************************** * WPA Supplicant control stuff * @@ -1887,9 +1899,7 @@ merge_scanned_ap (NMDeviceWifi *self, g_object_ref (merge_ap); priv->ap_list = g_slist_prepend (priv->ap_list, merge_ap); nm_ap_export_to_dbus (merge_ap); - g_signal_emit (self, signals[ACCESS_POINT_ADDED], 0, merge_ap); - g_object_notify (G_OBJECT (self), NM_DEVICE_WIFI_ACCESS_POINTS); - nm_device_recheck_available_connections (NM_DEVICE (self)); + emit_ap_added_removed (self, ACCESS_POINT_ADDED, merge_ap, TRUE); } } @@ -2900,10 +2910,8 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) nm_ap_export_to_dbus (ap); g_object_freeze_notify (G_OBJECT (self)); set_current_ap (self, ap, FALSE, FALSE); - g_signal_emit (self, signals[ACCESS_POINT_ADDED], 0, ap); - g_object_notify (G_OBJECT (self), NM_DEVICE_WIFI_ACCESS_POINTS); + emit_ap_added_removed (self, ACCESS_POINT_ADDED, ap, TRUE); g_object_thaw_notify (G_OBJECT (self)); - nm_device_recheck_available_connections (NM_DEVICE (self)); nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req), nm_ap_get_dbus_path (ap)); return NM_ACT_STAGE_RETURN_SUCCESS; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index d4f16a62e7..3c069e04f8 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -113,6 +113,7 @@ enum { IP4_CONFIG_CHANGED, IP6_CONFIG_CHANGED, REMOVED, + RECHECK_AUTO_ACTIVATE, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -1964,6 +1965,12 @@ nm_device_can_assume_connections (NMDevice *device) return !!NM_DEVICE_GET_CLASS (device)->update_connection; } +void +nm_device_emit_recheck_auto_activate (NMDevice *self) +{ + g_signal_emit (self, signals[RECHECK_AUTO_ACTIVATE], 0); +} + static void dnsmasq_state_changed_cb (NMDnsMasqManager *manager, guint32 status, gpointer user_data) { @@ -6167,6 +6174,13 @@ nm_device_class_init (NMDeviceClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + signals[RECHECK_AUTO_ACTIVATE] = + g_signal_new (NM_DEVICE_RECHECK_AUTO_ACTIVATE, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), G_TYPE_FROM_CLASS (klass), &dbus_glib_nm_device_object_info); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 03e3b87ed0..48f7a3a00f 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -71,10 +71,11 @@ #define NM_DEVICE_HAS_PENDING_ACTION "has-pending-action" /* Internal only */ /* Internal signals */ -#define NM_DEVICE_AUTH_REQUEST "auth-request" -#define NM_DEVICE_IP4_CONFIG_CHANGED "ip4-config-changed" -#define NM_DEVICE_IP6_CONFIG_CHANGED "ip6-config-changed" -#define NM_DEVICE_REMOVED "removed" +#define NM_DEVICE_AUTH_REQUEST "auth-request" +#define NM_DEVICE_IP4_CONFIG_CHANGED "ip4-config-changed" +#define NM_DEVICE_IP6_CONFIG_CHANGED "ip6-config-changed" +#define NM_DEVICE_REMOVED "removed" +#define NM_DEVICE_RECHECK_AUTO_ACTIVATE "recheck-auto-activate" G_BEGIN_DECLS diff --git a/src/devices/wimax/nm-device-wimax.c b/src/devices/wimax/nm-device-wimax.c index 995d3cf01b..bdf7d9d6e8 100644 --- a/src/devices/wimax/nm-device-wimax.c +++ b/src/devices/wimax/nm-device-wimax.c @@ -221,6 +221,19 @@ activation_timed_out (gpointer data) return FALSE; } +static void +emit_nsp_added_removed (NMDeviceWimax *self, + guint signum, + NMWimaxNsp *nsp, + gboolean recheck_available_connections) +{ + g_signal_emit (self, signals[signum], 0, nsp); + g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_NSPS); + nm_device_emit_recheck_auto_activate (NM_DEVICE (self)); + if (recheck_available_connections) + nm_device_recheck_available_connections (NM_DEVICE (self)); +} + static void remove_all_nsps (NMDeviceWimax *self) { @@ -232,8 +245,7 @@ remove_all_nsps (NMDeviceWimax *self) NMWimaxNsp *nsp = NM_WIMAX_NSP (priv->nsp_list->data); priv->nsp_list = g_slist_remove (priv->nsp_list, nsp); - g_signal_emit (self, signals[NSP_REMOVED], 0, nsp); - g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_NSPS); + emit_nsp_added_removed (self, NSP_REMOVED, nsp, FALSE); g_object_unref (nsp); } @@ -971,7 +983,7 @@ remove_outdated_nsps (NMDeviceWimax *self, for (iter = to_remove; iter; iter = iter->next) { NMWimaxNsp *nsp = NM_WIMAX_NSP (iter->data); - g_signal_emit (self, signals[NSP_REMOVED], 0, nsp); + emit_nsp_added_removed (self, NSP_REMOVED, nsp, FALSE); priv->nsp_list = g_slist_remove (priv->nsp_list, nsp); g_object_unref (nsp); } @@ -1025,9 +1037,7 @@ wmx_scan_result_cb (struct wmxsdk *wmxsdk, if (new_nsp) { priv->nsp_list = g_slist_append (priv->nsp_list, nsp); nm_wimax_nsp_export_to_dbus (nsp); - g_signal_emit (self, signals[NSP_ADDED], 0, nsp); - g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_NSPS); - nm_device_recheck_available_connections (NM_DEVICE (self)); + emit_nsp_added_removed (self, NSP_ADDED, nsp, TRUE); } } } diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index 723f86e4dd..d731c809a9 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -181,6 +181,7 @@ modem_enabled_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) set_enabled (NM_DEVICE (self), nm_modem_get_mm_enabled (priv->modem)); g_signal_emit (G_OBJECT (self), signals[ENABLE_CHANGED], 0); + nm_device_emit_recheck_auto_activate (NM_DEVICE (self)); } static void diff --git a/src/nm-policy.c b/src/nm-policy.c index 0eac715251..9fef8ff75b 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -1602,21 +1602,9 @@ device_autoconnect_changed (NMDevice *device, } static void -wireless_networks_changed (NMDevice *device, GObject *ap, gpointer user_data) +device_recheck_auto_activate (NMDevice *device, gpointer user_data) { - schedule_activate_check ((NMPolicy *) user_data, device); -} - -static void -nsps_changed (NMDevice *device, GObject *nsp, gpointer user_data) -{ - schedule_activate_check ((NMPolicy *) user_data, device); -} - -static void -modem_enabled_changed (NMDevice *device, gpointer user_data) -{ - schedule_activate_check ((NMPolicy *) (user_data), device); + schedule_activate_check (NM_POLICY (user_data), device); } typedef struct { @@ -1654,22 +1642,7 @@ device_added (NMManager *manager, NMDevice *device, gpointer user_data) _connect_device_signal (policy, device, NM_DEVICE_IP4_CONFIG_CHANGED, device_ip4_config_changed, FALSE); _connect_device_signal (policy, device, NM_DEVICE_IP6_CONFIG_CHANGED, device_ip6_config_changed, FALSE); _connect_device_signal (policy, device, "notify::" NM_DEVICE_AUTOCONNECT, device_autoconnect_changed, FALSE); - - switch (nm_device_get_device_type (device)) { - case NM_DEVICE_TYPE_WIFI: - _connect_device_signal (policy, device, "access-point-added", wireless_networks_changed, FALSE); - _connect_device_signal (policy, device, "access-point-removed", wireless_networks_changed, FALSE); - break; - case NM_DEVICE_TYPE_WIMAX: - _connect_device_signal (policy, device, "nsp-added", nsps_changed, FALSE); - _connect_device_signal (policy, device, "nsp-removed", nsps_changed, FALSE); - break; - case NM_DEVICE_TYPE_MODEM: - _connect_device_signal (policy, device, "enable-changed", modem_enabled_changed, FALSE); - break; - default: - break; - } + _connect_device_signal (policy, device, NM_DEVICE_RECHECK_AUTO_ACTIVATE, device_recheck_auto_activate, FALSE); } static void -- cgit v1.2.1