summary refs log tree commit diff
path: root/src/devices
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices')
-rw-r--r--src/devices/bluetooth/nm-device-bt.c3
-rw-r--r--src/devices/nm-device.c160
-rw-r--r--src/devices/nm-device.h33
-rw-r--r--src/devices/wifi/nm-device-olpc-mesh.c8
-rw-r--r--src/devices/wifi/nm-device-wifi.c3
-rw-r--r--src/devices/wwan/nm-device-modem.c3
-rw-r--r--src/devices/wwan/nm-modem-ofono.c189
7 files changed, 198 insertions, 201 deletions
diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c
index 0d46be8f..977c1e1a 100644
--- a/src/devices/bluetooth/nm-device-bt.c
+++ b/src/devices/bluetooth/nm-device-bt.c
@@ -491,8 +491,7 @@ modem_prepare_result (NMModem *modem,
 			 * the device to be auto-activated anymore, which would risk locking
 			 * the SIM if the incorrect PIN continues to be used.
 			 */
-			_LOGI (LOGD_MB, "disabling autoconnect due to failed SIM PIN");
-			nm_device_set_autoconnect_intern (device, FALSE);
+			nm_device_autoconnect_blocked_set (device, NM_DEVICE_AUTOCONNECT_BLOCKED_WRONG_PIN);
 		}
 
 		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index e979b875..6a1a10f4 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -354,6 +354,8 @@ typedef struct _NMDevicePrivate {
 	bool            v4_route_table_initalized:1;
 	bool            v6_route_table_initalized:1;
 
+	NMDeviceAutoconnectBlockedFlags autoconnect_blocked_flags:4;
+
 	/* Generic DHCP stuff */
 	char *          dhcp_anycast_address;
 
@@ -466,10 +468,6 @@ typedef struct _NMDevicePrivate {
 
 	gboolean needs_ip6_subnet;
 
-	/* allow autoconnect feature */
-	bool autoconnect_intern:1;
-	bool autoconnect_user:1;
-
 	/* master interface for bridge/bond/team slave */
 	NMDevice *      master;
 	bool            is_enslaved;
@@ -533,9 +531,6 @@ static NMActStageReturn linklocal6_start (NMDevice *self);
 
 static void _carrier_wait_check_queued_act_request (NMDevice *self);
 
-static void nm_device_set_autoconnect_both (NMDevice *self, gboolean autoconnect);
-static void nm_device_set_autoconnect_full (NMDevice *self, int autoconnect_intern, int autoconnect_user);
-
 static const char *_activation_func_to_string (ActivationHandleFunc func);
 static void activation_source_handle_cb (NMDevice *self, int addr_family);
 
@@ -3392,8 +3387,6 @@ realize_start_setup (NMDevice *self,
 	if (real_rate)
 		priv->stats.timeout_id = g_timeout_add (real_rate, _stats_timeout_cb, self);
 
-	nm_device_set_autoconnect_full (self, !!DEFAULT_AUTOCONNECT, TRUE);
-
 	klass->realize_start_notify (self, plink);
 
 	nm_assert (!nm_device_get_unmanaged_mask (self, NM_UNMANAGED_USER_EXPLICIT));
@@ -3593,8 +3586,6 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
 	priv->real = FALSE;
 	_notify (self, PROP_REAL);
 
-	nm_device_set_autoconnect_both (self, FALSE);
-
 	g_object_thaw_notify (G_OBJECT (self));
 
 	nm_device_set_unmanaged_flags (self,
@@ -4219,62 +4210,55 @@ 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)
+NM_UTILS_FLAGS2STR_DEFINE_STATIC (_autoconnect_blocked_flags_to_string, NMDeviceAutoconnectBlockedFlags,
+	NM_UTILS_FLAGS2STR (NM_DEVICE_AUTOCONNECT_BLOCKED_NONE,              "none"),
+	NM_UTILS_FLAGS2STR (NM_DEVICE_AUTOCONNECT_BLOCKED_USER,              "user"),
+	NM_UTILS_FLAGS2STR (NM_DEVICE_AUTOCONNECT_BLOCKED_WRONG_PIN,         "wrong-pin"),
+	NM_UTILS_FLAGS2STR (NM_DEVICE_AUTOCONNECT_BLOCKED_MANUAL_DISCONNECT, "manual-disconnect"),
+);
+
+NMDeviceAutoconnectBlockedFlags
+nm_device_autoconnect_blocked_get (NMDevice *self, NMDeviceAutoconnectBlockedFlags mask)
 {
 	NMDevicePrivate *priv;
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
 
+	if (mask == 0)
+		mask = NM_DEVICE_AUTOCONNECT_BLOCKED_ALL;
+
 	priv = NM_DEVICE_GET_PRIVATE (self);
-	return priv->autoconnect_intern && priv->autoconnect_user;
+	return priv->autoconnect_blocked_flags & mask;
 }
 
-static void
-nm_device_set_autoconnect_full (NMDevice *self, int autoconnect_intern, int autoconnect_user)
+void
+nm_device_autoconnect_blocked_set_full (NMDevice *self, NMDeviceAutoconnectBlockedFlags mask, NMDeviceAutoconnectBlockedFlags value)
 {
 	NMDevicePrivate *priv;
-	gboolean old_value;
+	gboolean changed;
+	char buf1[128], buf2[128];
 
 	g_return_if_fail (NM_IS_DEVICE (self));
+	nm_assert (mask);
+	nm_assert (!NM_FLAGS_ANY (mask, ~NM_DEVICE_AUTOCONNECT_BLOCKED_ALL));
+	nm_assert (!NM_FLAGS_ANY (value, ~mask));
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
 
-	old_value = nm_device_get_autoconnect (self);
-	if (autoconnect_intern != -1)
-		priv->autoconnect_intern = autoconnect_intern;
-	if (autoconnect_user != -1)
-		priv->autoconnect_user = autoconnect_user;
-	if (old_value != nm_device_get_autoconnect (self))
-		_notify (self, PROP_AUTOCONNECT);
-}
+	value = (priv->autoconnect_blocked_flags & ~mask) | (mask & value);
+	if (value == priv->autoconnect_blocked_flags)
+		return;
 
-void
-nm_device_set_autoconnect_intern (NMDevice *self, gboolean autoconnect)
-{
-	nm_device_set_autoconnect_full (self, !!autoconnect, -1);
-}
+	changed = ((!value) != (!priv->autoconnect_blocked_flags));
 
-static void
-nm_device_set_autoconnect_both (NMDevice *self, gboolean autoconnect)
-{
-	autoconnect = !!autoconnect;
-	nm_device_set_autoconnect_full (self, autoconnect, autoconnect);
-}
+	_LOGT (LOGD_DEVICE, "autoconnect-blocked: set \"%s\" (was \"%s\")",
+	       _autoconnect_blocked_flags_to_string (value, buf1, sizeof (buf1)),
+	       _autoconnect_blocked_flags_to_string (priv->autoconnect_blocked_flags, buf2, sizeof (buf2)));
 
-static gboolean
-get_autoconnect_allowed (NMDevice *self)
-{
-	return TRUE;
+	priv->autoconnect_blocked_flags = value;
+	nm_assert (priv->autoconnect_blocked_flags == value);
+	if (changed)
+		_notify (self, PROP_AUTOCONNECT);
 }
 
 static gboolean
@@ -4303,14 +4287,23 @@ nm_device_autoconnect_allowed (NMDevice *self)
 	GValue instance = G_VALUE_INIT;
 	GValue retval = G_VALUE_INIT;
 
-	if (   !nm_device_get_autoconnect (self)
-	    || !klass->get_autoconnect_allowed (self))
+	if (nm_device_autoconnect_blocked_get (self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL))
 		return FALSE;
 
-	/* Unrealized devices can always autoconnect. */
-	if (nm_device_is_real (self) && priv->state < NM_DEVICE_STATE_DISCONNECTED)
+	if (   klass->get_autoconnect_allowed
+	    && !klass->get_autoconnect_allowed (self))
 		return FALSE;
 
+	if (!nm_device_get_enabled (self))
+		return FALSE;
+
+	if (nm_device_is_real (self)) {
+		if (priv->state < NM_DEVICE_STATE_DISCONNECTED)
+			return FALSE;
+	} else {
+		/* Unrealized devices can always autoconnect. */
+	}
+
 	/* 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
@@ -4337,15 +4330,8 @@ can_auto_connect (NMDevice *self,
                   NMConnection *connection,
                   char **specific_object)
 {
-	NMSettingConnection *s_con;
-
 	nm_assert (!specific_object || !*specific_object);
-
-	s_con = nm_connection_get_setting_connection (connection);
-	if (!nm_setting_connection_get_autoconnect (s_con))
-		return FALSE;
-
-	return nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL);
+	return TRUE;
 }
 
 /**
@@ -4372,11 +4358,24 @@ nm_device_can_auto_connect (NMDevice *self,
 {
 	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
-	g_return_val_if_fail (specific_object && !*specific_object, FALSE);
+	g_return_val_if_fail (!specific_object || !*specific_object, FALSE);
 
-	if (nm_device_autoconnect_allowed (self))
-		return NM_DEVICE_GET_CLASS (self)->can_auto_connect (self, connection, specific_object);
-	return FALSE;
+	/* the caller must ensure that nm_device_autoconnect_allowed() returns
+	 * TRUE as well. This is done, because nm_device_can_auto_connect()
+	 * has only one caller, and it iterates over a list of available
+	 * connections.
+	 *
+	 * Hence, we don't need to re-check nm_device_autoconnect_allowed()
+	 * over and over again. The caller is supposed to do that. */
+	nm_assert (nm_device_autoconnect_allowed (self));
+
+	if (!nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL))
+		return FALSE;
+
+	if (!NM_DEVICE_GET_CLASS (self)->can_auto_connect (self, connection, specific_object))
+		return FALSE;
+
+	return TRUE;
 }
 
 static gboolean
@@ -4975,7 +4974,7 @@ static void
 activation_source_schedule (NMDevice *self, ActivationHandleFunc func, int addr_family)
 {
 	ActivationHandleData *act_data;
-	GSourceFunc source_func;
+	GSourceFunc source_func = NULL;
 	guint new_id = 0;
 
 	act_data = activation_source_get_by_family (self, addr_family, &source_func);
@@ -5396,8 +5395,8 @@ ipv4_manual_method_apply (NMDevice *self, NMIP4Config **configs, gboolean succes
 		nm_device_activate_schedule_ip4_config_result (self, empty);
 		g_object_unref (empty);
 	} else {
-		nm_device_queue_state (self, NM_DEVICE_STATE_FAILED,
-		                       NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+		nm_device_ip_method_failed (self, AF_INET,
+		                            NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
 	}
 }
 
@@ -5977,8 +5976,8 @@ dhcp4_dad_cb (NMDevice *self, NMIP4Config **configs, gboolean success)
 	if (success)
 		nm_device_activate_schedule_ip4_config_result (self, configs[1]);
 	else {
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED,
-		                         NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+		nm_device_ip_method_failed (self, AF_INET,
+		                            NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
 	}
 }
 
@@ -9732,7 +9731,7 @@ disconnect_cb (NMDevice *self,
 		nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, FALSE, NULL, subject, local->message);
 		g_dbus_method_invocation_take_error (context, local);
 	} else {
-		nm_device_set_autoconnect_intern (self, FALSE);
+		nm_device_autoconnect_blocked_set (self, NM_DEVICE_AUTOCONNECT_BLOCKED_MANUAL_DISCONNECT);
 
 		nm_device_state_changed (self,
 		                         NM_DEVICE_STATE_DEACTIVATING,
@@ -12988,10 +12987,10 @@ _set_state_full (NMDevice *self,
 		break;
 	}
 
-	/* Reset autoconnect flag when the device is activating or connected. */
+	/* Reset intern autoconnect flags when the device is activating or connected. */
 	if (   state >= NM_DEVICE_STATE_PREPARE
 	    && state <= NM_DEVICE_STATE_ACTIVATED)
-		nm_device_set_autoconnect_intern  (self, TRUE);
+		nm_device_autoconnect_blocked_unset (self, NM_DEVICE_AUTOCONNECT_BLOCKED_INTERNAL);
 
 	_notify (self, PROP_STATE);
 	_notify (self, PROP_STATE_REASON);
@@ -14116,6 +14115,10 @@ nm_device_init (NMDevice *self)
 
 	priv->netns = g_object_ref (NM_NETNS_GET);
 
+	priv->autoconnect_blocked_flags = DEFAULT_AUTOCONNECT
+	                                  ? NM_DEVICE_AUTOCONNECT_BLOCKED_NONE
+	                                  : NM_DEVICE_AUTOCONNECT_BLOCKED_USER;
+
 	priv->auth_retries = NM_DEVICE_AUTH_RETRIES_UNSET;
 	priv->type = NM_DEVICE_TYPE_UNKNOWN;
 	priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED;
@@ -14402,7 +14405,10 @@ set_property (GObject *object, guint prop_id,
 		}
 		break;
 	case PROP_AUTOCONNECT:
-		nm_device_set_autoconnect_both (self, g_value_get_boolean (value));
+		if (g_value_get_boolean (value))
+			nm_device_autoconnect_blocked_unset (self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL);
+		else
+			nm_device_autoconnect_blocked_set (self, NM_DEVICE_AUTOCONNECT_BLOCKED_USER);
 		break;
 	case PROP_FIRMWARE_MISSING:
 		/* construct-only */
@@ -14539,7 +14545,10 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_boolean (value, nm_device_get_state (self) > NM_DEVICE_STATE_UNMANAGED);
 		break;
 	case PROP_AUTOCONNECT:
-		g_value_set_boolean (value, nm_device_get_autoconnect (self));
+		g_value_set_boolean (value,
+		                     nm_device_autoconnect_blocked_get (self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL)
+		                       ? FALSE
+		                       : TRUE);
 		break;
 	case PROP_FIRMWARE_MISSING:
 		g_value_set_boolean (value, priv->firmware_missing);
@@ -14668,7 +14677,6 @@ nm_device_class_init (NMDeviceClass *klass)
 	klass->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout;
 
 	klass->get_type_description = get_type_description;
-	klass->get_autoconnect_allowed = get_autoconnect_allowed;
 	klass->can_auto_connect = can_auto_connect;
 	klass->check_connection_compatible = check_connection_compatible;
 	klass->check_connection_available = check_connection_available;
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 350a17b2..bd8104b4 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -663,8 +663,37 @@ gboolean nm_device_unrealize          (NMDevice *device,
 void nm_device_update_from_platform_link (NMDevice *self,
                                           const NMPlatformLink *plink);
 
-gboolean nm_device_get_autoconnect (NMDevice *device);
-void nm_device_set_autoconnect_intern (NMDevice *device, gboolean autoconnect);
+typedef enum {
+	NM_DEVICE_AUTOCONNECT_BLOCKED_NONE                  = 0,
+
+	NM_DEVICE_AUTOCONNECT_BLOCKED_USER                  = (1LL <<  0),
+
+	NM_DEVICE_AUTOCONNECT_BLOCKED_WRONG_PIN             = (1LL <<  1),
+	NM_DEVICE_AUTOCONNECT_BLOCKED_MANUAL_DISCONNECT     = (1LL <<  2),
+
+	_NM_DEVICE_AUTOCONNECT_BLOCKED_LAST,
+
+	NM_DEVICE_AUTOCONNECT_BLOCKED_ALL                   = (((_NM_DEVICE_AUTOCONNECT_BLOCKED_LAST - 1) << 1) - 1),
+
+	NM_DEVICE_AUTOCONNECT_BLOCKED_INTERNAL              = NM_DEVICE_AUTOCONNECT_BLOCKED_ALL & ~NM_DEVICE_AUTOCONNECT_BLOCKED_USER,
+} NMDeviceAutoconnectBlockedFlags;
+
+NMDeviceAutoconnectBlockedFlags nm_device_autoconnect_blocked_get (NMDevice *device, NMDeviceAutoconnectBlockedFlags mask);
+
+void nm_device_autoconnect_blocked_set_full (NMDevice *device, NMDeviceAutoconnectBlockedFlags mask, NMDeviceAutoconnectBlockedFlags values);
+
+static inline void
+nm_device_autoconnect_blocked_set (NMDevice *device, NMDeviceAutoconnectBlockedFlags mask)
+{
+	nm_device_autoconnect_blocked_set_full (device, mask, mask);
+}
+
+static inline void
+nm_device_autoconnect_blocked_unset (NMDevice *device, NMDeviceAutoconnectBlockedFlags mask)
+{
+	nm_device_autoconnect_blocked_set_full (device, mask, NM_DEVICE_AUTOCONNECT_BLOCKED_NONE);
+}
+
 void nm_device_emit_recheck_auto_activate (NMDevice *device);
 
 NMDeviceSysIfaceState nm_device_sys_iface_state_get (NMDevice *device);
diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c
index ac78757d..3a4a027a 100644
--- a/src/devices/wifi/nm-device-olpc-mesh.c
+++ b/src/devices/wifi/nm-device-olpc-mesh.c
@@ -107,12 +107,8 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 }
 
 static gboolean
-can_auto_connect (NMDevice *device,
-                  NMConnection *connection,
-                  char **specific_object)
+get_autoconnect_allowed (NMDevice *device)
 {
-	nm_assert (!specific_object || !*specific_object);
-
 	return FALSE;
 }
 
@@ -517,7 +513,7 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass)
 	object_class->dispose = dispose;
 
 	parent_class->check_connection_compatible = check_connection_compatible;
-	parent_class->can_auto_connect = can_auto_connect;
+	parent_class->get_autoconnect_allowed = get_autoconnect_allowed;
 	parent_class->complete_connection = complete_connection;
 	parent_class->is_available = is_available;
 	parent_class->act_stage1_prepare = act_stage1_prepare;
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index 8bfddbd9..5e92f47b 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -997,9 +997,6 @@ get_autoconnect_allowed (NMDevice *device)
 {
 	NMDeviceWifiPrivate *priv;
 
-	if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->get_autoconnect_allowed (device))
-		return FALSE;
-
 	priv = NM_DEVICE_WIFI_GET_PRIVATE (NM_DEVICE_WIFI (device));
 	return !priv->requested_scan;
 }
diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c
index 22fb8c67..b79d145d 100644
--- a/src/devices/wwan/nm-device-modem.c
+++ b/src/devices/wwan/nm-device-modem.c
@@ -132,8 +132,7 @@ modem_prepare_result (NMModem *modem,
 			 * the device to be auto-activated anymore, which would risk locking
 			 * the SIM if the incorrect PIN continues to be used.
 			 */
-			nm_device_set_autoconnect_intern (device, FALSE);
-			_LOGI (LOGD_MB, "disabling autoconnect due to failed SIM PIN");
+			nm_device_autoconnect_blocked_set (device, NM_DEVICE_AUTOCONNECT_BLOCKED_WRONG_PIN);
 		}
 
 		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c
index 8b3fc2e8..811c3afb 100644
--- a/src/devices/wwan/nm-modem-ofono.c
+++ b/src/devices/wwan/nm-modem-ofono.c
@@ -829,12 +829,13 @@ context_property_changed (GDBusProxy *proxy,
 	NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self);
 	NMPlatformIP4Address addr;
 	gboolean ret = FALSE;
-	GVariant *v_dict;
-	const gchar *s, *addr_s;
+	gs_unref_variant GVariant *v_dict = NULL;
+	const char *interface;
+	const gchar *s;
 	const gchar **array, **iter;
 	guint32 address_network, gateway_network;
 	guint32 ip4_route_table, ip4_route_metric;
-	guint prefix = 0;
+	int ifindex;
 
 	_LOGD ("PropertyChanged: %s", property);
 
@@ -855,141 +856,109 @@ context_property_changed (GDBusProxy *proxy,
 
 	_LOGI ("IPv4 static Settings:");
 
-	if (g_variant_lookup (v_dict, "Interface", "&s", &s)) {
-		if (s && strlen (s)) {
-			_LOGD ("Interface: %s", s);
-			g_object_set (self,
-			              NM_MODEM_DATA_PORT, g_strdup (s),
-			              NM_MODEM_IP4_METHOD, NM_MODEM_IP_METHOD_STATIC,
-			              NULL);
-		} else {
-			_LOGW ("Settings 'Interface'; empty");
-			goto out;
-		}
-
-	} else {
+	if (!g_variant_lookup (v_dict, "Interface", "&s", &interface)) {
 		_LOGW ("Settings 'Interface' missing");
 		goto out;
 	}
+	if (!interface || !interface[0]) {
+		_LOGW ("Settings 'Interface'; empty");
+		goto out;
+	}
+
+	ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, interface);
+	if (ifindex <= 0) {
+		_LOGW ("Interface \"%s\" not found", interface);
+		goto out;
+	}
+
+	_LOGD ("Interface: %s", interface);
+	g_object_set (self,
+	              NM_MODEM_DATA_PORT, interface,
+	              NM_MODEM_IP4_METHOD, NM_MODEM_IP_METHOD_STATIC,
+	              NULL);
 
 	/* TODO: verify handling of ip4_config; check other places it's used... */
 	g_clear_object (&priv->ip4_config);
 
-	memset (&addr, 0, sizeof (addr));
 
-	/*
-	 * TODO:
-	 *
-	 * NM 1.2 changed the NMIP4Config constructor to take an ifindex
-	 * ( vs. void pre 1.2 ), to tie config instance to a specific
-	 * platform interface.
-	 *
-	 * This doesn't work for ofono, as the devices are created
-	 * dynamically ( eg. ril_0, ril_1 ) in NMModemManager.  The
-	 * device created doesn't really map directly to a platform
-	 * link.  The closest would be one of the devices owned by
-	 * rild ( eg. ccmin0 ), which is passed to us above as
-	 * 'Interface'.
-	 *
-	 * This needs discussion with upstream.
-	 *
-	 * FIXME: it is no longer allowed to omit the ifindex for NMIP4Config instances.
-	 * This is broken.
-	 */
 	priv->ip4_config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET),
-	                                      0);
-
-	/* TODO: simply if/else error logic! */
+	                                      ifindex);
 
-	if (g_variant_lookup (v_dict, "Address", "&s", &addr_s)) {
-		_LOGD ("Address: %s", addr_s);
-
-		if (   addr_s
-		    && nm_utils_parse_inaddr_bin (AF_INET, addr_s, &address_network)) {
-			addr.address = address_network;
-			addr.addr_source = NM_IP_CONFIG_SOURCE_WWAN;
-		} else {
-			_LOGW ("can't convert 'Address' %s to addr", s);
-			goto out;
-		}
-
-	} else {
+	if (!g_variant_lookup (v_dict, "Address", "&s", &s)) {
 		_LOGW ("Settings 'Address' missing");
 		goto out;
 	}
+	if (   !s
+	    || !nm_utils_parse_inaddr_bin (AF_INET, s, &address_network)) {
+		_LOGW ("can't convert 'Address' %s to addr", s ?: "");
+		goto out;
+	}
+	memset (&addr, 0, sizeof (addr));
+	addr.ifindex = ifindex;
+	addr.address = address_network;
+	addr.addr_source = NM_IP_CONFIG_SOURCE_WWAN;
 
-	if (g_variant_lookup (v_dict, "Netmask", "&s", &s)) {
-		_LOGD ("Netmask: %s", s);
-
-		if (   s
-		    && nm_utils_parse_inaddr_bin (AF_INET, s, &address_network)) {
-			prefix = nm_utils_ip4_netmask_to_prefix (address_network);
-			if (prefix > 0)
-				addr.plen = prefix;
-		} else {
-			_LOGW ("invalid 'Netmask': %s", s);
-			goto out;
-		}
-	} else {
+	if (!g_variant_lookup (v_dict, "Netmask", "&s", &s)) {
 		_LOGW ("Settings 'Netmask' missing");
 		goto out;
 	}
+	if (   !s
+	    || !nm_utils_parse_inaddr_bin (AF_INET, s, &address_network)) {
+		_LOGW ("invalid 'Netmask': %s", s ?: "");
+		goto out;
+	}
+	addr.plen = nm_utils_ip4_netmask_to_prefix (address_network);
 
-	_LOGI ("Address: %s/%d", addr_s, prefix);
-
+	_LOGI ("Address: %s", nm_platform_ip4_address_to_string (&addr, NULL, 0));
 	nm_ip4_config_add_address (priv->ip4_config, &addr);
 
-	if (   g_variant_lookup (v_dict, "Gateway", "&s", &s)
-	    && s) {
-
-		if (!nm_utils_parse_inaddr_bin (AF_INET, s, &gateway_network)) {
-			_LOGW ("invalid 'Gateway': %s", s);
-			goto out;
-		}
-
-		nm_modem_get_route_parameters (NM_MODEM (self),
-		                               &ip4_route_table,
-		                               &ip4_route_metric,
-		                               NULL,
-		                               NULL);
-		{
-			const NMPlatformIP4Route r = {
-				.rt_source = NM_IP_CONFIG_SOURCE_WWAN,
-				.gateway = gateway_network,
-				.table_coerced = nm_platform_route_table_coerce (ip4_route_table),
-				.metric = ip4_route_metric,
-			};
-
-			_LOGI ("Gateway: %s", s);
-			nm_ip4_config_add_route (priv->ip4_config, &r, NULL);
-		}
-	} else {
+	if (   !g_variant_lookup (v_dict, "Gateway", "&s", &s)
+	    || !s) {
 		_LOGW ("Settings 'Gateway' missing");
 		goto out;
 	}
+	if (!nm_utils_parse_inaddr_bin (AF_INET, s, &gateway_network)) {
+		_LOGW ("invalid 'Gateway': %s", s);
+		goto out;
+	}
+	nm_modem_get_route_parameters (NM_MODEM (self),
+	                               &ip4_route_table,
+	                               &ip4_route_metric,
+	                               NULL,
+	                               NULL);
+	{
+		const NMPlatformIP4Route r = {
+			.rt_source = NM_IP_CONFIG_SOURCE_WWAN,
+			.gateway = gateway_network,
+			.table_coerced = nm_platform_route_table_coerce (ip4_route_table),
+			.metric = ip4_route_metric,
+		};
+
+		_LOGI ("Gateway: %s", s);
+		nm_ip4_config_add_route (priv->ip4_config, &r, NULL);
+	}
 
-	if (g_variant_lookup (v_dict, "DomainNameServers", "^a&s", &array)) {
-		if (array) {
-			for (iter = array; *iter; iter++) {
-				if (   nm_utils_parse_inaddr_bin (AF_INET, *iter, &address_network)
-				    && address_network) {
-					_LOGI ("DNS: %s", *iter);
-					nm_ip4_config_add_nameserver (priv->ip4_config, address_network);
-				} else {
-					_LOGW ("invalid NameServer: %s", *iter);
-				}
+	if (!g_variant_lookup (v_dict, "DomainNameServers", "^a&s", &array)) {
+		_LOGW ("Settings 'DomainNameServers' missing");
+		goto out;
+	}
+	if (array) {
+		for (iter = array; *iter; iter++) {
+			if (   nm_utils_parse_inaddr_bin (AF_INET, *iter, &address_network)
+			    && address_network) {
+				_LOGI ("DNS: %s", *iter);
+				nm_ip4_config_add_nameserver (priv->ip4_config, address_network);
+			} else {
+				_LOGW ("invalid NameServer: %s", *iter);
 			}
+		}
 
-			if (iter == array) {
-				_LOGW ("Settings: 'DomainNameServers': none specified");
-				g_free (array);
-				goto out;
-			}
+		if (iter == array) {
+			_LOGW ("Settings: 'DomainNameServers': none specified");
 			g_free (array);
+			goto out;
 		}
-	} else {
-		_LOGW ("Settings 'DomainNameServers' missing");
-		goto out;
+		g_free (array);
 	}
 
 	if (g_variant_lookup (v_dict, "MessageProxy", "&s", &s)) {