diff --git a/src/devices/nm-device-adsl.c b/src/devices/nm-device-adsl.c index e400a01a6..5b2d5444f 100644 --- a/src/devices/nm-device-adsl.c +++ b/src/devices/nm-device-adsl.c @@ -67,7 +67,6 @@ nm_adsl_error_quark (void) typedef struct { gboolean disposed; - gboolean carrier; guint carrier_poll_id; int atm_index; @@ -84,48 +83,14 @@ typedef struct { char * nas_ifname; } NMDeviceAdslPrivate; -enum { - PROP_0, - PROP_CARRIER, - - LAST_PROP -}; - /**************************************************************/ static guint32 get_generic_capabilities (NMDevice *dev) { - guint32 caps = NM_DEVICE_CAP_NM_SUPPORTED; - caps |= NM_DEVICE_CAP_CARRIER_DETECT; - return caps; -} - -static gboolean -can_interrupt_activation (NMDevice *dev) -{ - NMDeviceAdsl *self = NM_DEVICE_ADSL (dev); - gboolean interrupt = FALSE; - - /* Devices that support carrier detect can interrupt activation - * if the link becomes inactive. - */ - if (NM_DEVICE_ADSL_GET_PRIVATE (self)->carrier == FALSE) - interrupt = TRUE; - - return interrupt; -} - -static gboolean -is_available (NMDevice *dev) -{ - NMDeviceAdsl *self = NM_DEVICE_ADSL (dev); - - /* Can't do anything if there isn't a carrier */ - if (!NM_DEVICE_ADSL_GET_PRIVATE (self)->carrier) - return FALSE; - - return TRUE; + return ( NM_DEVICE_CAP_NM_SUPPORTED + | NM_DEVICE_CAP_CARRIER_DETECT + | NM_DEVICE_CAP_NONSTANDARD_CARRIER); } static gboolean @@ -576,22 +541,6 @@ get_hw_address_length (NMDevice *device) return priv->nas_ifname ? ETH_ALEN : 0; } -static void -set_carrier (NMDeviceAdsl *self, const gboolean carrier) -{ - NMDeviceAdslPrivate *priv; - - g_return_if_fail (NM_IS_DEVICE (self)); - - priv = NM_DEVICE_ADSL_GET_PRIVATE (self); - - if (priv->carrier == carrier) - return; - - priv->carrier = carrier; - g_object_notify (G_OBJECT (self), NM_DEVICE_ADSL_CARRIER); -} - static gboolean carrier_update_cb (gpointer user_data) { @@ -619,7 +568,7 @@ carrier_update_cb (gpointer user_data) carrier = (gboolean) atoi (contents); g_free (contents); - set_carrier (self, carrier); + nm_device_set_carrier (NM_DEVICE (self), carrier); return TRUE; } @@ -720,34 +669,6 @@ dispose (GObject *object) G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object); } -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMDeviceAdsl *self = NM_DEVICE_ADSL (object); - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_CARRIER: - g_value_set_boolean (value, priv->carrier); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - static void nm_device_adsl_init (NMDeviceAdsl *self) { @@ -767,12 +688,8 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass) object_class->constructor = constructor; object_class->dispose = dispose; - object_class->get_property = get_property; - object_class->set_property = set_property; parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->can_interrupt_activation = can_interrupt_activation; - parent_class->is_available = is_available; parent_class->check_connection_compatible = check_connection_compatible; parent_class->complete_connection = complete_connection; @@ -782,15 +699,6 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass) parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; parent_class->deactivate = deactivate; - /* properties */ - g_object_class_install_property - (object_class, PROP_CARRIER, - g_param_spec_boolean (NM_DEVICE_ADSL_CARRIER, - "Carrier", - "Carrier", - FALSE, - G_PARAM_READABLE)); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), G_TYPE_FROM_CLASS (klass), &dbus_glib_nm_device_adsl_object_info); diff --git a/src/devices/nm-device-adsl.h b/src/devices/nm-device-adsl.h index 5cd2c5668..b0a094dd9 100644 --- a/src/devices/nm-device-adsl.h +++ b/src/devices/nm-device-adsl.h @@ -42,8 +42,6 @@ typedef enum { NM_ADSL_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ } NMAdslError; -#define NM_DEVICE_ADSL_CARRIER "carrier" - typedef struct { NMDevice parent; } NMDeviceAdsl; diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 485862d9a..fa74b124e 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -51,7 +51,6 @@ typedef struct { enum { PROP_0, - PROP_CARRIER, PROP_SLAVES, LAST_PROP @@ -320,8 +319,6 @@ get_property (GObject *object, guint prop_id, GSList *list, *iter; switch (prop_id) { - case PROP_CARRIER: - g_value_set_boolean (value, nm_device_wired_get_carrier (NM_DEVICE_WIRED (object))); break; case PROP_SLAVES: slaves = g_ptr_array_new (); @@ -374,14 +371,6 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) parent_class->release_slave = release_slave; /* properties */ - g_object_class_install_property - (object_class, PROP_CARRIER, - g_param_spec_boolean (NM_DEVICE_BOND_CARRIER, - "Carrier", - "Carrier", - FALSE, - G_PARAM_READABLE)); - g_object_class_install_property (object_class, PROP_SLAVES, g_param_spec_boxed (NM_DEVICE_BOND_SLAVES, diff --git a/src/devices/nm-device-bond.h b/src/devices/nm-device-bond.h index 84991ce64..cea1a0e3e 100644 --- a/src/devices/nm-device-bond.h +++ b/src/devices/nm-device-bond.h @@ -40,7 +40,6 @@ typedef enum { NM_BOND_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ } NMBondError; -#define NM_DEVICE_BOND_CARRIER "carrier" #define NM_DEVICE_BOND_SLAVES "slaves" typedef struct { diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index cfa98c6ed..a8f16c523 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -51,7 +51,6 @@ typedef struct { enum { PROP_0, - PROP_CARRIER, PROP_SLAVES, LAST_PROP @@ -353,8 +352,6 @@ get_property (GObject *object, guint prop_id, GSList *list, *iter; switch (prop_id) { - case PROP_CARRIER: - g_value_set_boolean (value, nm_device_wired_get_carrier (NM_DEVICE_WIRED (object))); break; case PROP_SLAVES: slaves = g_ptr_array_new (); @@ -406,14 +403,6 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass) parent_class->release_slave = release_slave; /* properties */ - g_object_class_install_property - (object_class, PROP_CARRIER, - g_param_spec_boolean (NM_DEVICE_BRIDGE_CARRIER, - "Carrier", - "Carrier", - FALSE, - G_PARAM_READABLE)); - g_object_class_install_property (object_class, PROP_SLAVES, g_param_spec_boxed (NM_DEVICE_BRIDGE_SLAVES, diff --git a/src/devices/nm-device-bridge.h b/src/devices/nm-device-bridge.h index 7edfde201..8f9652175 100644 --- a/src/devices/nm-device-bridge.h +++ b/src/devices/nm-device-bridge.h @@ -40,7 +40,6 @@ typedef enum { NM_BRIDGE_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ } NMBridgeError; -#define NM_DEVICE_BRIDGE_CARRIER "carrier" #define NM_DEVICE_BRIDGE_SLAVES "slaves" typedef struct { diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index ab828968c..f2ed9c489 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -102,7 +102,6 @@ enum { PROP_0, PROP_PERM_HW_ADDRESS, PROP_SPEED, - PROP_CARRIER, LAST_PROP }; @@ -1345,9 +1344,6 @@ get_property (GObject *object, guint prop_id, case PROP_SPEED: g_value_set_uint (value, nm_device_wired_get_speed (NM_DEVICE_WIRED (self))); break; - case PROP_CARRIER: - g_value_set_boolean (value, nm_device_wired_get_carrier (NM_DEVICE_WIRED (self))); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1416,14 +1412,6 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) 0, G_MAXUINT32, 0, G_PARAM_READABLE)); - g_object_class_install_property - (object_class, PROP_CARRIER, - g_param_spec_boolean (NM_DEVICE_ETHERNET_CARRIER, - "Carrier", - "Carrier", - FALSE, - G_PARAM_READABLE)); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), G_TYPE_FROM_CLASS (klass), &dbus_glib_nm_device_ethernet_object_info); diff --git a/src/devices/nm-device-ethernet.h b/src/devices/nm-device-ethernet.h index 24a66dce5..117dfd590 100644 --- a/src/devices/nm-device-ethernet.h +++ b/src/devices/nm-device-ethernet.h @@ -44,7 +44,6 @@ typedef enum #define NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS "perm-hw-address" #define NM_DEVICE_ETHERNET_SPEED "speed" -#define NM_DEVICE_ETHERNET_CARRIER "carrier" typedef struct { NMDeviceWired parent; diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index 200370fce..b95193609 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -49,7 +49,6 @@ typedef struct { enum { PROP_0, - PROP_CARRIER, LAST_PROP }; @@ -300,9 +299,6 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { - case PROP_CARRIER: - g_value_set_boolean (value, nm_device_wired_get_carrier (NM_DEVICE_WIRED (object))); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -344,13 +340,6 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) parent_class->get_connection_hw_address = get_connection_hw_address; /* properties */ - g_object_class_install_property - (object_class, PROP_CARRIER, - g_param_spec_boolean (NM_DEVICE_INFINIBAND_CARRIER, - "Carrier", - "Carrier", - FALSE, - G_PARAM_READABLE)); nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), G_TYPE_FROM_CLASS (klass), diff --git a/src/devices/nm-device-infiniband.h b/src/devices/nm-device-infiniband.h index 685a741f6..73f517365 100644 --- a/src/devices/nm-device-infiniband.h +++ b/src/devices/nm-device-infiniband.h @@ -40,8 +40,6 @@ typedef enum { NM_INFINIBAND_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ } NMInfinibandError; -#define NM_DEVICE_INFINIBAND_CARRIER "carrier" - typedef struct { NMDeviceWired parent; } NMDeviceInfiniband; diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index 1d250a438..538d2293c 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -34,6 +34,10 @@ enum NMActStageReturn { NM_ACT_STAGE_RETURN_STOP /* Activation stage done; nothing to do */ }; +#define NM_DEVICE_CAP_NONSTANDARD_CARRIER 0x80000000 + +#define NM_DEVICE_CAP_INTERNAL_MASK 0x80000000 + void nm_device_set_ip_iface (NMDevice *self, const char *iface); void nm_device_activate_schedule_stage3_ip_config_start (NMDevice *device); @@ -87,4 +91,6 @@ gboolean nm_device_get_enslaved (NMDevice *device); NMDevice *nm_device_master_get_slave_by_ifindex (NMDevice *dev, int ifindex); +void nm_device_set_carrier (NMDevice *device, gboolean carrier); + #endif /* NM_DEVICE_PRIVATE_H */ diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index 1a71091ca..7f13bf4e3 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -32,10 +32,10 @@ #include "nm-utils.h" #include "NetworkManagerUtils.h" #include "nm-device-private.h" -#include "nm-netlink-monitor.h" #include "nm-enum-types.h" #include "nm-system.h" #include "nm-dbus-manager.h" +#include "nm-netlink-monitor.h" #include "nm-device-vlan-glue.h" @@ -53,25 +53,15 @@ typedef struct { guint parent_state_id; guint vlan_id; - - gboolean carrier; - NMNetlinkMonitor *monitor; - gulong link_connected_id; - gulong link_disconnected_id; } NMDeviceVlanPrivate; enum { PROP_0, - PROP_CARRIER, PROP_VLAN_ID, LAST_PROP }; -static void -set_carrier (NMDeviceVlan *self, - const gboolean carrier); - /******************************************************************/ static GQuark @@ -92,29 +82,6 @@ get_generic_capabilities (NMDevice *dev) return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NM_SUPPORTED; } -static gboolean -get_carrier_sync (NMDeviceVlan *self) -{ - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - GError *error = NULL; - guint32 ifflags = 0; - - /* Get initial link state */ - if (!nm_netlink_monitor_get_flags_sync (priv->monitor, - nm_device_get_ip_ifindex (NM_DEVICE (self)), - &ifflags, - &error)) { - nm_log_warn (LOGD_HW | LOGD_VLAN, - "(%s): couldn't get carrier state: (%d) %s", - nm_device_get_ip_iface (NM_DEVICE (self)), - error ? error->code : -1, - (error && error->message) ? error->message : "unknown"); - g_clear_error (&error); - } - - return !!(ifflags & IFF_LOWER_UP); -} - static gboolean hw_bring_up (NMDevice *dev, gboolean *no_firmware) { @@ -132,8 +99,22 @@ hw_bring_up (NMDevice *dev, gboolean *no_firmware) */ i = 20; while (i-- > 0) { - carrier = get_carrier_sync (NM_DEVICE_VLAN (dev)); - set_carrier (NM_DEVICE_VLAN (dev), carrier); + GError *error = NULL; + guint32 ifflags = 0; + + if (!nm_netlink_monitor_get_flags_sync (nm_netlink_monitor_get (), + nm_device_get_ifindex (dev), + &ifflags, &error)) { + nm_log_warn (LOGD_DEVICE | LOGD_VLAN, + "(%s): couldn't get carrier state: %s", + nm_device_get_iface (dev), + error->message); + g_clear_error (&error); + break; + } + + carrier = !!(ifflags & IFF_LOWER_UP); + nm_device_set_carrier (dev, carrier); if (carrier) break; g_usleep (100); @@ -142,24 +123,6 @@ hw_bring_up (NMDevice *dev, gboolean *no_firmware) return success; } -static gboolean -can_interrupt_activation (NMDevice *dev) -{ - /* Can interrupt activation if the carrier drops while activating */ - - if (nm_device_ignore_carrier (dev)) - return FALSE; - return NM_DEVICE_VLAN_GET_PRIVATE (dev)->carrier ? FALSE : TRUE; -} - -static gboolean -is_available (NMDevice *dev) -{ - if (nm_device_ignore_carrier (dev)) - return TRUE; - return NM_DEVICE_VLAN_GET_PRIVATE (dev)->carrier ? TRUE : FALSE; -} - /******************************************************************/ static gboolean @@ -340,62 +303,6 @@ match_l2_config (NMDevice *device, NMConnection *connection) /******************************************************************/ -static void -set_carrier (NMDeviceVlan *self, - const gboolean carrier) -{ - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - - if (priv->carrier == carrier) - return; - - priv->carrier = carrier; - g_object_notify (G_OBJECT (self), NM_DEVICE_VLAN_CARRIER); -} - -static void -carrier_on (NMNetlinkMonitor *monitor, int idx, NMDevice *device) -{ - /* Make sure signal is for us */ - if (idx == nm_device_get_ifindex (device)) - set_carrier (NM_DEVICE_VLAN (device), TRUE); -} - -static void -carrier_off (NMNetlinkMonitor *monitor, int idx, NMDevice *device) -{ - /* Make sure signal is for us */ - if (idx == nm_device_get_ifindex (device)) - set_carrier (NM_DEVICE_VLAN (device), FALSE); -} - -static void -carrier_watch_init (NMDeviceVlan *self) -{ - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - - priv->monitor = nm_netlink_monitor_get (); - priv->link_connected_id = g_signal_connect (priv->monitor, "carrier-on", - G_CALLBACK (carrier_on), - self); - priv->link_disconnected_id = g_signal_connect (priv->monitor, "carrier-off", - G_CALLBACK (carrier_off), - self); - - priv->carrier = get_carrier_sync (NM_DEVICE_VLAN (self)); - - nm_log_info (LOGD_HW | LOGD_VLAN, "(%s): carrier is %s", - nm_device_get_iface (NM_DEVICE (self)), - priv->carrier ? "ON" : "OFF"); - - /* Request link state again just in case an error occurred getting the - * initial link state. - */ - nm_netlink_monitor_request_status (priv->monitor); -} - -/******************************************************************/ - static void parent_state_changed (NMDevice *parent, NMDeviceState new_state, @@ -405,14 +312,17 @@ parent_state_changed (NMDevice *parent, { NMDeviceVlan *self = NM_DEVICE_VLAN (user_data); + /* We'll react to our own carrier state notifications. Ignore the parent's. */ + if (reason == NM_DEVICE_STATE_REASON_CARRIER) + return; + if (new_state < NM_DEVICE_STATE_DISCONNECTED) { /* If the parent becomes unavailable or unmanaged so does the VLAN */ nm_device_state_changed (NM_DEVICE (self), new_state, reason); } else if ( new_state == NM_DEVICE_STATE_DISCONNECTED && old_state < NM_DEVICE_STATE_DISCONNECTED) { /* Mark VLAN interface as available/disconnected when the parent - * becomes available as a result of carrier changes or becoming - * initialized. + * becomes available as a result of becoming initialized. */ nm_device_state_changed (NM_DEVICE (self), new_state, reason); } @@ -471,8 +381,6 @@ nm_device_vlan_new (const char *udi, const char *iface, NMDevice *parent) G_CALLBACK (parent_state_changed), device); - carrier_watch_init (NM_DEVICE_VLAN (device)); - nm_log_dbg (LOGD_HW | LOGD_ETHER, "(%s): kernel ifindex %d", iface, ifindex); nm_log_info (LOGD_HW | LOGD_ETHER, "(%s): VLAN ID %d with parent %s", iface, priv->vlan_id, nm_device_get_iface (parent)); @@ -493,9 +401,6 @@ get_property (GObject *object, guint prop_id, NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (object); switch (prop_id) { - case PROP_CARRIER: - g_value_set_boolean (value, priv->carrier); - break; case PROP_VLAN_ID: g_value_set_uint (value, priv->vlan_id); break; @@ -533,11 +438,6 @@ dispose (GObject *object) } priv->disposed = TRUE; - if (priv->link_connected_id) - g_signal_handler_disconnect (priv->monitor, priv->link_connected_id); - if (priv->link_disconnected_id) - g_signal_handler_disconnect (priv->monitor, priv->link_disconnected_id); - g_signal_handler_disconnect (priv->parent, priv->parent_state_id); g_object_unref (priv->parent); @@ -559,22 +459,12 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->hw_bring_up = hw_bring_up; - parent_class->can_interrupt_activation = can_interrupt_activation; - parent_class->is_available = is_available; parent_class->check_connection_compatible = check_connection_compatible; parent_class->complete_connection = complete_connection; parent_class->match_l2_config = match_l2_config; /* properties */ - g_object_class_install_property - (object_class, PROP_CARRIER, - g_param_spec_boolean (NM_DEVICE_VLAN_CARRIER, - "Carrier", - "Carrier", - FALSE, - G_PARAM_READABLE)); - g_object_class_install_property (object_class, PROP_VLAN_ID, g_param_spec_uint (NM_DEVICE_VLAN_ID, diff --git a/src/devices/nm-device-vlan.h b/src/devices/nm-device-vlan.h index ba6ce232a..c5c531733 100644 --- a/src/devices/nm-device-vlan.h +++ b/src/devices/nm-device-vlan.h @@ -40,7 +40,6 @@ typedef enum { NM_VLAN_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ } NMVlanError; -#define NM_DEVICE_VLAN_CARRIER "carrier" #define NM_DEVICE_VLAN_ID "vlan-id" typedef struct { diff --git a/src/devices/nm-device-wired.c b/src/devices/nm-device-wired.c index 776bb7225..b57ad1509 100644 --- a/src/devices/nm-device-wired.c +++ b/src/devices/nm-device-wired.c @@ -21,6 +21,7 @@ #include "config.h" #include +#include #include #include #include @@ -35,8 +36,6 @@ #include "nm-device-private.h" #include "nm-dhcp-manager.h" #include "nm-logging.h" -#include "nm-netlink-monitor.h" -#include "nm-netlink-utils.h" #include "nm-system.h" #include "nm-utils.h" #include "NetworkManagerUtils.h" @@ -49,13 +48,7 @@ G_DEFINE_TYPE (NMDeviceWired, nm_device_wired, NM_TYPE_DEVICE) #define NM_DEVICE_WIRED_LOG_LEVEL(dev) ((nm_device_get_device_type (dev) == NM_DEVICE_TYPE_INFINIBAND) ? LOGD_INFINIBAND : LOGD_ETHER) typedef struct { - gboolean carrier; guint32 speed; - - NMNetlinkMonitor * monitor; - gulong link_connected_id; - gulong link_disconnected_id; - } NMDeviceWiredPrivate; @@ -120,134 +113,14 @@ set_speed (NMDeviceWired *self, const guint32 speed) } static void -set_carrier (NMDeviceWired *self, - gboolean carrier) +carrier_changed (NMDevice *device, gboolean carrier) { - NMDevice *device = NM_DEVICE (self); - NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self); - guint32 caps; + NMDeviceWired *wired_device = NM_DEVICE_WIRED (device); - if (priv->carrier == carrier) - return; + if (carrier) + set_speed (wired_device, ethtool_get_speed (wired_device)); - /* Warn if we try to set carrier down on a device that - * doesn't support carrier detect. These devices assume - * the carrier is always up. - */ - caps = nm_device_get_capabilities (device); - g_return_if_fail (caps & NM_DEVICE_CAP_CARRIER_DETECT); - - priv->carrier = carrier; - g_object_notify (G_OBJECT (self), "carrier"); -} - -static void -carrier_on (NMNetlinkMonitor *monitor, - int idx, - gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - NMDeviceWired *self = NM_DEVICE_WIRED (device); - - /* Make sure signal is for us */ - if (idx == nm_device_get_ifindex (device)) { - set_carrier (self, TRUE); - set_speed (self, ethtool_get_speed (self)); - } -} - -static void -carrier_off (NMNetlinkMonitor *monitor, - int idx, - gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - NMDeviceWired *self = NM_DEVICE_WIRED (device); - - /* Make sure signal is for us */ - if (idx == nm_device_get_ifindex (device)) - set_carrier (self, FALSE); -} - -static gboolean -get_carrier_sync (NMDeviceWired *self) -{ - NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self); - GError *error = NULL; - guint32 ifflags = 0; - - /* Get initial link state */ - if (!nm_netlink_monitor_get_flags_sync (priv->monitor, - nm_device_get_ip_ifindex (NM_DEVICE (self)), - &ifflags, - &error)) { - nm_log_warn (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)), - "(%s): couldn't get carrier state: (%d) %s", - nm_device_get_ip_iface (NM_DEVICE (self)), - error ? error->code : -1, - (error && error->message) ? error->message : "unknown"); - g_clear_error (&error); - } - - return !!(ifflags & IFF_LOWER_UP); -} - -static GObject* -constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) -{ - GObject *object; - NMDeviceWiredPrivate *priv; - NMDevice *self; - guint32 caps; - - object = G_OBJECT_CLASS (nm_device_wired_parent_class)->constructor (type, - n_construct_params, - construct_params); - if (!object) - return NULL; - - self = NM_DEVICE (object); - priv = NM_DEVICE_WIRED_GET_PRIVATE (self); - - nm_log_dbg (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)), - "(%s): kernel ifindex %d", - nm_device_get_iface (NM_DEVICE (self)), - nm_device_get_ifindex (NM_DEVICE (self))); - - caps = nm_device_get_capabilities (self); - if (caps & NM_DEVICE_CAP_CARRIER_DETECT) { - /* Only listen to netlink for cards that support carrier detect */ - priv->monitor = nm_netlink_monitor_get (); - - priv->link_connected_id = g_signal_connect (priv->monitor, "carrier-on", - G_CALLBACK (carrier_on), - self); - priv->link_disconnected_id = g_signal_connect (priv->monitor, "carrier-off", - G_CALLBACK (carrier_off), - self); - - priv->carrier = get_carrier_sync (NM_DEVICE_WIRED (self)); - - nm_log_info (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)), - "(%s): carrier is %s", - nm_device_get_iface (NM_DEVICE (self)), - priv->carrier ? "ON" : "OFF"); - - /* Request link state again just in case an error occurred getting the - * initial link state. - */ - nm_netlink_monitor_request_status (priv->monitor); - } else { - nm_log_info (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)), - "(%s): driver '%s' does not support carrier detection.", - nm_device_get_iface (self), - nm_device_get_driver (self)); - priv->carrier = TRUE; - } - - return object; + G_OBJECT_CLASS (nm_device_wired_parent_class)->carrier_changed (device, carrier); } static void @@ -255,103 +128,6 @@ nm_device_wired_init (NMDeviceWired * self) { } -static gboolean -hw_bring_up (NMDevice *dev, gboolean *no_firmware) -{ - gboolean result, carrier; - guint32 caps; - - result = NM_DEVICE_CLASS(nm_device_wired_parent_class)->hw_bring_up (dev, no_firmware); - if (result) { - caps = nm_device_get_capabilities (dev); - if (caps & NM_DEVICE_CAP_CARRIER_DETECT) { - carrier = get_carrier_sync (NM_DEVICE_WIRED (dev)); - set_carrier (NM_DEVICE_WIRED (dev), carrier); - } - } - return result; -} - -/* Returns %TRUE if @self is unavailable for connections because it - * needs carrier but does not have it. - */ -static gboolean -nm_device_wired_unavailable_because_of_carrier (NMDeviceWired *self) -{ - NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self); - - return !priv->carrier && !nm_device_ignore_carrier (NM_DEVICE (self)); -} - -static gboolean -can_interrupt_activation (NMDevice *dev) -{ - NMDeviceWired *self = NM_DEVICE_WIRED (dev); - - /* Devices that support carrier detect can interrupt activation - * if the link becomes inactive. - */ - return nm_device_wired_unavailable_because_of_carrier (self); -} - -static gboolean -is_available (NMDevice *dev) -{ - NMDeviceWired *self = NM_DEVICE_WIRED (dev); - - return !nm_device_wired_unavailable_because_of_carrier (self); -} - -static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *device, - NMIP4Config **out_config, - NMDeviceStateReason *reason) -{ - if ( nm_device_is_master (device) - && nm_device_wired_unavailable_because_of_carrier (NM_DEVICE_WIRED (device))) { - nm_log_info (LOGD_IP4 | NM_DEVICE_WIRED_LOG_LEVEL (device), - "(%s): IPv4 config waiting until carrier is on", - nm_device_get_ip_iface (device)); - return NM_ACT_STAGE_RETURN_WAIT; - } - - return NM_DEVICE_CLASS (nm_device_wired_parent_class)->act_stage3_ip4_config_start (device, out_config, reason); -} - -static NMActStageReturn -act_stage3_ip6_config_start (NMDevice *device, - NMIP6Config **out_config, - NMDeviceStateReason *reason) -{ - if ( nm_device_is_master (device) - && nm_device_wired_unavailable_because_of_carrier (NM_DEVICE_WIRED (device))) { - nm_log_info (LOGD_IP6 | NM_DEVICE_WIRED_LOG_LEVEL (device), - "(%s): IPv6 config waiting until carrier is on", - nm_device_get_ip_iface (device)); - return NM_ACT_STAGE_RETURN_WAIT; - } - - return NM_DEVICE_CLASS (nm_device_wired_parent_class)->act_stage3_ip6_config_start (device, out_config, reason); -} - -static void -dispose (GObject *object) -{ - NMDeviceWired *self = NM_DEVICE_WIRED (object); - NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self); - - if (priv->link_connected_id) { - g_signal_handler_disconnect (priv->monitor, priv->link_connected_id); - priv->link_connected_id = 0; - } - if (priv->link_disconnected_id) { - g_signal_handler_disconnect (priv->monitor, priv->link_disconnected_id); - priv->link_disconnected_id = 0; - } - - G_OBJECT_CLASS (nm_device_wired_parent_class)->dispose (object); -} - static void nm_device_wired_class_init (NMDeviceWiredClass *klass) { @@ -361,33 +137,8 @@ nm_device_wired_class_init (NMDeviceWiredClass *klass) g_type_class_add_private (object_class, sizeof (NMDeviceWiredPrivate)); /* virtual methods */ - object_class->constructor = constructor; - object_class->dispose = dispose; - parent_class->hw_bring_up = hw_bring_up; - parent_class->can_interrupt_activation = can_interrupt_activation; - parent_class->is_available = is_available; - parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - parent_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; -} - -/** - * nm_device_wired_get_carrier: - * @dev: an #NMDeviceWired - * - * Get @dev's carrier status - * - * Return value: @dev's carrier - */ -gboolean -nm_device_wired_get_carrier (NMDeviceWired *dev) -{ - NMDeviceWiredPrivate *priv; - - g_return_val_if_fail (dev != NULL, FALSE); - - priv = NM_DEVICE_WIRED_GET_PRIVATE (dev); - return priv->carrier; + parent_class->carrier_changed = carrier_changed; } /** diff --git a/src/devices/nm-device-wired.h b/src/devices/nm-device-wired.h index c88f2b8f3..140037469 100644 --- a/src/devices/nm-device-wired.h +++ b/src/devices/nm-device-wired.h @@ -41,12 +41,10 @@ typedef struct { typedef struct { NMDeviceClass parent; - } NMDeviceWiredClass; GType nm_device_wired_get_type (void); -gboolean nm_device_wired_get_carrier (NMDeviceWired *dev); guint32 nm_device_wired_get_speed (NMDeviceWired *dev); G_END_DECLS diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 17f164719..1438b5faf 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -111,6 +111,7 @@ enum { PROP_DRIVER_VERSION, PROP_FIRMWARE_VERSION, PROP_CAPABILITIES, + PROP_CARRIER, PROP_IP4_ADDRESS, PROP_IP4_CONFIG, PROP_DHCP4_CONFIG, @@ -202,6 +203,13 @@ typedef struct { gulong secrets_updated_id; gulong secrets_failed_id; + /* Link stuff */ + guint link_connected_id; + guint link_disconnected_id; + guint carrier_defer_id; + gboolean carrier; + gboolean ignore_carrier; + /* Generic DHCP stuff */ NMDHCPManager * dhcp_manager; guint32 dhcp_timeout; @@ -273,10 +281,6 @@ typedef struct { guint cp_removed_id; guint cp_updated_id; - /* carrier handling */ - gboolean ignore_carrier; - guint carrier_action_defer_id; - } NMDevicePrivate; static void nm_device_take_down (NMDevice *dev, gboolean wait, NMDeviceStateReason reason); @@ -312,8 +316,9 @@ static void cp_connection_updated (NMConnectionProvider *cp, NMConnection *conne static const char *state_to_string (NMDeviceState state); -static void carrier_changed (GObject *object, GParamSpec *param, gpointer user_data); -static void carrier_action_defer_clear (NMDevice *self); +static void link_connected_cb (NMNetlinkMonitor *monitor, int ifindex, NMDevice *device); +static void link_disconnected_cb (NMNetlinkMonitor *monitor, int ifindex, NMDevice *device); +static void check_carrier (NMDevice *device); static void nm_device_queued_ip_config_change_clear (NMDevice *self); static void update_ip_config (NMDevice *self); @@ -468,6 +473,12 @@ device_get_driver_info (const char *iface, char **driver_version, char **firmwar return TRUE; } +static gboolean +device_has_capability (NMDevice *device, NMDeviceCapabilities caps) +{ + return !!(NM_DEVICE_GET_PRIVATE (device)->capabilities & caps); +} + static GObject* constructor (GType type, guint n_construct_params, @@ -497,7 +508,7 @@ constructor (GType type, } priv->capabilities |= NM_DEVICE_GET_CLASS (dev)->get_generic_capabilities (dev); - if (!(priv->capabilities & NM_DEVICE_CAP_NM_SUPPORTED)) { + if (!device_has_capability (dev, NM_DEVICE_CAP_NM_SUPPORTED)) { nm_log_warn (LOGD_DEVICE, "(%s): Device unsupported, ignoring.", priv->iface); goto error; } @@ -524,6 +535,7 @@ static void constructed (GObject *object) { NMDevice *dev = NM_DEVICE (object); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev); nm_device_update_hw_address (dev); @@ -534,13 +546,38 @@ constructed (GObject *object) NM_DEVICE_GET_CLASS (dev)->update_initial_hw_address (dev); /* Have to call update_initial_hw_address() before calling get_ignore_carrier() */ - if (g_object_class_find_property (G_OBJECT_GET_CLASS (dev), "carrier")) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev); - NMConfig *config = nm_config_get (); + if (device_has_capability (dev, NM_DEVICE_CAP_CARRIER_DETECT)) { + priv->ignore_carrier = nm_config_get_ignore_carrier (nm_config_get (), NM_CONFIG_DEVICE (dev)); - priv->ignore_carrier = nm_config_get_ignore_carrier (config, NM_CONFIG_DEVICE (dev)); - if (!priv->ignore_carrier) - g_signal_connect (dev, "notify::carrier", G_CALLBACK (carrier_changed), NULL); + check_carrier (dev); + nm_log_info (LOGD_HW, + "(%s): carrier is %s%s", + nm_device_get_iface (NM_DEVICE (dev)), + priv->carrier ? "ON" : "OFF", + priv->ignore_carrier ? " (but ignored)" : ""); + + if (!device_has_capability (dev, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) { + NMNetlinkMonitor *netlink_monitor = nm_netlink_monitor_get (); + + priv->link_connected_id = g_signal_connect (netlink_monitor, "carrier-on", + G_CALLBACK (link_connected_cb), dev); + priv->link_disconnected_id = g_signal_connect (netlink_monitor, "carrier-off", + G_CALLBACK (link_disconnected_cb), dev); + + /* Request link state again just in case an error occurred getting the + * initial link state. + * + * TODO: Check if this is necessary at all. + */ + nm_netlink_monitor_request_status (netlink_monitor); + } + } else { + nm_log_info (LOGD_HW, + "(%s): driver '%s' does not support carrier detection.", + nm_device_get_iface (dev), + nm_device_get_driver (dev)); + /* Fake online link when carrier detection is not available. */ + priv->carrier = TRUE; } if (G_OBJECT_CLASS (nm_device_parent_class)->constructed) @@ -986,6 +1023,162 @@ nm_device_release_one_slave (NMDevice *dev, NMDevice *slave, gboolean failed) return success; } +static void +carrier_changed (NMDevice *device, gboolean carrier) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); + + if (priv->ignore_carrier || !nm_device_get_managed (device)) + return; + + if (nm_device_is_master (device)) { + /* Bridge/bond carrier does not affect its own activation, but + * when carrier comes on, if there are slaves waiting, it will + * restart them. + */ + if (!carrier) + return; + + if (nm_device_activate_ip4_state_in_wait (device)) + nm_device_activate_stage3_ip4_start (device); + if (nm_device_activate_ip6_state_in_wait (device)) + nm_device_activate_stage3_ip6_start (device); + + return; + } else if (nm_device_get_enslaved (device) && !carrier) { + /* Slaves don't deactivate when they lose carrier; for bonds + * in particular that would be actively counterproductive. + */ + return; + } + + if (carrier) { + g_warn_if_fail (priv->state >= NM_DEVICE_STATE_UNAVAILABLE); + + if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) { + nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_CARRIER); + } + } else { + g_return_if_fail (priv->state >= NM_DEVICE_STATE_UNAVAILABLE); + + if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) { + if (nm_device_queued_state_peek (device) >= NM_DEVICE_STATE_DISCONNECTED) + nm_device_queued_state_clear (device); + } else { + nm_device_queue_state (device, NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_CARRIER); + } + } +} + +gboolean +nm_device_has_carrier (NMDevice *device) +{ + return NM_DEVICE_GET_PRIVATE (device)->carrier; +} + +/* Returns %TRUE if @device is unavailable for connections because it + * needs carrier but does not have it. + */ +static gboolean +nm_device_is_unavailable_because_of_carrier (NMDevice *device) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); + + return !priv->carrier && !priv->ignore_carrier; +} + +#define LINK_DISCONNECT_DELAY 4 + +static gboolean +link_disconnect_action_cb (gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); + + priv->carrier_defer_id = 0; + + nm_log_info (LOGD_DEVICE, "(%s): link disconnected (calling deferred action)", + nm_device_get_iface (device)); + + NM_DEVICE_GET_CLASS (device)->carrier_changed (device, FALSE); + + return FALSE; +} + +void +nm_device_set_carrier (NMDevice *device, gboolean carrier) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); + NMDeviceClass *klass = NM_DEVICE_GET_CLASS (device); + NMDeviceState state = nm_device_get_state (device); + const char *iface = nm_device_get_iface (device); + + if (priv->carrier == carrier) + return; + + priv->carrier = carrier; + g_object_notify (G_OBJECT (device), NM_DEVICE_CARRIER); + + if (priv->carrier) { + nm_log_info (LOGD_DEVICE, "(%s): link connected", iface); + if (priv->carrier_defer_id) { + g_source_remove (priv->carrier_defer_id); + priv->carrier_defer_id = 0; + } + klass->carrier_changed (device, TRUE); + } else if (state <= NM_DEVICE_STATE_DISCONNECTED) { + nm_log_info (LOGD_DEVICE, "(%s): link disconnected", iface); + klass->carrier_changed (device, FALSE); + } else { + nm_log_info (LOGD_DEVICE, "(%s): link disconnected (deferring action for %d seconds)", + iface, LINK_DISCONNECT_DELAY); + priv->carrier_defer_id = g_timeout_add_seconds (LINK_DISCONNECT_DELAY, + link_disconnect_action_cb, device); + } +} + +static void +link_connected_cb (NMNetlinkMonitor *monitor, int ifindex, NMDevice *device) +{ + if (ifindex == nm_device_get_ifindex (device)) + nm_device_set_carrier (device, TRUE); +} + +static void +link_disconnected_cb (NMNetlinkMonitor *monitor, int ifindex, NMDevice *device) +{ + if (ifindex == nm_device_get_ifindex (device)) + nm_device_set_carrier (device, FALSE); +} + +static void +check_carrier (NMDevice *device) +{ + GError *error = NULL; + guint32 ifflags = 0; + + if (device_has_capability (device, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) { + /* Don't try to get an updated state, just keep the old one. */ + return; + } + + if (!nm_netlink_monitor_get_flags_sync (nm_netlink_monitor_get (), + nm_device_get_ip_ifindex (device), + &ifflags, + &error)) { + nm_log_warn (LOGD_DEVICE, + "(%s): couldn't get carrier state: (%d) %s", + nm_device_get_ip_iface (device), + error ? error->code : -1, + (error && error->message) ? error->message : "unknown"); + g_clear_error (&error); + } + + nm_device_set_carrier (device, !!(ifflags & IFF_LOWER_UP)); +} + static void slave_state_changed (NMDevice *slave, NMDeviceState slave_new_state, @@ -1219,109 +1412,6 @@ nm_device_get_act_request (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->act_request; } -static void -carrier_action_defer_clear (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - if (priv->carrier_action_defer_id) { - g_source_remove (priv->carrier_action_defer_id); - priv->carrier_action_defer_id = 0; - } -} - -static gboolean -carrier_action_defer_cb (gpointer user_data) -{ - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceState state; - - priv->carrier_action_defer_id = 0; - - /* We know that carrier is FALSE */ - - state = nm_device_get_state (self); - if (state >= NM_DEVICE_STATE_DISCONNECTED) - nm_device_queue_state (self, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER); - - return FALSE; -} - -static void -carrier_changed (GObject *object, GParamSpec *param, gpointer user_data) -{ - NMDevice *self = NM_DEVICE (object); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean carrier, defer_action = FALSE; - NMDeviceState state; - - /* Clear any previous deferred action */ - carrier_action_defer_clear (self); - - state = nm_device_get_state (self); - if (state < NM_DEVICE_STATE_UNAVAILABLE) - return; - - g_object_get (object, "carrier", &carrier, NULL); - - if (nm_device_is_master (self)) { - /* Bridge/bond carrier does not affect its own activation, but - * when carrier comes on, if there are slaves waiting, it will - * restart them. - */ - if (!carrier) - return; - - if (!nm_device_activate_ip4_state_in_wait (self) && - !nm_device_activate_ip6_state_in_wait (self)) - return; - } else if (nm_device_get_enslaved (self) && !carrier) { - /* Slaves don't deactivate when they lose carrier; for bonds - * in particular that would be actively counterproductive. - */ - return; - } - - if (priv->act_request && !carrier) - defer_action = TRUE; - - nm_log_info (LOGD_HW | LOGD_DEVICE, "(%s): carrier now %s (device state %d%s)", - nm_device_get_iface (self), - carrier ? "ON" : "OFF", - state, - defer_action ? ", deferring action for 4 seconds" : ""); - - if (nm_device_is_master (self)) { - if (nm_device_activate_ip4_state_in_wait (self)) - nm_device_activate_stage3_ip4_start (self); - - if (nm_device_activate_ip6_state_in_wait (self)) - nm_device_activate_stage3_ip6_start (self); - - return; - } - - if (state == NM_DEVICE_STATE_UNAVAILABLE) { - if (carrier) - nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER); - else { - /* clear any queued state changes if they wouldn't be valid when the - * carrier is off. - */ - if (nm_device_queued_state_peek (self) >= NM_DEVICE_STATE_DISCONNECTED) - nm_device_queued_state_clear (self); - } - } else if (state >= NM_DEVICE_STATE_DISCONNECTED) { - if (!carrier) { - if (defer_action) - priv->carrier_action_defer_id = g_timeout_add_seconds (4, carrier_action_defer_cb, self); - else - nm_device_queue_state (self, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER); - } - } -} - NMConnection * nm_device_get_connection (NMDevice *self) { @@ -1330,6 +1420,14 @@ nm_device_get_connection (NMDevice *self) return priv->act_request ? nm_act_request_get_connection (priv->act_request) : NULL; } +static gboolean +is_available (NMDevice *device) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); + + return priv->carrier || priv->ignore_carrier; +} + gboolean nm_device_is_available (NMDevice *self) { @@ -1338,9 +1436,7 @@ nm_device_is_available (NMDevice *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; + return NM_DEVICE_GET_CLASS (self)->is_available (self); } gboolean @@ -2420,6 +2516,14 @@ act_stage3_ip4_config_start (NMDevice *self, g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); + if ( nm_device_is_master (self) + && nm_device_is_unavailable_because_of_carrier (self)) { + nm_log_info (LOGD_IP4 | LOGD_DEVICE, + "(%s): IPv4 config waiting until carrier is on", + nm_device_get_ip_iface (self)); + return NM_ACT_STAGE_RETURN_WAIT; + } + connection = nm_device_get_connection (self); g_assert (connection); @@ -3019,6 +3123,14 @@ act_stage3_ip6_config_start (NMDevice *self, g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); + if ( nm_device_is_master (self) + && nm_device_is_unavailable_because_of_carrier (self)) { + nm_log_info (LOGD_IP6 | LOGD_DEVICE, + "(%s): IPv6 config waiting until carrier is on", + nm_device_get_ip_iface (self)); + return NM_ACT_STAGE_RETURN_WAIT; + } + connection = nm_device_get_connection (self); g_assert (connection); @@ -4212,6 +4324,15 @@ nm_device_is_activating (NMDevice *device) } +static gboolean +can_interrupt_activation (NMDevice *device) +{ + /* Devices that support carrier detect can interrupt activation + * if the link becomes inactive. + */ + return nm_device_is_unavailable_because_of_carrier (device); +} + gboolean nm_device_can_interrupt_activation (NMDevice *self) { @@ -4426,8 +4547,18 @@ static gboolean hw_bring_up (NMDevice *device, gboolean *no_firmware) { int ifindex = nm_device_get_ip_ifindex (device); + gboolean result; - return ifindex > 0 ? nm_system_iface_set_up (ifindex, TRUE, no_firmware) : TRUE; + if (!ifindex) + return TRUE; + + result = nm_system_iface_set_up (ifindex, TRUE, no_firmware); + + /* Store carrier immediately. */ + if (result && device_has_capability (device, NM_DEVICE_CAP_CARRIER_DETECT)) + check_carrier (device); + + return result; } void @@ -4572,6 +4703,15 @@ dispose (GObject *object) } g_free (priv->ip6_privacy_tempaddr_path); + if (priv->link_connected_id) + g_signal_handler_disconnect (nm_netlink_monitor_get (), priv->link_connected_id); + if (priv->link_disconnected_id) + g_signal_handler_disconnect (nm_netlink_monitor_get (), priv->link_disconnected_id); + if (priv->carrier_defer_id) { + g_source_remove (priv->carrier_defer_id); + priv->carrier_defer_id = 0; + } + if (priv->cp_added_id) { g_signal_handler_disconnect (priv->con_provider, priv->cp_added_id); priv->cp_added_id = 0; @@ -4592,8 +4732,6 @@ dispose (GObject *object) priv->cp_updated_id = 0; } - carrier_action_defer_clear (self); - g_hash_table_unref (priv->available_connections); activation_source_clear (self, TRUE, AF_INET); @@ -4781,11 +4919,14 @@ get_property (GObject *object, guint prop_id, g_value_set_string (value, priv->firmware_version); break; case PROP_CAPABILITIES: - g_value_set_uint (value, priv->capabilities); + g_value_set_uint (value, (priv->capabilities & ~NM_DEVICE_CAP_INTERNAL_MASK)); break; case PROP_IP4_ADDRESS: g_value_set_uint (value, priv->ip4_address); break; + case PROP_CARRIER: + g_value_set_boolean (value, priv->carrier); + break; case PROP_IP4_CONFIG: if (has_ip_config (self) && priv->ip4_config) g_value_set_boxed (value, nm_ip4_config_get_dbus_path (priv->ip4_config)); @@ -4865,7 +5006,6 @@ get_property (GObject *object, guint prop_id, } } - static void nm_device_class_init (NMDeviceClass *klass) { @@ -4883,6 +5023,7 @@ nm_device_class_init (NMDeviceClass *klass) klass->get_type_capabilities = get_type_capabilities; klass->get_generic_capabilities = get_generic_capabilities; + klass->is_available = is_available; klass->act_stage1_prepare = act_stage1_prepare; klass->act_stage2_config = act_stage2_config; klass->act_stage3_ip4_config_start = act_stage3_ip4_config_start; @@ -4898,6 +5039,8 @@ nm_device_class_init (NMDeviceClass *klass) klass->hw_is_up = hw_is_up; klass->hw_bring_up = hw_bring_up; klass->hw_take_down = hw_take_down; + klass->carrier_changed = carrier_changed; + klass->can_interrupt_activation = can_interrupt_activation; /* Properties */ g_object_class_install_property @@ -4956,6 +5099,14 @@ nm_device_class_init (NMDeviceClass *klass) 0, G_MAXUINT32, NM_DEVICE_CAP_NONE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property + (object_class, PROP_CARRIER, + g_param_spec_boolean (NM_DEVICE_CARRIER, + "Carrier", + "Carrier", + FALSE, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_IP4_ADDRESS, g_param_spec_uint (NM_DEVICE_IP4_ADDRESS, diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index f6b4f95f4..e62664cdb 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -45,6 +45,7 @@ #define NM_DEVICE_DRIVER_VERSION "driver-version" #define NM_DEVICE_FIRMWARE_VERSION "firmware-version" #define NM_DEVICE_CAPABILITIES "capabilities" +#define NM_DEVICE_CARRIER "carrier" #define NM_DEVICE_IP4_ADDRESS "ip4-address" #define NM_DEVICE_IP4_CONFIG "ip4-config" #define NM_DEVICE_DHCP4_CONFIG "dhcp4-config" @@ -99,11 +100,14 @@ typedef struct { NMDeviceState old_state, NMDeviceStateReason reason); - /* Hardware state, ie IFF_UP */ + /* Hardware state (IFF_UP) */ gboolean (*hw_is_up) (NMDevice *self); gboolean (*hw_bring_up) (NMDevice *self, gboolean *no_firmware); void (*hw_take_down) (NMDevice *self); + /* Carrier state (IFF_LOWER_UP) */ + void (*carrier_changed) (NMDevice *, gboolean carrier); + /* Additional stuff required to operate the device, like a * connection to the supplicant, Bluez, etc */ @@ -239,6 +243,7 @@ NMConnection * nm_device_get_connection (NMDevice *dev); gboolean nm_device_is_available (NMDevice *dev); gboolean nm_device_can_activate (NMDevice *dev); +gboolean nm_device_has_carrier (NMDevice *dev); gboolean nm_device_ignore_carrier (NMDevice *dev); NMConnection * nm_device_get_best_auto_connection (NMDevice *dev,