diff options
| author | Michael Biebl <biebl@debian.org> | 2010-11-29 19:00:22 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2010-11-29 19:00:22 +0100 |
| commit | a6b89d35fabd9f5934b84d7cde22e9268f92c3d3 (patch) | |
| tree | 9e44755880d5933fcc90c6008d4585a76298a1bd /src/nm-device.c | |
| parent | 9fae01fa351805b2903e535736e06971bc0b925e (diff) | |
Imported Upstream version 0.8.2 upstream/0.8.2
Diffstat (limited to 'src/nm-device.c')
| -rw-r--r-- | src/nm-device.c | 192 |
1 files changed, 144 insertions, 48 deletions
diff --git a/src/nm-device.c b/src/nm-device.c index 176d90f9..e8f0b206 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -19,6 +19,7 @@ * Copyright (C) 2006 - 2008 Novell, Inc. */ +#include <config.h> #include <glib.h> #include <glib/gi18n.h> #include <dbus/dbus.h> @@ -42,7 +43,7 @@ #include "nm-system.h" #include "nm-dhcp-manager.h" #include "nm-dbus-manager.h" -#include "nm-named-manager.h" +#include "nm-dns-manager.h" #include "nm-utils.h" #include "nm-logging.h" #include "nm-netlink-monitor.h" @@ -92,6 +93,7 @@ typedef struct { char * driver; gboolean managed; /* whether managed by NM or not */ RfKillType rfkill_type; + gboolean firmware_missing; guint32 ip4_address; @@ -158,6 +160,7 @@ static void nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason static gboolean device_disconnect (NMDeviceInterface *device, GError **error); static gboolean spec_match_list (NMDeviceInterface *device, const GSList *specs); static NMConnection *connection_match_config (NMDeviceInterface *device, const GSList *connections); +static gboolean can_assume_connections (NMDeviceInterface *device); static void nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self, int family); @@ -195,6 +198,7 @@ device_interface_init (NMDeviceInterface *device_interface_class) device_interface_class->disconnect = device_disconnect; device_interface_class->spec_match_list = spec_match_list; device_interface_class->connection_match_config = connection_match_config; + device_interface_class->can_assume_connections = can_assume_connections; } @@ -282,6 +286,12 @@ constructor (GType type, if (NM_DEVICE_GET_CLASS (dev)->update_hw_address) NM_DEVICE_GET_CLASS (dev)->update_hw_address (dev); + if (NM_DEVICE_GET_CLASS (dev)->update_permanent_hw_address) + NM_DEVICE_GET_CLASS (dev)->update_permanent_hw_address (dev); + + if (NM_DEVICE_GET_CLASS (dev)->update_initial_hw_address) + NM_DEVICE_GET_CLASS (dev)->update_initial_hw_address (dev); + priv->dhcp_manager = nm_dhcp_manager_get (); update_accept_ra_save (dev); @@ -387,11 +397,12 @@ void nm_device_set_ip_iface (NMDevice *self, const char *iface) { NMDevicePrivate *priv; + char *old_ip_iface; g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - g_free (priv->ip_iface); + old_ip_iface = priv->ip_iface; priv->ip_ifindex = 0; priv->ip_iface = g_strdup (iface); @@ -401,6 +412,11 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface) nm_log_warn (LOGD_HW, "(%s): failed to look up interface index", iface); } } + + /* Emit change notification */ + if (g_strcmp0 (old_ip_iface, priv->ip_iface)) + g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_IP_IFACE); + g_free (old_ip_iface); } @@ -492,6 +508,11 @@ nm_device_get_act_request (NMDevice *self) gboolean nm_device_is_available (NMDevice *self) { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->firmware_missing) + return FALSE; + if (NM_DEVICE_GET_CLASS (self)->is_available) return NM_DEVICE_GET_CLASS (self)->is_available (self); return TRUE; @@ -1222,7 +1243,7 @@ static gboolean aipd_exec (NMDevice *self, GError **error) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - char *argv[5]; + char *argv[6], *cmdline; gboolean success = FALSE; const char **aipd_binary = NULL; static const char *aipd_paths[] = { @@ -1230,6 +1251,7 @@ aipd_exec (NMDevice *self, GError **error) "/usr/local/sbin/avahi-autoipd", NULL }; + int i = 0; aipd_cleanup (self); @@ -1246,11 +1268,17 @@ aipd_exec (NMDevice *self, GError **error) return FALSE; } - argv[0] = (char *) (*aipd_binary); - argv[1] = "--script"; - argv[2] = LIBEXECDIR "/nm-avahi-autoipd.action"; - argv[3] = (char *) nm_device_get_ip_iface (self); - argv[4] = NULL; + argv[i++] = (char *) (*aipd_binary); + argv[i++] = "--script"; + argv[i++] = LIBEXECDIR "/nm-avahi-autoipd.action"; + if (nm_logging_level_enabled (LOGL_DEBUG)) + argv[i++] = "--debug"; + argv[i++] = (char *) nm_device_get_ip_iface (self); + argv[i++] = NULL; + + cmdline = g_strjoinv (" ", argv); + nm_log_dbg(LOGD_AUTOIP4, "running: %s", cmdline); + g_free (cmdline); success = g_spawn_async ("/", argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, &aipd_child_setup, NULL, &(priv->aipd_pid), error); @@ -1320,6 +1348,7 @@ handle_dhcp_lease_change (NMDevice *device, gboolean ipv6) nm_dhcp_client_foreach_option (priv->dhcp6_client, dhcp6_add_option_cb, priv->dhcp6_config); + nm_utils_call_dispatcher ("dhcp6-change", connection, device, NULL); } else { nm_log_warn (LOGD_DHCP6, "(%s): failed to update IPv6 config in response to DHCP event.", nm_device_get_ip_iface (device)); @@ -1344,6 +1373,7 @@ handle_dhcp_lease_change (NMDevice *device, gboolean ipv6) nm_dhcp_client_foreach_option (priv->dhcp4_client, dhcp4_add_option_cb, priv->dhcp4_config); + nm_utils_call_dispatcher ("dhcp4-change", connection, device, NULL); } else { nm_log_warn (LOGD_DHCP6, "(%s): failed to update IPv4 config in response to DHCP event.", nm_device_get_ip_iface (device)); @@ -1424,22 +1454,6 @@ dhcp_state_changed (NMDHCPClient *client, } else if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); break; - case DHC_STOP: - case DHC_STOP6: - case DHC_EXPIRE: - case DHC_EXPIRE6: - if (dev_state == NM_DEVICE_STATE_ACTIVATED) { - if (ipv6) - nm_dhcp6_config_reset (priv->dhcp6_config); - else - nm_dhcp4_config_reset (priv->dhcp4_config); - - /* dhclient quit and can't get/renew a lease; so kill the connection */ - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); - } - break; default: break; } @@ -1573,6 +1587,8 @@ dhcp6_start (NMDevice *self, NMSettingConnection *s_con; const char *uuid; const char *ip_iface; + const struct in6_addr dest = { { { 0xFF,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }; + int err; if (!connection) { NMActRequest *req; @@ -1593,6 +1609,18 @@ dhcp6_start (NMDevice *self, g_object_unref (priv->dhcp6_config); priv->dhcp6_config = nm_dhcp6_config_new (); + /* DHCPv6 communicates with the DHCPv6 server via two multicast addresses, + * ff02::1:2 (link-scope) and ff05::1:3 (site-scope). Make sure we have + * a multicast route (ff00::/8) for client <-> server communication. + */ + err = nm_system_set_ip6_route (priv->ip_iface ? priv->ip_ifindex : priv->ifindex, + &dest, 8, NULL, 256, 0, RTPROT_BOOT, RT_TABLE_LOCAL, NULL); + if (err) { + nm_log_err (LOGD_DEVICE | LOGD_IP6, + "(%s): failed to add IPv6 multicast route: %s", + priv->ip_iface ? priv->ip_iface : priv->iface, nl_geterror ()); + } + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); g_assert (s_con); uuid = nm_setting_connection_get_uuid (s_con); @@ -1657,6 +1685,13 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) } nm_ip6_manager_begin_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self)); ret = NM_ACT_STAGE_RETURN_POSTPONE; + } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { + /* Router advertisements shouldn't be used in pure DHCP mode */ + if (priv->ip6_accept_ra_path) + nm_utils_do_sysctl (priv->ip6_accept_ra_path, "0\n"); + + priv->dhcp6_mode = IP6_DHCP_OPT_MANAGED; + ret = dhcp6_start (self, connection, priv->dhcp6_mode, reason); } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { /* reset the saved RA value when ipv6 is ignored */ if (priv->ip6_accept_ra_path) { @@ -2110,7 +2145,8 @@ real_act_stage4_get_ip6_config (NMDevice *self, *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; goto out; } - } + } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) + g_assert (priv->dhcp6_client); /* sanity check */ /* Autoconf might have triggered DHCPv6 too */ if (priv->dhcp6_client) { @@ -2740,6 +2776,8 @@ nm_device_deactivate_quickly (NMDevice *self) dnsmasq_cleanup (self); aipd_cleanup (self); + nm_device_set_ip_iface (self, NULL); + /* Turn off router advertisements until they are needed */ if (priv->ip6_accept_ra_path) nm_utils_do_sysctl (priv->ip6_accept_ra_path, "0\n"); @@ -2987,7 +3025,7 @@ nm_device_set_ip4_config (NMDevice *self, NMIP4Config *old_config = NULL; gboolean success = TRUE; NMIP4ConfigCompareFlags diff = NM_IP4_COMPARE_FLAG_ALL; - NMNamedManager *named_mgr; + NMDnsManager *dns_mgr; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); g_return_val_if_fail (reason != NULL, FALSE); @@ -3004,10 +3042,10 @@ nm_device_set_ip4_config (NMDevice *self, if (diff == NM_IP4_COMPARE_FLAG_NONE) return TRUE; - named_mgr = nm_named_manager_get (); + dns_mgr = nm_dns_manager_get (NULL); if (old_config) { - /* Remove any previous IP4 Config from the named manager */ - nm_named_manager_remove_ip4_config (named_mgr, ip_iface, old_config); + /* Remove any previous IP4 Config from the DNS manager */ + nm_dns_manager_remove_ip4_config (dns_mgr, ip_iface, old_config); g_object_unref (old_config); priv->ip4_config = NULL; } @@ -3026,13 +3064,13 @@ nm_device_set_ip4_config (NMDevice *self, if (!nm_ip4_config_get_dbus_path (new_config)) nm_ip4_config_export (new_config); - /* Add the DNS information to the named manager */ - nm_named_manager_add_ip4_config (named_mgr, ip_iface, new_config, NM_NAMED_IP_CONFIG_TYPE_DEFAULT); + /* Add the DNS information to the DNS manager */ + nm_dns_manager_add_ip4_config (dns_mgr, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); nm_device_update_ip4_address (self); } } - g_object_unref (named_mgr); + g_object_unref (dns_mgr); g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_IP4_CONFIG); @@ -3090,7 +3128,7 @@ nm_device_set_ip6_config (NMDevice *self, NMIP6Config *old_config = NULL; gboolean success = TRUE; NMIP6ConfigCompareFlags diff = NM_IP6_COMPARE_FLAG_ALL; - NMNamedManager *named_mgr; + NMDnsManager *dns_mgr; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); g_return_val_if_fail (reason != NULL, FALSE); @@ -3107,10 +3145,10 @@ nm_device_set_ip6_config (NMDevice *self, if (diff == NM_IP6_COMPARE_FLAG_NONE) return TRUE; - named_mgr = nm_named_manager_get (); + dns_mgr = nm_dns_manager_get (NULL); if (old_config) { - /* Remove any previous IP6 Config from the named manager */ - nm_named_manager_remove_ip6_config (named_mgr, ip_iface, old_config); + /* Remove any previous IP6 Config from the DNS manager */ + nm_dns_manager_remove_ip6_config (dns_mgr, ip_iface, old_config); g_object_unref (old_config); priv->ip6_config = NULL; } @@ -3129,11 +3167,11 @@ nm_device_set_ip6_config (NMDevice *self, if (!nm_ip6_config_get_dbus_path (new_config)) nm_ip6_config_export (new_config); - /* Add the DNS information to the named manager */ - nm_named_manager_add_ip6_config (named_mgr, ip_iface, new_config, NM_NAMED_IP_CONFIG_TYPE_DEFAULT); + /* Add the DNS information to the DNS manager */ + nm_dns_manager_add_ip6_config (dns_mgr, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); } } - g_object_unref (named_mgr); + g_object_unref (dns_mgr); g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_IP6_CONFIG); @@ -3280,7 +3318,7 @@ dispose (GObject *object) /* Don't down can-assume-connection capable devices that are activated with * a connection that can be assumed. */ - if ( nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (self)) + if ( nm_device_interface_can_assume_connections (NM_DEVICE_INTERFACE (self)) && (nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED)) { NMConnection *connection; NMSettingIP4Config *s_ip4; @@ -3345,7 +3383,8 @@ finalize (GObject *object) NMDevice *self = NM_DEVICE (object); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - g_object_unref (priv->dhcp_manager); + if (priv->dhcp_manager) + g_object_unref (priv->dhcp_manager); g_free (priv->udi); g_free (priv->iface); @@ -3381,6 +3420,8 @@ set_property (GObject *object, guint prop_id, } } break; + case NM_DEVICE_INTERFACE_PROP_IP_IFACE: + break; case NM_DEVICE_INTERFACE_PROP_DRIVER: priv->driver = g_strdup (g_value_get_string (value)); break; @@ -3393,6 +3434,9 @@ set_property (GObject *object, guint prop_id, case NM_DEVICE_INTERFACE_PROP_MANAGED: priv->managed = g_value_get_boolean (value); break; + case NM_DEVICE_INTERFACE_PROP_FIRMWARE_MISSING: + priv->firmware_missing = g_value_get_boolean (value); + break; case NM_DEVICE_INTERFACE_PROP_DEVICE_TYPE: g_return_if_fail (priv->type == NM_DEVICE_TYPE_UNKNOWN); priv->type = g_value_get_uint (value); @@ -3427,6 +3471,12 @@ get_property (GObject *object, guint prop_id, case NM_DEVICE_INTERFACE_PROP_IFACE: g_value_set_string (value, priv->iface); break; + case NM_DEVICE_INTERFACE_PROP_IP_IFACE: + if ((state == NM_DEVICE_STATE_ACTIVATED) || (state == NM_DEVICE_STATE_IP_CONFIG)) + g_value_set_string (value, nm_device_get_ip_iface (self)); + else + g_value_set_string (value, NULL); + break; case NM_DEVICE_INTERFACE_PROP_IFINDEX: g_value_set_int (value, priv->ifindex); break; @@ -3480,6 +3530,9 @@ get_property (GObject *object, guint prop_id, case NM_DEVICE_INTERFACE_PROP_MANAGED: g_value_set_boolean (value, priv->managed); break; + case NM_DEVICE_INTERFACE_PROP_FIRMWARE_MISSING: + g_value_set_boolean (value, priv->firmware_missing); + break; case NM_DEVICE_INTERFACE_PROP_TYPE_DESC: g_value_set_string (value, priv->type_desc); break; @@ -3529,6 +3582,10 @@ nm_device_class_init (NMDeviceClass *klass) NM_DEVICE_INTERFACE_IFACE); g_object_class_override_property (object_class, + NM_DEVICE_INTERFACE_PROP_IP_IFACE, + NM_DEVICE_INTERFACE_IP_IFACE); + + g_object_class_override_property (object_class, NM_DEVICE_INTERFACE_PROP_IFINDEX, NM_DEVICE_INTERFACE_IFINDEX); @@ -3573,6 +3630,10 @@ nm_device_class_init (NMDeviceClass *klass) NM_DEVICE_INTERFACE_MANAGED); g_object_class_override_property (object_class, + NM_DEVICE_INTERFACE_PROP_FIRMWARE_MISSING, + NM_DEVICE_INTERFACE_FIRMWARE_MISSING); + + g_object_class_override_property (object_class, NM_DEVICE_INTERFACE_PROP_TYPE_DESC, NM_DEVICE_INTERFACE_TYPE_DESC); @@ -3617,6 +3678,27 @@ unavailable_to_disconnected (gpointer user_data) } void +nm_device_set_firmware_missing (NMDevice *self, gboolean new_missing) +{ + NMDevicePrivate *priv; + + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_DEVICE (self)); + + priv = NM_DEVICE_GET_PRIVATE (self); + if (priv->firmware_missing != new_missing) { + priv->firmware_missing = new_missing; + g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_FIRMWARE_MISSING); + } +} + +gboolean +nm_device_get_firmware_missing (NMDevice *self) +{ + return NM_DEVICE_GET_PRIVATE (self)->firmware_missing; +} + +void nm_device_state_changed (NMDevice *device, NMDeviceState state, NMDeviceStateReason reason) @@ -3628,7 +3710,12 @@ nm_device_state_changed (NMDevice *device, g_return_if_fail (NM_IS_DEVICE (device)); - if (priv->state == state) + /* Do nothing if state isn't changing, but as a special case allow + * re-setting UNAVAILABLE if the device is missing firmware so that we + * can retry device initialization. + */ + if ( (priv->state == state) + && !(state == NM_DEVICE_STATE_UNAVAILABLE && priv->firmware_missing)) return; old_state = priv->state; @@ -3648,14 +3735,15 @@ nm_device_state_changed (NMDevice *device, */ switch (state) { case NM_DEVICE_STATE_UNMANAGED: + nm_device_set_firmware_missing (device, FALSE); if (old_state > NM_DEVICE_STATE_UNMANAGED) nm_device_take_down (device, TRUE, reason); break; case NM_DEVICE_STATE_UNAVAILABLE: - if (old_state == NM_DEVICE_STATE_UNMANAGED) { - if (!nm_device_bring_up (device, TRUE, &no_firmware) && no_firmware) { - nm_log_warn (LOGD_HW, "%s: firmware may be missing.", nm_device_get_iface (device)); - } + if (old_state == NM_DEVICE_STATE_UNMANAGED || priv->firmware_missing) { + if (!nm_device_bring_up (device, TRUE, &no_firmware) && no_firmware) + nm_log_warn (LOGD_HW, "(%s): firmware may be missing.", nm_device_get_iface (device)); + nm_device_set_firmware_missing (device, no_firmware ? TRUE : FALSE); } /* Ensure the device gets deactivated in response to stuff like * carrier changes or rfkill. But don't deactivate devices that are @@ -3683,7 +3771,7 @@ nm_device_state_changed (NMDevice *device, case NM_DEVICE_STATE_UNAVAILABLE: /* If the device can activate now (ie, it's got a carrier, the supplicant * is active, or whatever) schedule a delayed transition to DISCONNECTED - * to get things rolling. The device can't transition immediately becuase + * to get things rolling. The device can't transition immediately because * we can't change states again from the state handler for a variety of * reasons. */ @@ -3704,7 +3792,7 @@ nm_device_state_changed (NMDevice *device, case NM_DEVICE_STATE_FAILED: nm_log_warn (LOGD_DEVICE, "Activation (%s) failed.", nm_device_get_iface (device)); /* Schedule the transition to DISCONNECTED. The device can't transition - * immediately becuase we can't change states again from the state + * immediately because we can't change states again from the state * handler for a variety of reasons. */ priv->failed_to_disconnected_id = g_idle_add (failed_to_disconnected, device); @@ -3788,6 +3876,14 @@ connection_match_config (NMDeviceInterface *device, const GSList *connections) return NULL; } +static gboolean +can_assume_connections (NMDeviceInterface *device) +{ + g_return_val_if_fail (device != NULL, FALSE); + + return !!NM_DEVICE_GET_CLASS (device)->connection_match_config; +} + void nm_device_set_dhcp_timeout (NMDevice *device, guint32 timeout) { |