static void
update_properties (NMDevice *device)
{
	NMDeviceMacvlan *self = NM_DEVICE_MACVLAN (device);
	NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device);
	GObject *object = G_OBJECT (device);
	NMPlatformMacvlanProperties props;

	if (!nm_platform_macvlan_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) {
		_LOGW (LOGD_HW, "could not read macvlan properties");
		return;
	}

	g_object_freeze_notify (object);

	if (priv->props.parent_ifindex != props.parent_ifindex)
		g_object_notify (object, NM_DEVICE_MACVLAN_PARENT);
	if (g_strcmp0 (priv->props.mode, props.mode) != 0)
		g_object_notify (object, NM_DEVICE_MACVLAN_MODE);
	if (priv->props.no_promisc != props.no_promisc)
		g_object_notify (object, NM_DEVICE_MACVLAN_NO_PROMISC);

	memcpy (&priv->props, &props, sizeof (NMPlatformMacvlanProperties));

	g_object_thaw_notify (object);
}
static void
update_properties (NMDevice *device)
{
	NMDeviceMacvlan *self = NM_DEVICE_MACVLAN (device);
	NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device);
	GObject *object = G_OBJECT (device);
	const NMPlatformLnkMacvlan *props;
	const NMPlatformLink *plink;

	props = nm_platform_link_get_lnk_macvlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink);
	if (!props) {
		_LOGW (LOGD_HW, "could not get macvlan properties");
		return;
	}

	g_object_freeze_notify (object);

	if (priv->parent_ifindex != plink->parent)
		g_object_notify (object, NM_DEVICE_MACVLAN_PARENT);
	if (g_strcmp0 (priv->props.mode, props->mode) != 0)
		g_object_notify (object, NM_DEVICE_MACVLAN_MODE);
	if (priv->props.no_promisc != props->no_promisc)
		g_object_notify (object, NM_DEVICE_MACVLAN_NO_PROMISC);

	priv->parent_ifindex = plink->parent;
	priv->props = *props;

	g_object_thaw_notify (object);
}
static void
dispose (GObject *object)
{
	nm_device_macvlan_set_parent (NM_DEVICE_MACVLAN (object), NULL);

	G_OBJECT_CLASS (nm_device_macvlan_parent_class)->dispose (object);
}
static void
parent_state_changed (NMDevice *parent,
                      NMDeviceState new_state,
                      NMDeviceState old_state,
                      NMDeviceStateReason reason,
                      gpointer user_data)
{
	NMDeviceMacvlan *self = NM_DEVICE_MACVLAN (user_data);

	/* We'll react to our own carrier state notifications. Ignore the parent's. */
	if (reason == NM_DEVICE_STATE_REASON_CARRIER)
		return;

	nm_device_set_unmanaged_by_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent, FALSE), reason);
}
static void
notify_new_device_added (NMDevice *device, NMDevice *new_device)
{
	NMDeviceMacvlan *self = NM_DEVICE_MACVLAN (device);
	NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (self);

	if (priv->parent)
		return;

	if (!nm_device_is_real (device))
		return;

	update_properties (device);

	if (   priv->parent_ifindex <= 0
	    || nm_device_get_ifindex (new_device) != priv->parent_ifindex)
		return;

	priv->parent_ifindex = nm_device_get_ifindex (new_device);
	nm_device_macvlan_set_parent (self, new_device);
}
static gboolean
check_connection_compatible (NMDevice *device, NMConnection *connection)
{
	NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device);
	NMSettingMacvlan *s_macvlan;
	const char *parent = NULL;

	if (!NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->check_connection_compatible (device, connection))
		return FALSE;

	s_macvlan = nm_connection_get_setting_macvlan (connection);
	if (!s_macvlan)
		return FALSE;

	if (nm_setting_macvlan_get_tap (s_macvlan) != priv->props.tap)
		return FALSE;

	/* Before the device is realized some properties will not be set */
	if (nm_device_is_real (device)) {

		if (setting_mode_to_platform (nm_setting_macvlan_get_mode (s_macvlan)) != priv->props.mode)
			return FALSE;

		if (nm_setting_macvlan_get_promiscuous (s_macvlan) ==  priv->props.no_promisc)
			return FALSE;

		/* Check parent interface; could be an interface name or a UUID */
		parent = nm_setting_macvlan_get_parent (s_macvlan);
		if (parent) {
			if (!match_parent (NM_DEVICE_MACVLAN (device), parent))
				return FALSE;
		} else {
			/* Parent could be a MAC address in an NMSettingWired */
			if (!match_hwaddr (device, connection, TRUE))
				return FALSE;
		}
	}

	return TRUE;
}
static void
update_properties (NMDevice *device)
{
	NMDeviceMacvlan *self = NM_DEVICE_MACVLAN (device);
	NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device);
	GObject *object = G_OBJECT (device);
	const NMPlatformLnkMacvlan *props;
	const NMPlatformLink *plink;
	NMDevice *parent = NULL;

	if (priv->props.tap)
		props = nm_platform_link_get_lnk_macvtap (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink);
	else
		props = nm_platform_link_get_lnk_macvlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink);

	if (!props) {
		_LOGW (LOGD_HW, "could not get %s properties", priv->props.tap ? "macvtap" : "macvlan");
		return;
	}

	g_object_freeze_notify (object);

	if (priv->parent_ifindex != plink->parent) {
		parent = nm_manager_get_device_by_ifindex (nm_manager_get (), plink->parent);
		nm_device_macvlan_set_parent (self, parent);
	}
	if (priv->props.mode != props->mode)
		g_object_notify (object, NM_DEVICE_MACVLAN_MODE);
	if (priv->props.no_promisc != props->no_promisc)
		g_object_notify (object, NM_DEVICE_MACVLAN_NO_PROMISC);

	priv->parent_ifindex = plink->parent;
	priv->props = *props;

	g_object_thaw_notify (object);
}