diff -up NetworkManager-0.6.4/src/nm-device-802-3-ethernet.c.device-order-fixes NetworkManager-0.6.4/src/nm-device-802-3-ethernet.c --- NetworkManager-0.6.4/src/nm-device-802-3-ethernet.c.device-order-fixes 2006-05-13 15:06:05.000000000 -0400 +++ NetworkManager-0.6.4/src/nm-device-802-3-ethernet.c 2007-12-03 10:57:39.000000000 -0500 @@ -32,6 +32,7 @@ #include "NetworkManagerMain.h" #include "nm-activation-request.h" #include "NetworkManagerUtils.h" +#include "NetworkManagerPolicy.h" #include "nm-utils.h" #include "kernel-types.h" @@ -43,11 +44,20 @@ struct _NMDevice8023EthernetPrivate struct ether_addr hw_addr; char * carrier_file_path; + gulong link_connected_id; + gulong link_disconnected_id; }; static gboolean supports_mii_carrier_detect (NMDevice8023Ethernet *dev); static gboolean supports_ethtool_carrier_detect (NMDevice8023Ethernet *dev); +static void nm_device_802_3_ethernet_link_activated (NmNetlinkMonitor *monitor, + const char *iface, + NMDevice8023Ethernet *self); +static void nm_device_802_3_ethernet_link_deactivated (NmNetlinkMonitor *monitor, + const char *iface, + NMDevice8023Ethernet *self); + static void nm_device_802_3_ethernet_init (NMDevice8023Ethernet * self) @@ -58,77 +68,128 @@ nm_device_802_3_ethernet_init (NMDevice8 memset (&(self->priv->hw_addr), 0, sizeof (struct ether_addr)); } +static void +real_init (NMDevice *dev) +{ + NMDevice8023Ethernet * self = NM_DEVICE_802_3_ETHERNET (dev); + NMData * app_data; + NmNetlinkMonitor * monitor; + guint32 caps; + + app_data = nm_device_get_app_data (NM_DEVICE (self)); + monitor = app_data->netlink_monitor; + + caps = nm_device_get_capabilities (NM_DEVICE (self)); + if (caps & NM_DEVICE_CAP_CARRIER_DETECT) { + /* Only listen to netlink for cards that support carrier detect */ + self->priv->link_connected_id = + g_signal_connect (G_OBJECT (monitor), "interface-connected", + G_CALLBACK (nm_device_802_3_ethernet_link_activated), self); + + self->priv->link_disconnected_id = + g_signal_connect (G_OBJECT (monitor), "interface-disconnected", + G_CALLBACK (nm_device_802_3_ethernet_link_deactivated), self); + + self->priv->carrier_file_path = g_strdup_printf ("/sys/class/net/%s/carrier", + nm_device_get_iface (NM_DEVICE (dev))); + } else { + self->priv->link_connected_id = 0; + self->priv->link_disconnected_id = 0; + self->priv->carrier_file_path = NULL; + nm_device_set_active_link (NM_DEVICE (dev), TRUE); + } +} static gboolean -probe_link (NMDevice8023Ethernet *self) +link_activated_helper (NMDevice8023Ethernet *self) { - gboolean have_link = FALSE; - gchar * contents; - gsize length; - - if (nm_device_get_removed (NM_DEVICE (self))) - return FALSE; + NMData * app_data = nm_device_get_app_data (NM_DEVICE (self)); - if (g_file_get_contents (self->priv->carrier_file_path, &contents, &length, NULL)) - { - have_link = (gboolean) atoi (contents); - g_free (contents); + if (app_data->wireless_suppression_source) { + /* If a wired device's link becomes active, stop suppressing + * wireless device activation, because the wired device can now be + * activated. + */ + g_source_destroy (app_data->wireless_suppression_source); + g_source_unref (app_data->wireless_suppression_source); + app_data->wireless_suppression_source = NULL; + nm_policy_schedule_device_change_check (app_data); } - /* We say that non-carrier-detect devices always have a link, because - * they never get auto-selected by NM. The user has to force them on us, - * so we just hope the user knows whether or not the cable's plugged in. - */ - if (!have_link && !(nm_device_get_capabilities (NM_DEVICE (self)) & NM_DEVICE_CAP_CARRIER_DETECT)) - have_link = TRUE; - - return have_link; + nm_device_set_active_link (NM_DEVICE (self), TRUE); + return FALSE; } - static void -real_update_link (NMDevice *dev) +nm_device_802_3_ethernet_link_activated (NmNetlinkMonitor *monitor, + const char *iface, + NMDevice8023Ethernet *self) { - NMDevice8023Ethernet * self = NM_DEVICE_802_3_ETHERNET (dev); + GSource * source; - nm_device_set_active_link (NM_DEVICE (self), probe_link (self)); + /* Make sure signal is for us */ + if (strcmp (nm_device_get_iface (NM_DEVICE (self)), iface)) + return; + + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) link_activated_helper, self, NULL); + g_source_attach (source, nm_device_get_main_context (NM_DEVICE (self))); + g_source_unref (source); } -/* - * nm_device_802_3_periodic_update - * - * Periodically update device statistics and link state. - * - */ static gboolean -nm_device_802_3_periodic_update (gpointer data) +link_deactivated_helper (NMDevice8023Ethernet *self) { - NMDevice8023Ethernet * self = NM_DEVICE_802_3_ETHERNET (data); + nm_device_set_active_link (NM_DEVICE (self), FALSE); + return FALSE; +} - g_return_val_if_fail (self != NULL, TRUE); +static void +nm_device_802_3_ethernet_link_deactivated (NmNetlinkMonitor *monitor, + const char *iface, + NMDevice8023Ethernet *self) +{ + GSource * source; - nm_device_set_active_link (NM_DEVICE (self), probe_link (self)); + /* Make sure signal is for us */ + if (strcmp (nm_device_get_iface (NM_DEVICE (self)), iface)) + return; - return TRUE; + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) link_deactivated_helper, self, NULL); + g_source_attach (source, nm_device_get_main_context (NM_DEVICE (self))); + g_source_unref (source); } - static void -real_start (NMDevice *dev) +real_update_link (NMDevice *dev) { NMDevice8023Ethernet * self = NM_DEVICE_802_3_ETHERNET (dev); - GSource * source; - guint source_id; + gboolean have_link = FALSE; + guint32 caps; + gchar * contents; + gsize length; - self->priv->carrier_file_path = g_strdup_printf ("/sys/class/net/%s/carrier", - nm_device_get_iface (NM_DEVICE (dev))); + if (nm_device_get_removed (NM_DEVICE (self))) + goto out; - /* Peridoically update link status and signal strength */ - source = g_timeout_source_new (2000); - g_source_set_callback (source, nm_device_802_3_periodic_update, self, NULL); - source_id = g_source_attach (source, nm_device_get_main_context (dev)); - g_source_unref (source); + /* Devices that don't support carrier detect are always "on" and + * must be manually chosen by the user. + */ + caps = nm_device_get_capabilities (NM_DEVICE (self)); + if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT)) { + have_link = TRUE; + goto out; + } + + if (g_file_get_contents (self->priv->carrier_file_path, &contents, &length, NULL)) { + have_link = atoi (contents) > 0 ? TRUE : FALSE; + g_free (contents); + } + +out: + nm_device_set_active_link (NM_DEVICE (self), have_link); } @@ -212,12 +273,33 @@ real_get_generic_capabilities (NMDevice return caps; } + +static NMActStageReturn +real_act_stage1_prepare (NMDevice *dev, NMActRequest *req) +{ + NMDevice8023Ethernet * self = NM_DEVICE_802_3_ETHERNET (dev); + NMDevice8023EthernetClass * klass; + NMDeviceClass * parent_class; + + /* Ensure ethernet devices have a link before going further with activation, + * partially works around Fedora #194124. + */ + if (!nm_device_has_active_link (dev)) + return NM_ACT_STAGE_RETURN_FAILURE; + + /* Chain up to parent */ + klass = NM_DEVICE_802_3_ETHERNET_GET_CLASS (self); + parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass)); + return parent_class->act_stage1_prepare (dev, req); +} + static void nm_device_802_3_ethernet_dispose (GObject *object) { NMDevice8023Ethernet * self = NM_DEVICE_802_3_ETHERNET (object); NMDevice8023EthernetClass * klass = NM_DEVICE_802_3_ETHERNET_GET_CLASS (object); NMDeviceClass * parent_class; + NMData * data = nm_device_get_app_data (NM_DEVICE (self)); if (self->priv->dispose_has_run) /* If dispose did already run, return. */ @@ -233,6 +315,15 @@ nm_device_802_3_ethernet_dispose (GObjec * reference. */ + if (self->priv->link_connected_id > 0) { + g_signal_handler_disconnect (G_OBJECT (data->netlink_monitor), + self->priv->link_connected_id); + } + if (self->priv->link_disconnected_id > 0) { + g_signal_handler_disconnect (G_OBJECT (data->netlink_monitor), + self->priv->link_disconnected_id); + } + /* Chain up to the parent class */ parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass)); G_OBJECT_CLASS (parent_class)->dispose (object); @@ -245,7 +336,8 @@ nm_device_802_3_ethernet_finalize (GObje NMDevice8023EthernetClass * klass = NM_DEVICE_802_3_ETHERNET_GET_CLASS (object); NMDeviceClass * parent_class; - g_free (self->priv->carrier_file_path); + if (self->priv->carrier_file_path) + g_free (self->priv->carrier_file_path); /* Chain up to the parent class */ parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass)); @@ -263,8 +355,9 @@ nm_device_802_3_ethernet_class_init (NMD object_class->finalize = nm_device_802_3_ethernet_finalize; parent_class->get_generic_capabilities = real_get_generic_capabilities; - parent_class->start = real_start; + parent_class->init = real_init; parent_class->update_link = real_update_link; + parent_class->act_stage1_prepare = real_act_stage1_prepare; g_type_class_add_private (object_class, sizeof (NMDevice8023EthernetPrivate)); } diff -up NetworkManager-0.6.4/src/NetworkManagerPolicy.c.device-order-fixes NetworkManager-0.6.4/src/NetworkManagerPolicy.c --- NetworkManager-0.6.4/src/NetworkManagerPolicy.c.device-order-fixes 2006-05-28 16:08:11.000000000 -0400 +++ NetworkManager-0.6.4/src/NetworkManagerPolicy.c 2007-12-03 10:57:16.000000000 -0500 @@ -224,7 +224,7 @@ static NMDevice * nm_policy_auto_get_bes best_wired_prio = prio; } } - else if (nm_device_is_802_11_wireless (dev) && data->wireless_enabled) + else if (nm_device_is_802_11_wireless (dev) && data->wireless_enabled && !data->wireless_suppression_source) { /* Don't automatically choose a device that doesn't support wireless scanning */ if (!(caps & NM_DEVICE_CAP_WIRELESS_SCAN)) diff -up NetworkManager-0.6.4/src/NetworkManager.c.device-order-fixes NetworkManager-0.6.4/src/NetworkManager.c --- NetworkManager-0.6.4/src/NetworkManager.c.device-order-fixes 2006-05-27 23:31:53.000000000 -0400 +++ NetworkManager-0.6.4/src/NetworkManager.c 2007-12-03 10:57:16.000000000 -0500 @@ -299,6 +299,21 @@ static void nm_hal_device_new_capability } +static gboolean +wireless_suppression_timeout (gpointer user_data) +{ + NMData * data = (NMData *) user_data; + + g_return_val_if_fail (data != NULL, FALSE); + + g_source_unref (data->wireless_suppression_source); + data->wireless_suppression_source = NULL; + nm_policy_schedule_device_change_check (data); + + return FALSE; +} + + /* * nm_add_initial_devices * @@ -331,7 +345,31 @@ void nm_add_initial_devices (NMData *dat if ((iface = nm_get_device_interface_from_hal (data->hal_ctx, net_devices[i]))) { - nm_create_device_and_add_to_list (data, net_devices[i], iface, FALSE, DEVICE_TYPE_UNKNOWN); + NMDevice *dev; + + dev = nm_create_device_and_add_to_list (data, net_devices[i], iface, FALSE, DEVICE_TYPE_UNKNOWN); + if (NM_IS_DEVICE_802_3_ETHERNET (dev)) { + GSource *source; + guint32 caps; + + if (data->wireless_suppression_source) { + g_source_destroy (data->wireless_suppression_source); + g_source_unref (data->wireless_suppression_source); + } + + caps = nm_device_get_capabilities (dev); + if (caps & NM_DEVICE_CAP_CARRIER_DETECT) { + /* Suppress wireless activation for a bit after initially adding + * a wired device to give the wired device time to perform + * link negotiation and report its carrier status. + */ + source = g_timeout_source_new (5000); + g_source_set_callback (source, wireless_suppression_timeout, data, NULL); + g_source_attach (source, data->main_context); + data->wireless_suppression_source = source; + } + } + g_free (iface); } } @@ -375,6 +413,45 @@ void nm_schedule_state_change_signal_bro } +static void +nm_error_monitoring_device_link_state (NmNetlinkMonitor *monitor, + GError *error, + NMData *data) +{ + /* FIXME: Try to handle the error instead of just printing it. */ + nm_warning ("error monitoring wired ethernet link state: %s\n", + error->message); +} + +static NmNetlinkMonitor * +nm_monitor_setup (NMData *data) +{ + GError *error = NULL; + NmNetlinkMonitor *monitor; + + monitor = nm_netlink_monitor_new (); + nm_netlink_monitor_open_connection (monitor, &error); + if (error != NULL) + { + nm_warning ("could not monitor wired ethernet devices: %s", + error->message); + g_error_free (error); + g_object_unref (monitor); + return NULL; + } + + g_signal_connect (G_OBJECT (monitor), "error", + G_CALLBACK (nm_error_monitoring_device_link_state), + data); + + nm_netlink_monitor_attach (monitor, data->main_context); + + /* Request initial status of cards */ + nm_netlink_monitor_request_status (monitor, NULL); + return monitor; +} + + /* * nm_data_new * @@ -428,12 +505,17 @@ static NMData *nm_data_new (gboolean ena return (NULL); } + /* Create watch functions that monitor cards for link status. */ + if (!(data->netlink_monitor = nm_monitor_setup (data))) + { + nm_data_free (data); + nm_warning ("could not create netlink monitor."); + return NULL; + } + data->enable_test_devices = enable_test_devices; data->wireless_enabled = TRUE; - - nm_policy_schedule_device_change_check (data); - - return (data); + return data; } @@ -478,6 +560,11 @@ static void nm_data_free (NMData *data) nm_dhcp_manager_dispose (data->dhcp_manager); g_object_unref (data->named_manager); + if (data->wireless_suppression_source) { + g_source_destroy (data->wireless_suppression_source); + g_source_unref (data->wireless_suppression_source); + } + g_main_loop_unref (data->main_loop); g_main_context_unref (data->main_context); @@ -502,98 +589,6 @@ static gboolean sigterm_pipe_handler (GI return FALSE; } -static void nm_device_link_activated (NmNetlinkMonitor *monitor, const gchar *interface_name, NMData *data) -{ - NMDevice *dev = NULL; - - if (nm_try_acquire_mutex (data->dev_list_mutex, __func__)) - { - if ((dev = nm_get_device_by_iface (data, interface_name))) - g_object_ref (G_OBJECT (dev)); - nm_unlock_mutex (data->dev_list_mutex, __func__); - } - - /* Don't do anything if we already have a link */ - if (dev) - { - if (nm_device_is_802_3_ethernet (dev) && !nm_device_has_active_link (dev)) - { - nm_device_set_active_link (dev, TRUE); - nm_policy_schedule_device_change_check (data); - } - g_object_unref (G_OBJECT (dev)); - } -} - -static void nm_device_link_deactivated (NmNetlinkMonitor *monitor, const gchar *interface_name, NMData *data) -{ - NMDevice *dev = NULL; - - if (nm_try_acquire_mutex (data->dev_list_mutex, __func__)) - { - if ((dev = nm_get_device_by_iface (data, interface_name))) - g_object_ref (G_OBJECT (dev)); - nm_unlock_mutex (data->dev_list_mutex, __func__); - } - - if (dev) - { - if (nm_device_is_802_3_ethernet (dev)) - nm_device_set_active_link (dev, FALSE); - g_object_unref (G_OBJECT (dev)); - } -} - -static void -nm_error_monitoring_device_link_state (NmNetlinkMonitor *monitor, - GError *error, - NMData *data) -{ - /* FIXME: Try to handle the error instead of just printing it. - */ - nm_warning ("error monitoring wired ethernet link state: %s\n", - error->message); -} - -static void -nm_monitor_wired_link_state (NMData *data) -{ - GError *error; - NmNetlinkMonitor *monitor; - - monitor = nm_netlink_monitor_new (); - - error = NULL; - nm_netlink_monitor_open_connection (monitor, &error); - - if (error != NULL) - { - nm_warning ("could not monitor wired ethernet devices: %s", - error->message); - g_error_free (error); - g_object_unref (monitor); - return; - } - - g_signal_connect (G_OBJECT (monitor), "interface-connected", - G_CALLBACK (nm_device_link_activated), data); - - g_signal_connect (G_OBJECT (monitor), "interface-disconnected", - G_CALLBACK (nm_device_link_deactivated), data); - - g_signal_connect (G_OBJECT (monitor), "error", - G_CALLBACK (nm_error_monitoring_device_link_state), - data); - - nm_netlink_monitor_attach (monitor, data->main_context); - - /* Request initial status of cards - */ - nm_netlink_monitor_request_status (monitor, NULL); - - data->netlink_monitor = monitor; -} - static LibHalContext *nm_get_hal_ctx (NMData *data) { @@ -839,15 +834,12 @@ int main( int argc, char *argv[] ) /* Bring up the loopback interface. */ nm_system_enable_loopback (); - /* Create watch functions that monitor cards for link status. */ - nm_monitor_wired_link_state (nm_data); - /* Get modems, ISDN, and so on's configuration from the system */ nm_data->dialup_list = nm_system_get_dialup_config (); + /* Run the main loop */ + nm_policy_schedule_device_change_check (nm_data); nm_schedule_state_change_signal_broadcast (nm_data); - - /* Wheeee!!! */ g_main_loop_run (nm_data->main_loop); nm_print_open_socks (); diff -up NetworkManager-0.6.4/src/NetworkManagerMain.h.device-order-fixes NetworkManager-0.6.4/src/NetworkManagerMain.h --- NetworkManager-0.6.4/src/NetworkManagerMain.h.device-order-fixes 2006-04-06 10:12:23.000000000 -0400 +++ NetworkManager-0.6.4/src/NetworkManagerMain.h 2007-12-03 10:57:16.000000000 -0500 @@ -91,6 +91,8 @@ typedef struct NMData struct NMAccessPointList *allowed_ap_list; struct NMAccessPointList *invalid_ap_list; + + GSource * wireless_suppression_source; } NMData;