From 5605709e806ecec46b03ff3c4afc4c12692d165d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 23 Dec 2009 00:03:45 -0800 Subject: [PATCH] manager: generalize rfkill operations So it's easier to support other killswitches like WWAN and WiMAX. --- src/nm-manager.c | 227 +++++++++++++++++++++++++++++++++-------------- src/nm-manager.h | 5 -- 2 files changed, 160 insertions(+), 72 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index 0d315f4bbc..10f5388f93 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -57,6 +57,11 @@ #define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd" #define NM_AUTOIP_DBUS_IFACE "org.freedesktop.nm_avahi_autoipd" +#define NM_MANAGER_STATE "state" +#define NM_MANAGER_WIRELESS_ENABLED "wireless-enabled" +#define NM_MANAGER_WIRELESS_HARDWARE_ENABLED "wireless-hardware-enabled" +#define NM_MANAGER_ACTIVE_CONNECTIONS "active-connections" + static gboolean impl_manager_get_devices (NMManager *manager, GPtrArray **devices, GError **err); static void impl_manager_activate_connection (NMManager *manager, const char *service_name, @@ -142,6 +147,21 @@ typedef struct { guint timeout_id; } PendingConnectionInfo; +typedef struct { + gboolean enabled; + gboolean hw_enabled; + const char *desc; + const char *key; + const char *prop; + const char *hw_prop; + /* Hack for WWAN for 0.8 release; we'll start using udev + * after 0.8 gets out. + */ + gboolean ignore_udev; + RfKillState (*other_enabled_func) (NMManager *); + gboolean (*object_filter_func) (GObject *); +} RadioState; + typedef struct { char *config_file; char *state_file; @@ -163,8 +183,8 @@ typedef struct { GSList *secrets_calls; PendingConnectionInfo *pending_connection_info; - gboolean wireless_enabled; - gboolean wireless_hw_enabled; + + RadioState radio_states[RFKILL_TYPE_MAX]; gboolean sleeping; NMVPNManager *vpn_manager; @@ -1147,28 +1167,34 @@ write_value_to_state_file (const char *filename, } static void -manager_set_wireless_enabled (NMManager *manager, gboolean enabled) +manager_set_radio_enabled (NMManager *manager, + RadioState *rstate, + gboolean enabled) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); GSList *iter; GError *error = NULL; - if (priv->wireless_enabled == enabled) + /* Do nothing for radio types not yet implemented */ + if (!rstate->prop) + return; + + if (rstate->enabled == enabled) return; /* Can't set wireless enabled if it's disabled in hardware */ - if (!priv->wireless_hw_enabled && enabled) + if (!rstate->hw_enabled && enabled) return; - priv->wireless_enabled = enabled; + rstate->enabled = enabled; - g_object_notify (G_OBJECT (manager), NM_MANAGER_WIRELESS_ENABLED); + g_object_notify (G_OBJECT (manager), rstate->prop); - /* Update "WirelessEnabled" key in state file */ + /* Update enabled key in state file */ if (priv->state_file) { if (!write_value_to_state_file (priv->state_file, - "main", "WirelessEnabled", - G_TYPE_BOOLEAN, (gpointer) &priv->wireless_enabled, + "main", rstate->key, + G_TYPE_BOOLEAN, (gpointer) &enabled, &error)) { g_warning ("Writing to state file %s failed: (%d) %s.", priv->state_file, @@ -1183,7 +1209,7 @@ manager_set_wireless_enabled (NMManager *manager, gboolean enabled) /* enable/disable wireless devices as required */ for (iter = priv->devices; iter; iter = iter->next) { - if (NM_IS_DEVICE_WIFI (iter->data)) + if (rstate->object_filter_func (G_OBJECT (iter->data))) nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (iter->data), enabled); } } @@ -1273,48 +1299,79 @@ nm_manager_get_ipw_rfkill_state (NMManager *self) return ipw_state; } +static gboolean +rfkill_wlan_filter (GObject *object) +{ + return NM_IS_DEVICE_WIFI (object); +} + static void -nm_manager_rfkill_update (NMManager *self) +manager_rfkill_update_one_type (NMManager *self, + RadioState *rstate, + RfKillType rtype) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - RfKillState udev_state, ipw_state, composite; - gboolean new_we = TRUE, new_whe = TRUE; + RfKillState udev_state = RFKILL_UNBLOCKED; + RfKillState other_state = RFKILL_UNBLOCKED; + RfKillState composite; + gboolean new_e = TRUE, new_he = TRUE; - udev_state = nm_udev_manager_get_rfkill_state (priv->udev_mgr, RFKILL_TYPE_WLAN); - ipw_state = nm_manager_get_ipw_rfkill_state (self); + if (!rstate->ignore_udev) + udev_state = nm_udev_manager_get_rfkill_state (priv->udev_mgr, rtype); - /* The composite state is the "worst" of either udev or ipw states */ - if (udev_state == RFKILL_HARD_BLOCKED || ipw_state == RFKILL_HARD_BLOCKED) + if (rstate->other_enabled_func) + other_state = rstate->other_enabled_func (self); + + /* The composite state is the "worst" of either udev or other states */ + if (udev_state == RFKILL_HARD_BLOCKED || other_state == RFKILL_HARD_BLOCKED) composite = RFKILL_HARD_BLOCKED; - else if (udev_state == RFKILL_SOFT_BLOCKED || ipw_state == RFKILL_SOFT_BLOCKED) + else if (udev_state == RFKILL_SOFT_BLOCKED || other_state == RFKILL_SOFT_BLOCKED) composite = RFKILL_SOFT_BLOCKED; else composite = RFKILL_UNBLOCKED; switch (composite) { case RFKILL_UNBLOCKED: - new_we = TRUE; - new_whe = TRUE; + new_e = TRUE; + new_he = TRUE; break; case RFKILL_SOFT_BLOCKED: - new_we = FALSE; - new_whe = TRUE; + new_e = FALSE; + new_he = TRUE; break; case RFKILL_HARD_BLOCKED: - new_we = FALSE; - new_whe = FALSE; + new_e = FALSE; + new_he = FALSE; break; default: break; } - nm_info ("Wireless now %s by radio killswitch", - (new_we && new_whe) ? "enabled" : "disabled"); - if (new_whe != priv->wireless_hw_enabled) { - priv->wireless_hw_enabled = new_whe; - g_object_notify (G_OBJECT (self), NM_MANAGER_WIRELESS_HARDWARE_ENABLED); + if (new_he != rstate->hw_enabled) { + nm_info ("%s now %s by radio killswitch", + rstate->desc, + (new_e && new_he) ? "enabled" : "disabled"); + + rstate->hw_enabled = new_he; + g_object_notify (G_OBJECT (self), rstate->hw_prop); } - manager_set_wireless_enabled (self, new_we); + manager_set_radio_enabled (self, rstate, new_e); +} + +static void +nm_manager_rfkill_update (NMManager *self, RfKillType rtype) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + guint i; + + if (rtype != RFKILL_TYPE_UNKNOWN) { + manager_rfkill_update_one_type (self, &priv->radio_states[rtype], rtype); + return; + } + + /* Otherwise sync all radio types */ + for (i = 0; i < RFKILL_TYPE_MAX; i++) + manager_rfkill_update_one_type (self, &priv->radio_states[i], i); } static void @@ -1322,7 +1379,7 @@ manager_ipw_rfkill_state_changed (NMDeviceWifi *device, GParamSpec *pspec, gpointer user_data) { - nm_manager_rfkill_update (NM_MANAGER (user_data)); + nm_manager_rfkill_update (NM_MANAGER (user_data), RFKILL_TYPE_WLAN); } static void @@ -1370,8 +1427,9 @@ add_device (NMManager *self, NMDevice *device) /* Update global rfkill state with this device's rfkill state, and * then set this device's rfkill state based on the global state. */ - nm_manager_rfkill_update (self); - nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device), priv->wireless_enabled); + nm_manager_rfkill_update (self, RFKILL_TYPE_WLAN); + nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device), + priv->radio_states[RFKILL_TYPE_WLAN].enabled); } type_desc = nm_device_get_type_desc (device); @@ -1696,7 +1754,7 @@ udev_manager_rfkill_changed_cb (NMUdevManager *udev_mgr, RfKillState udev_state, gpointer user_data) { - nm_manager_rfkill_update (NM_MANAGER (user_data)); + nm_manager_rfkill_update (NM_MANAGER (user_data), rtype); } GSList * @@ -2552,18 +2610,23 @@ impl_manager_sleep (NMManager *self, gboolean sleep, GError **error) /* Ensure rfkill state is up-to-date since we don't respond to state * changes during sleep. */ - nm_manager_rfkill_update (self); + nm_manager_rfkill_update (self, RFKILL_TYPE_UNKNOWN); /* Re-manage managed devices */ for (iter = priv->devices; iter; iter = iter->next) { NMDevice *device = NM_DEVICE (iter->data); - gboolean wifi_enabled = (priv->wireless_hw_enabled && priv->wireless_enabled); + guint i; /* enable/disable wireless devices since that we don't respond * to killswitch changes during sleep. */ - if (NM_IS_DEVICE_WIFI (iter->data)) - nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (iter->data), wifi_enabled); + for (i = 0; i < RFKILL_TYPE_MAX; i++) { + RadioState *rstate = &priv->radio_states[i]; + gboolean enabled = (rstate->hw_enabled && rstate->enabled); + + if (rstate->object_filter_func (G_OBJECT (iter->data))) + nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (iter->data), enabled); + } nm_device_clear_autoconnect_inhibit (device); if (nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs)) @@ -2697,30 +2760,43 @@ void nm_manager_start (NMManager *self) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - gboolean we = FALSE; + guint i; - switch (nm_udev_manager_get_rfkill_state (priv->udev_mgr, RFKILL_TYPE_WLAN)) { - case RFKILL_UNBLOCKED: - we = TRUE; - priv->wireless_hw_enabled = TRUE; - break; - case RFKILL_SOFT_BLOCKED: - we = FALSE; - priv->wireless_hw_enabled = TRUE; - break; - case RFKILL_HARD_BLOCKED: - we = FALSE; - priv->wireless_hw_enabled = FALSE; - break; - default: - break; + /* Set initial radio enabled/disabled state */ + for (i = 0; i < RFKILL_TYPE_MAX; i++) { + RadioState *rstate = &priv->radio_states[i]; + gboolean enabled = TRUE, hw_enabled = TRUE; + + if (!rstate->desc) + continue; + + if (!rstate->ignore_udev) { + switch (nm_udev_manager_get_rfkill_state (priv->udev_mgr, i)) { + case RFKILL_UNBLOCKED: + enabled = TRUE; + hw_enabled = TRUE; + break; + case RFKILL_SOFT_BLOCKED: + enabled = FALSE; + hw_enabled = TRUE; + break; + case RFKILL_HARD_BLOCKED: + enabled = FALSE; + hw_enabled = FALSE; + break; + default: + break; + } + } + + rstate->hw_enabled = hw_enabled; + nm_info ("%s %s by radio killswitch; %s by state file", + rstate->desc, + (rstate->hw_enabled && enabled) ? "enabled" : "disabled", + (rstate->enabled) ? "enabled" : "disabled"); + manager_set_radio_enabled (self, rstate, rstate->enabled && enabled); } - nm_info ("Wireless %s by radio killswitch; %s by state file", - (priv->wireless_hw_enabled && we) ? "enabled" : "disabled", - (priv->wireless_enabled) ? "enabled" : "disabled"); - manager_set_wireless_enabled (self, priv->wireless_enabled && we); - system_unmanaged_devices_changed_cb (priv->sys_settings, NULL, self); system_hostname_changed_cb (priv->sys_settings, NULL, self); system_query_connections (self); @@ -2773,7 +2849,7 @@ nm_manager_get (const char *config_file, priv->sleeping = !initial_net_enabled; - priv->wireless_enabled = initial_wifi_enabled; + priv->radio_states[RFKILL_TYPE_WLAN].enabled = initial_wifi_enabled; g_signal_connect (priv->sys_settings, "notify::" NM_SYSCONFIG_SETTINGS_UNMANAGED_SPECS, G_CALLBACK (system_unmanaged_devices_changed_cb), singleton); @@ -2890,9 +2966,14 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { + NMManager *self = NM_MANAGER (object); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + switch (prop_id) { case PROP_WIRELESS_ENABLED: - manager_set_wireless_enabled (NM_MANAGER (object), g_value_get_boolean (value)); + manager_set_radio_enabled (NM_MANAGER (object), + &priv->radio_states[RFKILL_TYPE_WLAN], + g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -2913,10 +2994,10 @@ get_property (GObject *object, guint prop_id, g_value_set_uint (value, priv->state); break; case PROP_WIRELESS_ENABLED: - g_value_set_boolean (value, priv->wireless_enabled); + g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WLAN].enabled); break; case PROP_WIRELESS_HARDWARE_ENABLED: - g_value_set_boolean (value, priv->wireless_hw_enabled); + g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WLAN].hw_enabled); break; case PROP_ACTIVE_CONNECTIONS: g_value_take_boxed (value, get_active_connections (self, NULL)); @@ -2938,10 +3019,22 @@ nm_manager_init (NMManager *manager) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); DBusGConnection *g_connection; - guint id; + guint id, i; + + /* Initialize rfkill structures and states */ + memset (priv->radio_states, 0, sizeof (priv->radio_states)); + + priv->radio_states[RFKILL_TYPE_WLAN].enabled = TRUE; + priv->radio_states[RFKILL_TYPE_WLAN].key = "WirelessEnabled"; + priv->radio_states[RFKILL_TYPE_WLAN].prop = NM_MANAGER_WIRELESS_ENABLED; + priv->radio_states[RFKILL_TYPE_WLAN].hw_prop = NM_MANAGER_WIRELESS_HARDWARE_ENABLED; + priv->radio_states[RFKILL_TYPE_WLAN].desc = "WiFi"; + priv->radio_states[RFKILL_TYPE_WLAN].other_enabled_func = nm_manager_get_ipw_rfkill_state; + priv->radio_states[RFKILL_TYPE_WLAN].object_filter_func = rfkill_wlan_filter; + + for (i = 0; i < RFKILL_TYPE_MAX; i++) + priv->radio_states[i].hw_enabled = TRUE; - priv->wireless_enabled = TRUE; - priv->wireless_hw_enabled = TRUE; priv->sleeping = FALSE; priv->state = NM_STATE_DISCONNECTED; diff --git a/src/nm-manager.h b/src/nm-manager.h index 5e8fcda11c..1090409a9b 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -35,11 +35,6 @@ #define NM_IS_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_MANAGER)) #define NM_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MANAGER, NMManagerClass)) -#define NM_MANAGER_STATE "state" -#define NM_MANAGER_WIRELESS_ENABLED "wireless-enabled" -#define NM_MANAGER_WIRELESS_HARDWARE_ENABLED "wireless-hardware-enabled" -#define NM_MANAGER_ACTIVE_CONNECTIONS "active-connections" - /* Not exported */ #define NM_MANAGER_HOSTNAME "hostname" #define NM_MANAGER_SLEEPING "sleeping"