core: autoconnect fixes for default-unmanaged devices and property notification
authorDan Williams <dcbw@redhat.com>
Thu, 23 Oct 2014 19:57:22 +0000 (14:57 -0500)
committerDan Williams <dcbw@redhat.com>
Mon, 27 Oct 2014 18:46:06 +0000 (13:46 -0500)
Previously the only thing preventing default-unmanaged devices from
being auto-activated was luck and the fact that they didn't have any
available connections when in the UNMANAGED state.  That's no longer
true, so we must be more explicit about their behavior.

Furthermore it makes no sense to allow default-unmanaged devices
to set priv->autoconnect=TRUE since that is never supposed to
happen, so enforce that both in NM itself and if the change
request comes in over the D-Bus interface.

Lastly, internal priv->autoconnect=TRUE changes never emitted a
property change notification, meaning the NMPolicy would never
schedule an autoconnect check if the device's priv->autoconnect
was set to TRUE as a result of re-activating or waking from sleep.

introspection/nm-device.xml
src/devices/nm-device.c
src/nm-policy.c

index 0dca23c..0c2a330 100644 (file)
         If TRUE, indicates the device is allowed to autoconnect.  If FALSE,
         manual intervention is required before the device will automatically
         connect to a known network, such as activating a connection using the
-        device, or setting this property to TRUE.
+        device, or setting this property to TRUE.  This property cannot be
+        set to TRUE for default-unmanaged devices, since they never autoconnect.
       </tp:docstring>
     </property>
     <property name="FirmwareMissing" type="b" access="read">
index 87bebdb..9f03831 100644 (file)
@@ -1573,6 +1573,15 @@ nm_device_set_enabled (NMDevice *self, gboolean enabled)
                NM_DEVICE_GET_CLASS (self)->set_enabled (self, enabled);
 }
 
+/**
+ * nm_device_get_autoconnect:
+ * @self: the #NMDevice
+ *
+ * Returns: %TRUE if the device allows autoconnect connections, or %FALSE if the
+ * device is explicitly blocking all autoconnect connections.  Does not take
+ * into account transient conditions like companion devices that may wish to
+ * block the device.
+ */
 gboolean
 nm_device_get_autoconnect (NMDevice *self)
 {
@@ -1581,6 +1590,29 @@ nm_device_get_autoconnect (NMDevice *self)
        return NM_DEVICE_GET_PRIVATE (self)->autoconnect;
 }
 
+static void
+nm_device_set_autoconnect (NMDevice *self, gboolean autoconnect)
+{
+       NMDevicePrivate *priv;
+
+       g_return_if_fail (NM_IS_DEVICE (self));
+
+       priv = NM_DEVICE_GET_PRIVATE (self);
+       if (priv->autoconnect == autoconnect)
+               return;
+
+       if (autoconnect) {
+               /* Default-unmanaged devices never autoconnect */
+               if (!nm_device_get_default_unmanaged (self)) {
+                       priv->autoconnect = TRUE;
+                       g_object_notify (G_OBJECT (self), NM_DEVICE_AUTOCONNECT);
+               }
+       } else {
+               priv->autoconnect = FALSE;
+               g_object_notify (G_OBJECT (self), NM_DEVICE_AUTOCONNECT);
+       }
+}
+
 static gboolean
 autoconnect_allowed_accumulator (GSignalInvocationHint *ihint,
                                  GValue *return_accu,
@@ -1591,6 +1623,14 @@ autoconnect_allowed_accumulator (GSignalInvocationHint *ihint,
        return TRUE;
 }
 
+/**
+ * nm_device_autoconnect_allowed:
+ * @self: the #NMDevice
+ *
+ * Returns: %TRUE if the device can be auto-connected immediately, taking
+ * transient conditions into account (like companion devices that may wish to
+ * block autoconnect for a time).
+ */
 gboolean
 nm_device_autoconnect_allowed (NMDevice *self)
 {
@@ -1598,6 +1638,16 @@ nm_device_autoconnect_allowed (NMDevice *self)
        GValue instance = G_VALUE_INIT;
        GValue retval = G_VALUE_INIT;
 
+       if (priv->state < NM_DEVICE_STATE_DISCONNECTED || !priv->autoconnect)
+               return FALSE;
+
+       /* The 'autoconnect-allowed' signal is emitted on a device to allow
+        * other listeners to block autoconnect on the device if they wish.
+        * This is mainly used by the OLPC Mesh devices to block autoconnect
+        * on their companion WiFi device as they share radio resources and
+        * cannot be connected at the same time.
+        */
+
        g_value_init (&instance, G_TYPE_OBJECT);
        g_value_set_object (&instance, self);
 
@@ -1639,8 +1689,9 @@ can_auto_connect (NMDevice *self,
  * Checks if @connection can be auto-activated on @self right now.
  * This requires, at a minimum, that the connection be compatible with
  * @self, and that it have the #NMSettingConnection:autoconnect property
- * set. Some devices impose additional requirements. (Eg, a Wi-Fi connection
- * can only be activated if its SSID was seen in the last scan.)
+ * set, and that the device allow auto connections. Some devices impose
+ * additional requirements. (Eg, a Wi-Fi connection can only be activated
+ * if its SSID was seen in the last scan.)
  *
  * Returns: %TRUE, if the @connection can be auto-activated.
  **/
@@ -1653,7 +1704,9 @@ nm_device_can_auto_connect (NMDevice *self,
        g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
        g_return_val_if_fail (specific_object && !*specific_object, FALSE);
 
-       return NM_DEVICE_GET_CLASS (self)->can_auto_connect (self, connection, specific_object);
+       if (nm_device_autoconnect_allowed (self))
+               return NM_DEVICE_GET_CLASS (self)->can_auto_connect (self, connection, specific_object);
+       return FALSE;
 }
 
 static gboolean
@@ -5076,7 +5129,7 @@ disconnect_cb (NMDevice *self,
                dbus_g_method_return_error (context, local);
                g_error_free (local);
        } else {
-               priv->autoconnect = FALSE;
+               nm_device_set_autoconnect (self, FALSE);
 
                nm_device_state_changed (self,
                                         NM_DEVICE_STATE_DEACTIVATING,
@@ -6856,7 +6909,7 @@ _set_state_full (NMDevice *self,
        /* Reset autoconnect flag when the device is activating or connected. */
        if (   state >= NM_DEVICE_STATE_PREPARE
            && state <= NM_DEVICE_STATE_ACTIVATED)
-               priv->autoconnect = TRUE;
+               nm_device_set_autoconnect (self, TRUE);
 
        g_object_notify (G_OBJECT (self), NM_DEVICE_STATE);
        g_object_notify (G_OBJECT (self), NM_DEVICE_STATE_REASON);
@@ -7412,8 +7465,10 @@ constructed (GObject *object)
         * since they don't transition from UNMANAGED (and thus the state handler
         * doesn't run and update them) until something external happens.
         */
-       if (nm_device_get_default_unmanaged (self))
+       if (nm_device_get_default_unmanaged (self)) {
+               nm_device_set_autoconnect (self, FALSE);
                nm_device_recheck_available_connections (self);
+       }
 
        G_OBJECT_CLASS (nm_device_parent_class)->constructed (object);
 }
@@ -7561,7 +7616,7 @@ set_property (GObject *object, guint prop_id,
                priv->ip4_address = g_value_get_uint (value);
                break;
        case PROP_AUTOCONNECT:
-               priv->autoconnect = g_value_get_boolean (value);
+               nm_device_set_autoconnect (self, g_value_get_boolean (value));
                break;
        case PROP_FIRMWARE_MISSING:
                priv->firmware_missing = g_value_get_boolean (value);
index ff100d0..ddb85bd 100644 (file)
@@ -1658,7 +1658,7 @@ device_autoconnect_changed (NMDevice *device,
                             GParamSpec *pspec,
                             gpointer user_data)
 {
-       if (nm_device_get_autoconnect (device))
+       if (nm_device_autoconnect_allowed (device))
                schedule_activate_check ((NMPolicy *) user_data, device);
 }