2008-03-07 Dan Williams <dcbw@redhat.com>

First pass of multiple active device support.  Expect bugs.

	* src/nm-ip4-config.c
	  src/nm-ip4-config.h
		- (nm_ip4_config_get_secondary, nm_ip4_config_set_secondary): remove;
			there are better ways to do this in the named manager

	* src/nm-device.c
	  src/nm-device.h
		- (nm_device_can_activate): return whether the device can activate a
			connection right now; taking into account things like carrier state
			and rfkill state
		- (nm_device_get_best_auto_connection): renamed from
			nm_device_get_best_connection
		- (real_act_stage4_get_ip4_config): MTU stuff is now handled in the
			device subclasses themselves, so that each device can override the
			MTU from it's NMSetting subclass if needed
		- (nm_device_set_ip4_config): set MTU when setting up routes and stuff
			in NetworkManagerSystem.c, not here

	* src/named-manager/nm-named-manager.c
	  src/named-manager/nm-named-manager.h
		- (nm_named_manager_name_owner_changed,
		   nm_named_manager_dbus_connection_changed): fix for changes to
			rewrite_resolv_conf()
		- (compute_nameservers): don't need the NMNamedManager at all, remove
			from parameter list
		- (merge_one_ip4_config): new function; merge ip4 configs together
		- (rewrite_resolv_conf): write out resolv.conf from all the stored
			ip4 configs; the VPN config takes precedence, then the best
			device config, then the rest of the configs
		- (get_domain_for_config): take the NMNamedManager as an argument
			to check whether the config is the VPN config
		- (add_ip4_config_to_named): fixups for removal of the 'secondary'
			attribute from ip4 configs
		- (add_all_ip4_configs_to_named): add all the configs in priority order
		- (remove_ip4_config_from_named): fix for changes to
			get_domain_for_config()
		- (nm_named_manager_add_ip4_config): assign the config to the right slot
			based on its type; callers must pass in the type now
		- (get_last_default_domain): remove, unused
		- (nm_named_manager_remove_ip4_config): handle config slots correctly

	* src/nm-device-802-11-wireless.c
		- (real_can_activate): new function
		- (real_get_best_auto_connection): renamed from real_get_best_connection
		- (real_act_stage4_get_ip4_config): handle MTU override

	* src/nm-device-802-3-ethernet.c
		- (real_can_activate): new function
		- (real_get_best_auto_connection): renamed from real_get_best_connection
		- (real_act_stage4_get_ip4_config): new function; handle MTU override

	* src/vpn-manager/nm-vpn-connection.c
		- (nm_vpn_connection_ip4_config_get): don't need to set the 'secondary'
			attribute on the ip4 config

	* src/NetworkManagerPolicy.c
		- (nm_policy_auto_get_best_device): remove
		- (nm_policy_device_change_check): remove
		- (update_default_route): new function; set the default route via
			the specified device
		- (get_device_priority): new function; return the priority number of
			a device type WRT which one should have the default route.  Order is
			(highest to lowest)  wired, wireless, GSM, CDMA.
		- (update_routing_and_dns): new function; determine which device should
			have the default route, then update the routing table and DNS
		- (maybe_auto_activate_device): new function; if a device is now
			available for activation, find out what connection it would like to
			activate and do it
		- (schedule_activate_check): new function; if a device can be activated
			now, schedule the activation.  Each device may have only one
			pending activation at a given time.
		- (device_state_changed): if activation was canceled, try again,
			possibly with another connection; if the device was activated,
			update routing and DNS; if the device was deactivated, try again
			with another connection
		- (device_carrier_changed): if there is no carrier, deactivate the
			device; otherwise schedule an activation check for the device
		- (wireless_networks_changed): schedule an activation check for the
			device
		- (device_added): keep track of the signal handler IDs so they can
			be removed when the device goes away
		- (device_removed): remove any signal handlers that might be attached
			to the device; update routing and DNS
		- (schedule_activate_all): new function
		- (connections_added, connection_added, connection_updated): when
			connections change, schedule all devices for an activation check
		- (connection_removed): when a device is deactivated because its
			connection was removed, schedule another activation check for it
		- (nm_policy_destroy): destroy pending activations and disconnect
			all device signal handlers

	* src/nm-manager.c
		- (nm_manager_activate_device): if the device was already actived,
			deactivate it
		- (deactivate_old_device): remove
		- (connection_added_default_handler, impl_manager_activate_device):
			don't deactivate other devices when activating this one

	* src/backends/NetworkManagerGentoo.c
	  src/backends/NetworkManagerFrugalware.c
	  src/backends/NetworkManagerPaldo.c
	  src/backends/NetworkManagerRedHat.c
	  src/backends/NetworkManagerSlackware.c
	  src/backends/NetworkManagerArch.c
	  src/backends/NetworkManagerSuSE.c
	  src/backends/NetworkManagerDebian.c
		- (nm_system_get_mtu): remove; MTU should be provided through the
			distro's system settings service plugin instead
		- (nm_system_device_add_default_route_via_device): remove
		- (nm_system_device_add_default_route_via_device_with_iface): remove
		- (nm_system_device_replace_default_route): new function; call
			generic implementation

	* src/backends/NetworkManagerGeneric.c
	  src/backends/NetworkManagerGeneric.h
		- (nm_generic_device_add_default_route_via_device,
		   nm_generic_device_add_default_route_via_device_with_iface): remove
		- (nm_generic_device_replace_default_route): replace the default route
			with the given route via some gateway

	* src/NetworkManagerSystem.c
	  src/NetworkManagerSystem.h
		- (nm_system_device_set_from_ip4_config): let the policy handle updates
			to routing and DNS; but set the MTU here
		- (nm_system_vpn_device_set_from_ip4_config): set the route with the
			ip_iface of the active device; use the standard MTU setting function
		- (nm_system_set_mtu): remove
		- (nm_system_device_set_mtu): consolidate MTU setting code in one place



git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3391 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Dan Williams
2008-03-07 19:41:32 +00:00
parent d84a51a145
commit 3fec481414
25 changed files with 819 additions and 968 deletions

View File

@@ -35,22 +35,28 @@
#include "nm-activation-request.h"
#include "nm-utils.h"
#include "nm-device-interface.h"
#include "nm-device.h"
#include "nm-device-802-11-wireless.h"
#include "nm-device-802-3-ethernet.h"
#include "nm-gsm-device.h"
#include "nm-cdma-device.h"
#include "nm-dbus-manager.h"
#include "nm-setting-connection.h"
#include "NetworkManagerSystem.h"
#include "nm-named-manager.h"
struct NMPolicy {
NMManager *manager;
guint update_state_id;
GSList *pending_activation_checks;
GSList *signal_ids;
GSList *dev_signal_ids;
NMDevice *default_device;
};
#define INVALID_TAG "invalid"
static void schedule_change_check (NMPolicy *policy);
static const char *
get_connection_id (NMConnection *connection)
{
@@ -64,362 +70,149 @@ get_connection_id (NMConnection *connection)
return s_con->id;
}
/*
* nm_policy_auto_get_best_device
*
* Find the best device to use, regardless of whether we are
* "locked" on one device at this time.
*
*/
static NMDevice *
nm_policy_auto_get_best_device (NMPolicy *policy,
NMConnection **connection,
char **specific_object)
static void
update_default_route (NMPolicy *policy, NMDevice *new)
{
GSList *connections;
GSList * elt;
NMDevice8023Ethernet * best_wired_dev = NULL;
guint best_wired_prio = 0;
NMConnection * best_wired_connection = NULL;
char * best_wired_specific_object = NULL;
NMDevice80211Wireless * best_wireless_dev = NULL;
guint best_wireless_prio = 0;
NMConnection * best_wireless_connection = NULL;
char * best_wireless_specific_object = NULL;
NMDevice * highest_priority_dev = NULL;
const char *ip_iface;
g_return_val_if_fail (connection != NULL, NULL);
g_return_val_if_fail (*connection == NULL, NULL);
g_return_val_if_fail (specific_object != NULL, NULL);
g_return_val_if_fail (*specific_object == NULL, NULL);
/* FIXME: Not sure if the following makes any sense. */
/* If iface and ip_iface are the same, it's a regular network device and we
treat it as such. However, if they differ, it's most likely something like
a serial device with ppp interface, so route all the traffic to it. */
ip_iface = nm_device_get_ip_iface (new);
if (strcmp (ip_iface, nm_device_get_iface (new))) {
nm_system_device_replace_default_route (ip_iface, 0, 0);
} else {
NMIP4Config *config;
if (nm_manager_get_state (policy->manager) == NM_STATE_ASLEEP)
return NULL;
config = nm_device_get_ip4_config (new);
nm_system_device_replace_default_route (ip_iface, nm_ip4_config_get_gateway (config),
nm_ip4_config_get_mss (config));
}
}
static guint32
get_device_priority (NMDevice *dev)
{
if (NM_IS_CDMA_DEVICE (dev))
return 2;
if (NM_IS_GSM_DEVICE (dev))
return 3;
if (NM_IS_DEVICE_802_11_WIRELESS (dev))
return 4;
if (NM_IS_DEVICE_802_3_ETHERNET (dev))
return 5;
return 1;
}
static void
update_routing_and_dns (NMPolicy *policy)
{
NMDevice *best = NULL;
guint32 best_prio = 0;
GSList *devices, *iter;
NMNamedManager *named_mgr;
NMIP4Config *config;
devices = nm_manager_get_devices (policy->manager);
for (iter = devices; iter; iter = g_slist_next (iter)) {
NMDevice *dev = NM_DEVICE (iter->data);
guint32 prio;
if (nm_device_get_state (dev) != NM_DEVICE_STATE_ACTIVATED)
continue;
prio = get_device_priority (dev);
if (prio > best_prio) {
best = dev;
best_prio = prio;
}
}
if (!best)
goto out;
update_default_route (policy, best);
named_mgr = nm_named_manager_get ();
config = nm_device_get_ip4_config (best);
nm_named_manager_add_ip4_config (named_mgr, config, NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE);
g_object_unref (named_mgr);
out:
policy->default_device = best;
}
typedef struct {
NMPolicy *policy;
NMDevice *device;
guint id;
} ActivateData;
static gboolean
auto_activate_device (gpointer user_data)
{
ActivateData *data = (ActivateData *) user_data;
NMPolicy *policy;
NMConnection *best_connection;
char *specific_object = NULL;
GSList *connections, *iter;
g_assert (data);
policy = data->policy;
/* System connections first, then user connections */
connections = nm_manager_get_connections (policy->manager, NM_CONNECTION_SCOPE_SYSTEM);
connections = g_slist_concat (connections, nm_manager_get_connections (policy->manager, NM_CONNECTION_SCOPE_USER));
/* Remove connections that are in the invalid list. */
elt = connections;
while (elt) {
NMConnection *iter_connection = NM_CONNECTION (elt->data);
GSList *next = g_slist_next (elt);
iter = connections;
while (iter) {
NMConnection *iter_connection = NM_CONNECTION (iter->data);
GSList *next = g_slist_next (iter);
if (g_object_get_data (G_OBJECT (iter_connection), INVALID_TAG)) {
connections = g_slist_remove_link (connections, elt);
connections = g_slist_remove_link (connections, iter);
g_object_unref (iter_connection);
g_slist_free (elt);
g_slist_free (iter);
}
elt = next;
iter = next;
}
for (elt = nm_manager_get_devices (policy->manager); elt; elt = elt->next) {
NMConnection *tmp_con = NULL;
char *tmp_obj = NULL;
gboolean carrier;
guint prio = 0;
NMDevice * dev = (NMDevice *)(elt->data);
guint32 caps;
best_connection = nm_device_get_best_auto_connection (data->device, connections, &specific_object);
if (best_connection) {
GError *error = NULL;
carrier = nm_device_get_carrier (dev);
caps = nm_device_get_capabilities (dev);
tmp_con = nm_device_get_best_connection (dev, connections, &tmp_obj);
if (tmp_con == NULL) {
NMActRequest *req = nm_device_get_act_request (dev);
/* If the device is activating, the NMConnection it's got is the
* best one. In other words, follow activation of a particular
* NMConnection through to success/failure rather than cutting it
* off if it becomes invalid
*/
tmp_con = req ? nm_act_request_get_connection (req) : NULL;
if (!tmp_con)
continue;
}
if (NM_IS_DEVICE_802_3_ETHERNET (dev)) {
if (carrier)
prio += 1;
if (nm_device_get_act_request (dev) && carrier)
prio += 1;
if (prio > best_wired_prio) {
best_wired_dev = NM_DEVICE_802_3_ETHERNET (dev);
best_wired_prio = prio;
best_wired_connection = tmp_con;
best_wired_specific_object = tmp_obj;
}
} else if ( NM_IS_DEVICE_802_11_WIRELESS (dev)
&& nm_manager_wireless_enabled (policy->manager)) {
/* Bump by 1 so that _something_ gets chosen every time */
prio += 1;
if (carrier)
prio += 1;
if (nm_device_get_act_request (dev) && carrier)
prio += 3;
if (prio > best_wireless_prio) {
best_wireless_dev = NM_DEVICE_802_11_WIRELESS (dev);
best_wireless_prio = prio;
best_wireless_connection = tmp_con;
best_wireless_specific_object = tmp_obj;
}
if (!nm_manager_activate_device (policy->manager,
data->device,
best_connection,
specific_object,
FALSE,
&error)) {
nm_warning ("Failed to automatically activate device %s: (%d) %s",
nm_device_get_iface (data->device),
error->code,
error->message);
g_error_free (error);
}
}
if (best_wired_dev) {
highest_priority_dev = NM_DEVICE (best_wired_dev);
*connection = g_object_ref (best_wired_connection);
*specific_object = best_wired_specific_object;
} else if (best_wireless_dev) {
gboolean can_activate;
/* Remove this call's handler ID */
policy->pending_activation_checks = g_slist_remove (policy->pending_activation_checks, data);
can_activate = nm_device_802_11_wireless_can_activate (best_wireless_dev);
if (can_activate) {
highest_priority_dev = NM_DEVICE (best_wireless_dev);
*connection = g_object_ref (best_wireless_connection);
*specific_object = best_wireless_specific_object;
}
}
g_object_unref (data->device);
g_slist_foreach (connections, (GFunc) g_object_unref, NULL);
g_slist_free (connections);
if (FALSE) {
nm_info ("AUTO: Best wired device = %s, best wireless device = %s, best connection name = '%s'",
best_wired_dev ? nm_device_get_iface (NM_DEVICE (best_wired_dev)) : "(null)",
best_wireless_dev ? nm_device_get_iface (NM_DEVICE (best_wireless_dev)) : "(null)",
*connection ? get_connection_id (*connection) : "(none)");
}
return *connection ? highest_priority_dev : NULL;
}
/*
* nm_policy_device_change_check
*
* Figures out which interface to switch the active
* network connection to if our global network state has changed.
* Global network state changes are triggered by:
* 1) insertion/deletion of interfaces
* 2) link state change of an interface
* 3) wireless network topology changes
*
*/
static gboolean
nm_policy_device_change_check (gpointer user_data)
{
NMPolicy *policy = (NMPolicy *) user_data;
GSList *iter;
guint32 caps;
NMConnection *connection = NULL;
NMConnection *old_connection = NULL;
NMActRequest *old_act_req = NULL;
char * specific_object = NULL;
NMDevice * new_dev = NULL;
NMDevice * old_dev = NULL;
gboolean do_switch = FALSE;
policy->update_state_id = 0;
switch (nm_manager_get_state (policy->manager)) {
case NM_STATE_CONNECTED:
old_dev = nm_manager_get_active_device (policy->manager);
/* Don't touch devices that are not upped/downed automatically */
if (!NM_IS_DEVICE_802_3_ETHERNET (old_dev) && !NM_IS_DEVICE_802_11_WIRELESS (old_dev))
goto out;
caps = nm_device_get_capabilities (old_dev);
/* Don't interrupt semi-supported devices. If the user chose
* one, they must explicitly choose to move to another device, we're not
* going to move for them.
*/
if ((NM_IS_DEVICE_802_3_ETHERNET (old_dev) && !(caps & NM_DEVICE_CAP_CARRIER_DETECT))) {
nm_info ("Old device '%s' was semi-supported and user chosen, won't"
" change unless told to.",
nm_device_get_iface (old_dev));
goto out;
}
break;
case NM_STATE_CONNECTING:
for (iter = nm_manager_get_devices (policy->manager); iter; iter = iter->next) {
NMDevice *d = NM_DEVICE (iter->data);
if (nm_device_is_activating (d)) {
if (nm_device_can_interrupt_activation (d)) {
old_dev = d;
break;
} else
goto out;
}
}
break;
case NM_STATE_DISCONNECTED:
if (nm_manager_activation_pending (policy->manager)) {
nm_info ("There is a pending activation, won't change.");
goto out;
}
break;
default:
break;
}
new_dev = nm_policy_auto_get_best_device (policy, &connection, &specific_object);
if (old_dev) {
old_act_req = nm_device_get_act_request (old_dev);
if (old_act_req)
old_connection = nm_act_request_get_connection (old_act_req);
}
/* Four cases here:
*
* 1) old device is NULL, new device is NULL - we aren't currently connected to anything, and we
* can't find anything to connect to. Do nothing.
*
* 2) old device is NULL, new device is good - we aren't currently connected to anything, but
* we have something we can connect to. Connect to it.
*
* 3) old device is good, new device is NULL - have a current connection, but it's no good since
* auto device picking didn't come up with the save device. Terminate current connection.
*
* 4) old device is good, new device is good - have a current connection, and auto device picking
* came up with a device too. More considerations:
* a) different devices? activate new device
* b) same device, different access points? activate new device
* c) same device, same access point? do nothing
*/
if (!old_dev && !new_dev) {
; /* Do nothing, wait for something like link-state to change, or an access point to be found */
} else if (!old_dev && new_dev) {
/* Activate new device */
nm_info ("SWITCH: no current connection, found better connection '%s (%s)'.",
connection ? get_connection_id (connection) : "(none)",
nm_device_get_iface (new_dev));
do_switch = TRUE;
} else if (old_dev && !new_dev) {
/* Terminate current connection */
nm_info ("SWITCH: terminating current connection '%s (%s)' because it's"
" no longer valid.",
old_connection ? get_connection_id (old_connection) : "(none)",
nm_device_get_iface (old_dev));
do_switch = TRUE;
} else if (old_dev && new_dev) {
gboolean old_user_requested = nm_act_request_get_user_requested (old_act_req);
gboolean old_carrier = nm_device_get_carrier (old_dev);
/* If an old device is active or being activated (and has an active link),
* and its connection is a system connection, and the best connection is
* a user connection, don't switch.
*/
if ( old_connection
&& (nm_connection_get_scope (old_connection) == NM_CONNECTION_SCOPE_SYSTEM)
&& (nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_USER)
&& old_carrier)
goto out;
if ( (nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_SYSTEM)
&& (nm_connection_get_scope (old_connection) == NM_CONNECTION_SCOPE_USER)) {
do_switch = TRUE;
nm_info ("SWITCH: found system connection '%s (%s)', overrides"
" current connection '%s (%s)'.",
connection ? get_connection_id (connection) : "(none)",
nm_device_get_iface (new_dev),
old_connection ? get_connection_id (old_connection) : "(none)",
nm_device_get_iface (old_dev));
goto do_switch;
}
if (NM_IS_DEVICE_802_3_ETHERNET (old_dev)) {
/* Only switch if the old device was not user requested, and we are switching to
* a new device. Note that new_dev will never be wireless since automatic device picking
* above will prefer a wired device to a wireless device.
*/
if ((!old_user_requested || !old_carrier) && (new_dev != old_dev)) {
nm_info ("SWITCH: found better connection '%s (%s)' than "
" current connection '%s (%s)'.",
connection ? get_connection_id (connection) : "(none)",
nm_device_get_iface (new_dev),
old_connection ? get_connection_id (old_connection) : "(none)",
nm_device_get_iface (old_dev));
do_switch = TRUE;
}
} else if (NM_IS_DEVICE_802_11_WIRELESS (old_dev)) {
/* Only switch if the old device's wireless config is invalid */
if (NM_IS_DEVICE_802_11_WIRELESS (new_dev)) {
NMAccessPoint *old_ap = nm_device_802_11_wireless_get_activation_ap (NM_DEVICE_802_11_WIRELESS (old_dev));
int old_mode = nm_ap_get_mode (old_ap);
gboolean same_activating = FALSE;
/* Don't interrupt activation of a wireless device by
* trying to auto-activate any connection on that device.
*/
if (old_dev == new_dev && nm_device_is_activating (new_dev))
same_activating = TRUE;
if (!same_activating && !old_carrier && (old_mode != IW_MODE_ADHOC)) {
NMSettingConnection * new_sc = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
NMSettingConnection * old_sc = (NMSettingConnection *) nm_connection_get_setting (old_connection, NM_TYPE_SETTING_CONNECTION);
nm_info ("SWITCH: found better connection '%s/%s'"
" than current connection '%s/%s'. "
"have_link=%d",
nm_device_get_iface (new_dev),
new_sc->id,
nm_device_get_iface (old_dev),
old_sc->id,
old_carrier);
do_switch = TRUE;
}
} else if (NM_IS_DEVICE_802_3_ETHERNET (new_dev)) {
/* Always prefer Ethernet over wireless, unless the user explicitly switched away. */
if (!old_user_requested)
do_switch = TRUE;
}
}
}
do_switch:
if (do_switch) {
// FIXME: remove old_dev deactivation when multiple device support lands
if (old_dev)
nm_device_interface_deactivate (NM_DEVICE_INTERFACE (old_dev));
if (new_dev) {
GError *error = NULL;
gboolean success;
success = nm_manager_activate_device (policy->manager,
new_dev,
connection,
specific_object,
FALSE,
&error);
if (!success) {
nm_warning ("Failed to automatically activate device %s: (%d) %s",
nm_device_get_iface (new_dev),
error->code,
error->message);
g_error_free (error);
}
}
}
out:
if (connection)
g_object_unref (connection);
g_free (data);
return FALSE;
}
/*****************************************************************************/
static void
@@ -430,13 +223,41 @@ global_state_changed (NMManager *manager, NMState state, gpointer user_data)
}
static void
schedule_change_check (NMPolicy *policy)
schedule_activate_check (NMPolicy *policy, NMDevice *device)
{
if (policy->update_state_id > 0)
ActivateData *data;
GSList *iter;
gboolean wireless_enabled;
if (nm_manager_get_state (policy->manager) == NM_STATE_ASLEEP)
return;
policy->update_state_id = g_idle_add (nm_policy_device_change_check,
policy);
// FIXME: kind of a hack, but devices don't have access to the manager
// object directly
wireless_enabled = nm_manager_wireless_enabled (policy->manager);
if (!nm_device_can_activate (device, wireless_enabled))
return;
// FIXME: if a device is already activating (or activated) with a connection
// but another connection now overrides the current one for that device,
// deactivate the device and activate the new connection instead of just
// bailing if the device is already active
if (nm_device_get_act_request (device))
return;
for (iter = policy->pending_activation_checks; iter; iter = g_slist_next (iter)) {
/* Only one pending activation check at a time */
if (((ActivateData *) iter->data)->device == device)
return;
}
data = g_malloc0 (sizeof (ActivateData));
g_return_if_fail (data != NULL);
data->policy = policy;
data->device = g_object_ref (device);
data->id = g_idle_add (auto_activate_device, data);
policy->pending_activation_checks = g_slist_append (policy->pending_activation_checks, data);
}
static NMConnection *
@@ -458,69 +279,126 @@ device_state_changed (NMDevice *device, NMDeviceState state, gpointer user_data)
NMConnection *connection = get_device_connection (device);
if ((state == NM_DEVICE_STATE_FAILED) || (state == NM_DEVICE_STATE_CANCELLED)) {
schedule_change_check (policy);
/* Mark the connection invalid so it doesn't get automatically chosen */
if (connection) {
g_object_set_data (G_OBJECT (connection), INVALID_TAG, GUINT_TO_POINTER (TRUE));
nm_info ("Marking connection '%s' invalid.", get_connection_id (connection));
}
if (state == NM_DEVICE_STATE_CANCELLED)
schedule_activate_check (policy, device);
} else if (state == NM_DEVICE_STATE_ACTIVATED) {
/* Clear the invalid tag on the connection */
if (connection)
g_object_set_data (G_OBJECT (connection), INVALID_TAG, NULL);
update_routing_and_dns (policy);
} else if (state == NM_DEVICE_STATE_DISCONNECTED) {
schedule_change_check (policy);
update_routing_and_dns (policy);
schedule_activate_check (policy, device);
}
}
static void
device_carrier_changed (NMDevice *device, gboolean carrier_on, gpointer user_data)
device_carrier_changed (NMDevice *device, gboolean carrier, gpointer user_data)
{
NMPolicy *policy = (NMPolicy *) user_data;
schedule_change_check (policy);
if (!carrier) {
if (NM_IS_DEVICE_802_3_ETHERNET (device))
nm_device_interface_deactivate (NM_DEVICE_INTERFACE (device));
} else {
schedule_activate_check ((NMPolicy *) user_data, device);
}
}
static void
wireless_networks_changed (NMDevice80211Wireless *device, NMAccessPoint *ap, gpointer user_data)
{
NMPolicy *policy = (NMPolicy *) user_data;
schedule_activate_check ((NMPolicy *) user_data, NM_DEVICE (device));
}
schedule_change_check (policy);
typedef struct {
gulong id;
NMDevice *device;
} DeviceSignalID;
static GSList *
add_device_signal_id (GSList *list, gulong id, NMDevice *device)
{
DeviceSignalID *data;
data = g_malloc0 (sizeof (DeviceSignalID));
if (!data)
return list;
data->id = id;
data->device = device;
return g_slist_append (list, data);
}
static void
device_added (NMManager *manager, NMDevice *device, gpointer user_data)
{
NMPolicy *policy = (NMPolicy *) user_data;
gulong id;
g_signal_connect (device, "state-changed",
G_CALLBACK (device_state_changed),
policy);
id = g_signal_connect (device, "state-changed",
G_CALLBACK (device_state_changed),
policy);
policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device);
g_signal_connect (device, "carrier-changed",
G_CALLBACK (device_carrier_changed),
policy);
id = g_signal_connect (device, "carrier-changed",
G_CALLBACK (device_carrier_changed),
policy);
policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device);
if (NM_IS_DEVICE_802_11_WIRELESS (device)) {
g_signal_connect (device, "access-point-added",
G_CALLBACK (wireless_networks_changed),
policy);
g_signal_connect (device, "access-point-removed",
G_CALLBACK (wireless_networks_changed),
policy);
id = g_signal_connect (device, "access-point-added",
G_CALLBACK (wireless_networks_changed),
policy);
policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device);
id = g_signal_connect (device, "access-point-removed",
G_CALLBACK (wireless_networks_changed),
policy);
policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device);
}
schedule_change_check (policy);
schedule_activate_check (policy, device);
}
static void
device_removed (NMManager *manager, NMDevice *device, gpointer user_data)
{
NMPolicy *policy = (NMPolicy *) user_data;
GSList *iter = policy->dev_signal_ids;
schedule_change_check (policy);
/* Clear any signal handlers for this device */
while (iter) {
DeviceSignalID *data = (DeviceSignalID *) iter->data;
GSList *next = g_slist_next (iter);
if (data->device == device) {
policy->dev_signal_ids = g_slist_remove_link (policy->dev_signal_ids, iter);
g_signal_handler_disconnect (data->device, data->id);
g_free (data);
g_slist_free (iter);
}
iter = next;
}
update_routing_and_dns (policy);
}
static void
schedule_activate_all (NMPolicy *policy)
{
GSList *iter, *devices;
devices = nm_manager_get_devices (policy->manager);
for (iter = devices; iter; iter = g_slist_next (iter))
schedule_activate_check (policy, NM_DEVICE (iter->data));
}
static void
@@ -528,9 +406,7 @@ connections_added (NMManager *manager,
NMConnectionScope scope,
gpointer user_data)
{
NMPolicy *policy = (NMPolicy *) user_data;
schedule_change_check (policy);
schedule_activate_all ((NMPolicy *) user_data);
}
static void
@@ -539,9 +415,7 @@ connection_added (NMManager *manager,
NMConnectionScope scope,
gpointer user_data)
{
NMPolicy *policy = (NMPolicy *) user_data;
schedule_change_check (policy);
schedule_activate_all ((NMPolicy *) user_data);
}
static void
@@ -550,12 +424,10 @@ connection_updated (NMManager *manager,
NMConnectionScope scope,
gpointer user_data)
{
NMPolicy *policy = (NMPolicy *) user_data;
/* Clear the invalid tag on the connection if it got updated. */
g_object_set_data (G_OBJECT (connection), INVALID_TAG, NULL);
schedule_change_check (policy);
schedule_activate_all ((NMPolicy *) user_data);
}
static void
@@ -564,12 +436,11 @@ connection_removed (NMManager *manager,
NMConnectionScope scope,
gpointer user_data)
{
NMPolicy *policy = (NMPolicy *) user_data;
GSList *iter;
/* If the connection just removed was active, deactive it */
for (iter = nm_manager_get_devices (manager); iter; iter = g_slist_next (iter)) {
NMDevice *device = (NMDevice *) iter->data;
NMDevice *device = NM_DEVICE (iter->data);
NMActRequest *req = nm_device_get_act_request (device);
NMConnection *dev_connection;
@@ -577,11 +448,11 @@ connection_removed (NMManager *manager,
continue;
dev_connection = nm_act_request_get_connection (req);
if (dev_connection == connection)
if (dev_connection == connection) {
nm_device_interface_deactivate (NM_DEVICE_INTERFACE (device));
schedule_activate_check ((NMPolicy *) user_data, device);
}
}
schedule_change_check (policy);
}
NMPolicy *
@@ -640,15 +511,27 @@ nm_policy_destroy (NMPolicy *policy)
g_return_if_fail (policy != NULL);
if (policy->update_state_id) {
g_source_remove (policy->update_state_id);
policy->update_state_id = 0;
for (iter = policy->pending_activation_checks; iter; iter = g_slist_next (iter)) {
ActivateData *data = (ActivateData *) iter->data;
g_source_remove (data->id);
g_object_unref (data->device);
g_free (data);
}
g_slist_free (policy->pending_activation_checks);
for (iter = policy->signal_ids; iter; iter = g_slist_next (iter))
g_signal_handler_disconnect (policy->manager, (gulong) iter->data);
g_slist_free (policy->signal_ids);
for (iter = policy->dev_signal_ids; iter; iter = g_slist_next (iter)) {
DeviceSignalID *data = (DeviceSignalID *) iter->data;
g_signal_handler_disconnect (data->device, data->id);
g_free (data);
}
g_slist_free (policy->dev_signal_ids);
g_object_unref (policy->manager);
g_free (policy);
}