diff --git a/introspection/nm-manager-client.xml b/introspection/nm-manager-client.xml index cf89611438..9a0d4da214 100644 --- a/introspection/nm-manager-client.xml +++ b/introspection/nm-manager-client.xml @@ -41,6 +41,8 @@ object. dbus-glib generates the same bound function names for D-Bus the methods + + diff --git a/introspection/nm-manager.xml b/introspection/nm-manager.xml index 02e8bcf51a..8303f4d469 100644 --- a/introspection/nm-manager.xml +++ b/introspection/nm-manager.xml @@ -108,6 +108,18 @@ + + + Indicates if mobile broadband devices are currently enabled or not. + + + + + + Indicates if the mobile broadband hardware is currently enabled, i.e. the state of the RF kill switch. + + + List of active connection object paths. diff --git a/libnm-glib/Makefile.am b/libnm-glib/Makefile.am index f91623e1b9..2aa6124e76 100644 --- a/libnm-glib/Makefile.am +++ b/libnm-glib/Makefile.am @@ -105,7 +105,7 @@ libnm_glib_la_LIBADD = \ $(GUDEV_LIBS) libnm_glib_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-glib.ver \ - -version-info "3:0:1" + -version-info "4:0:2" noinst_PROGRAMS = libnm-glib-test diff --git a/libnm-glib/libnm-glib.ver b/libnm-glib/libnm-glib.ver index 25556391dd..1caa2d42ba 100644 --- a/libnm-glib/libnm-glib.ver +++ b/libnm-glib/libnm-glib.ver @@ -40,6 +40,9 @@ global: nm_client_wireless_get_enabled; nm_client_wireless_hardware_get_enabled; nm_client_wireless_set_enabled; + nm_client_wwan_get_enabled; + nm_client_wwan_hardware_get_enabled; + nm_client_wwan_set_enabled; nm_dbus_settings_get_connection_by_path; nm_dbus_settings_get_type; nm_dbus_settings_new; diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c index 07f77cedde..05fa4dbf24 100644 --- a/libnm-glib/nm-client.c +++ b/libnm-glib/nm-client.c @@ -60,6 +60,9 @@ typedef struct { gboolean wireless_enabled; gboolean wireless_hw_enabled; + + gboolean wwan_enabled; + gboolean wwan_hw_enabled; } NMClientPrivate; enum { @@ -68,6 +71,8 @@ enum { PROP_MANAGER_RUNNING, PROP_WIRELESS_ENABLED, PROP_WIRELESS_HARDWARE_ENABLED, + PROP_WWAN_ENABLED, + PROP_WWAN_HARDWARE_ENABLED, PROP_ACTIVE_CONNECTIONS, LAST_PROP @@ -153,6 +158,36 @@ wireless_enabled_cb (GObject *object, GParamSpec *pspec, gpointer user_data) poke_wireless_devices_with_rf_status (NM_CLIENT (object)); } +static void +update_wwan_status (NMClient *client, gboolean notify) +{ + NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client); + gboolean val; + + val = _nm_object_get_boolean_property (NM_OBJECT (client), + NM_DBUS_INTERFACE, + "WwanHardwareEnabled"); + if (val != priv->wwan_hw_enabled) { + priv->wwan_hw_enabled = val; + if (notify) + _nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_WWAN_HARDWARE_ENABLED); + } + + if (priv->wwan_hw_enabled == FALSE) + val = FALSE; + else { + val = _nm_object_get_boolean_property (NM_OBJECT (client), + NM_DBUS_INTERFACE, + "WwanEnabled"); + } + + if (val != priv->wwan_enabled) { + priv->wwan_enabled = val; + if (notify) + _nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_WWAN_ENABLED); + } +} + static GObject * new_active_connection (DBusGConnection *connection, const char *path) { @@ -217,6 +252,8 @@ register_for_property_changed (NMClient *client) { NM_CLIENT_STATE, _nm_object_demarshal_generic, &priv->state }, { NM_CLIENT_WIRELESS_ENABLED, _nm_object_demarshal_generic, &priv->wireless_enabled }, { NM_CLIENT_WIRELESS_HARDWARE_ENABLED, _nm_object_demarshal_generic, &priv->wireless_hw_enabled }, + { NM_CLIENT_WWAN_ENABLED, _nm_object_demarshal_generic, &priv->wwan_enabled }, + { NM_CLIENT_WWAN_HARDWARE_ENABLED, _nm_object_demarshal_generic, &priv->wwan_hw_enabled }, { NM_CLIENT_ACTIVE_CONNECTIONS, demarshal_active_connections, &priv->active_connections }, { NULL }, }; @@ -291,6 +328,7 @@ constructor (GType type, if (priv->manager_running) { update_wireless_status (NM_CLIENT (object), FALSE); + update_wwan_status (NM_CLIENT (object), FALSE); nm_client_get_state (NM_CLIENT (object)); } @@ -353,6 +391,20 @@ set_property (GObject *object, guint prop_id, _nm_object_queue_notify (NM_OBJECT (object), NM_CLIENT_WIRELESS_HARDWARE_ENABLED); } break; + case PROP_WWAN_ENABLED: + b = g_value_get_boolean (value); + if (priv->wwan_enabled != b) { + priv->wwan_enabled = b; + _nm_object_queue_notify (NM_OBJECT (object), NM_CLIENT_WWAN_ENABLED); + } + break; + case PROP_WWAN_HARDWARE_ENABLED: + b = g_value_get_boolean (value); + if (priv->wwan_hw_enabled != b) { + priv->wwan_hw_enabled = b; + _nm_object_queue_notify (NM_OBJECT (object), NM_CLIENT_WWAN_HARDWARE_ENABLED); + } + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -381,6 +433,12 @@ get_property (GObject *object, case PROP_WIRELESS_HARDWARE_ENABLED: g_value_set_boolean (value, priv->wireless_hw_enabled); break; + case PROP_WWAN_ENABLED: + g_value_set_boolean (value, priv->wwan_enabled); + break; + case PROP_WWAN_HARDWARE_ENABLED: + g_value_set_boolean (value, priv->wwan_hw_enabled); + break; case PROP_ACTIVE_CONNECTIONS: g_value_set_boxed (value, nm_client_get_active_connections (self)); break; @@ -457,6 +515,32 @@ nm_client_class_init (NMClientClass *client_class) TRUE, G_PARAM_READABLE)); + /** + * NMClient::wwan-enabled: + * + * Whether WWAN functionality is enabled. + **/ + g_object_class_install_property + (object_class, PROP_WWAN_ENABLED, + g_param_spec_boolean (NM_CLIENT_WWAN_ENABLED, + "WwanEnabled", + "Is WWAN enabled", + TRUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + /** + * NMClient::wwan-hardware-enabled: + * + * Whether the WWAN hardware is enabled. + **/ + g_object_class_install_property + (object_class, PROP_WWAN_HARDWARE_ENABLED, + g_param_spec_boolean (NM_CLIENT_WWAN_HARDWARE_ENABLED, + "WwanHardwareEnabled", + "Is WWAN hardware enabled", + TRUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + /** * NMClient::active-connections: * @@ -566,9 +650,12 @@ proxy_name_owner_changed (DBusGProxy *proxy, free_object_array (&priv->active_connections); priv->wireless_enabled = FALSE; priv->wireless_hw_enabled = FALSE; + priv->wwan_enabled = FALSE; + priv->wwan_hw_enabled = FALSE; } else { _nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_MANAGER_RUNNING); update_wireless_status (client, TRUE); + update_wwan_status (client, TRUE); } } @@ -873,6 +960,61 @@ nm_client_wireless_hardware_get_enabled (NMClient *client) return NM_CLIENT_GET_PRIVATE (client)->wireless_hw_enabled; } +/** + * nm_client_wwan_get_enabled: + * @client: a #NMClient + * + * Determines whether WWAN is enabled. + * + * Returns: %TRUE if WWAN is enabled + **/ +gboolean +nm_client_wwan_get_enabled (NMClient *client) +{ + g_return_val_if_fail (NM_IS_CLIENT (client), FALSE); + + return NM_CLIENT_GET_PRIVATE (client)->wwan_enabled; +} + +/** + * nm_client_wwan_set_enabled: + * @client: a #NMClient + * @enabled: %TRUE to enable WWAN + * + * Enables or disables WWAN devices. + **/ +void +nm_client_wwan_set_enabled (NMClient *client, gboolean enabled) +{ + GValue value = {0,}; + + g_return_if_fail (NM_IS_CLIENT (client)); + + g_value_init (&value, G_TYPE_BOOLEAN); + g_value_set_boolean (&value, enabled); + + _nm_object_set_property (NM_OBJECT (client), + NM_DBUS_INTERFACE, + "WwanEnabled", + &value); +} + +/** + * nm_client_wwan_hardware_get_enabled: + * @client: a #NMClient + * + * Determines whether the WWAN hardware is enabled. + * + * Returns: %TRUE if the WWAN hardware is enabled + **/ +gboolean +nm_client_wwan_hardware_get_enabled (NMClient *client) +{ + g_return_val_if_fail (NM_IS_CLIENT (client), FALSE); + + return NM_CLIENT_GET_PRIVATE (client)->wwan_hw_enabled; +} + /** * nm_client_get_state: * @client: a #NMClient diff --git a/libnm-glib/nm-client.h b/libnm-glib/nm-client.h index d6df98ec5b..6aafc0872c 100644 --- a/libnm-glib/nm-client.h +++ b/libnm-glib/nm-client.h @@ -45,6 +45,8 @@ G_BEGIN_DECLS #define NM_CLIENT_MANAGER_RUNNING "manager-running" #define NM_CLIENT_WIRELESS_ENABLED "wireless-enabled" #define NM_CLIENT_WIRELESS_HARDWARE_ENABLED "wireless-hardware-enabled" +#define NM_CLIENT_WWAN_ENABLED "wwan-enabled" +#define NM_CLIENT_WWAN_HARDWARE_ENABLED "wwan-hardware-enabled" #define NM_CLIENT_ACTIVE_CONNECTIONS "active-connections" typedef struct { @@ -89,6 +91,11 @@ void nm_client_deactivate_connection (NMClient *client, NMActiveConnection *acti 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); + +gboolean nm_client_wwan_get_enabled (NMClient *client); +void nm_client_wwan_set_enabled (NMClient *client, gboolean enabled); +gboolean nm_client_wwan_hardware_get_enabled (NMClient *client); + NMState nm_client_get_state (NMClient *client); gboolean nm_client_get_manager_running (NMClient *client); const GPtrArray *nm_client_get_active_connections (NMClient *client); diff --git a/src/NetworkManager.c b/src/NetworkManager.c index a79d5c86ec..257a996a0e 100644 --- a/src/NetworkManager.c +++ b/src/NetworkManager.c @@ -329,6 +329,7 @@ static gboolean parse_state_file (const char *filename, gboolean *net_enabled, gboolean *wifi_enabled, + gboolean *wwan_enabled, GError **error) { GKeyFile *state_file; @@ -337,6 +338,7 @@ parse_state_file (const char *filename, g_return_val_if_fail (net_enabled != NULL, FALSE); g_return_val_if_fail (wifi_enabled != NULL, FALSE); + g_return_val_if_fail (wwan_enabled != NULL, FALSE); state_file = g_key_file_new (); if (!state_file) { @@ -374,6 +376,7 @@ parse_state_file (const char *filename, /* Write out the initial state to the state file */ g_key_file_set_boolean (state_file, "main", "NetworkingEnabled", *net_enabled); g_key_file_set_boolean (state_file, "main", "WirelessEnabled", *wifi_enabled); + g_key_file_set_boolean (state_file, "main", "WWANEnabled", *wwan_enabled); data = g_key_file_to_data (state_file, &len, NULL); if (data) @@ -426,7 +429,7 @@ main (int argc, char *argv[]) char *pidfile = NULL, *user_pidfile = NULL; char *config = NULL, *plugins = NULL; char *state_file = NM_DEFAULT_SYSTEM_STATE_FILE; - gboolean wifi_enabled = TRUE, net_enabled = TRUE; + gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE; gboolean success; NMPolicy *policy = NULL; NMVPNManager *vpn_manager = NULL; @@ -509,7 +512,7 @@ main (int argc, char *argv[]) g_clear_error (&error); /* Parse the state file */ - if (!parse_state_file (state_file, &net_enabled, &wifi_enabled, &error)) { + if (!parse_state_file (state_file, &net_enabled, &wifi_enabled, &wwan_enabled, &error)) { g_warning ("State file %s parsing failed: (%d) %s.", state_file, error ? error->code : -1, @@ -583,7 +586,13 @@ main (int argc, char *argv[]) goto done; } - manager = nm_manager_get (config, plugins, state_file, net_enabled, wifi_enabled, &error); + manager = nm_manager_get (config, + plugins, + state_file, + net_enabled, + wifi_enabled, + wwan_enabled, + &error); if (manager == NULL) { nm_error ("Failed to initialize the network manager: %s", error && error->message ? error->message : "(unknown)"); diff --git a/src/modem-manager/nm-modem-cdma.c b/src/modem-manager/nm-modem-cdma.c index f5964d4276..13370ced43 100644 --- a/src/modem-manager/nm-modem-cdma.c +++ b/src/modem-manager/nm-modem-cdma.c @@ -119,6 +119,45 @@ create_connect_properties (NMConnection *connection) return properties; } +static void +do_connect (NMModem *modem) +{ + NMModemCdma *self = NM_MODEM_CDMA (modem); + NMModemCdmaPrivate *priv = NM_MODEM_CDMA_GET_PRIVATE (self); + NMConnection *connection; + DBusGProxy *proxy; + GHashTable *properties; + + connection = nm_act_request_get_connection (nm_device_get_act_request (NM_DEVICE (modem))); + g_assert (connection); + + properties = create_connect_properties (connection); + proxy = nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM_SIMPLE); + priv->call = dbus_g_proxy_begin_call_with_timeout (proxy, + "Connect", stage1_prepare_done, + self, NULL, 120000, + DBUS_TYPE_G_MAP_OF_VARIANT, properties, + G_TYPE_INVALID); + g_hash_table_destroy (properties); +} + +static void +stage1_enable_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + GError *error = NULL; + + if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) + do_connect (NM_MODEM (device)); + else { + nm_warning ("CDMA modem enable failed: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_error_free (error); + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NONE); + } +} + static NMActStageReturn real_act_stage1_prepare (NMModem *modem, NMActRequest *req, @@ -126,8 +165,6 @@ real_act_stage1_prepare (NMModem *modem, const char **out_setting_name, NMDeviceStateReason *reason) { - NMModemCdma *self = NM_MODEM_CDMA (modem); - NMModemCdmaPrivate *priv = NM_MODEM_CDMA_GET_PRIVATE (self); NMConnection *connection; connection = nm_act_request_get_connection (req); @@ -135,17 +172,19 @@ real_act_stage1_prepare (NMModem *modem, *out_setting_name = nm_connection_need_secrets (connection, out_hints); if (!*out_setting_name) { + gboolean enabled = nm_modem_get_mm_enabled (modem); DBusGProxy *proxy; - GHashTable *properties; - properties = create_connect_properties (connection); - proxy = nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM_SIMPLE); - priv->call = dbus_g_proxy_begin_call_with_timeout (proxy, - "Connect", stage1_prepare_done, - self, NULL, 120000, - DBUS_TYPE_G_MAP_OF_VARIANT, properties, - G_TYPE_INVALID); - g_hash_table_destroy (properties); + if (enabled) + do_connect (modem); + else { + proxy = nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM); + dbus_g_proxy_begin_call_with_timeout (proxy, + "Enable", stage1_enable_done, + modem, NULL, 20000, + G_TYPE_BOOLEAN, TRUE, + G_TYPE_INVALID); + } } else { /* NMModem will handle requesting secrets... */ } diff --git a/src/modem-manager/nm-modem-gsm.c b/src/modem-manager/nm-modem-gsm.c index 322f8d404c..1752eaf535 100644 --- a/src/modem-manager/nm-modem-gsm.c +++ b/src/modem-manager/nm-modem-gsm.c @@ -229,6 +229,43 @@ create_connect_properties (NMConnection *connection) return properties; } +static void +do_connect (NMModem *modem) +{ + NMConnection *connection; + DBusGProxy *proxy; + GHashTable *properties; + + connection = nm_act_request_get_connection (nm_device_get_act_request (NM_DEVICE (modem))); + g_assert (connection); + + properties = create_connect_properties (connection); + proxy = nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM_SIMPLE); + dbus_g_proxy_begin_call_with_timeout (proxy, + "Connect", stage1_prepare_done, + modem, NULL, 120000, + DBUS_TYPE_G_MAP_OF_VARIANT, properties, + G_TYPE_INVALID); + g_hash_table_destroy (properties); +} + +static void +stage1_enable_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + GError *error = NULL; + + if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) + do_connect (NM_MODEM (device)); + else { + nm_warning ("GSM modem enable failed: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_error_free (error); + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NONE); + } +} + static NMActStageReturn real_act_stage1_prepare (NMModem *modem, NMActRequest *req, @@ -236,8 +273,6 @@ real_act_stage1_prepare (NMModem *modem, const char **out_setting_name, NMDeviceStateReason *reason) { - NMModemGsm *self = NM_MODEM_GSM (modem); - NMModemGsmPrivate *priv = NM_MODEM_GSM_GET_PRIVATE (self); NMConnection *connection; connection = nm_act_request_get_connection (req); @@ -245,17 +280,19 @@ real_act_stage1_prepare (NMModem *modem, *out_setting_name = nm_connection_need_secrets (connection, out_hints); if (!*out_setting_name) { + gboolean enabled = nm_modem_get_mm_enabled (modem); DBusGProxy *proxy; - GHashTable *properties; - properties = create_connect_properties (connection); - proxy = nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM_SIMPLE); - priv->call = dbus_g_proxy_begin_call_with_timeout (proxy, - "Connect", stage1_prepare_done, - self, NULL, 120000, - DBUS_TYPE_G_MAP_OF_VARIANT, properties, - G_TYPE_INVALID); - g_hash_table_destroy (properties); + if (enabled) + do_connect (modem); + else { + proxy = nm_modem_get_proxy (modem, MM_DBUS_INTERFACE_MODEM); + dbus_g_proxy_begin_call_with_timeout (proxy, + "Enable", stage1_enable_done, + modem, NULL, 20000, + G_TYPE_BOOLEAN, TRUE, + G_TYPE_INVALID); + } } else { /* NMModem will handle requesting secrets... */ } diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c index 8f04db372f..5d876f2a19 100644 --- a/src/modem-manager/nm-modem.c +++ b/src/modem-manager/nm-modem.c @@ -12,10 +12,14 @@ #include "NetworkManagerUtils.h" #include "nm-device-private.h" #include "nm-device-interface.h" +#include "nm-dbus-glib-types.h" #include "nm-serial-device-glue.h" -G_DEFINE_TYPE (NMModem, nm_modem, G_TYPE_OBJECT) +static void device_interface_init (NMDeviceInterface *iface_class); + +G_DEFINE_TYPE_EXTENDED (NMModem, nm_modem, NM_TYPE_DEVICE, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_INTERFACE, device_interface_init)) #define NM_MODEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM, NMModemPrivate)) @@ -25,14 +29,17 @@ enum { PROP_IFACE, PROP_PATH, PROP_IP_METHOD, + PROP_ENABLED, LAST_PROP }; typedef struct { NMDBusManager *dbus_mgr; - char *path; DBusGProxy *proxy; + DBusGProxy *props_proxy; + + char *path; NMPPPManager *ppp_manager; NMIP4Config *pending_ip4_config; guint32 ip_method; @@ -43,6 +50,8 @@ typedef struct { DBusGProxyCall *call; + gboolean mm_enabled; + /* PPP stats */ guint32 in_bytes; guint32 out_bytes; @@ -68,6 +77,14 @@ nm_modem_get_ppp_manager (NMModem *self) return NM_MODEM_GET_PRIVATE (self)->ppp_manager; } +gboolean +nm_modem_get_mm_enabled (NMModem *self) +{ + g_return_val_if_fail (NM_IS_MODEM (self), TRUE); + + return NM_MODEM_GET_PRIVATE (self)->mm_enabled; +} + DBusGProxy * nm_modem_get_proxy (NMModem *self, const char *interface) @@ -82,6 +99,9 @@ nm_modem_get_proxy (NMModem *self, if (interface == NULL) interface = MM_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); @@ -651,9 +671,14 @@ nm_modem_device_state_changed (NMModem *self, NMDeviceState old_state, NMDeviceStateReason reason) { + gboolean was_connected = FALSE; + g_return_if_fail (self != NULL); g_return_if_fail (NM_IS_MODEM (self)); + if (IS_ACTIVATING_STATE (old_state) || (old_state == NM_DEVICE_STATE_ACTIVATED)) + was_connected = TRUE; + /* Make sure we don't leave the serial device open */ switch (new_state) { case NM_DEVICE_STATE_NEED_AUTH: @@ -664,10 +689,11 @@ nm_modem_device_state_changed (NMModem *self, case NM_DEVICE_STATE_UNAVAILABLE: case NM_DEVICE_STATE_FAILED: case NM_DEVICE_STATE_DISCONNECTED: - dbus_g_proxy_call_no_reply (nm_modem_get_proxy (self, MM_DBUS_INTERFACE_MODEM), - "Enable", - G_TYPE_BOOLEAN, FALSE, - G_TYPE_INVALID); + if (was_connected) { + dbus_g_proxy_call_no_reply (nm_modem_get_proxy (self, MM_DBUS_INTERFACE_MODEM), + "Disconnect", + G_TYPE_INVALID); + } break; default: break; @@ -726,8 +752,119 @@ nm_modem_get_path (NMModem *self) return NM_MODEM_GET_PRIVATE (self)->path; } +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 = { 0, }; + + if (!dbus_g_proxy_end_call (proxy, call_id, &error, + G_TYPE_VALUE, &value, + G_TYPE_INVALID)) { + g_warning ("%s: failed get modem enabled state: (%d) %s", + __func__, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + return; + } + + if (G_VALUE_HOLDS_BOOLEAN (&value)) { + NM_MODEM_GET_PRIVATE (self)->mm_enabled = g_value_get_boolean (&value); + g_object_notify (G_OBJECT (self), NM_MODEM_ENABLED); + } else + g_warning ("%s: failed get modem enabled state: unexpected reply type", __func__); + + g_value_unset (&value); +} + +static void +query_mm_enabled (NMModem *self) +{ + dbus_g_proxy_begin_call (NM_MODEM_GET_PRIVATE (self)->props_proxy, + "Get", get_mm_enabled_done, + self, NULL, + G_TYPE_STRING, MM_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)) { + g_warning ("%s: failed to enable/disable modem: (%d) %s", + __func__, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + } + + /* Update enabled/disabled state again */ + query_mm_enabled (NM_MODEM (user_data)); +} + +static void +real_set_enabled (NMDeviceInterface *device, gboolean enabled) +{ + NMModem *self = NM_MODEM (device); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + + /* FIXME: For now this just toggles the ModemManager enabled state. In the + * future we want to tie this into rfkill state instead so that the user can + * toggle rfkill status of the WWAN modem. + */ + + if (priv->mm_enabled != enabled) { + DBusGProxy *proxy; + + proxy = nm_modem_get_proxy (NM_MODEM (device), MM_DBUS_INTERFACE_MODEM); + dbus_g_proxy_begin_call (proxy, + "Enable", set_mm_enabled_done, + device, NULL, + G_TYPE_BOOLEAN, enabled, + G_TYPE_INVALID); + } +} + +static void +modem_properties_changed (DBusGProxy *proxy, + const char *interface, + GHashTable *props, + gpointer user_data) +{ + NMModem *self = NM_MODEM (user_data); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + GValue *value; + + if (strcmp (interface, MM_DBUS_INTERFACE_MODEM)) + return; + + value = g_hash_table_lookup (props, "Enabled"); + if (value && G_VALUE_HOLDS_BOOLEAN (value)) { + NMDeviceState state; + + priv->mm_enabled = g_value_get_boolean (value); + g_object_notify (G_OBJECT (self), NM_MODEM_ENABLED); + + state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self)); + if (IS_ACTIVATING_STATE (state) || (state == NM_DEVICE_STATE_ACTIVATED)) { + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_NONE); + } + } +} + /*****************************************************************************/ +static void +device_interface_init (NMDeviceInterface *iface_class) +{ + iface_class->set_enabled = real_set_enabled; +} + static void nm_modem_init (NMModem *self) { @@ -743,6 +880,7 @@ constructor (GType type, { GObject *object; NMModemPrivate *priv; + DBusGConnection *bus; object = G_OBJECT_CLASS (nm_modem_parent_class)->constructor (type, n_construct_params, @@ -767,8 +905,29 @@ constructor (GType type, goto err; } - priv->proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr), - MM_DBUS_SERVICE, priv->path, MM_DBUS_INTERFACE_MODEM); + bus = nm_dbus_manager_get_connection (priv->dbus_mgr); + priv->proxy = dbus_g_proxy_new_for_name (bus, + MM_DBUS_SERVICE, + priv->path, + MM_DBUS_INTERFACE_MODEM); + + priv->props_proxy = dbus_g_proxy_new_for_name (bus, + MM_DBUS_SERVICE, + priv->path, + DBUS_INTERFACE_PROPERTIES); + dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_BOXED, + 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 (object)); return object; @@ -796,6 +955,9 @@ get_property (GObject *object, guint prop_id, case PROP_IP_METHOD: g_value_set_uint (value, priv->ip_method); break; + case PROP_ENABLED: + g_value_set_boolean (value, priv->mm_enabled); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -826,6 +988,8 @@ set_property (GObject *object, guint prop_id, /* Construct only */ priv->ip_method = g_value_get_uint (value); break; + case PROP_ENABLED: + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -840,6 +1004,9 @@ finalize (GObject *object) if (priv->proxy) g_object_unref (priv->proxy); + if (priv->props_proxy) + g_object_unref (priv->props_proxy); + g_object_unref (priv->dbus_mgr); g_free (priv->iface); @@ -900,6 +1067,14 @@ nm_modem_class_init (NMModemClass *klass) MM_MODEM_IP_METHOD_PPP, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property + (object_class, PROP_ENABLED, + g_param_spec_boolean (NM_MODEM_ENABLED, + "Enabled", + "Enabled", + TRUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT)); + /* Signals */ signals[PPP_STATS] = g_signal_new ("ppp-stats", diff --git a/src/modem-manager/nm-modem.h b/src/modem-manager/nm-modem.h index 5c0c741c5e..0203552766 100644 --- a/src/modem-manager/nm-modem.h +++ b/src/modem-manager/nm-modem.h @@ -21,6 +21,7 @@ G_BEGIN_DECLS #define NM_MODEM_DEVICE "device" #define NM_MODEM_IFACE "iface" #define NM_MODEM_IP_METHOD "ip-method" +#define NM_MODEM_ENABLED "enabled" #define NM_MODEM_PPP_STATS "ppp-stats" #define NM_MODEM_PPP_FAILED "ppp-failed" @@ -128,6 +129,8 @@ gboolean nm_modem_connection_secrets_updated (NMModem *modem, const DBusGObjectInfo *nm_modem_get_serial_dbus_info (void); +gboolean nm_modem_get_mm_enabled (NMModem *self); + G_END_DECLS #endif /* NM_MODEM_H */ diff --git a/src/nm-device-interface.c b/src/nm-device-interface.c index f53a6028b8..70cce8b624 100644 --- a/src/nm-device-interface.c +++ b/src/nm-device-interface.c @@ -355,3 +355,12 @@ nm_device_interface_can_assume_connection (NMDeviceInterface *device) return !!NM_DEVICE_INTERFACE_GET_INTERFACE (device)->connection_match_config; } +void +nm_device_interface_set_enabled (NMDeviceInterface *device, gboolean enabled) +{ + g_return_if_fail (NM_IS_DEVICE_INTERFACE (device)); + + if (NM_DEVICE_INTERFACE_GET_INTERFACE (device)->set_enabled) + return NM_DEVICE_INTERFACE_GET_INTERFACE (device)->set_enabled (device, enabled); +} + diff --git a/src/nm-device-interface.h b/src/nm-device-interface.h index 54b5c41a59..0ec5e3da14 100644 --- a/src/nm-device-interface.h +++ b/src/nm-device-interface.h @@ -97,6 +97,8 @@ struct _NMDeviceInterface { NMConnection * (*connection_match_config) (NMDeviceInterface *device, const GSList *specs); + void (*set_enabled) (NMDeviceInterface *device, gboolean enabled); + /* Signals */ void (*state_changed) (NMDeviceInterface *device, NMDeviceState new_state, @@ -131,4 +133,6 @@ NMConnection * nm_device_interface_connection_match_config (NMDeviceInterface *d gboolean nm_device_interface_can_assume_connection (NMDeviceInterface *device); +void nm_device_interface_set_enabled (NMDeviceInterface *device, gboolean enabled); + #endif /* NM_DEVICE_INTERFACE_H */ diff --git a/src/nm-device-olpc-mesh.c b/src/nm-device-olpc-mesh.c index fb47cf7d56..ad81a5a78b 100644 --- a/src/nm-device-olpc-mesh.c +++ b/src/nm-device-olpc-mesh.c @@ -909,7 +909,7 @@ check_companion_cb (gpointer user_data) if (priv->device_added_cb != 0) return FALSE; - manager = nm_manager_get (NULL, NULL, NULL, FALSE, FALSE, NULL); + manager = nm_manager_get (NULL, NULL, NULL, FALSE, FALSE, FALSE, NULL); priv->device_added_cb = g_signal_connect (manager, "device-added", G_CALLBACK (device_added_cb), self); diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c index 20b73fb2fb..972a7de597 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -69,8 +69,10 @@ static gboolean impl_device_get_access_points (NMDeviceWifi *device, #define WIRELESS_SECRETS_TRIES "wireless-secrets-tries" +static void device_interface_init (NMDeviceInterface *iface_class); -G_DEFINE_TYPE (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE) +G_DEFINE_TYPE_EXTENDED (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_INTERFACE, device_interface_init)) #define NM_DEVICE_WIFI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_WIFI, NMDeviceWifiPrivate)) @@ -3420,15 +3422,13 @@ nm_device_wifi_get_activation_ap (NMDeviceWifi *self) return NULL; } -void -nm_device_wifi_set_enabled (NMDeviceWifi *self, gboolean enabled) +static void +real_set_enabled (NMDeviceInterface *device, gboolean enabled) { - NMDeviceWifiPrivate *priv; + NMDeviceWifi *self = NM_DEVICE_WIFI (device); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMDeviceState state; - g_return_if_fail (NM_IS_DEVICE_WIFI (self)); - - priv = NM_DEVICE_WIFI_GET_PRIVATE (self); if (priv->enabled == enabled) return; @@ -3490,6 +3490,12 @@ nm_device_wifi_new (const char *udi, NULL); } +static void +device_interface_init (NMDeviceInterface *iface_class) +{ + iface_class->set_enabled = real_set_enabled; +} + static void nm_device_wifi_init (NMDeviceWifi * self) { diff --git a/src/nm-device-wifi.h b/src/nm-device-wifi.h index 126bc13982..c793844c5c 100644 --- a/src/nm-device-wifi.h +++ b/src/nm-device-wifi.h @@ -102,8 +102,6 @@ NM80211Mode nm_device_wifi_get_mode (NMDeviceWifi *self); NMAccessPoint * nm_device_wifi_get_activation_ap (NMDeviceWifi *self); -void nm_device_wifi_set_enabled (NMDeviceWifi *self, gboolean enabled); - guint32 nm_device_wifi_get_ifindex (NMDeviceWifi *self); RfKillState nm_device_wifi_get_ipw_rfkill_state (NMDeviceWifi *self); diff --git a/src/nm-manager.c b/src/nm-manager.c index 84b26217c6..dbc81ee0c6 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -59,6 +59,13 @@ #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_WWAN_ENABLED "wwan-enabled" +#define NM_MANAGER_WWAN_HARDWARE_ENABLED "wwan-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, @@ -144,6 +151,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; @@ -165,8 +187,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; @@ -208,6 +230,8 @@ enum { PROP_STATE, PROP_WIRELESS_ENABLED, PROP_WIRELESS_HARDWARE_ENABLED, + PROP_WWAN_ENABLED, + PROP_WWAN_HARDWARE_ENABLED, PROP_ACTIVE_CONNECTIONS, /* Not exported */ @@ -1150,28 +1174,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, @@ -1186,8 +1216,8 @@ 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)) - nm_device_wifi_set_enabled (NM_DEVICE_WIFI (iter->data), enabled); + if (rstate->object_filter_func (G_OBJECT (iter->data))) + nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (iter->data), enabled); } } @@ -1276,48 +1306,108 @@ nm_manager_get_ipw_rfkill_state (NMManager *self) return ipw_state; } -static void -nm_manager_rfkill_update (NMManager *self) +static RfKillState +nm_manager_get_modem_enabled_state (NMManager *self) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - RfKillState udev_state, ipw_state, composite; - gboolean new_we = TRUE, new_whe = TRUE; + GSList *iter; + RfKillState wwan_state = RFKILL_UNBLOCKED; - udev_state = nm_udev_manager_get_rfkill_state (priv->udev_mgr); - ipw_state = nm_manager_get_ipw_rfkill_state (self); + for (iter = priv->devices; iter; iter = g_slist_next (iter)) { + NMDevice *candidate = NM_DEVICE (iter->data); + RfKillState candidate_state = RFKILL_UNBLOCKED; - /* The composite state is the "worst" of either udev or ipw states */ - if (udev_state == RFKILL_HARD_BLOCKED || ipw_state == RFKILL_HARD_BLOCKED) + if (NM_IS_MODEM (candidate)) { + if (nm_modem_get_mm_enabled (NM_MODEM (candidate)) == FALSE) + candidate_state = RFKILL_SOFT_BLOCKED; + + if (candidate_state > wwan_state) + wwan_state = candidate_state; + } + } + + return wwan_state; +} + +static gboolean +rfkill_wlan_filter (GObject *object) +{ + return NM_IS_DEVICE_WIFI (object); +} + +static gboolean +rfkill_wwan_filter (GObject *object) +{ + return NM_IS_MODEM (object); +} + +static void +manager_rfkill_update_one_type (NMManager *self, + RadioState *rstate, + RfKillType rtype) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + RfKillState udev_state = RFKILL_UNBLOCKED; + RfKillState other_state = RFKILL_UNBLOCKED; + RfKillState composite; + gboolean new_e = TRUE, new_he = TRUE; + + if (!rstate->ignore_udev) + udev_state = nm_udev_manager_get_rfkill_state (priv->udev_mgr, rtype); + + 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 @@ -1325,7 +1415,15 @@ 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 +manager_modem_enabled_changed (NMModem *device, + GParamSpec *pspec, + gpointer user_data) +{ + nm_manager_rfkill_update (NM_MANAGER (user_data), RFKILL_TYPE_WWAN); } static void @@ -1373,8 +1471,21 @@ 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_wifi_set_enabled (NM_DEVICE_WIFI (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); + } else if (NM_IS_MODEM (device)) { + g_signal_connect (device, "notify::" NM_MODEM_ENABLED, + G_CALLBACK (manager_modem_enabled_changed), + self); + + nm_manager_rfkill_update (self, RFKILL_TYPE_WWAN); + /* Until we start respecting WWAN rfkill switches the modem itself + * is the source of the enabled/disabled state, so the manager shouldn't + * touch it here. + nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device), + priv->radio_states[RFKILL_TYPE_WWAN].enabled); + */ } type_desc = nm_device_get_type_desc (device); @@ -1695,10 +1806,11 @@ udev_device_removed_cb (NMUdevManager *manager, static void udev_manager_rfkill_changed_cb (NMUdevManager *udev_mgr, + RfKillType rtype, RfKillState udev_state, gpointer user_data) { - nm_manager_rfkill_update (NM_MANAGER (user_data)); + nm_manager_rfkill_update (NM_MANAGER (user_data), rtype); } GSList * @@ -2554,18 +2666,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_wifi_set_enabled (NM_DEVICE_WIFI (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)) @@ -2699,30 +2816,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)) { - 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); @@ -2744,6 +2874,7 @@ nm_manager_get (const char *config_file, const char *state_file, gboolean initial_net_enabled, gboolean initial_wifi_enabled, + gboolean initial_wwan_enabled, GError **error) { static NMManager *singleton = NULL; @@ -2774,7 +2905,8 @@ 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; + priv->radio_states[RFKILL_TYPE_WWAN].enabled = initial_wwan_enabled; g_signal_connect (priv->sys_settings, "notify::" NM_SYSCONFIG_SETTINGS_UNMANAGED_SPECS, G_CALLBACK (system_unmanaged_devices_changed_cb), singleton); @@ -2891,9 +3023,19 @@ 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; + case PROP_WWAN_ENABLED: + manager_set_radio_enabled (NM_MANAGER (object), + &priv->radio_states[RFKILL_TYPE_WWAN], + g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -2914,10 +3056,16 @@ 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_WWAN_ENABLED: + g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WWAN].enabled); + break; + case PROP_WWAN_HARDWARE_ENABLED: + g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WWAN].hw_enabled); break; case PROP_ACTIVE_CONNECTIONS: g_value_take_boxed (value, get_active_connections (self, NULL)); @@ -2939,10 +3087,30 @@ 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; + + priv->radio_states[RFKILL_TYPE_WWAN].enabled = TRUE; + priv->radio_states[RFKILL_TYPE_WWAN].key = "WWANEnabled"; + priv->radio_states[RFKILL_TYPE_WWAN].prop = NM_MANAGER_WWAN_ENABLED; + priv->radio_states[RFKILL_TYPE_WWAN].hw_prop = NM_MANAGER_WWAN_HARDWARE_ENABLED; + priv->radio_states[RFKILL_TYPE_WWAN].desc = "WWAN"; + priv->radio_states[RFKILL_TYPE_WWAN].other_enabled_func = nm_manager_get_modem_enabled_state; + priv->radio_states[RFKILL_TYPE_WWAN].object_filter_func = rfkill_wwan_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; @@ -3034,6 +3202,22 @@ nm_manager_class_init (NMManagerClass *manager_class) TRUE, G_PARAM_READABLE)); + g_object_class_install_property + (object_class, PROP_WWAN_ENABLED, + g_param_spec_boolean (NM_MANAGER_WWAN_ENABLED, + "WwanEnabled", + "Is mobile broadband enabled", + TRUE, + G_PARAM_READWRITE)); + + g_object_class_install_property + (object_class, PROP_WWAN_HARDWARE_ENABLED, + g_param_spec_boolean (NM_MANAGER_WWAN_HARDWARE_ENABLED, + "WwanHardwareEnabled", + "Whether WWAN is disabled by a hardware switch or not", + TRUE, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_ACTIVE_CONNECTIONS, g_param_spec_boxed (NM_MANAGER_ACTIVE_CONNECTIONS, diff --git a/src/nm-manager.h b/src/nm-manager.h index a17323d42f..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" @@ -79,6 +74,7 @@ NMManager *nm_manager_get (const char *config_file, const char *state_file, gboolean initial_net_enabled, gboolean initial_wifi_enabled, + gboolean initial_wwan_enabled, GError **error); void nm_manager_start (NMManager *manager); diff --git a/src/nm-rfkill.h b/src/nm-rfkill.h index cc03e9e1fa..d3cd77744b 100644 --- a/src/nm-rfkill.h +++ b/src/nm-rfkill.h @@ -28,5 +28,18 @@ typedef enum { RFKILL_HARD_BLOCKED = 2 } RfKillState; +typedef enum { + RFKILL_TYPE_WLAN = 0, + RFKILL_TYPE_WWAN = 1, + RFKILL_TYPE_WIMAX = 2, + + /* UNKNOWN and MAX should always be 1 more than + * the last rfkill type since RFKILL_TYPE_MAX is + * used as an array size. + */ + RFKILL_TYPE_UNKNOWN = 3, /* KEEP LAST */ + RFKILL_TYPE_MAX = RFKILL_TYPE_UNKNOWN +} RfKillType; + #endif /* NM_RFKILL_H */ diff --git a/src/nm-udev-manager.c b/src/nm-udev-manager.c index be0825c6b3..956068de41 100644 --- a/src/nm-udev-manager.c +++ b/src/nm-udev-manager.c @@ -43,7 +43,7 @@ typedef struct { GUdevClient *client; /* Authoritative rfkill state (RFKILL_* enum) */ - RfKillState rfkill_state; + RfKillState rfkill_states[RFKILL_TYPE_MAX]; GSList *killswitches; gboolean disposed; @@ -69,19 +69,21 @@ typedef struct { guint64 seqnum; char *path; char *driver; + RfKillType rtype; gint state; } Killswitch; RfKillState -nm_udev_manager_get_rfkill_state (NMUdevManager *self) +nm_udev_manager_get_rfkill_state (NMUdevManager *self, RfKillType rtype) { g_return_val_if_fail (self != NULL, RFKILL_UNBLOCKED); + g_return_val_if_fail (rtype < RFKILL_TYPE_MAX, RFKILL_UNBLOCKED); - return NM_UDEV_MANAGER_GET_PRIVATE (self)->rfkill_state; + return NM_UDEV_MANAGER_GET_PRIVATE (self)->rfkill_states[rtype]; } static Killswitch * -killswitch_new (GUdevDevice *device) +killswitch_new (GUdevDevice *device, RfKillType rtype) { Killswitch *ks; GUdevDevice *parent = NULL; @@ -91,6 +93,7 @@ killswitch_new (GUdevDevice *device) ks->name = g_strdup (g_udev_device_get_name (device)); ks->seqnum = g_udev_device_get_seqnum (device); ks->path = g_strdup (g_udev_device_get_sysfs_path (device)); + ks->rtype = rtype; driver = g_udev_device_get_property (device, "DRIVER"); if (!driver) { @@ -147,7 +150,12 @@ recheck_killswitches (NMUdevManager *self) { NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self); GSList *iter; - RfKillState poll_state = RFKILL_UNBLOCKED; + RfKillState poll_states[RFKILL_TYPE_MAX]; + int i; + + /* Default state is unblocked */ + for (i = 0; i < RFKILL_TYPE_MAX; i++) + poll_states[i] = RFKILL_UNBLOCKED; for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) { Killswitch *ks = iter->data; @@ -159,15 +167,17 @@ recheck_killswitches (NMUdevManager *self) continue; dev_state = sysfs_state_to_nm_state (g_udev_device_get_property_as_int (device, "RFKILL_STATE")); - if (dev_state > poll_state) - poll_state = dev_state; + if (dev_state > poll_states[ks->rtype]) + poll_states[ks->rtype] = dev_state; g_object_unref (device); } - if (poll_state != priv->rfkill_state) { - priv->rfkill_state = poll_state; - g_signal_emit (self, signals[RFKILL_CHANGED], 0, priv->rfkill_state); + for (i = 0; i < RFKILL_TYPE_MAX; i++) { + if (poll_states[i] != priv->rfkill_states[i]) { + priv->rfkill_states[i] = poll_states[i]; + g_signal_emit (self, signals[RFKILL_CHANGED], 0, i, priv->rfkill_states[i]); + } } } @@ -188,21 +198,39 @@ killswitch_find_by_name (NMUdevManager *self, const char *name) return NULL; } +static const RfKillType +rfkill_type_to_enum (const char *str) +{ + g_return_val_if_fail (str != NULL, RFKILL_TYPE_UNKNOWN); + + if (!strcmp (str, "wlan")) + return RFKILL_TYPE_WLAN; + else if (!strcmp (str, "wwan")) + return RFKILL_TYPE_WWAN; + else if (!strcmp (str, "wimax")) + return RFKILL_TYPE_WIMAX; + + return RFKILL_TYPE_UNKNOWN; +} + static void add_one_killswitch (NMUdevManager *self, GUdevDevice *device) { NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self); - const char *type; + const char *str_type; + RfKillType rtype; Killswitch *ks; - type = g_udev_device_get_property (device, "RFKILL_TYPE"); - if (!type || strcmp (type, "wlan")) + str_type = g_udev_device_get_property (device, "RFKILL_TYPE"); + rtype = rfkill_type_to_enum (str_type); + if (rtype == RFKILL_TYPE_UNKNOWN) return; - ks = killswitch_new (device); + ks = killswitch_new (device, rtype); priv->killswitches = g_slist_prepend (priv->killswitches, ks); - nm_info ("Found radio killswitch %s (at %s) (driver %s)", + nm_info ("Found %s radio killswitch %s (at %s) (driver %s)", + str_type, ks->name, ks->path, ks->driver ? ks->driver : ""); @@ -422,8 +450,11 @@ nm_udev_manager_init (NMUdevManager *self) NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self); const char *subsys[3] = { "rfkill", "net", NULL }; GList *switches, *iter; + guint32 i; + + for (i = 0; i < RFKILL_TYPE_MAX; i++) + priv->rfkill_states[i] = RFKILL_UNBLOCKED; - priv->rfkill_state = RFKILL_UNBLOCKED; priv->client = g_udev_client_new (subsys); g_signal_connect (priv->client, "uevent", G_CALLBACK (handle_uevent), self); @@ -492,8 +523,7 @@ nm_udev_manager_class_init (NMUdevManagerClass *klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMUdevManagerClass, rfkill_changed), NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, - G_TYPE_UINT); + _nm_marshal_VOID__UINT_UINT, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); } diff --git a/src/nm-udev-manager.h b/src/nm-udev-manager.h index 61b60a40c3..06a2d35ce3 100644 --- a/src/nm-udev-manager.h +++ b/src/nm-udev-manager.h @@ -57,7 +57,7 @@ typedef struct { void (*device_removed) (NMUdevManager *manager, GUdevDevice *device); - void (*rfkill_changed) (NMUdevManager *manager, RfKillState state); + void (*rfkill_changed) (NMUdevManager *manager, RfKillType rtype, RfKillState state); } NMUdevManagerClass; GType nm_udev_manager_get_type (void); @@ -66,7 +66,7 @@ NMUdevManager *nm_udev_manager_new (void); void nm_udev_manager_query_devices (NMUdevManager *manager); -RfKillState nm_udev_manager_get_rfkill_state (NMUdevManager *manager); +RfKillState nm_udev_manager_get_rfkill_state (NMUdevManager *manager, RfKillType rtype); #endif /* NM_UDEV_MANAGER_H */ diff --git a/src/system-settings/nm-sysconfig-settings.c b/src/system-settings/nm-sysconfig-settings.c index 104eb008ab..7580319db0 100644 --- a/src/system-settings/nm-sysconfig-settings.c +++ b/src/system-settings/nm-sysconfig-settings.c @@ -254,6 +254,7 @@ nm_sysconfig_settings_get_hostname (NMSysconfigSettings *self) NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); GSList *iter; char *hostname = NULL; + gboolean have_hostname_providers = FALSE; /* Hostname returned is the hostname returned from the first plugin * that provides one. @@ -263,6 +264,8 @@ nm_sysconfig_settings_get_hostname (NMSysconfigSettings *self) g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) { + have_hostname_providers = TRUE; + g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, &hostname, NULL); if (hostname && strlen (hostname)) return hostname; @@ -271,7 +274,7 @@ nm_sysconfig_settings_get_hostname (NMSysconfigSettings *self) } /* If no plugin provided a hostname, try the original hostname of the machine */ - if (priv->orig_hostname) + if (!have_hostname_providers && priv->orig_hostname) hostname = g_strdup (priv->orig_hostname); return hostname;