1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
From: Michael Biebl <biebl@debian.org>
Date: Wed, 2 Apr 2014 03:15:53 +0200
Subject: Force online state with unmanaged devices
If we have unmanaged devices in /e/n/i, monitor the ifupdown state file
and in case we find active interfaces besides lo, forcefully set the
online state to CONNECTED.
Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=512286
---
src/core/nm-manager.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 115 insertions(+)
diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c
index a861b2f..e42bed5 100644
--- a/src/core/nm-manager.c
+++ b/src/core/nm-manager.c
@@ -53,6 +53,8 @@
#define DEVICE_STATE_PRUNE_RATELIMIT_MAX 100u
+#define IFUPDOWN_STATE_FILE "/run/network/ifstate"
+
/*****************************************************************************/
typedef struct {
@@ -228,6 +230,10 @@ typedef struct {
GFileMonitor *fw_monitor;
guint fw_changed_id;
+ /* ifupdown state file monitor */
+ GFileMonitor *ifstate_monitor;
+ gboolean ifstate_force_online;
+
guint timestamp_update_id;
guint devices_inited_id;
@@ -2040,6 +2046,27 @@ find_best_device_state(NMManager *manager)
return best_state;
}
+static NMState
+find_unmanaged_state(NMManager *self, NMState current_state)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
+ NMState new_state = current_state;
+ NMDevice *device;
+
+ c_list_for_each_entry(device, &priv->devices_lst_head, devices_lst) {
+ NMDeviceState state = nm_device_get_state(device);
+
+ if (state == NM_DEVICE_STATE_UNMANAGED) {
+ const char *iface = nm_device_get_ip_iface(device);
+ if (priv->ifstate_force_online) {
+ new_state = NM_STATE_CONNECTED_GLOBAL;
+ nm_log_dbg(LOGD_CORE, "Unmanaged device found: %s; state CONNECTED forced.", iface);
+ }
+ }
+ }
+ return new_state;
+}
+
static void
nm_manager_update_metered(NMManager *self)
{
@@ -2086,6 +2113,9 @@ nm_manager_update_state(NMManager *self)
else
new_state = find_best_device_state(self);
+ if (new_state != NM_STATE_CONNECTED_GLOBAL)
+ new_state = find_unmanaged_state(self, new_state);
+
if (new_state >= NM_STATE_CONNECTED_LOCAL && priv->connectivity_state == NM_CONNECTIVITY_FULL) {
new_state = NM_STATE_CONNECTED_GLOBAL;
}
@@ -7821,6 +7851,62 @@ impl_manager_get_logging(NMDBusObject *obj,
g_variant_new("(ss)", nm_logging_level_to_string(), nm_logging_domains_to_string()));
}
+static void
+check_ifstate_file(gpointer user_data)
+{
+ NMManager *self = NM_MANAGER(user_data);
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
+ GIOChannel *channel;
+ gchar *line;
+ gboolean online = FALSE;
+
+ channel = g_io_channel_new_file(IFUPDOWN_STATE_FILE, "r", NULL);
+ if (!channel) {
+ nm_log_info(LOGD_CORE, "failed to open %s", IFUPDOWN_STATE_FILE);
+ return;
+ }
+
+ while (g_io_channel_read_line(channel, &line, NULL, NULL, NULL)
+ != G_IO_STATUS_EOF && !online) {
+ g_strstrip(line);
+ if (strlen(line) > 0 && g_strcmp0(line, "lo=lo") != 0) {
+ online = TRUE;
+ }
+ g_free(line);
+ }
+
+ g_io_channel_shutdown(channel, FALSE, NULL);
+ g_io_channel_unref(channel);
+
+ if (priv->ifstate_force_online != online) {
+ priv->ifstate_force_online = online;
+ nm_manager_update_state(self);
+ }
+}
+
+static void
+ifstate_file_changed(GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ gpointer user_data)
+{
+ switch (event_type) {
+// case G_FILE_MONITOR_EVENT_CREATED:
+//#if GLIB_CHECK_VERSION(2,23,4)
+// case G_FILE_MONITOR_EVENT_MOVED:
+//#endif
+// case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
+ case G_FILE_MONITOR_EVENT_CHANGED:
+ case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+ nm_log_dbg(LOGD_CORE, "ifupdown state file %s was changed", IFUPDOWN_STATE_FILE);
+ check_ifstate_file(user_data);
+ break;
+ default:
+ break;
+ }
+}
+
typedef struct {
NMManager *self;
GDBusMethodInvocation *context;
@@ -8125,6 +8211,9 @@ nm_manager_start(NMManager *self, GError **error)
nm_clear_g_source(&priv->devices_inited_id);
priv->devices_inited_id = g_idle_add_full(G_PRIORITY_LOW + 10, devices_inited_cb, self, NULL);
+ /* Trigger ifupdown state file check */
+ check_ifstate_file(self);
+
return TRUE;
}
@@ -9010,6 +9099,22 @@ nm_manager_init(NMManager *self)
_LOGW(LOGD_CORE, "failed to monitor kernel firmware directory '%s'.", KERNEL_FIRMWARE_DIR);
}
+ /* Monitor the ifupdown state file */
+ file = g_file_new_for_path(IFUPDOWN_STATE_FILE);
+ priv->ifstate_monitor = g_file_monitor_file(file, G_FILE_MONITOR_NONE, NULL, NULL);
+ g_object_unref(file);
+
+ if (priv->ifstate_monitor) {
+ g_signal_connect(priv->ifstate_monitor, "changed",
+ G_CALLBACK(ifstate_file_changed),
+ self);
+ nm_log_info(LOGD_CORE, "monitoring ifupdown state file '%s'.",
+ IFUPDOWN_STATE_FILE);
+ } else {
+ nm_log_warn(LOGD_CORE, "failed to monitor ifupdown state file '%s'.",
+ IFUPDOWN_STATE_FILE);
+ }
+
priv->metered = NM_METERED_UNKNOWN;
priv->sleep_devices = g_hash_table_new(nm_direct_hash, NULL);
}
@@ -9301,6 +9406,16 @@ dispose(GObject *object)
g_clear_object(&priv->fw_monitor);
}
+ if (priv->ifstate_monitor) {
+ g_signal_handlers_disconnect_by_func(priv->ifstate_monitor, ifstate_file_changed, self);
+
+ if (priv->ifstate_force_online)
+ g_source_remove(priv->ifstate_force_online);
+
+ g_file_monitor_cancel(priv->ifstate_monitor);
+ g_clear_object(&priv->ifstate_monitor);
+ }
+
if (priv->rfkill_mgr) {
g_signal_handlers_disconnect_by_func(priv->rfkill_mgr,
rfkill_manager_rfkill_changed_cb,
|