diff options
Diffstat (limited to 'src/nm-manager.c')
| -rw-r--r-- | src/nm-manager.c | 208 |
1 files changed, 180 insertions, 28 deletions
diff --git a/src/nm-manager.c b/src/nm-manager.c index fbc9d23d..3dc60d85 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -165,6 +165,8 @@ static GSList * remove_one_device (NMManager *manager, NMDevice *device, gboolean quitting); +static void rfkill_change_wifi (const char *desc, gboolean enabled); + #define SSD_POKE_INTERVAL 120 #define ORIGDEV_TAG "originating-device" @@ -244,6 +246,8 @@ typedef struct { guint timestamp_update_id; + GHashTable *nm_bridges; + gboolean disposed; } NMManagerPrivate; @@ -1130,6 +1134,92 @@ get_virtual_iface_placeholder_udi (void) return g_strdup_printf ("/virtual/device/placeholder/%d", id++); } +/***************************/ + +/* FIXME: remove when we handle bridges non-destructively */ + +#define NM_BRIDGE_FILE NMRUNDIR "/nm-bridges" + +static void +read_nm_created_bridges (NMManager *self) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + char *contents; + char **lines, **iter; + GTimeVal tv; + glong ts; + + if (!g_file_get_contents (NM_BRIDGE_FILE, &contents, NULL, NULL)) + return; + + g_get_current_time (&tv); + + lines = g_strsplit_set (contents, "\n", 0); + g_free (contents); + + for (iter = lines; iter && *iter; iter++) { + if (g_str_has_prefix (*iter, "ts=")) { + errno = 0; + ts = strtol (*iter + 3, NULL, 10); + /* allow 30 minutes time difference before we ignore the file */ + if (errno || ABS (tv.tv_sec - ts) > 1800) + goto out; + } else if (g_str_has_prefix (*iter, "iface=")) + g_hash_table_insert (priv->nm_bridges, g_strdup (*iter + 6), GUINT_TO_POINTER (1)); + } + +out: + g_strfreev (lines); + unlink (NM_BRIDGE_FILE); +} + +static void +write_nm_created_bridges (NMManager *self) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + GString *br_list; + GSList *iter; + GError *error = NULL; + GTimeVal tv; + gboolean found = FALSE; + + /* write out nm-created bridges list */ + br_list = g_string_sized_new (50); + + /* Timestamp is first line */ + g_get_current_time (&tv); + g_string_append_printf (br_list, "ts=%ld\n", tv.tv_sec); + + for (iter = priv->devices; iter; iter = g_slist_next (iter)) { + NMDevice *device = iter->data; + + if (nm_device_get_device_type (device) == NM_DEVICE_TYPE_BRIDGE) { + g_string_append_printf (br_list, "iface=%s\n", nm_device_get_iface (device)); + found = TRUE; + } + } + + if (found) { + if (!g_file_set_contents (NM_BRIDGE_FILE, br_list->str, -1, &error)) { + nm_log_warn (LOGD_BRIDGE, "Failed to write NetworkManager-created bridge list; " + "on restart bridges may not be recognized. (%s)", + error ? error->message : "unknown"); + g_clear_error (&error); + } + } + g_string_free (br_list, TRUE); +} + +static gboolean +bridge_created_by_nm (NMManager *self, const char *iface) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + + return (priv->nm_bridges && g_hash_table_lookup (priv->nm_bridges, iface)); +} + +/***************************/ + /** * system_create_virtual_device: * @self: the #NMManager @@ -1179,12 +1269,21 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) device = nm_device_bond_new (udi, iface); g_free (udi); } else if (nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)) { - if (!nm_system_create_bridge (iface)) { + gboolean exists = FALSE; + + if (!nm_system_create_bridge (iface, &exists)) { nm_log_warn (LOGD_DEVICE, "(%s): failed to add bridging interface for '%s'", iface, nm_connection_get_id (connection)); goto out; } + /* FIXME: remove when we handle bridges non-destructively */ + if (exists && !bridge_created_by_nm (self, iface)) { + nm_log_warn (LOGD_DEVICE, "(%s): cannot use existing bridge for '%s'", + iface, nm_connection_get_id (connection)); + goto out; + } + udi = get_virtual_iface_placeholder_udi (); device = nm_device_bridge_new (udi, iface); g_free (udi); @@ -2175,9 +2274,14 @@ udev_device_added_cb (NMUdevManager *udev_mgr, device = nm_device_infiniband_new (sysfs_path, iface, driver); else if (is_bond (ifindex)) device = nm_device_bond_new (sysfs_path, iface); - else if (is_bridge (ifindex)) - device = nm_device_bridge_new (sysfs_path, iface); - else if (is_vlan (ifindex)) { + else if (is_bridge (ifindex)) { + + /* FIXME: always create device when we handle bridges non-destructively */ + if (bridge_created_by_nm (self, iface)) + device = nm_device_bridge_new (sysfs_path, iface); + else + nm_log_info (LOGD_BRIDGE, "(%s): ignoring bridge not created by NetworkManager", iface); + } else if (is_vlan (ifindex)) { int parent_ifindex = -1; NMDevice *parent; @@ -2215,23 +2319,32 @@ udev_device_removed_cb (NMUdevManager *manager, NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDevice *device; guint32 ifindex; - const char *iface = g_udev_device_get_name (udev_device); - - /* Ignore PPP interfaces as they are the IP interface of a device, - * but they come and go when the device gets activated or deactivated. - * We don't want their transient nature to affect their master device. - */ - if (strncmp (iface, "ppp", 3) == 0) - return; ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX"); device = find_device_by_ifindex (self, ifindex); if (!device) { - /* On removal we won't always be able to read properties anymore, as - * they may have already been removed from sysfs. Instead, we just - * have to fall back to the device's interface name. + GSList *iter; + const char *iface = g_udev_device_get_name (udev_device); + + /* On removal we aren't always be able to read properties like IFINDEX + * anymore, as they may have already been removed from sysfs. So we + * have to fall back on device name (eg, interface name). + * + * Also, some devices (namely PPPoE (pppX), ADSL (nasX, pppX), and + * mobile broadband (pppX, bnepX)) create a kernel netdevice for IP + * communication (called the "IP interface" in NM) as part of the + * connection process and thus the IP interface lifetime does not + * correspond to the NMDevice lifetime. For these devices we must + * ignore removal events for the IP interface name otherwise the + * NMDevice would be removed. Hence the usage here of + * nm_device_get_iface() rather than nm_device_get_ip_iface(). */ - device = find_device_by_ip_iface (self, iface); + 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) @@ -2529,6 +2642,8 @@ ensure_master_active_connection (NMManager *self, nm_device_get_path (master_device), dbus_sender, error); + if (!master_ac) + g_prefix_error (error, "%s", "Master device activation failed: "); g_slist_free (connections); return master_ac; } @@ -2569,24 +2684,30 @@ ensure_master_active_connection (NMManager *self, if (master_state != NM_DEVICE_STATE_DISCONNECTED) continue; - return nm_manager_activate_connection (self, - master_connection, - NULL, - nm_device_get_path (candidate), - dbus_sender, - error); + master_ac = nm_manager_activate_connection (self, + master_connection, + NULL, + nm_device_get_path (candidate), + dbus_sender, + error); + if (!master_ac) + g_prefix_error (error, "%s", "Master device activation failed: "); + return master_ac; } /* Device described by master_connection may be a virtual one that's * not created yet. */ if (!found_device && connection_needs_virtual_device (master_connection)) { - return nm_manager_activate_connection (self, - master_connection, - NULL, - NULL, - dbus_sender, - error); + master_ac = nm_manager_activate_connection (self, + master_connection, + NULL, + NULL, + dbus_sender, + error); + if (!master_ac) + g_prefix_error (error, "%s", "Master device activation failed: "); + return master_ac; } g_set_error (error, @@ -2774,6 +2895,16 @@ nm_manager_activate_connection (NMManager *manager, return NULL; } + /* If this is an autoconnect request, but the device isn't allowing autoconnect + * right now, we reject it. + */ + if (!dbus_sender && !nm_device_autoconnect_allowed (device)) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED, + "%s does not allow automatic connections at this time", + nm_device_get_iface (device)); + return NULL; + } + /* Try to find the master connection/device if the connection has a dependency */ if (!find_master (manager, connection, device, &master_connection, &master_device)) { g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, @@ -3621,6 +3752,13 @@ nm_manager_start (NMManager *self) system_unmanaged_devices_changed_cb (priv->settings, NULL, self); system_hostname_changed_cb (priv->settings, NULL, self); + /* FIXME: remove when we handle bridges non-destructively */ + /* Read a list of bridges NM managed when it last quit, and only + * manage those bridges to avoid conflicts with external tools. + */ + priv->nm_bridges = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + read_nm_created_bridges (self); + nm_udev_manager_query_devices (priv->udev_mgr); nm_bluez_manager_query_devices (priv->bluez_mgr); @@ -3637,6 +3775,10 @@ nm_manager_start (NMManager *self) * connection-added signals thus devices have to be created manually. */ system_create_virtual_devices (self); + + /* FIXME: remove when we handle bridges non-destructively */ + g_hash_table_unref (priv->nm_bridges); + priv->nm_bridges = NULL; } static gboolean @@ -4016,6 +4158,12 @@ nm_manager_new (NMSettings *settings, 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. + */ + rfkill_change_wifi (priv->radio_states[RFKILL_TYPE_WLAN].desc, initial_wifi_enabled); + return singleton; } @@ -4046,6 +4194,10 @@ dispose (GObject *object) nm_auth_changed_func_unregister (authority_changed_cb, manager); + /* FIXME: remove when we handle bridges non-destructively */ + write_nm_created_bridges (manager); + + /* Remove all devices */ while (g_slist_length (priv->devices)) { priv->devices = remove_one_device (manager, priv->devices, |