summaryrefslogtreecommitdiff
path: root/src/devices/nm-device.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/nm-device.c')
-rw-r--r--src/devices/nm-device.c515
1 files changed, 453 insertions, 62 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index af5e52750c..263e1f64d3 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -68,6 +68,7 @@
#include "nm-config.h"
#include "nm-dns-manager.h"
#include "nm-core-internal.h"
+#include "nm-default-route-manager.h"
#include "nm-device-logging.h"
_LOG_DECLARE_SELF (NMDevice);
@@ -237,6 +238,12 @@ typedef struct {
NMIP4Config * dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */
NMIP4Config * ext_ip4_config; /* Stuff added outside NM */
NMIP4Config * wwan_ip4_config; /* WWAN configuration */
+ struct {
+ gboolean v4_has;
+ NMPlatformIP4Route v4;
+ gboolean v6_has;
+ NMPlatformIP6Route v6;
+ } default_route;
/* DHCPv4 tracking */
NMDhcpClient * dhcp4_client;
@@ -640,7 +647,7 @@ nm_device_get_device_type (NMDevice *self)
int
nm_device_get_priority (NMDevice *self)
{
- g_return_val_if_fail (NM_IS_DEVICE (self), 100);
+ g_return_val_if_fail (NM_IS_DEVICE (self), 1000);
/* Device 'priority' is used for two things:
*
@@ -653,33 +660,90 @@ nm_device_get_priority (NMDevice *self)
*/
switch (nm_device_get_device_type (self)) {
+ /* 10 is reserved for VPN (NM_VPN_ROUTE_METRIC_DEFAULT) */
case NM_DEVICE_TYPE_ETHERNET:
- return 1;
+ return 20;
case NM_DEVICE_TYPE_INFINIBAND:
- return 2;
+ return 30;
case NM_DEVICE_TYPE_ADSL:
- return 3;
+ return 40;
case NM_DEVICE_TYPE_WIMAX:
- return 4;
+ return 50;
case NM_DEVICE_TYPE_BOND:
- return 5;
+ return 60;
case NM_DEVICE_TYPE_TEAM:
- return 6;
+ return 70;
case NM_DEVICE_TYPE_VLAN:
- return 7;
+ return 80;
case NM_DEVICE_TYPE_MODEM:
- return 8;
+ return 90;
case NM_DEVICE_TYPE_BT:
- return 9;
+ return 100;
case NM_DEVICE_TYPE_WIFI:
- return 10;
+ return 110;
case NM_DEVICE_TYPE_OLPC_MESH:
- return 11;
+ return 120;
default:
- return 20;
+ return 200;
}
}
+guint32
+nm_device_get_ip4_route_metric (NMDevice *self)
+{
+ NMConnection *connection;
+ gint64 route_metric = -1;
+
+ g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32);
+
+ connection = nm_device_get_connection (self);
+
+ if (connection)
+ route_metric = nm_setting_ip_config_get_route_metric (nm_connection_get_setting_ip4_config (connection));
+
+ return route_metric >= 0 ? route_metric : nm_device_get_priority (self);
+}
+
+guint32
+nm_device_get_ip6_route_metric (NMDevice *self)
+{
+ NMConnection *connection;
+ gint64 route_metric = -1;
+
+ g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32);
+
+ connection = nm_device_get_connection (self);
+
+ if (connection)
+ route_metric = nm_setting_ip_config_get_route_metric (nm_connection_get_setting_ip6_config (connection));
+
+ return route_metric >= 0 ? route_metric : nm_device_get_priority (self);
+}
+
+const NMPlatformIP4Route *
+nm_device_get_ip4_default_route (NMDevice *self)
+{
+ NMDevicePrivate *priv;
+
+ g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
+
+ priv = NM_DEVICE_GET_PRIVATE (self);
+
+ return priv->default_route.v4_has ? &priv->default_route.v4 : NULL;
+}
+
+const NMPlatformIP6Route *
+nm_device_get_ip6_default_route (NMDevice *self)
+{
+ NMDevicePrivate *priv;
+
+ g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
+
+ priv = NM_DEVICE_GET_PRIVATE (self);
+
+ return priv->default_route.v6_has ? &priv->default_route.v6 : NULL;
+}
+
const char *
nm_device_get_type_desc (NMDevice *self)
{
@@ -742,6 +806,17 @@ nm_device_uses_generated_assumed_connection (NMDevice *self)
return FALSE;
}
+gboolean
+nm_device_uses_assumed_connection (NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+ if ( priv->act_request
+ && nm_active_connection_get_assumed (NM_ACTIVE_CONNECTION (priv->act_request)))
+ return TRUE;
+ return FALSE;
+}
+
static SlaveInfo *
find_slave_info (NMDevice *self, NMDevice *slave)
{
@@ -2106,8 +2181,7 @@ gboolean
nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6)
{
NMConnection *connection;
- NMSettingIP4Config *s_ip4;
- NMSettingIP6Config *s_ip6;
+ NMSettingIPConfig *s_ip4, *s_ip6;
g_return_val_if_fail (self != NULL, TRUE);
@@ -2117,11 +2191,11 @@ nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6)
/* Fail the connection if the failed IP method is required to complete */
if (ip6) {
s_ip6 = nm_connection_get_setting_ip6_config (connection);
- if (!nm_setting_ip6_config_get_may_fail (s_ip6))
+ if (!nm_setting_ip_config_get_may_fail (s_ip6))
return TRUE;
} else {
s_ip4 = nm_connection_get_setting_ip4_config (connection);
- if (!nm_setting_ip4_config_get_may_fail (s_ip4))
+ if (!nm_setting_ip_config_get_may_fail (s_ip4))
return TRUE;
}
@@ -2394,7 +2468,7 @@ aipd_get_ip4_config (NMDevice *self, guint32 lla)
route.network = htonl (0xE0000000L);
route.plen = 4;
route.source = NM_IP_CONFIG_SOURCE_IP4LL;
- route.metric = nm_device_get_priority (self);
+ route.metric = nm_device_get_ip4_route_metric (self);
nm_ip4_config_add_route (config, &route);
return config;
@@ -2594,6 +2668,52 @@ aipd_start (NMDevice *self, NMDeviceStateReason *reason)
}
/*********************************************/
+
+static gboolean
+_device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlatformIPRoute *out_route)
+{
+ gboolean success = FALSE;
+ int ifindex = nm_device_get_ip_ifindex (self);
+ GArray *routes;
+
+ if (addr_family == AF_INET)
+ routes = nm_platform_ip4_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT);
+ else
+ routes = nm_platform_ip6_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT);
+
+ if (routes) {
+ guint route_metric = G_MAXUINT32, m;
+ const NMPlatformIPRoute *route = NULL, *r;
+ guint i;
+
+ /* if there are several default routes, find the one with the best metric */
+ for (i = 0; i < routes->len; i++) {
+ if (addr_family == AF_INET) {
+ r = (const NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP4Route, i);
+ m = r->metric;
+ } else {
+ r = (const NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP6Route, i);
+ m = nm_utils_ip6_route_metric_normalize (r->metric);
+ }
+ if (!route || m < route_metric) {
+ route = r;
+ route_metric = m;
+ }
+ }
+
+ if (route) {
+ if (addr_family == AF_INET)
+ *((NMPlatformIP4Route *) out_route) = *((NMPlatformIP4Route *) route);
+ else
+ *((NMPlatformIP6Route *) out_route) = *((NMPlatformIP6Route *) route);
+ success = TRUE;
+ }
+ g_array_free (routes, TRUE);
+ }
+ return success;
+}
+
+/*********************************************/
/* DHCPv4 stuff */
static void
@@ -2658,11 +2778,58 @@ ip4_config_merge_and_apply (NMDevice *self,
* be redundant, so don't bother.
*/
connection = nm_device_get_connection (self);
- if ( connection
- && !nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) {
- nm_ip4_config_merge_setting (composite,
- nm_connection_get_setting_ip4_config (connection),
- nm_device_get_priority (self));
+ priv->default_route.v4_has = FALSE;
+ if (connection) {
+ gboolean assumed = nm_device_uses_assumed_connection (self);
+
+ if (!nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) {
+ nm_ip4_config_merge_setting (composite,
+ nm_connection_get_setting_ip4_config (connection),
+ nm_device_get_ip4_route_metric (self));
+ }
+
+ /* Add the default route.
+ *
+ * We keep track of the default route of a device in a private field.
+ * NMDevice needs to know the default route at this point, because the gateway
+ * might require a direct route (see below).
+ *
+ * But also, we don't want to add the default route to priv->ip4_config,
+ * because the default route from the setting might not be the same that
+ * NMDefaultRouteManager eventually configures (because the it might
+ * tweak the effective metric).
+ */
+ if (nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), connection)) {
+ guint32 gateway = 0;
+ NMPlatformIP4Route *route = &priv->default_route.v4;
+
+ if (assumed)
+ priv->default_route.v4_has = _device_get_default_route_from_platform (self, AF_INET, (NMPlatformIPRoute *) route);
+ else {
+ gateway = nm_ip4_config_get_gateway (composite);
+ if ( gateway
+ || nm_device_get_device_type (self) == NM_DEVICE_TYPE_MODEM) {
+ memset (route, 0, sizeof (*route));
+ route->source = NM_IP_CONFIG_SOURCE_USER;
+ route->gateway = gateway;
+ route->metric = nm_device_get_ip4_route_metric (self);
+ route->mss = nm_ip4_config_get_mss (composite);
+ priv->default_route.v4_has = TRUE;
+
+ if ( gateway
+ && !nm_ip4_config_get_subnet_for_host (composite, gateway)
+ && !nm_ip4_config_get_direct_route_for_host (composite, gateway)) {
+ /* add a direct route to the gateway */
+ NMPlatformIP4Route r = *route;
+
+ r.network = gateway;
+ r.plen = 32;
+ r.gateway = 0;
+ nm_ip4_config_add_route (composite, &r);
+ }
+ }
+ }
+ }
}
/* Allow setting MTU etc */
@@ -2778,7 +2945,7 @@ dhcp4_start (NMDevice *self,
NMDeviceStateReason *reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- NMSettingIP4Config *s_ip4;
+ NMSettingIPConfig *s_ip4;
const guint8 *hw_addr;
size_t hw_addr_len = 0;
GByteArray *tmp = NULL;
@@ -2803,12 +2970,13 @@ dhcp4_start (NMDevice *self,
nm_device_get_ip_ifindex (self),
tmp,
nm_connection_get_uuid (connection),
- nm_device_get_priority (self),
- nm_setting_ip4_config_get_dhcp_send_hostname (s_ip4),
- nm_setting_ip4_config_get_dhcp_hostname (s_ip4),
- nm_setting_ip4_config_get_dhcp_client_id (s_ip4),
+ nm_device_get_ip4_route_metric (self),
+ nm_setting_ip_config_get_dhcp_send_hostname (s_ip4),
+ nm_setting_ip_config_get_dhcp_hostname (s_ip4),
+ nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4)),
priv->dhcp_timeout,
- priv->dhcp_anycast_address);
+ priv->dhcp_anycast_address,
+ NULL);
if (tmp)
g_byte_array_free (tmp, TRUE);
@@ -2864,20 +3032,20 @@ release_shared_ip (gpointer data)
}
static gboolean
-reserve_shared_ip (NMDevice *self, NMSettingIP4Config *s_ip4, NMPlatformIP4Address *address)
+reserve_shared_ip (NMDevice *self, NMSettingIPConfig *s_ip4, NMPlatformIP4Address *address)
{
if (G_UNLIKELY (shared_ips == NULL))
shared_ips = g_hash_table_new (g_direct_hash, g_direct_equal);
memset (address, 0, sizeof (*address));
- if (s_ip4 && nm_setting_ip4_config_get_num_addresses (s_ip4)) {
+ if (s_ip4 && nm_setting_ip_config_get_num_addresses (s_ip4)) {
/* Use the first user-supplied address */
- NMIP4Address *user = nm_setting_ip4_config_get_address (s_ip4, 0);
+ NMIPAddress *user = nm_setting_ip_config_get_address (s_ip4, 0);
g_assert (user);
- address->address = nm_ip4_address_get_address (user);
- address->plen = nm_ip4_address_get_prefix (user);
+ nm_ip_address_get_address_binary (user, &address->address);
+ address->plen = nm_ip_address_get_prefix (user);
} else {
/* Find an unused address in the 10.42.x.x range */
guint32 start = (guint32) ntohl (0x0a2a0001); /* 10.42.0.1 */
@@ -2964,8 +3132,7 @@ connection_ip6_method_requires_carrier (NMConnection *connection,
static gboolean
connection_requires_carrier (NMConnection *connection)
{
- NMSettingIP4Config *s_ip4;
- NMSettingIP6Config *s_ip6;
+ NMSettingIPConfig *s_ip4, *s_ip6;
gboolean ip4_carrier_wanted, ip6_carrier_wanted;
gboolean ip4_used = FALSE, ip6_used = FALSE;
@@ -2975,7 +3142,7 @@ connection_requires_carrier (NMConnection *connection)
* requires a carrier regardless of the IPv6 method.
*/
s_ip4 = nm_connection_get_setting_ip4_config (connection);
- if (s_ip4 && !nm_setting_ip4_config_get_may_fail (s_ip4))
+ if (s_ip4 && !nm_setting_ip_config_get_may_fail (s_ip4))
return TRUE;
}
@@ -2985,7 +3152,7 @@ connection_requires_carrier (NMConnection *connection)
* requires a carrier regardless of the IPv4 method.
*/
s_ip6 = nm_connection_get_setting_ip6_config (connection);
- if (s_ip6 && !nm_setting_ip6_config_get_may_fail (s_ip6))
+ if (s_ip6 && !nm_setting_ip_config_get_may_fail (s_ip6))
return TRUE;
}
@@ -3160,11 +3327,57 @@ ip6_config_merge_and_apply (NMDevice *self,
* be redundant, so don't bother.
*/
connection = nm_device_get_connection (self);
- if ( connection
- && !nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) {
- nm_ip6_config_merge_setting (composite,
- nm_connection_get_setting_ip6_config (connection),
- nm_device_get_priority (self));
+ priv->default_route.v6_has = FALSE;
+ if (connection) {
+ gboolean assumed = nm_device_uses_assumed_connection (self);
+
+ if (!nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) {
+ nm_ip6_config_merge_setting (composite,
+ nm_connection_get_setting_ip6_config (connection),
+ nm_device_get_ip6_route_metric (self));
+ }
+
+ /* Add the default route.
+ *
+ * We keep track of the default route of a device in a private field.
+ * NMDevice needs to know the default route at this point, because the gateway
+ * might require a direct route (see below).
+ *
+ * But also, we don't want to add the default route to priv->ip4_config,
+ * because the default route from the setting might not be the same that
+ * NMDefaultRouteManager eventually configures (because the it might
+ * tweak the effective metric).
+ */
+ if (nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), connection)) {
+ const struct in6_addr *gateway = NULL;
+ NMPlatformIP6Route *route = &priv->default_route.v6;
+
+ if (assumed)
+ priv->default_route.v6_has = _device_get_default_route_from_platform (self, AF_INET6, (NMPlatformIPRoute *) route);
+ else {
+ gateway = nm_ip6_config_get_gateway (composite);
+ if (gateway) {
+ memset (route, 0, sizeof (*route));
+ route->source = NM_IP_CONFIG_SOURCE_USER;
+ route->gateway = *gateway;
+ route->metric = nm_device_get_ip6_route_metric (self);
+ route->mss = nm_ip6_config_get_mss (composite);
+ priv->default_route.v6_has = TRUE;
+
+ if ( gateway
+ && !nm_ip6_config_get_subnet_for_host (composite, gateway)
+ && !nm_ip6_config_get_direct_route_for_host (composite, gateway)) {
+ /* add a direct route to the gateway */
+ NMPlatformIP6Route r = *route;
+
+ r.network = *gateway;
+ r.plen = 128;
+ r.gateway = in6addr_any;
+ nm_ip6_config_add_route (composite, &r);
+ }
+ }
+ }
+ }
}
nm_ip6_config_addresses_sort (composite,
@@ -3320,7 +3533,7 @@ dhcp6_start (NMDevice *self,
guint32 dhcp_opt,
NMDeviceStateReason *reason)
{
- NMSettingIP6Config *s_ip6;
+ NMSettingIPConfig *s_ip6;
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
GByteArray *tmp = NULL;
@@ -3357,12 +3570,13 @@ dhcp6_start (NMDevice *self,
nm_device_get_ip_ifindex (self),
tmp,
nm_connection_get_uuid (connection),
- nm_device_get_priority (self),
- nm_setting_ip6_config_get_dhcp_hostname (s_ip6),
+ nm_device_get_ip6_route_metric (self),
+ nm_setting_ip_config_get_dhcp_send_hostname (s_ip6),
+ nm_setting_ip_config_get_dhcp_hostname (s_ip6),
priv->dhcp_timeout,
priv->dhcp_anycast_address,
(dhcp_opt == NM_RDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE,
- nm_setting_ip6_config_get_ip6_privacy (s_ip6));
+ nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)));
if (tmp)
g_byte_array_free (tmp, TRUE);
@@ -3373,8 +3587,8 @@ dhcp6_start (NMDevice *self,
self);
s_ip6 = nm_connection_get_setting_ip6_config (connection);
- if (!nm_setting_ip6_config_get_may_fail (s_ip6) ||
- !strcmp (nm_setting_ip6_config_get_method (s_ip6), NM_SETTING_IP6_CONFIG_METHOD_DHCP))
+ if (!nm_setting_ip_config_get_may_fail (s_ip6) ||
+ !strcmp (nm_setting_ip_config_get_method (s_ip6), NM_SETTING_IP6_CONFIG_METHOD_DHCP))
nm_device_add_pending_action (self, PENDING_ACTION_DHCP6, TRUE);
/* DHCP devices will be notified by the DHCP manager when stuff happens */
@@ -3700,7 +3914,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self)
route.plen = discovered_route->plen;
route.gateway = discovered_route->gateway;
route.source = NM_IP_CONFIG_SOURCE_RDISC;
- route.metric = nm_device_get_priority (self);
+ route.metric = nm_device_get_ip6_route_metric (self);
nm_ip6_config_add_route (priv->ac_ip6_config, &route);
}
@@ -3858,7 +4072,7 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
priv->rdisc_use_tempaddr = use_tempaddr;
print_support_extended_ifa_flags (use_tempaddr);
- if (!nm_setting_ip6_config_get_may_fail (nm_connection_get_setting_ip6_config (connection)))
+ if (!nm_setting_ip_config_get_may_fail (nm_connection_get_setting_ip6_config (connection)))
nm_device_add_pending_action (self, PENDING_ACTION_AUTOCONF6, TRUE);
/* ensure link local is ready... */
@@ -4116,10 +4330,10 @@ act_stage3_ip6_config_start (NMDevice *self,
*/
ip6_privacy = ip6_use_tempaddr ();
if (ip6_privacy == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) {
- NMSettingIP6Config *s_ip6 = nm_connection_get_setting_ip6_config (connection);
+ NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection);
if (s_ip6)
- ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (s_ip6);
+ ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6));
}
ip6_privacy = use_tempaddr_clamp (ip6_privacy);
@@ -4648,10 +4862,9 @@ send_arps (NMDevice *self, const char *mode_arg)
const char *argv[] = { NULL, mode_arg, "-q", "-I", nm_device_get_ip_iface (self), "-c", "1", NULL, NULL };
int ip_arg = G_N_ELEMENTS (argv) - 2;
NMConnection *connection;
- NMSettingIP4Config *s_ip4;
+ NMSettingIPConfig *s_ip4;
int i, num;
- NMIP4Address *addr;
- guint32 ipaddr;
+ NMIPAddress *addr;
GError *error = NULL;
connection = nm_device_get_connection (self);
@@ -4660,7 +4873,7 @@ send_arps (NMDevice *self, const char *mode_arg)
s_ip4 = nm_connection_get_setting_ip4_config (connection);
if (!s_ip4)
return;
- num = nm_setting_ip4_config_get_num_addresses (s_ip4);
+ num = nm_setting_ip_config_get_num_addresses (s_ip4);
if (num == 0)
return;
@@ -4672,9 +4885,8 @@ send_arps (NMDevice *self, const char *mode_arg)
for (i = 0; i < num; i++) {
gs_free char *tmp_str = NULL;
- addr = nm_setting_ip4_config_get_address (s_ip4, i);
- ipaddr = nm_ip4_address_get_address (addr);
- argv[ip_arg] = (char *) nm_utils_inet4_ntop (ipaddr, NULL);
+ addr = nm_setting_ip_config_get_address (s_ip4, i);
+ argv[ip_arg] = nm_ip_address_get_address (addr);
_LOGD (LOGD_DEVICE | LOGD_IP4,
"arping: run %s", (tmp_str = g_strjoinv (" ", (char **) argv)));
@@ -4721,7 +4933,7 @@ arp_announce (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
- NMSettingIP4Config *s_ip4;
+ NMSettingIPConfig *s_ip4;
int num;
arp_cleanup (self);
@@ -4735,7 +4947,7 @@ arp_announce (NMDevice *self)
s_ip4 = nm_connection_get_setting_ip4_config (connection);
if (!s_ip4)
return;
- num = nm_setting_ip4_config_get_num_addresses (s_ip4);
+ num = nm_setting_ip_config_get_num_addresses (s_ip4);
if (num == 0)
return;
@@ -5084,6 +5296,8 @@ delete_on_deactivate_check_and_schedule (NMDevice *self, int ifindex)
return;
if (!priv->is_nm_owned)
return;
+ if (priv->queued_act_request)
+ return;
if (!nm_device_is_software (self))
return;
if (nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED)
@@ -5362,6 +5576,8 @@ nm_device_set_ip4_config (NMDevice *self,
g_clear_object (&priv->dev_ip4_config);
}
+ nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self);
+
if (has_changes) {
_update_ip4_address (self);
@@ -5483,6 +5699,8 @@ nm_device_set_ip6_config (NMDevice *self,
nm_ip6_config_get_dbus_path (old_config));
}
+ nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), self);
+
if (has_changes) {
if (old_config != priv->ip6_config)
g_object_notify (G_OBJECT (self), NM_DEVICE_IP6_CONFIG);
@@ -6677,6 +6895,12 @@ _cleanup_generic_post (NMDevice *self, gboolean deconfigure)
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE;
+ priv->default_route.v4_has = FALSE;
+ priv->default_route.v6_has = FALSE;
+
+ nm_default_route_manager_ip4_remove_default_route (nm_default_route_manager_get (), self);
+ nm_default_route_manager_ip6_remove_default_route (nm_default_route_manager_get (), self);
+
/* Clean up IP configs; this does not actually deconfigure the
* interface; the caller must flush routes and addresses explicitly.
*/
@@ -6766,6 +6990,173 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason)
_cleanup_generic_post (self, TRUE);
}
+static char *
+bin2hexstr (const char *bytes, gsize len)
+{
+ GString *str;
+ int i;
+
+ g_return_val_if_fail (bytes != NULL, NULL);
+ g_return_val_if_fail (len > 0, NULL);
+
+ str = g_string_sized_new (len * 2 + 1);
+ for (i = 0; i < len; i++) {
+ if (str->len)
+ g_string_append_c (str, ':');
+ g_string_append_printf (str, "%02x", (guint8) bytes[i]);
+ }
+ return g_string_free (str, FALSE);
+}
+
+static char *
+find_dhcp4_address (NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ guint i, n;
+
+ if (!priv->ip4_config)
+ return NULL;
+
+ n = nm_ip4_config_get_num_addresses (priv->ip4_config);
+ for (i = 0; i < n; i++) {
+ const NMPlatformIP4Address *a = nm_ip4_config_get_address (priv->ip4_config, i);
+
+ if (a->source == NM_IP_CONFIG_SOURCE_DHCP)
+ return g_strdup (nm_utils_inet4_ntop (a->address, NULL));
+ }
+ return NULL;
+}
+
+void
+nm_device_spawn_iface_helper (NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ gboolean priority_set = FALSE, configured = FALSE;
+ NMConnection *connection;
+ GError *error = NULL;
+ const char *method;
+ GPtrArray *argv;
+ gs_free char *dhcp4_address = NULL;
+
+ if (priv->state != NM_DEVICE_STATE_ACTIVATED)
+ return;
+ if (!nm_device_can_assume_connections (self))
+ return;
+
+ connection = nm_device_get_connection (self);
+ g_assert (connection);
+
+ argv = g_ptr_array_sized_new (10);
+ g_ptr_array_set_free_func (argv, g_free);
+
+ g_ptr_array_add (argv, g_strdup (LIBEXECDIR "/nm-iface-helper"));
+ g_ptr_array_add (argv, g_strdup ("--ifname"));
+ g_ptr_array_add (argv, g_strdup (nm_device_get_ip_iface (self)));
+ g_ptr_array_add (argv, g_strdup ("--uuid"));
+ g_ptr_array_add (argv, g_strdup (nm_connection_get_uuid (connection)));
+
+ dhcp4_address = find_dhcp4_address (self);
+
+ method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
+ if ( priv->ip4_config
+ && priv->ip4_state == IP_DONE
+ && g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0
+ && priv->dhcp4_client
+ && dhcp4_address) {
+ NMSettingIPConfig *s_ip4;
+ GBytes *client_id;
+ char *hex_client_id;
+ const char *hostname;
+
+ s_ip4 = nm_connection_get_setting_ip4_config (connection);
+ g_assert (s_ip4);
+
+ g_ptr_array_add (argv, g_strdup ("--priority"));
+ g_ptr_array_add (argv, g_strdup_printf ("%u", nm_dhcp_client_get_priority (priv->dhcp4_client)));
+ priority_set = TRUE;
+
+ g_ptr_array_add (argv, g_strdup ("--dhcp4"));
+ g_ptr_array_add (argv, g_strdup (dhcp4_address));
+ if (nm_setting_ip_config_get_may_fail (s_ip4) == FALSE)
+ g_ptr_array_add (argv, g_strdup ("--dhcp4-required"));
+
+ client_id = nm_dhcp_client_get_client_id (priv->dhcp4_client);
+ if (client_id) {
+ g_ptr_array_add (argv, g_strdup ("--dhcp4-clientid"));
+ hex_client_id = bin2hexstr (g_bytes_get_data (client_id, NULL),
+ g_bytes_get_size (client_id));
+ g_ptr_array_add (argv, hex_client_id);
+ }
+
+ hostname = nm_dhcp_client_get_hostname (priv->dhcp4_client);
+ if (client_id) {
+ g_ptr_array_add (argv, g_strdup ("--dhcp4-hostname"));
+ g_ptr_array_add (argv, g_strdup (hostname));
+ }
+
+ configured = TRUE;
+ }
+
+ method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
+ if ( priv->ip6_config
+ && priv->ip6_state == IP_DONE
+ && g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0
+ && priv->rdisc
+ && priv->ac_ip6_config) {
+ NMSettingIPConfig *s_ip6;
+ char *hex_iid;
+ NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT;
+
+ s_ip6 = nm_connection_get_setting_ip6_config (connection);
+ g_assert (s_ip6);
+
+ g_ptr_array_add (argv, g_strdup ("--slaac"));
+
+ if (nm_setting_ip_config_get_may_fail (s_ip6) == FALSE)
+ g_ptr_array_add (argv, g_strdup ("--slaac-required"));
+
+ g_ptr_array_add (argv, g_strdup ("--slaac-tempaddr"));
+ g_ptr_array_add (argv, g_strdup_printf ("%d", priv->rdisc_use_tempaddr));
+
+ if (nm_device_get_ip_iface_identifier (self, &iid)) {
+ g_ptr_array_add (argv, g_strdup ("--iid"));
+ hex_iid = bin2hexstr ((const char *) iid.id_u8, sizeof (NMUtilsIPv6IfaceId));
+ g_ptr_array_add (argv, hex_iid);
+ }
+
+ configured = TRUE;
+ }
+
+ if (configured) {
+ GPid pid;
+
+ if (!priority_set) {
+ g_ptr_array_add (argv, g_strdup ("--priority"));
+ g_ptr_array_add (argv, g_strdup_printf ("%u", nm_device_get_priority (self)));
+ }
+
+ g_ptr_array_add (argv, NULL);
+
+ if (nm_logging_enabled (LOGL_DEBUG, LOGD_DEVICE)) {
+ char *tmp;
+
+ tmp = g_strjoinv (" ", (char **) argv->pdata);
+ _LOGD (LOGD_DEVICE, "running '%s'", tmp);
+ g_free (tmp);
+ }
+
+ if (g_spawn_async (NULL, (char **) argv->pdata, NULL,
+ G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error)) {
+ _LOGI (LOGD_DEVICE, "spawned helper PID %u", (guint) pid);
+ } else {
+ _LOGW (LOGD_DEVICE, "failed to spawn helper: %s", error->message);
+ g_error_free (error);
+ }
+ }
+
+ g_ptr_array_unref (argv);
+}
+
/***********************************************************/
static gboolean