diff --git a/ChangeLog b/ChangeLog index db5cf06cc3..e3ce5113cc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2007-10-15 Tambet Ingo + + Implement killswitch polling through HAL. + + * src/nm-manager.c: Add wireless hardware status property. Add + 'properties-changed' signal for changes in wireless and wireless hardware + state changes. + + * src/nm-hal-manager.c: Poll hal for killswitch statuses in every 6 seconds + and update NMManager's wireless hardware state when it has changed. + (nm_hal_manager_new): Don't try to add initial devices here - (hal_init) + already does that. + + * libnm-glib/nm-client.c: Add wireless hardware status property. Cache the + values of wireless state and wireless hardware state. Listen for the + 'properties-changed' signals, update the cached values and emit notify. + + * include/NetworkManager.h: Fix a typo in a comment. + 2007-10-14 Dan Williams * libnm-util/nm-setting.c diff --git a/include/NetworkManager.h b/include/NetworkManager.h index a2c378dc46..4958e91deb 100644 --- a/include/NetworkManager.h +++ b/include/NetworkManager.h @@ -48,7 +48,7 @@ /* - * Types of NetworkManager devices + * Types of NetworkManager states */ typedef enum NMState { diff --git a/introspection/nm-manager-client.xml b/introspection/nm-manager-client.xml index 99cfd7eccb..0f5f231764 100644 --- a/introspection/nm-manager-client.xml +++ b/introspection/nm-manager-client.xml @@ -41,12 +41,17 @@ + + + + + diff --git a/introspection/nm-manager.xml b/introspection/nm-manager.xml index 24c48164ad..ec7c800a3f 100644 --- a/introspection/nm-manager.xml +++ b/introspection/nm-manager.xml @@ -41,12 +41,17 @@ + + + + + diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c index 7d20ccf71d..da9989aad5 100644 --- a/libnm-glib/nm-client.c +++ b/libnm-glib/nm-client.c @@ -22,8 +22,19 @@ typedef struct { NMState state; gboolean have_device_list; GHashTable *devices; + + gboolean wireless_enabled; + gboolean wireless_hw_enabled; } NMClientPrivate; +enum { + PROP_0, + PROP_WIRELESS_ENABLED, + PROP_WIRELESS_HARDWARE_ENABLED, + + LAST_PROP +}; + enum { MANAGER_RUNNING, DEVICE_ADDED, @@ -58,8 +69,8 @@ nm_client_init (NMClient *client) static GObject* constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) + guint n_construct_params, + GObjectConstructParam *construct_params) { NMObject *object; DBusGConnection *connection; @@ -67,8 +78,8 @@ constructor (GType type, GError *err = NULL; object = (NMObject *) G_OBJECT_CLASS (nm_client_parent_class)->constructor (type, - n_construct_params, - construct_params); + n_construct_params, + construct_params); if (!object) return NULL; @@ -76,50 +87,61 @@ constructor (GType type, connection = nm_object_get_connection (object); priv->client_proxy = dbus_g_proxy_new_for_name (connection, - NM_DBUS_SERVICE, - nm_object_get_path (object), - NM_DBUS_INTERFACE); + NM_DBUS_SERVICE, + nm_object_get_path (object), + NM_DBUS_INTERFACE); dbus_g_proxy_add_signal (priv->client_proxy, "StateChange", G_TYPE_UINT, G_TYPE_INVALID); dbus_g_proxy_connect_signal (priv->client_proxy, - "StateChange", - G_CALLBACK (client_state_change_proxy), - object, - NULL); + "StateChange", + G_CALLBACK (client_state_change_proxy), + object, + NULL); dbus_g_proxy_add_signal (priv->client_proxy, "DeviceAdded", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); dbus_g_proxy_connect_signal (priv->client_proxy, - "DeviceAdded", - G_CALLBACK (client_device_added_proxy), - object, - NULL); + "DeviceAdded", + G_CALLBACK (client_device_added_proxy), + object, + NULL); dbus_g_proxy_add_signal (priv->client_proxy, "DeviceRemoved", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); dbus_g_proxy_connect_signal (priv->client_proxy, - "DeviceRemoved", - G_CALLBACK (client_device_removed_proxy), - object, - NULL); + "DeviceRemoved", + G_CALLBACK (client_device_removed_proxy), + object, + NULL); + + nm_object_handle_properties_changed (NM_OBJECT (object), priv->client_proxy); + + priv->wireless_enabled = nm_object_get_boolean_property (NM_OBJECT (object), + NM_DBUS_INTERFACE, + "WirelessEnabled"); + + priv->wireless_hw_enabled = priv->wireless_enabled ? + TRUE : nm_object_get_boolean_property (NM_OBJECT (object), + NM_DBUS_INTERFACE, + "WirelessHardwareEnabled"); priv->bus_proxy = dbus_g_proxy_new_for_name (connection, - "org.freedesktop.DBus", - "/org/freedesktop/DBus", - "org.freedesktop.DBus"); + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus"); dbus_g_proxy_add_signal (priv->bus_proxy, "NameOwnerChanged", - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_INVALID); + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_INVALID); dbus_g_proxy_connect_signal (priv->bus_proxy, - "NameOwnerChanged", - G_CALLBACK (proxy_name_owner_changed), - object, NULL); + "NameOwnerChanged", + G_CALLBACK (proxy_name_owner_changed), + object, NULL); if (!dbus_g_proxy_call (priv->bus_proxy, - "NameHasOwner", &err, - G_TYPE_STRING, NM_DBUS_SERVICE, - G_TYPE_INVALID, - G_TYPE_BOOLEAN, &priv->manager_running, - G_TYPE_INVALID)) { + "NameHasOwner", &err, + G_TYPE_STRING, NM_DBUS_SERVICE, + G_TYPE_INVALID, + G_TYPE_BOOLEAN, &priv->manager_running, + G_TYPE_INVALID)) { g_warning ("Error on NameHasOwner DBUS call: %s", err->message); g_error_free (err); } @@ -137,6 +159,56 @@ finalize (GObject *object) g_hash_table_destroy (priv->devices); } +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object); + gboolean b; + + switch (prop_id) { + case PROP_WIRELESS_ENABLED: + b = g_value_get_boolean (value); + if (priv->wireless_enabled != b) { + priv->wireless_enabled = b; + g_object_notify (object, NM_CLIENT_WIRELESS_ENABLED); + } + break; + case PROP_WIRELESS_HARDWARE_ENABLED: + b = g_value_get_boolean (value); + if (priv->wireless_hw_enabled != b) { + priv->wireless_hw_enabled = b; + g_object_notify (object, NM_CLIENT_WIRELESS_HARDWARE_ENABLED); + } + 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) +{ + NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_WIRELESS_ENABLED: + g_value_set_boolean (value, priv->wireless_enabled); + break; + case PROP_WIRELESS_HARDWARE_ENABLED: + g_value_set_boolean (value, priv->wireless_hw_enabled); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + static void manager_running (NMClient *client, gboolean running) { @@ -158,10 +230,29 @@ nm_client_class_init (NMClientClass *client_class) /* virtual methods */ object_class->constructor = constructor; + object_class->set_property = set_property; + object_class->get_property = get_property; object_class->finalize = finalize; client_class->manager_running = manager_running; + /* properties */ + g_object_class_install_property + (object_class, PROP_WIRELESS_ENABLED, + g_param_spec_boolean (NM_CLIENT_WIRELESS_ENABLED, + "WirelessEnabled", + "Is wirless enabled", + TRUE, + G_PARAM_READWRITE)); + + g_object_class_install_property + (object_class, PROP_WIRELESS_HARDWARE_ENABLED, + g_param_spec_boolean (NM_CLIENT_WIRELESS_HARDWARE_ENABLED, + "WirelessHardwareEnabled", + "Is wirless hardware enabled", + TRUE, + G_PARAM_READWRITE)); + /* signals */ signals[MANAGER_RUNNING] = g_signal_new ("manager-running", @@ -548,7 +639,7 @@ nm_client_wireless_get_enabled (NMClient *client) { g_return_val_if_fail (NM_IS_CLIENT (client), FALSE); - return nm_object_get_boolean_property (NM_OBJECT (client), NM_DBUS_INTERFACE, "WirelessEnabled"); + return NM_CLIENT_GET_PRIVATE (client)->wireless_enabled; } void @@ -562,9 +653,17 @@ nm_client_wireless_set_enabled (NMClient *client, gboolean enabled) g_value_set_boolean (&value, enabled); nm_object_set_property (NM_OBJECT (client), - NM_DBUS_INTERFACE, - "WirelessEnabled", - &value); + NM_DBUS_INTERFACE, + "WirelessEnabled", + &value); +} + +gboolean +nm_client_wireless_hardware_get_enabled (NMClient *client) +{ + g_return_val_if_fail (NM_IS_CLIENT (client), FALSE); + + return NM_CLIENT_GET_PRIVATE (client)->wireless_hw_enabled; } NMState diff --git a/libnm-glib/nm-client.h b/libnm-glib/nm-client.h index 9b4e5fc7a3..8d7920d51d 100644 --- a/libnm-glib/nm-client.h +++ b/libnm-glib/nm-client.h @@ -19,6 +19,9 @@ G_BEGIN_DECLS #define NM_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_CLIENT)) #define NM_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CLIENT, NMClientClass)) +#define NM_CLIENT_WIRELESS_ENABLED "wireless_enabled" +#define NM_CLIENT_WIRELESS_HARDWARE_ENABLED "wireless_hardware_enabled" + typedef struct { NMObject parent; } NMClient; @@ -65,6 +68,7 @@ void nm_client_activate_device (NMClient *client, gboolean nm_client_wireless_get_enabled (NMClient *client); void nm_client_wireless_set_enabled (NMClient *client, gboolean enabled); +gboolean nm_client_wireless_hardware_get_enabled (NMClient *client); NMState nm_client_get_state (NMClient *client); void nm_client_sleep (NMClient *client, gboolean sleep); diff --git a/src/nm-hal-manager.c b/src/nm-hal-manager.c index d69f395299..1100d8e013 100644 --- a/src/nm-hal-manager.c +++ b/src/nm-hal-manager.c @@ -1,3 +1,5 @@ +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ + #include #include #include @@ -8,6 +10,9 @@ #include "nm-device-802-11-wireless.h" #include "nm-device-802-3-ethernet.h" +/* Killswitch poll frequency in seconds */ +#define NM_HAL_MANAGER_KILLSWITCH_POLL_FREQUENCY 6 + struct _NMHalManager { LibHalContext *hal_ctx; NMDBusManager *dbus_mgr; @@ -15,6 +20,10 @@ struct _NMHalManager { GSList *device_creators; gboolean nm_sleeping; + + /* Killswitch handling */ + GSList *killswitch_list; + guint32 killswitch_poll_id; }; /* Device creators */ @@ -295,6 +304,162 @@ add_initial_devices (NMHalManager *manager) } } +typedef struct { + NMHalManager *manager; + gboolean initial_state; + gboolean changed; + guint32 pending_polls; + GSList *proxies; +} NMKillswitchPollInfo; + +static void +killswitch_getpower_done (gpointer user_data) +{ + NMKillswitchPollInfo *info = (NMKillswitchPollInfo *) user_data; + + info->pending_polls--; + + if (info->pending_polls == 0) { + g_slist_foreach (info->proxies, (GFunc) g_object_unref, NULL); + g_slist_free (info->proxies); + info->proxies = NULL; + + if (info->changed) + nm_manager_set_wireless_hardware_enabled (info->manager->nm_manager, !info->initial_state); + } +} + +static void +killswitch_getpower_reply (DBusGProxy *proxy, + DBusGProxyCall *call_id, + gpointer user_data) +{ + NMKillswitchPollInfo *info = (NMKillswitchPollInfo *) user_data; + guint32 status; + GError *err = NULL; + + if (dbus_g_proxy_end_call (proxy, call_id, &err, + G_TYPE_UINT, &status, + G_TYPE_INVALID)) { + if (!info->changed && info->initial_state != (status == 0) ? FALSE : TRUE) + info->changed = TRUE; + } else { + nm_warning ("Error getting killswitch power: %s.", err->message); + g_error_free (err); + } +} + +static void +poll_killswitches_real (gpointer data, gpointer user_data) +{ + NMKillswitchPollInfo *info = (NMKillswitchPollInfo *) user_data; + DBusGProxy *proxy; + + proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (info->manager->dbus_mgr), + "org.freedesktop.Hal", + (char *) data, + "org.freedesktop.Hal.Device.KillSwitch"); + + dbus_g_proxy_begin_call (proxy, "GetPower", + killswitch_getpower_reply, + info, + killswitch_getpower_done, + G_TYPE_INVALID); + info->pending_polls++; + info->proxies = g_slist_prepend (info->proxies, proxy); +} + +static gboolean +poll_killswitches (gpointer user_data) +{ + NMKillswitchPollInfo *info = (NMKillswitchPollInfo *) user_data; + + info->initial_state = nm_manager_wireless_hardware_enabled (info->manager->nm_manager); + info->changed = FALSE; + info->pending_polls = 0; + + g_slist_foreach (info->manager->killswitch_list, poll_killswitches_real, info); + return TRUE; +} + +static void +killswitch_poll_destroy (gpointer data) +{ + NMKillswitchPollInfo *info = (NMKillswitchPollInfo *) data; + + if (info->proxies) { + g_slist_foreach (info->proxies, (GFunc) g_object_unref, NULL); + g_slist_free (info->proxies); + } + g_slice_free (NMKillswitchPollInfo, info); +} + +static void +add_killswitch_device (NMHalManager *manager, const char *udi) +{ + char *type; + GSList *iter; + + type = libhal_device_get_property_string (manager->hal_ctx, udi, "killswitch.type", NULL); + if (!type) + return; + + if (strcmp (type, "wlan")) + goto out; + + /* see if it's already in the list */ + for (iter = manager->killswitch_list; iter; iter = iter->next) { + const char *list_udi = (const char *) iter->data; + if (!strcmp (list_udi, udi)) + goto out; + } + + /* Start polling switches if this is the first switch we've found */ + if (!manager->killswitch_list) { + NMKillswitchPollInfo *info; + + info = g_slice_new0 (NMKillswitchPollInfo); + info->manager = manager; + + manager->killswitch_poll_id = g_timeout_add_full (G_PRIORITY_DEFAULT, + NM_HAL_MANAGER_KILLSWITCH_POLL_FREQUENCY * 1000, + poll_killswitches, + info, + killswitch_poll_destroy); + } + + manager->killswitch_list = g_slist_append (manager->killswitch_list, g_strdup (udi)); + nm_info ("Found radio killswitch %s", udi); + +out: + libhal_free_string (type); +} + +static void +add_killswitch_devices (NMHalManager *manager) +{ + char **udis; + int num_udis; + int i; + DBusError err; + + dbus_error_init (&err); + udis = libhal_find_device_by_capability (manager->hal_ctx, "killswitch", &num_udis, &err); + if (!udis) + return; + + if (dbus_error_is_set (&err)) { + nm_warning ("Could not find killswitch devices: %s", err.message); + dbus_error_free (&err); + return; + } + + for (i = 0; i < num_udis; i++) + add_killswitch_device (manager, udis[i]); + + libhal_free_string_array (udis); +} + static gboolean hal_init (NMHalManager *manager) { @@ -333,6 +498,7 @@ hal_init (NMHalManager *manager) } /* Add any devices we know about */ + add_killswitch_devices (manager); add_initial_devices (manager); success = TRUE; @@ -354,6 +520,17 @@ hal_deinit (NMHalManager *manager) { DBusError error; + if (manager->killswitch_poll_id) { + g_source_remove (manager->killswitch_poll_id); + manager->killswitch_poll_id = 0; + } + + if (manager->killswitch_list) { + g_slist_foreach (manager->killswitch_list, (GFunc) g_free, NULL); + g_slist_free (manager->killswitch_list); + manager->killswitch_list = NULL; + } + if (!manager->hal_ctx) return; @@ -463,7 +640,6 @@ nm_hal_manager_new (NMManager *nm_manager) manager); hal_init (manager); - add_initial_devices (manager); return manager; } diff --git a/src/nm-manager.c b/src/nm-manager.c index 7f7fede333..95c0d1ef52 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -9,6 +9,7 @@ #include "nm-device-interface.h" #include "nm-device-802-11-wireless.h" #include "NetworkManagerSystem.h" +#include "nm-properties-changed-signal.h" #include "nm-marshal.h" static gboolean impl_manager_get_devices (NMManager *manager, GPtrArray **devices, GError **err); @@ -65,6 +66,7 @@ typedef struct { PendingConnectionInfo *pending_connection_info; gboolean wireless_enabled; + gboolean wireless_hw_enabled; gboolean sleeping; } NMManagerPrivate; @@ -76,6 +78,7 @@ enum { DEVICE_ADDED, DEVICE_REMOVED, STATE_CHANGE, + PROPERTIES_CHANGED, CONNECTIONS_ADDED, CONNECTION_ADDED, CONNECTION_UPDATED, @@ -90,6 +93,7 @@ enum { PROP_0, PROP_STATE, PROP_WIRELESS_ENABLED, + PROP_WIRELESS_HARDWARE_ENABLED, LAST_PROP }; @@ -100,6 +104,7 @@ nm_manager_init (NMManager *manager) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); priv->wireless_enabled = TRUE; + priv->wireless_hw_enabled = TRUE; priv->sleeping = FALSE; priv->state = NM_STATE_DISCONNECTED; @@ -202,6 +207,9 @@ set_property (GObject *object, guint prop_id, case PROP_WIRELESS_ENABLED: manager_set_wireless_enabled (NM_MANAGER (object), g_value_get_boolean (value)); break; + case PROP_WIRELESS_HARDWARE_ENABLED: + nm_manager_set_wireless_hardware_enabled (NM_MANAGER (object), g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -222,6 +230,9 @@ get_property (GObject *object, guint prop_id, case PROP_WIRELESS_ENABLED: g_value_set_boolean (value, priv->wireless_enabled); break; + case PROP_WIRELESS_HARDWARE_ENABLED: + g_value_set_boolean (value, priv->wireless_hw_enabled); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -259,6 +270,14 @@ nm_manager_class_init (NMManagerClass *manager_class) TRUE, G_PARAM_READWRITE)); + g_object_class_install_property + (object_class, PROP_WIRELESS_HARDWARE_ENABLED, + g_param_spec_boolean (NM_MANAGER_WIRELESS_HARDWARE_ENABLED, + "WirelessHardwareEnabled", + "RF kill state", + TRUE, + G_PARAM_READWRITE)); + /* signals */ signals[DEVICE_ADDED] = g_signal_new ("device-added", @@ -290,6 +309,10 @@ nm_manager_class_init (NMManagerClass *manager_class) G_TYPE_NONE, 1, G_TYPE_UINT); + signals[PROPERTIES_CHANGED] = + nm_properties_changed_signal_new (object_class, + G_STRUCT_OFFSET (NMManagerClass, properties_changed)); + signals[CONNECTIONS_ADDED] = g_signal_new ("connections-added", G_OBJECT_CLASS_TYPE (object_class), @@ -841,6 +864,8 @@ manager_set_wireless_enabled (NMManager *manager, gboolean enabled) priv->wireless_enabled = enabled; + g_object_notify (G_OBJECT (manager), NM_MANAGER_WIRELESS_ENABLED); + /* Tear down all wireless devices */ for (iter = priv->devices; iter; iter = iter->next) { if (NM_IS_DEVICE_802_11_WIRELESS (iter->data)) { @@ -1373,6 +1398,33 @@ nm_manager_wireless_enabled (NMManager *manager) return enabled; } +gboolean +nm_manager_wireless_hardware_enabled (NMManager *manager) +{ + g_return_val_if_fail (NM_IS_MANAGER (manager), FALSE); + + return NM_MANAGER_GET_PRIVATE (manager)->wireless_hw_enabled; +} + +void +nm_manager_set_wireless_hardware_enabled (NMManager *manager, + gboolean enabled) +{ + NMManagerPrivate *priv; + + g_return_if_fail (NM_IS_MANAGER (manager)); + + priv = NM_MANAGER_GET_PRIVATE (manager); + + if (priv->wireless_hw_enabled != enabled) { + nm_info ("Wireless now %s by radio killswitch", enabled ? "enabled" : "disabled"); + priv->wireless_hw_enabled = enabled; + g_object_notify (G_OBJECT (manager), NM_MANAGER_WIRELESS_HARDWARE_ENABLED); + + manager_set_wireless_enabled (manager, enabled); + } +} + void nm_manager_sleep (NMManager *manager, gboolean sleep) { diff --git a/src/nm-manager.h b/src/nm-manager.h index cfcbf1868c..9ad304c3d9 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -16,6 +16,7 @@ #define NM_MANAGER_STATE "state" #define NM_MANAGER_WIRELESS_ENABLED "wireless-enabled" +#define NM_MANAGER_WIRELESS_HARDWARE_ENABLED "wireless-hardware-enabled" #define NM_MANAGER_CONNECTION_PROXY_TAG "dbus-proxy" #define NM_MANAGER_CONNECTION_TYPE_TAG "service-type" @@ -37,6 +38,7 @@ typedef struct { void (*device_added) (NMManager *manager, NMDevice *device); void (*device_removed) (NMManager *manager, NMDevice *device); void (*state_change) (NMManager *manager, guint state); + void (*properties_changed) (NMManager *manager, GHashTable *properties); void (*connections_added) (NMManager *manager, NMConnectionType type); @@ -79,6 +81,9 @@ gboolean nm_manager_activation_pending (NMManager *manager); NMState nm_manager_get_state (NMManager *manager); gboolean nm_manager_wireless_enabled (NMManager *manager); +gboolean nm_manager_wireless_hardware_enabled (NMManager *manager); +void nm_manager_set_wireless_hardware_enabled (NMManager *manager, + gboolean enabled); void nm_manager_sleep (NMManager *manager, gboolean sleep); /* Connections */