NetworkManager r4167 - in trunk: . src src/vpn-manager



Author: dcbw
Date: Fri Oct 10 23:05:45 2008
New Revision: 4167
URL: http://svn.gnome.org/viewvc/NetworkManager?rev=4167&view=rev

Log:
2008-10-10  Dan Williams  <dcbw redhat com>

	Rework default route handling to consolidate decisions in the policy,
	and to take active VPN connections into account when changing the default
	route (bgo #545912)

	* src/NetworkManager.c
		- (main): pass the vpn_manager to the policy so it knows about active
			VPN connections; clean up the named manager which wasn't done before

	* src/NetworkManagerPolicy.c
	  src/NetworkManagerPolicy.h
		- (nm_policy_new): get a clue about the vpn_manager
		- (update_default_route): remove, fold into update_routing_and_dns()
		- (update_routing_and_dns): handle active VPN connections too; an
			active VPN connection becomes the default route if it does not have
			server-specified or user-specified custom routes.  Otherwise, the
			best active device gets the default route
		- (vpn_connection_activated, vpn_connection_deactivated, nm_policy_new,
		   nm_policy_destroy): track VPN connection activation and deactivation
			and update the default route when appropriate

	* src/NetworkManagerSystem.c
	  src/NetworkManagerSystem.h
		- (nm_system_vpn_device_unset_from_ip4_config): remove, put functionality
			in the VPN connection itself
		- (nm_system_vpn_device_set_from_ip4_config,
		   nm_system_device_set_from_ip4_config): merge together to make
			nm_system_apply_ip4_config()
		- (add_vpn_gateway_route): add a route to the VPN's external gateway
			via the parent device
		- (nm_system_apply_ip4_config): simplify
		- (add_ip4_route_to_gateway): new function; add a direct route to the
			gateway if needed
		- (nm_system_device_replace_default_ip4_route): simplify, break gateway
			route stuff out into add_ip4_route_to_gateway() for clarity

	* src/nm-device.c
		- (nm_device_set_ip4_config): update for nm_system_apply_ip4_config()

	* src/vpn-manager/nm-vpn-connection.c
	  src/vpn-manager/nm-vpn-connection.h
		- (nm_vpn_connection_get_ip4_config, nm_vpn_connection_get_ip_iface,
		   nm_vpn_connection_get_parent_device): add
		- (nm_vpn_connection_ip4_config_get): make the requirement of a tunnel
			device explicit
		- (connection_state_changed): update the named manager now that
			nm_system_vpn_device_unset_from_ip4_config() is gone; do something
			useful on errors

	* src/vpn-manager/nm-vpn-manager.c
	  src/vpn-manager/nm-vpn-manager.h
		- Add a 'connection-activated' signal
		- (nm_vpn_manager_get_active_connections): new function; mainly for the
			policy to find out about active VPN connections



Modified:
   trunk/ChangeLog
   trunk/src/NetworkManager.c
   trunk/src/NetworkManagerPolicy.c
   trunk/src/NetworkManagerPolicy.h
   trunk/src/NetworkManagerSystem.c
   trunk/src/NetworkManagerSystem.h
   trunk/src/nm-device.c
   trunk/src/vpn-manager/nm-vpn-connection.c
   trunk/src/vpn-manager/nm-vpn-connection.h
   trunk/src/vpn-manager/nm-vpn-manager.c
   trunk/src/vpn-manager/nm-vpn-manager.h

Modified: trunk/src/NetworkManager.c
==============================================================================
--- trunk/src/NetworkManager.c	(original)
+++ trunk/src/NetworkManager.c	Fri Oct 10 23:05:45 2008
@@ -308,7 +308,7 @@
 		goto done;
 	}
 
-	policy = nm_policy_new (manager);
+	policy = nm_policy_new (manager, vpn_manager);
 	if (policy == NULL) {
 		nm_error ("Failed to initialize the policy.");
 		goto done;
@@ -352,6 +352,9 @@
 	if (vpn_manager)
 		g_object_unref (vpn_manager);
 
+	if (named_mgr)
+		g_object_unref (named_mgr);
+
 	if (sup_mgr)
 		g_object_unref (sup_mgr);
 

Modified: trunk/src/NetworkManagerPolicy.c
==============================================================================
--- trunk/src/NetworkManagerPolicy.c	(original)
+++ trunk/src/NetworkManagerPolicy.c	Fri Oct 10 23:05:45 2008
@@ -43,6 +43,7 @@
 #include "nm-setting-connection.h"
 #include "NetworkManagerSystem.h"
 #include "nm-named-manager.h"
+#include "nm-vpn-manager.h"
 
 typedef struct LookupThread LookupThread;
 
@@ -69,6 +70,10 @@
 	GSList *signal_ids;
 	GSList *dev_signal_ids;
 
+	NMVPNManager *vpn_manager;
+	gulong vpn_activated_id;
+	gulong vpn_deactivated_id;
+
 	NMDevice *default_device;
 
 	LookupThread *lookup;
@@ -462,34 +467,21 @@
 }
 
 static void
-update_default_route (NMPolicy *policy, NMDevice *new)
-{
-	const char *ip_iface;
-
-	/* 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_ip4_route (ip_iface, 0, 0);
-	} else {
-		NMIP4Config *config;
-		const NMSettingIP4Address *def_addr;
-
-		config = nm_device_get_ip4_config (new);
-		def_addr = nm_ip4_config_get_address (config, 0);
-		nm_system_device_replace_default_ip4_route (ip_iface, def_addr->gateway, nm_ip4_config_get_mss (config));
-	}
-}
-
-static void
 update_routing_and_dns (NMPolicy *policy, gboolean force_update)
 {
+	NMNamedIPConfigType dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
 	NMDevice *best = NULL;
 	NMActRequest *best_req = NULL;
 	NMNamedManager *named_mgr;
-	GSList *devices = NULL, *iter;
+	GSList *devices = NULL, *iter, *vpns;
+	NMIP4Config *ip4_config = NULL;
+	const char *ip_iface = NULL;
+	const char *parent_iface = NULL;
+	NMVPNConnection *vpn = NULL;
+	NMConnection *connection = NULL;
+	NMSettingConnection *s_con = NULL;
+	guint32 parent_mss = 0;
+	guint32 gateway = 0;
 
 	best = get_best_device (policy->manager, &best_req);
 	if (!best)
@@ -497,8 +489,69 @@
 	if (!force_update && (best == policy->default_device))
 		goto out;
 
-	update_default_route (policy, best);
-	
+	/* If a VPN connection is active, it is preferred */
+	vpns = nm_vpn_manager_get_active_connections (policy->vpn_manager);
+	for (iter = vpns; iter; iter = g_slist_next (iter)) {
+		NMVPNConnection *candidate = NM_VPN_CONNECTION (iter->data);
+
+		if (!vpn && (nm_vpn_connection_get_vpn_state (candidate) == NM_VPN_CONNECTION_STATE_ACTIVATED))
+			vpn = g_object_ref (candidate);
+		g_object_unref (candidate);
+	}
+	g_slist_free (vpns);
+
+	/* VPNs are the default route only if they don't have custom routes */
+	if (vpn) {
+		NMIP4Config *vpn_config;
+
+		vpn_config = nm_vpn_connection_get_ip4_config (vpn);
+		if (nm_ip4_config_get_num_routes (vpn_config) == 0) {
+			NMIP4Config *parent_ip4;
+			NMDevice *parent;
+
+			connection = nm_vpn_connection_get_connection (vpn);
+			ip_iface = nm_vpn_connection_get_ip_iface (vpn);
+			ip4_config = vpn_config;
+
+			parent = nm_vpn_connection_get_parent_device (vpn);
+			parent_iface = nm_device_get_ip_iface (parent);
+			parent_ip4 = nm_device_get_ip4_config (parent);
+			if (parent_ip4)
+				parent_mss = nm_ip4_config_get_mss (parent_ip4);
+
+			dns_type = NM_NAMED_IP_CONFIG_TYPE_VPN;
+		}
+		g_object_unref (vpn);
+	}
+
+	/* The best device gets the default route if a VPN connection didn't */
+	if (!ip_iface || !ip4_config) {
+		const NMSettingIP4Address *addr;
+
+		connection = nm_act_request_get_connection (best_req);
+		ip_iface = nm_device_get_ip_iface (best);
+		ip4_config = nm_device_get_ip4_config (best);
+		if (ip4_config) {
+			addr = nm_ip4_config_get_address (ip4_config, 0);
+			gateway = addr->gateway;
+		}
+
+		dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
+	}
+
+	if (!ip_iface || !ip4_config) {
+		nm_warning ("%s: couldn't determine IP interface (%p) or IPv4 config (%p)!",
+		            __func__, ip_iface, ip4_config);
+		goto out;
+	}
+
+	/* Set the new default route */
+	nm_system_device_replace_default_ip4_route (ip_iface,
+	                                            gateway,
+	                                            nm_ip4_config_get_mss (ip4_config),
+	                                            parent_iface,
+	                                            parent_mss);
+
 	/* Update the default active connection.  Only mark the new default
 	 * active connection after setting default = FALSE on all other connections
 	 * first.  The order is important, we don't want two connections marked
@@ -515,10 +568,7 @@
 	}
 
 	named_mgr = nm_named_manager_get ();
-	nm_named_manager_add_ip4_config (named_mgr,
-									 nm_device_get_ip_iface (best),
-									 nm_device_get_ip4_config (best),
-									 NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE);
+	nm_named_manager_add_ip4_config (named_mgr, ip_iface, ip4_config, dns_type);
 	g_object_unref (named_mgr);
 
 	/* Now set new default active connection _after_ updating DNS info, so that
@@ -527,8 +577,13 @@
 	if (best_req)
 		nm_act_request_set_default (best_req, TRUE);
 
-	nm_info ("Policy set (%s) as default device for routing and DNS.",
-	         nm_device_get_iface (best));
+	if (connection)
+		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+
+	if (s_con && s_con->id)
+		nm_info ("Policy set '%s' (%s) as default for routing and DNS.", s_con->id, ip_iface);
+	else
+		nm_info ("Policy set (%s) as default for routing and DNS.", ip_iface);
 
 out:
 	/* Update the system hostname */
@@ -618,6 +673,24 @@
 /*****************************************************************************/
 
 static void
+vpn_connection_activated (NMVPNManager *manager,
+                          NMVPNConnection *vpn,
+                          gpointer user_data)
+{
+	update_routing_and_dns ((NMPolicy *) user_data, TRUE);
+}
+
+static void
+vpn_connection_deactivated (NMVPNManager *manager,
+                            NMVPNConnection *vpn,
+                            NMVPNConnectionState state,
+                            NMVPNConnectionStateReason reason,
+                            gpointer user_data)
+{
+	update_routing_and_dns ((NMPolicy *) user_data, TRUE);
+}
+
+static void
 global_state_changed (NMManager *manager, NMState state, gpointer user_data)
 {
 }
@@ -868,7 +941,7 @@
 }
 
 NMPolicy *
-nm_policy_new (NMManager *manager)
+nm_policy_new (NMManager *manager, NMVPNManager *vpn_manager)
 {
 	NMPolicy *policy;
 	static gboolean initialized = FALSE;
@@ -881,6 +954,14 @@
 	policy->manager = g_object_ref (manager);
 	policy->update_state_id = 0;
 
+	policy->vpn_manager = g_object_ref (vpn_manager);
+	id = g_signal_connect (policy->vpn_manager, "connection-activated",
+	                       G_CALLBACK (vpn_connection_activated), policy);
+	policy->vpn_activated_id = id;
+	id = g_signal_connect (policy->vpn_manager, "connection-deactivated",
+	                       G_CALLBACK (vpn_connection_deactivated), policy);
+	policy->vpn_deactivated_id = id;
+
 	id = g_signal_connect (manager, "state-changed",
 	                       G_CALLBACK (global_state_changed), policy);
 	policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id);
@@ -944,6 +1025,9 @@
 	}
 	g_slist_free (policy->pending_activation_checks);
 
+	g_signal_handler_disconnect (policy->vpn_manager, policy->vpn_activated_id);
+	g_signal_handler_disconnect (policy->vpn_manager, policy->vpn_deactivated_id);
+
 	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);

Modified: trunk/src/NetworkManagerPolicy.h
==============================================================================
--- trunk/src/NetworkManagerPolicy.h	(original)
+++ trunk/src/NetworkManagerPolicy.h	Fri Oct 10 23:05:45 2008
@@ -24,12 +24,13 @@
 
 #include "NetworkManager.h"
 #include "nm-manager.h"
+#include "nm-vpn-manager.h"
 #include "nm-device.h"
 #include "nm-activation-request.h"
 
 typedef struct NMPolicy NMPolicy;
 
-NMPolicy *nm_policy_new (NMManager *manager);
+NMPolicy *nm_policy_new (NMManager *manager, NMVPNManager *vpn_manager);
 void nm_policy_destroy (NMPolicy *policy);
 
 #endif /* NETWORK_MANAGER_POLICY_H */

Modified: trunk/src/NetworkManagerSystem.c
==============================================================================
--- trunk/src/NetworkManagerSystem.c	(original)
+++ trunk/src/NetworkManagerSystem.c	Fri Oct 10 23:05:45 2008
@@ -273,114 +273,75 @@
 	return TRUE;
 }
 
-/*
- * nm_system_device_set_from_ip4_config
- *
- * Set IPv4 configuration of the device from an NMIP4Config object.
- *
- */
-gboolean
-nm_system_device_set_from_ip4_config (const char *iface,
-							   NMIP4Config *config,
-							   int priority)
+static void
+add_vpn_gateway_route (NMDevice *device, const char *iface, NMIP4Config *config)
 {
-	int len, i;
-
-	g_return_val_if_fail (iface != NULL, FALSE);
-	g_return_val_if_fail (config != NULL, FALSE);
-
-	if (!add_ip4_addresses (config, iface))
-		return FALSE;
+	NMIP4Config *ad_config;
+	guint32 ad_gw = 0, vpn_gw = 0, i;
+	const NMSettingIP4Address *tmp;
 
-	sleep (1);
+	g_return_if_fail (NM_IS_DEVICE (device));
 
-	len = nm_ip4_config_get_num_routes (config);
-	for (i = 0; i < len; i++) {
-		const NMSettingIP4Route *route = nm_ip4_config_get_route (config, i);
+	ad_config = nm_device_get_ip4_config (device);
+	g_return_if_fail (ad_config != NULL);
 
-		nm_system_device_set_ip4_route (iface, config, 
-								  route->address,
-								  route->prefix,
-								  route->next_hop,
-								  route->metric,
-								  nm_ip4_config_get_mss (config));
+	/* Set up a route to the VPN gateway's public IP address through the default
+	 * network device.
+	 */
+	for (i = 0; i < nm_ip4_config_get_num_addresses (ad_config); i++) {
+		tmp = nm_ip4_config_get_address (ad_config, i);
+		if (tmp->gateway) {
+			ad_gw = tmp->gateway;
+			break;
+		}
 	}
 
-	if (nm_ip4_config_get_mtu (config))
-		nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config));
+	if (!ad_gw)
+		return;
 
-	if (priority > 0)
-		nm_system_device_set_priority (iface, config, priority);
+	for (i = 0; i < nm_ip4_config_get_num_addresses (config); i++) {
+		tmp = nm_ip4_config_get_address (config, i);
+		if (tmp->gateway) {
+			vpn_gw = tmp->gateway;
+			break;
+		}
+	}
 
-	return TRUE;
+	nm_system_device_set_ip4_route (nm_device_get_ip_iface (device),
+	                                ad_config, vpn_gw, 32, ad_gw, 0,
+	                                nm_ip4_config_get_mss (ad_config));
 }
 
 /*
- * nm_system_vpn_device_set_from_ip4_config
+ * nm_system_apply_ip4_config
  *
- * Set IPv4 configuration of a VPN device from an NMIP4Config object.
+ * Set IPv4 configuration of the device from an NMIP4Config object.
  *
  */
 gboolean
-nm_system_vpn_device_set_from_ip4_config (NMDevice *active_device,
-                                          const char *iface,
-                                          NMIP4Config *config)
+nm_system_apply_ip4_config (NMDevice *device,
+                            const char *iface,
+                            NMIP4Config *config,
+                            int priority,
+                            gboolean is_vpn)
 {
-	NMIP4Config *ad_config = NULL;
-	NMNamedManager *named_mgr;
-	int num;
 	int i;
 
+	g_return_val_if_fail (iface != NULL, FALSE);
 	g_return_val_if_fail (config != NULL, FALSE);
 
-	/* Set up a route to the VPN gateway through the real network device */
-	if (active_device && (ad_config = nm_device_get_ip4_config (active_device))) {
-		guint32 ad_gw = 0, vpn_gw = 0;
-		const NMSettingIP4Address *tmp;
-
-		num = nm_ip4_config_get_num_addresses (ad_config);
-		for (i = 0; i < num; i++) {
-			tmp = nm_ip4_config_get_address (ad_config, i);
-			if (tmp->gateway) {
-				ad_gw = tmp->gateway;
-				break;
-			}
-		}
-
-		if (ad_gw) {
-			num = nm_ip4_config_get_num_addresses (config);
-			for (i = 0; i < num; i++) {
-				tmp = nm_ip4_config_get_address (config, i);
-				if (tmp->gateway) {
-					vpn_gw = tmp->gateway;
-					break;
-				}
-			}
-
-			nm_system_device_set_ip4_route (nm_device_get_ip_iface (active_device),
-									  ad_config, vpn_gw, 32, ad_gw, 0,
-									  nm_ip4_config_get_mss (config));
-		}
-	}
-
-	if (!iface || !strlen (iface))
-		goto out;
-
-	nm_system_device_set_up_down_with_iface (iface, TRUE, NULL);
-
 	if (!add_ip4_addresses (config, iface))
-		goto out;
+		return FALSE;
 
-	/* Set the MTU */
-	if (nm_ip4_config_get_mtu (config))
-		nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config));
+	if (is_vpn)
+		add_vpn_gateway_route (device, iface, config);
 
-	/* Set routes */
-	num = nm_ip4_config_get_num_routes (config);
-	for (i = 0; i < num; i++) {
+	sleep (1);
+
+	for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) {
 		const NMSettingIP4Route *route = nm_ip4_config_get_route (config, i);
 
-		nm_system_device_set_ip4_route (iface, config,
+		nm_system_device_set_ip4_route (iface, config, 
 								  route->address,
 								  route->prefix,
 								  route->next_hop,
@@ -388,39 +349,15 @@
 								  nm_ip4_config_get_mss (config));
 	}
 
-	if (num == 0)
-		nm_system_device_replace_default_ip4_route (iface, 0, 0);
-
-out:
-	named_mgr = nm_named_manager_get ();
-	nm_named_manager_add_ip4_config (named_mgr, iface, config, NM_NAMED_IP_CONFIG_TYPE_VPN);
-	g_object_unref (named_mgr);
-
-	return TRUE;
-}
-
-
-/*
- * nm_system_vpn_device_unset_from_ip4_config
- *
- * Unset an IPv4 configuration of a VPN device from an NMIP4Config object.
- *
- */
-gboolean nm_system_vpn_device_unset_from_ip4_config (NMDevice *active_device, const char *iface, NMIP4Config *config)
-{
-	NMNamedManager *named_mgr;
-
-	g_return_val_if_fail (active_device != NULL, FALSE);
-	g_return_val_if_fail (config != NULL, FALSE);
+	if (nm_ip4_config_get_mtu (config))
+		nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config));
 
-	named_mgr = nm_named_manager_get ();
-	nm_named_manager_remove_ip4_config (named_mgr, iface, config);
-	g_object_unref (named_mgr);
+	if (priority > 0)
+		nm_system_device_set_priority (iface, config, priority);
 
 	return TRUE;
 }
 
-
 /*
  * nm_system_device_set_up_down
  *
@@ -547,6 +484,55 @@
 	return success;
 }
 
+static struct rtnl_route *
+add_ip4_route_to_gateway (const char *iface, guint32 gw, guint32 mss)
+{
+	struct nl_handle *nlh;
+	struct rtnl_route *route = NULL;
+	struct nl_addr *gw_addr = NULL;
+	int iface_idx, err;
+
+	nlh = nm_netlink_get_default_handle ();
+	g_return_val_if_fail (nlh != NULL, NULL);
+
+	iface_idx = nm_netlink_iface_to_index (iface);
+	if (iface_idx < 0)
+		return NULL;
+
+	/* Gateway might be over a bridge; try adding a route to gateway first */
+	route = rtnl_route_alloc ();
+	if (route == NULL)
+		return NULL;
+
+	rtnl_route_set_oif (route, iface_idx);
+	rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
+
+	gw_addr = nl_addr_build (AF_INET, &gw, sizeof (gw));
+	if (!gw_addr)
+		goto error;
+	rtnl_route_set_dst (route, gw_addr);
+	nl_addr_put (gw_addr);
+
+	if (mss) {
+		if (rtnl_route_set_metric (route, RTAX_ADVMSS, mss) < 0)
+			goto error;
+	}
+
+	/* Add direct route to the gateway */
+	err = rtnl_route_add (nlh, route, 0);
+	if (err) {
+		nm_warning ("Failed to add IPv4 default route on '%s': (%d) %s",
+		            iface, err, nl_geterror ());
+		goto error;
+	}
+
+	return route;
+
+error:
+	rtnl_route_put (route);
+	return NULL;
+}
+
 /*
  * nm_system_replace_default_ip4_route
  *
@@ -554,32 +540,35 @@
  *
  */
 void
-nm_system_device_replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss)
+nm_system_device_replace_default_ip4_route (const char *iface,
+                                            guint32 gw,
+                                            guint32 mss,
+                                            const char *parent_iface,
+                                            guint32 parent_mss)
 {
-	struct rtnl_route * route;
-	struct rtnl_route * route2 = NULL;
-	struct nl_handle  * nlh;
-	struct nl_addr    * gw_addr;
+	struct rtnl_route *route = NULL;
+	struct rtnl_route *gw_route = NULL;
+	struct nl_handle *nlh;
+	struct nl_addr *gw_addr = NULL;
 	int iface_idx, err;
+	gboolean success = FALSE;
 
 	nlh = nm_netlink_get_default_handle ();
 	g_return_if_fail (nlh != NULL);
 
+	iface_idx = nm_netlink_iface_to_index (iface);
+	if (iface_idx < 0)
+		return;
+
 	route = rtnl_route_alloc();
 	g_return_if_fail (route != NULL);
 
 	rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
-
-	iface_idx = nm_netlink_iface_to_index (iface);
-	if (iface_idx < 0)
-		goto out;
 	rtnl_route_set_oif (route, iface_idx);
 
-	/* Build up gateway address; a gateway of 0 (used in e.g. PPP links) means
-	 * that all packets should be sent to the gateway since it's a point-to-point
-	 * link and has no broadcast segment really.
-	 */
-	if (!(gw_addr = nl_addr_build (AF_INET, &gw, sizeof (gw))))
+	/* Build up the gateway address */
+	gw_addr = nl_addr_build (AF_INET, &gw, sizeof (gw));
+	if (!gw_addr)
 		goto out;
 	rtnl_route_set_gateway (route, gw_addr);
 	nl_addr_put (gw_addr);
@@ -589,9 +578,11 @@
 			goto out;
 	}
 
+	/* Add the new default route */
 	err = rtnl_route_add (nlh, route, NLM_F_REPLACE);
 	if (err == 0) {
 		/* Everything good */
+		success = TRUE;
 		goto out;
 	} else if (err != -ESRCH) {
 		nm_warning ("rtnl_route_add() returned error %s (%d)\n%s",
@@ -599,41 +590,26 @@
 		goto out;
 	}
 
-	/* Gateway might be over a bridge; try adding a route to gateway first */
-	route2 = rtnl_route_alloc ();
-	if (route2 == NULL)
+	/* Try adding a direct route to the gateway first */
+	gw_route = add_ip4_route_to_gateway (parent_iface ? parent_iface : iface,
+	                                     gw,
+	                                     parent_iface ? parent_mss : mss);
+	if (!gw_route)
 		goto out;
-	rtnl_route_set_oif (route2, iface_idx);
-	rtnl_route_set_dst (route2, gw_addr);
-
-	if (mss) {
-		if (rtnl_route_set_metric (route2, RTAX_ADVMSS, mss) < 0)
-			goto out;
-	}
 
-	/* Add route to gateway over bridge */
-	err = rtnl_route_add (nlh, route2, 0);
-	if (err) {
-		nm_warning ("Failed to add IPv4 default route on '%s': %s",
-				  iface,
-				  nl_geterror ());
-		goto out;
-	}
-
-	/* Try adding the route again */
-	err = rtnl_route_add (nlh, route, 0);
-	if (err) {
-		rtnl_route_del (nlh, route2, 0);
-		nm_warning ("Failed to set IPv4 default route on '%s': %s",
-				  iface,
-				  nl_geterror ());
+	/* Try adding the original route again */
+	err = rtnl_route_add (nlh, route, NLM_F_REPLACE);
+	if (err != 0) {
+		rtnl_route_del (nlh, gw_route, 0);
+		nm_warning ("Failed to set IPv4 default route on '%s': %s", iface, nl_geterror ());
 	}
 
 out:
-	if (route2)
-		rtnl_route_put (route2);
+	if (gw_route)
+		rtnl_route_put (gw_route);
 
-	rtnl_route_put (route);
+	if (route)
+		rtnl_route_put (route);
 }
 
 /*

Modified: trunk/src/NetworkManagerSystem.h
==============================================================================
--- trunk/src/NetworkManagerSystem.h	(original)
+++ trunk/src/NetworkManagerSystem.h	Fri Oct 10 23:05:45 2008
@@ -1,5 +1,4 @@
-/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
-
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 /* NetworkManager -- Network link manager
  *
  * Dan Williams <dcbw redhat com>
@@ -37,7 +36,9 @@
 
 void			nm_system_device_replace_default_ip4_route   (const char *iface,
                                                              guint32 gw,
-                                                             guint32 mss);
+                                                             guint32 mss,
+                                                             const char *parent_iface,
+                                                             guint32 parent_mss);
 
 void			nm_system_device_flush_ip4_addresses			(NMDevice *dev);
 void			nm_system_device_flush_ip4_addresses_with_iface	(const char *iface);
@@ -45,17 +46,11 @@
 void			nm_system_enable_loopback				(void);
 void			nm_system_update_dns					(void);
 
-gboolean		nm_system_device_set_from_ip4_config		(const char *iface,
-												 NMIP4Config *config,
-												 int priority);
-
-gboolean		nm_system_vpn_device_set_from_ip4_config	(NMDevice *active_device,
-									 const char *iface,
-									 NMIP4Config *config);
-
-gboolean		nm_system_vpn_device_unset_from_ip4_config	(NMDevice *active_device, 
-									 const char *iface,
-									 NMIP4Config *config);
+gboolean		nm_system_apply_ip4_config              (NMDevice *device,
+                                                         const char *iface,
+                                                         NMIP4Config *config,
+                                                         int priority,
+                                                         gboolean is_vpn);
 
 gboolean		nm_system_device_set_up_down				(NMDevice *dev,
                                                              gboolean up,

Modified: trunk/src/nm-device.c
==============================================================================
--- trunk/src/nm-device.c	(original)
+++ trunk/src/nm-device.c	Fri Oct 10 23:05:45 2008
@@ -1919,7 +1919,7 @@
 	if (!nm_ip4_config_get_dbus_path (config))
 		nm_ip4_config_export (config);
 
-	success = nm_system_device_set_from_ip4_config (ip_iface, config, nm_device_get_priority (self));
+	success = nm_system_apply_ip4_config (self, ip_iface, config, nm_device_get_priority (self), FALSE);
 	if (success)
 		nm_device_update_ip4_address (self);
 

Modified: trunk/src/vpn-manager/nm-vpn-connection.c
==============================================================================
--- trunk/src/vpn-manager/nm-vpn-connection.c	(original)
+++ trunk/src/vpn-manager/nm-vpn-connection.c	Fri Oct 10 23:05:45 2008
@@ -46,6 +46,7 @@
 #include "nm-properties-changed-signal.h"
 #include "nm-dbus-glib-types.h"
 #include "NetworkManagerUtils.h"
+#include "nm-named-manager.h"
 
 #include "nm-vpn-connection-glue.h"
 
@@ -354,8 +355,8 @@
 
 static void
 nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
-						    GHashTable *config_hash,
-						    gpointer user_data)
+                                  GHashTable *config_hash,
+                                  gpointer user_data)
 {
 	NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
 	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
@@ -376,6 +377,14 @@
 	addr = g_malloc0 (sizeof (NMSettingIP4Address));
 	addr->prefix = 24; /* default to class C */
 
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV);
+	if (val)
+		priv->tundev = g_strdup (g_value_get_string (val));
+	else {
+		nm_warning ("%s: invalid or missing tunnel device received!", __func__);
+		goto error;
+	}
+
 	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_GATEWAY);
 	if (val)
 		addr->gateway = g_value_get_uint (val);
@@ -395,8 +404,9 @@
 	if (addr->address && addr->prefix) {
 		nm_ip4_config_take_address (config, addr);
 	} else {
-		g_warning ("%s: invalid IP4 config received!", __func__);
+		nm_warning ("%s: invalid IP4 config received!", __func__);
 		g_free (addr);
+		goto error;
 	}
 
 	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DNS);
@@ -423,10 +433,6 @@
 	if (val)
 		nm_ip4_config_set_mtu (config, g_value_get_uint (val));
 
-	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV);
-	if (val)
-		priv->tundev = g_strdup (g_value_get_string (val));
-
 	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN);
 	if (val)
 		nm_ip4_config_add_domain (config, g_value_get_string (val));
@@ -452,26 +458,37 @@
 
 	print_vpn_config (config, priv->tundev, priv->banner);
 
-	priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
-	priv->ip4_config = config;
-
 	/* Merge in user overrides from the NMConnection's IPv4 setting */
 	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (priv->connection, NM_TYPE_SETTING_IP4_CONFIG));
 	nm_utils_merge_ip4_config (config, s_ip4);
 
-	if (nm_system_vpn_device_set_from_ip4_config (priv->parent_dev, priv->tundev, priv->ip4_config)) {
+	nm_system_device_set_up_down_with_iface (priv->tundev, TRUE, NULL);
+
+	if (nm_system_apply_ip4_config (priv->parent_dev, priv->tundev, config, 0, TRUE)) {
+		NMNamedManager *named_mgr;
+
+		/* Add the VPN to DNS */
+		named_mgr = nm_named_manager_get ();
+		nm_named_manager_add_ip4_config (named_mgr, priv->tundev, config, NM_NAMED_IP_CONFIG_TYPE_VPN);
+		g_object_unref (named_mgr);
+
+		priv->ip4_config = config;
+
 		nm_info ("VPN connection '%s' (IP Config Get) complete.",
 			    nm_vpn_connection_get_name (connection));
 		nm_vpn_connection_set_vpn_state (connection,
 		                                 NM_VPN_CONNECTION_STATE_ACTIVATED,
 		                                 NM_VPN_CONNECTION_STATE_REASON_NONE);
-	} else {
-		nm_warning ("VPN connection '%s' did not receive valid IP config information.",
-				  nm_vpn_connection_get_name (connection));
-		nm_vpn_connection_set_vpn_state (connection,
-		                                 NM_VPN_CONNECTION_STATE_FAILED,
-		                                 NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID);
+		return;
 	}
+
+error:
+	nm_warning ("VPN connection '%s' did not receive valid IP config information.",
+	            nm_vpn_connection_get_name (connection));
+	nm_vpn_connection_set_vpn_state (connection,
+	                                 NM_VPN_CONNECTION_STATE_FAILED,
+	                                 NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID);
+	g_object_unref (config);
 }
 
 static gboolean
@@ -631,6 +648,30 @@
 	return NM_VPN_CONNECTION_GET_PRIVATE (connection)->banner;
 }
 
+NMIP4Config *
+nm_vpn_connection_get_ip4_config (NMVPNConnection *connection)
+{
+	g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
+
+	return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip4_config;
+}
+
+const char *
+nm_vpn_connection_get_ip_iface (NMVPNConnection *connection)
+{
+	g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
+
+	return NM_VPN_CONNECTION_GET_PRIVATE (connection)->tundev;
+}
+
+NMDevice *
+nm_vpn_connection_get_parent_device (NMVPNConnection *connection)
+{
+	g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
+
+	return NM_VPN_CONNECTION_GET_PRIVATE (connection)->parent_dev;
+}
+
 void
 nm_vpn_connection_fail (NMVPNConnection *connection,
                         NMVPNConnectionStateReason reason)
@@ -870,9 +911,12 @@
 
 		if (priv->ip4_config) {
 			NMIP4Config *dev_ip4_config;
+			NMNamedManager *named_mgr;
 
 			/* Remove attributes of the VPN's IP4 Config */
-			nm_system_vpn_device_unset_from_ip4_config (priv->parent_dev, priv->tundev, priv->ip4_config);
+			named_mgr = nm_named_manager_get ();
+			nm_named_manager_remove_ip4_config (named_mgr, priv->tundev, priv->ip4_config);
+			g_object_unref (named_mgr);
 
 			/* Reset routes, nameservers, and domains of the currently active device */
 			dev_ip4_config = nm_device_get_ip4_config (priv->parent_dev);

Modified: trunk/src/vpn-manager/nm-vpn-connection.h
==============================================================================
--- trunk/src/vpn-manager/nm-vpn-connection.h	(original)
+++ trunk/src/vpn-manager/nm-vpn-connection.h	Fri Oct 10 23:05:45 2008
@@ -70,5 +70,8 @@
                                                         NMVPNConnectionStateReason reason);
 void                 nm_vpn_connection_disconnect      (NMVPNConnection *connection,
                                                         NMVPNConnectionStateReason reason);
+NMIP4Config *        nm_vpn_connection_get_ip4_config  (NMVPNConnection *connection);
+const char *         nm_vpn_connection_get_ip_iface    (NMVPNConnection *connection);
+NMDevice *           nm_vpn_connection_get_parent_device (NMVPNConnection *connection);
 
 #endif /* NM_VPN_CONNECTION_H */

Modified: trunk/src/vpn-manager/nm-vpn-manager.c
==============================================================================
--- trunk/src/vpn-manager/nm-vpn-manager.c	(original)
+++ trunk/src/vpn-manager/nm-vpn-manager.c	Fri Oct 10 23:05:45 2008
@@ -20,6 +20,7 @@
 } NMVPNManagerPrivate;
 
 enum {
+	CONNECTION_ACTIVATED,
 	CONNECTION_DEACTIVATED,
 
 	LAST_SIGNAL
@@ -128,6 +129,9 @@
 	NMVPNManager *manager = NM_VPN_MANAGER (user_data);
 
 	switch (state) {
+	case NM_VPN_CONNECTION_STATE_ACTIVATED:
+		g_signal_emit (manager, signals[CONNECTION_ACTIVATED], 0, connection);
+		break;
 	case NM_VPN_CONNECTION_STATE_FAILED:
 	case NM_VPN_CONNECTION_STATE_DISCONNECTED:
 		g_signal_emit (manager, signals[CONNECTION_DEACTIVATED], 0, connection, state, reason);
@@ -259,6 +263,27 @@
 	}
 }
 
+GSList *
+nm_vpn_manager_get_active_connections (NMVPNManager *manager)
+{
+	NMVPNManagerPrivate *priv;
+	GSList *iter;
+	GSList *list = NULL;
+
+	g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), NULL);
+
+	priv = NM_VPN_MANAGER_GET_PRIVATE (manager);
+	for (iter = priv->services; iter; iter = g_slist_next (iter)) {
+		GSList *active, *elt;
+
+		active = nm_vpn_service_get_active_connections (NM_VPN_SERVICE (iter->data));
+		for (elt = active; elt; elt = g_slist_next (elt))
+			list = g_slist_append (list, g_object_ref (NM_VPN_CONNECTION (elt->data)));
+	}
+
+	return list;
+}
+
 NMVPNManager *
 nm_vpn_manager_get (void)
 {
@@ -301,6 +326,14 @@
 	object_class->finalize = finalize;
 
 	/* signals */
+	signals[CONNECTION_ACTIVATED] =
+		g_signal_new ("connection-activated",
+				    G_OBJECT_CLASS_TYPE (object_class),
+				    G_SIGNAL_RUN_FIRST,
+				    0, NULL, NULL,
+				    g_cclosure_marshal_VOID__OBJECT,
+				    G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
 	signals[CONNECTION_DEACTIVATED] =
 		g_signal_new ("connection-deactivated",
 				    G_OBJECT_CLASS_TYPE (object_class),

Modified: trunk/src/vpn-manager/nm-vpn-manager.h
==============================================================================
--- trunk/src/vpn-manager/nm-vpn-manager.h	(original)
+++ trunk/src/vpn-manager/nm-vpn-manager.h	Fri Oct 10 23:05:45 2008
@@ -61,4 +61,6 @@
                                             NMConnection *filter,
                                             GPtrArray *list);
 
+GSList *nm_vpn_manager_get_active_connections (NMVPNManager *manager);
+
 #endif /* NM_VPN_VPN_MANAGER_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]