static gboolean
component_added (NMDevice *device, GObject *component)
{
	NMDeviceVlan *self = NM_DEVICE_VLAN (device);
	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
	NMDevice *added_device;
	int parent_ifindex = -1;

	if (priv->parent)
		return FALSE;

	if (!NM_IS_DEVICE (component))
		return FALSE;
	added_device = NM_DEVICE (component);

	if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, nm_device_get_ifindex (device), &parent_ifindex, NULL)) {
		_LOGW (LOGD_VLAN, "failed to get VLAN interface info while checking added component.");
		return FALSE;
	}

	if (   parent_ifindex <= 0
	    || nm_device_get_ifindex (added_device) != parent_ifindex)
		return FALSE;

	nm_device_vlan_set_parent (self, added_device);

	/* Don't claim parent exclusively */
	return FALSE;
}
static void
reload_tun_properties (NMDeviceTun *self)
{
	NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self);
	GObject *object = G_OBJECT (self);
	NMPlatformTunProperties props;

	if (!nm_platform_tun_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), &props)) {
		_LOGD (LOGD_HW, "could not read tun properties");
		return;
	}

	g_object_freeze_notify (object);

	if (priv->props.owner != props.owner)
		g_object_notify (object, NM_DEVICE_TUN_OWNER);
	if (priv->props.group != props.group)
		g_object_notify (object, NM_DEVICE_TUN_GROUP);
	if (priv->props.no_pi != props.no_pi)
		g_object_notify (object, NM_DEVICE_TUN_NO_PI);
	if (priv->props.vnet_hdr != props.vnet_hdr)
		g_object_notify (object, NM_DEVICE_TUN_VNET_HDR);
	if (priv->props.multi_queue != props.multi_queue)
		g_object_notify (object, NM_DEVICE_TUN_MULTI_QUEUE);

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

	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
update_connection (NMDevice *device, NMConnection *connection)
{
	NMSettingBond *s_bond = nm_connection_get_setting_bond (connection);
	int ifindex = nm_device_get_ifindex (device);
	const char **options;

	if (!s_bond) {
		s_bond = (NMSettingBond *) nm_setting_bond_new ();
		nm_connection_add_setting (connection, (NMSetting *) s_bond);
	}

	/* Read bond options from sysfs and update the Bond setting to match */
	options = nm_setting_bond_get_valid_options (s_bond);
	while (options && *options) {
		gs_free char *value = nm_platform_sysctl_master_get_option (nm_device_get_platform(device), ifindex, *options);
		const char *defvalue = nm_setting_bond_get_option_default (s_bond, *options);

		if (value && !ignore_if_zero (*options, value) && (g_strcmp0 (value, defvalue) != 0)) {
			/* Replace " " with "," for arp_ip_targets from the kernel */
			if (strcmp (*options, "arp_ip_target") == 0) {
				char *p = value;

				while (p && *p) {
					if (*p == ' ')
						*p = ',';
					p++;
				}
			}

			nm_setting_bond_add_option (s_bond, *options, value);
		}
		options++;
	}
}
static void
update_connection (NMDevice *device, NMConnection *connection)
{
	NMDeviceBridge *self = NM_DEVICE_BRIDGE (device);
	NMSettingBridge *s_bridge = nm_connection_get_setting_bridge (connection);
	int ifindex = nm_device_get_ifindex (device);
	const Option *option;

	if (!s_bridge) {
		s_bridge = (NMSettingBridge *) nm_setting_bridge_new ();
		nm_connection_add_setting (connection, (NMSetting *) s_bridge);
	}

	for (option = master_options; option->name; option++) {
		gs_free char *str = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, option->sysname);
		int value;

		if (str) {
			value = strtol (str, NULL, 10);

			/* See comments in set_sysfs_uint() about centiseconds. */
			if (option->user_hz_compensate)
				value /= 100;

			g_object_set (s_bridge, option->name, value, NULL);
		} else
			_LOGW (LOGD_BRIDGE, "failed to read bridge setting '%s'", option->sysname);
	}
}
static void
carrier_off (NMNetlinkMonitor *monitor,
             int idx,
             gpointer user_data)
{
	NMDevice *device = NM_DEVICE (user_data);
	NMDeviceWired *self = NM_DEVICE_WIRED (device);
	guint32 caps;

	/* Make sure signal is for us */
	if (idx == nm_device_get_ifindex (device)) {
		NMDeviceState state;
		gboolean defer = FALSE;

		caps = nm_device_get_capabilities (device);
		g_return_if_fail (caps & NM_DEVICE_CAP_CARRIER_DETECT);

		/* Defer carrier-off event actions while connected by a few seconds
		 * so that tripping over a cable, power-cycling a switch, or breaking
		 * off the RJ45 locking tab isn't so catastrophic.
		 */
		state = nm_device_get_state (device);
		if (state > NM_DEVICE_STATE_DISCONNECTED)
			defer = TRUE;

		set_carrier (self, FALSE, defer);
	}
}
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 GObject*
constructor (GType type,
             guint n_construct_params,
             GObjectConstructParam *construct_params)
{
	GObject *object;
	GObjectClass *klass;
	NMDeviceOlpcMesh *self;
	NMDeviceWifiCapabilities caps;

	klass = G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class);
	object = klass->constructor (type, n_construct_params, construct_params);
	if (!object)
		return NULL;

	self = NM_DEVICE_OLPC_MESH (object);

	if (!nm_platform_wifi_get_capabilities (nm_device_get_ifindex (NM_DEVICE (self)), &caps)) {
		_LOGW (LOGD_HW | LOGD_OLPC, "failed to initialize WiFi driver");
		g_object_unref (object);
		return NULL;
	}

	g_signal_connect (nm_manager_get (), "device-added", G_CALLBACK (device_added_cb), self);
	g_signal_connect (nm_manager_get (), "device-removed", G_CALLBACK (device_removed_cb), self);

	/* shorter timeout for mesh connectivity */
	nm_device_set_dhcp_timeout (NM_DEVICE (self), 20);
	return object;
}
static NMActStageReturn
act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
{
	NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device);
	NMConnection *connection;
	NMSettingOlpcMesh *s_mesh;
	guint32 channel;
	GBytes *ssid;
	const char *anycast_addr;

	connection = nm_device_get_connection (device);
	g_assert (connection);

	s_mesh = nm_connection_get_setting_olpc_mesh (connection);
	g_assert (s_mesh);

	channel = nm_setting_olpc_mesh_get_channel (s_mesh);
	if (channel != 0)
		_mesh_set_channel (self, channel);

	ssid = nm_setting_olpc_mesh_get_ssid (s_mesh);
	nm_platform_mesh_set_ssid (nm_device_get_ifindex (device),
	                           g_bytes_get_data (ssid, NULL),
	                           g_bytes_get_size (ssid));

	anycast_addr = nm_setting_olpc_mesh_get_dhcp_anycast_address (s_mesh);
	nm_device_set_dhcp_anycast_address (device, anycast_addr);

	return NM_ACT_STAGE_RETURN_SUCCESS;
}
static void
update_connection (NMDevice *device, NMConnection *connection)
{
	NMSettingBridge *s_bridge = nm_connection_get_setting_bridge (connection);
	const char *ifname = nm_device_get_iface (device);
	int ifindex = nm_device_get_ifindex (device);
	const Option *option;

	if (!s_bridge) {
		s_bridge = (NMSettingBridge *) nm_setting_bridge_new ();
		nm_connection_add_setting (connection, (NMSetting *) s_bridge);
		g_object_set (s_bridge, NM_SETTING_BRIDGE_INTERFACE_NAME, ifname, NULL);
	}

	for (option = master_options; option->name; option++) {
		gs_free char *str = nm_platform_master_get_option (ifindex, option->sysname);
		int value = strtol (str, NULL, 10);

		/* See comments in set_sysfs_uint() about centiseconds. */
		if (option->user_hz_compensate)
			value /= 100;

		g_object_set (s_bridge, option->name, value, NULL);
	}
}
gboolean
nm_team_update_slave_connection (NMDevice *slave, NMConnection *connection)
{
	NMSettingTeamPort *s_port;
	const char *iface = nm_device_get_iface (slave);
	char *port_config = NULL;
	gboolean with_teamdctl = FALSE;
	int err = 0;
#if WITH_TEAMDCTL
	const char *master_iface;
	int master_ifindex;
	struct teamdctl *tdc;
	const char *team_port_config = NULL;
#endif

	g_return_val_if_fail (NM_IS_DEVICE (slave), FALSE);
	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);

#if WITH_TEAMDCTL
	master_ifindex = nm_platform_link_get_master (nm_device_get_ifindex (slave));
	g_assert (master_ifindex > 0);
	master_iface = nm_platform_link_get_name (master_ifindex);
	g_assert (master_iface);

	tdc = teamdctl_alloc ();
	g_assert (tdc);
	err = teamdctl_connect (tdc, master_iface, NULL, NULL);
	if (err) {
		nm_log_err (LOGD_TEAM, "(%s): failed to connect to teamd for master %s (err=%d)",
		            iface, master_iface, err);
		teamdctl_free (tdc);
		return FALSE;
	}
	err = teamdctl_port_config_get_raw_direct (tdc, iface, (char **)&team_port_config);
	port_config = g_strdup (team_port_config);
	teamdctl_free (tdc);
	with_teamdctl = TRUE;
#endif

	s_port = nm_connection_get_setting_team_port (connection);
	if (!s_port) {
		s_port = (NMSettingTeamPort *) nm_setting_team_port_new ();
		nm_connection_add_setting (connection, NM_SETTING (s_port));
	}

	g_object_set (G_OBJECT (s_port), NM_SETTING_TEAM_PORT_CONFIG, port_config, NULL);
	g_free (port_config);

	if (!with_teamdctl || err != 0) {
		if (!with_teamdctl)
			nm_log_err (LOGD_TEAM, "(%s): failed to read teamd port configuration "
			                       " (compiled without libteamdctl support)", iface);
		else
			nm_log_err (LOGD_TEAM, "(%s): failed to read teamd port configuration (err=%d)",
			            iface, err);
		return FALSE;
	}

	return TRUE;
}
static NMDeviceCapabilities
get_generic_capabilities (NMDevice *dev)
{
	if (nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, nm_device_get_ifindex (dev)))
		return NM_DEVICE_CAP_CARRIER_DETECT;
	else
		return NM_DEVICE_CAP_NONE;
}
static void
constructed (GObject *object)
{
	G_OBJECT_CLASS (nm_device_bridge_parent_class)->constructed (object);

	nm_log_dbg (LOGD_HW | LOGD_BRIDGE, "(%s): kernel ifindex %d",
	            nm_device_get_iface (NM_DEVICE (object)),
	            nm_device_get_ifindex (NM_DEVICE (object)));
}
static void
update_properties (NMDevice *device)
{
	NMDeviceVxlan *self = NM_DEVICE_VXLAN (device);
	NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (device);
	GObject *object = G_OBJECT (device);
	NMPlatformVxlanProperties props;

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

	g_object_freeze_notify (object);

	if (priv->props.parent_ifindex != props.parent_ifindex)
		g_object_notify (object, NM_DEVICE_VXLAN_PARENT);
	if (priv->props.id != props.id)
		g_object_notify (object, NM_DEVICE_VXLAN_ID);
	if (priv->props.group != props.group)
		g_object_notify (object, NM_DEVICE_VXLAN_GROUP);
	if (priv->props.local != props.local)
		g_object_notify (object, NM_DEVICE_VXLAN_LOCAL);
	if (memcmp (&priv->props.group6, &props.group6, sizeof (props.group6)) != 0)
		g_object_notify (object, NM_DEVICE_VXLAN_GROUP);
	if (memcmp (&priv->props.local6, &props.local6, sizeof (props.local6)) != 0)
		g_object_notify (object, NM_DEVICE_VXLAN_LOCAL);
	if (priv->props.tos != props.tos)
		g_object_notify (object, NM_DEVICE_VXLAN_TOS);
	if (priv->props.ttl != props.ttl)
		g_object_notify (object, NM_DEVICE_VXLAN_TTL);
	if (priv->props.learning != props.learning)
		g_object_notify (object, NM_DEVICE_VXLAN_LEARNING);
	if (priv->props.ageing != props.ageing)
		g_object_notify (object, NM_DEVICE_VXLAN_AGEING);
	if (priv->props.limit != props.limit)
		g_object_notify (object, NM_DEVICE_VXLAN_LIMIT);
	if (priv->props.dst_port != props.dst_port)
		g_object_notify (object, NM_DEVICE_VXLAN_DST_PORT);
	if (priv->props.src_port_min != props.src_port_min)
		g_object_notify (object, NM_DEVICE_VXLAN_SRC_PORT_MIN);
	if (priv->props.src_port_max != props.src_port_max)
		g_object_notify (object, NM_DEVICE_VXLAN_SRC_PORT_MAX);
	if (priv->props.proxy != props.proxy)
		g_object_notify (object, NM_DEVICE_VXLAN_PROXY);
	if (priv->props.rsc != props.rsc)
		g_object_notify (object, NM_DEVICE_VXLAN_RSC);
	if (priv->props.l2miss != props.l2miss)
		g_object_notify (object, NM_DEVICE_VXLAN_L2MISS);
	if (priv->props.l3miss != props.l3miss)
		g_object_notify (object, NM_DEVICE_VXLAN_L3MISS);

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

	g_object_thaw_notify (object);
}
static void
_mesh_set_channel (NMDeviceOlpcMesh *self, guint32 channel)
{
	int ifindex = nm_device_get_ifindex (NM_DEVICE (self));

	if (nm_platform_mesh_get_channel (ifindex) != channel) {
		if (nm_platform_mesh_set_channel (ifindex, channel))
			g_object_notify (G_OBJECT (self), NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL);
	}
}
static gboolean
set_bond_attr (NMDevice *device, const char *attr, const char *value)
{
	NMDeviceBond *self = NM_DEVICE_BOND (device);
	gboolean ret;
	int ifindex = nm_device_get_ifindex (device);

	ret = nm_platform_sysctl_master_set_option (nm_device_get_platform(device), ifindex, attr, value);
	if (!ret)
		_LOGW (LOGD_HW, "failed to set bonding attribute '%s' to '%s'", attr, value);
	return ret;
}
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 void
update_connection (NMDevice *device, NMConnection *connection)
{
	NMDeviceVlan *self = NM_DEVICE_VLAN (device);
	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
	NMSettingVlan *s_vlan = nm_connection_get_setting_vlan (connection);
	int ifindex = nm_device_get_ifindex (device);
	int parent_ifindex = -1, vlan_id = -1;
	NMDevice *parent;
	const char *setting_parent, *new_parent;

	if (!s_vlan) {
		s_vlan = (NMSettingVlan *) nm_setting_vlan_new ();
		nm_connection_add_setting (connection, (NMSetting *) s_vlan);
	}

	if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, ifindex, &parent_ifindex, &vlan_id)) {
		_LOGW (LOGD_VLAN, "failed to get VLAN interface info while updating connection.");
		return;
	}

	if (priv->vlan_id != vlan_id) {
		priv->vlan_id = vlan_id;
		g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_ID);
	}

	if (vlan_id != nm_setting_vlan_get_id (s_vlan))
		g_object_set (s_vlan, NM_SETTING_VLAN_ID, priv->vlan_id, NULL);

	if (parent_ifindex != NM_PLATFORM_LINK_OTHER_NETNS)
		parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex);
	else
		parent = NULL;
	nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent);

	/* Update parent in the connection; default to parent's interface name */
	if (parent) {
		new_parent = nm_device_get_iface (parent);
		setting_parent = nm_setting_vlan_get_parent (s_vlan);
		if (setting_parent && nm_utils_is_uuid (setting_parent)) {
			NMConnection *parent_connection;

			/* Don't change a parent specified by UUID if it's still valid */
			parent_connection = nm_connection_provider_get_connection_by_uuid (nm_connection_provider_get (), setting_parent);
			if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection))
				new_parent = NULL;
		}
		if (new_parent)
			g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, new_parent, NULL);
	} else
		g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, NULL, NULL);
}
static gboolean
create_and_realize (NMDevice *device,
                    NMConnection *connection,
                    NMDevice *parent,
                    NMPlatformLink *out_plink,
                    GError **error)
{
	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
	const char *iface = nm_device_get_iface (device);
	NMSettingVlan *s_vlan;
	int parent_ifindex, vlan_id;
	NMPlatformError plerr;

	g_assert (out_plink);

	s_vlan = nm_connection_get_setting_vlan (connection);
	g_assert (s_vlan);

	if (!nm_device_supports_vlans (parent)) {
		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
		             "no support for VLANs on interface %s of type %s",
		             nm_device_get_iface (parent),
		             nm_device_get_type_desc (parent));
		return FALSE;
	}

	parent_ifindex = nm_device_get_ifindex (parent);
	g_warn_if_fail (parent_ifindex > 0);

	vlan_id = nm_setting_vlan_get_id (s_vlan);

	plerr = nm_platform_vlan_add (NM_PLATFORM_GET,
	                              iface,
	                              parent_ifindex,
	                              vlan_id,
	                              nm_setting_vlan_get_flags (s_vlan),
	                              out_plink);
	if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
		             "Failed to create VLAN interface '%s' for '%s': %s",
		             iface,
		             nm_connection_get_id (connection),
		             nm_platform_error_to_string (plerr));
		return FALSE;
	}

	g_warn_if_fail (priv->parent == NULL);
	nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent);
	priv->vlan_id = vlan_id;

	return TRUE;
}
static gboolean
set_bond_attr (NMDevice *device, const char *attr, const char *value)
{
	gboolean ret;
	int ifindex = nm_device_get_ifindex (device);

	ret = nm_platform_master_set_option (ifindex, attr, value);
	if (!ret) {
		nm_log_warn (LOGD_HW, "(%s): failed to set bonding attribute "
		             "'%s' to '%s'", nm_device_get_ip_iface (device), attr, value);
	}
	return ret;
}
static NMActStageReturn
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{
	NMActRequest *req;
	NMConnection *connection;
	NMSettingVlan *s_vlan;
	NMSettingWired *s_wired;
	const char *cloned_mac;
	NMActStageReturn ret;

	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);

	ret = NM_DEVICE_CLASS (nm_device_vlan_parent_class)->act_stage1_prepare (dev, reason);
	if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
		return ret;

	req = nm_device_get_act_request (dev);
	g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);

	connection = nm_act_request_get_connection (req);
	g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE);

	s_wired = nm_connection_get_setting_wired (connection);
	if (s_wired) {
		/* Set device MAC address if the connection wants to change it */
		cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
		if (cloned_mac)
			nm_device_set_hw_addr (dev, cloned_mac, "set", LOGD_VLAN);
	}

	s_vlan = nm_connection_get_setting_vlan (connection);
	if (s_vlan) {
		int ifindex = nm_device_get_ifindex (dev);
		int num, i;
		guint32 from, to;

		num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_INGRESS_MAP);
		for (i = 0; i < num; i++) {
			if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_INGRESS_MAP, i, &from, &to))
				nm_platform_vlan_set_ingress_map (ifindex, from, to);
		}
		num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_EGRESS_MAP);
		for (i = 0; i < num; i++) {
			if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, i, &from, &to))
				nm_platform_vlan_set_egress_map (ifindex, from, to);
		}
	}

	return ret;
}
static gboolean
create_and_realize (NMDevice *device,
                    NMConnection *connection,
                    NMDevice *parent,
                    const NMPlatformLink **out_plink,
                    GError **error)
{
	const char *iface = nm_device_get_iface (device);
	NMPlatformError plerr;
	NMSettingMacvlan *s_macvlan;
	NMPlatformLnkMacvlan lnk = { };
	int parent_ifindex;

	s_macvlan = nm_connection_get_setting_macvlan (connection);
	g_assert (s_macvlan);

	if (!parent) {
		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
		             "MACVLAN devices can not be created without a parent interface");
		return FALSE;
	}

	parent_ifindex = nm_device_get_ifindex (parent);
	g_warn_if_fail (parent_ifindex > 0);

	lnk.mode = setting_mode_to_platform (nm_setting_macvlan_get_mode (s_macvlan));
	if (!lnk.mode) {
		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
		             "unsupported MACVLAN mode %u in connection %s",
		             nm_setting_macvlan_get_mode (s_macvlan),
		             nm_connection_get_uuid (connection));
		return FALSE;
	}
	lnk.no_promisc = !nm_setting_macvlan_get_promiscuous (s_macvlan);
	lnk.tap = nm_setting_macvlan_get_tap (s_macvlan);

	plerr = nm_platform_link_macvlan_add (NM_PLATFORM_GET, iface, parent_ifindex, &lnk, out_plink);
	if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
		             "Failed to create %s interface '%s' for '%s': %s",
		             lnk.tap ? "macvtap" : "macvlan",
		             iface,
		             nm_connection_get_id (connection),
		             nm_platform_error_to_string (plerr));
		return FALSE;
	}

	return TRUE;
}
static void
commit_option (NMDevice *device, NMSetting *setting, const Option *option, gboolean slave)
{
	int ifindex = nm_device_get_ifindex (device);
	GParamSpec *pspec;
	GValue val = G_VALUE_INIT;
	guint32 uval = 0;
	gs_free char *value = NULL;

	g_assert (setting);

	pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), option->name);
	g_assert (pspec);

	/* Get the property's value */
	g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (pspec));
	g_object_get_property ((GObject *) setting, option->name, &val);
	if (G_VALUE_HOLDS_BOOLEAN (&val))
		uval = g_value_get_boolean (&val) ? 1 : 0;
	else if (G_VALUE_HOLDS_UINT (&val)) {
		uval = g_value_get_uint (&val);

		/* zero means "unspecified" for some NM properties but isn't in the
		 * allowed kernel range, so reset the property to the default value.
		 */
		if (option->default_if_zero && uval == 0) {
			g_value_unset (&val);
			g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (pspec));
			g_param_value_set_default (pspec, &val);
			uval = g_value_get_uint (&val);
		}

		/* Linux kernel bridge interfaces use 'centiseconds' for time-based values.
		 * In reality it's not centiseconds, but depends on HZ and USER_HZ, which
		 * is almost always works out to be a multiplier of 100, so we can assume
		 * centiseconds.  See clock_t_to_jiffies().
		 */
		if (option->user_hz_compensate)
			uval *= 100;
	} else
		g_assert_not_reached ();
	g_value_unset (&val);

	value = g_strdup_printf ("%u", uval);
	if (slave)
		nm_platform_slave_set_option (ifindex, option->sysname, value);
	else
		nm_platform_master_set_option (ifindex, option->sysname, value);
}
Exemple #24
0
static GObject*
constructor (GType type,
             guint n_construct_params,
             GObjectConstructParam *construct_params)
{
	GObject *object;
	GObjectClass *klass;
	NMDeviceOlpcMesh *self;
	NMDeviceOlpcMeshPrivate *priv;

	klass = G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class);
	object = klass->constructor (type, n_construct_params, construct_params);
	if (!object)
		return NULL;

	self = NM_DEVICE_OLPC_MESH (object);
	priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);

	nm_log_dbg (LOGD_HW | LOGD_OLPC_MESH, "(%s): kernel ifindex %d",
	            nm_device_get_iface (NM_DEVICE (self)),
	            nm_device_get_ifindex (NM_DEVICE (self)));

	priv->wifi_data = wifi_utils_init (nm_device_get_iface (NM_DEVICE (self)),
	                                   nm_device_get_ifindex (NM_DEVICE (self)),
	                                   FALSE);
	if (priv->wifi_data == NULL) {
		nm_log_warn (LOGD_HW | LOGD_OLPC_MESH, "(%s): failed to initialize WiFi driver",
		             nm_device_get_iface (NM_DEVICE (self)));
		g_object_unref (object);
		return NULL;
	}

	/* shorter timeout for mesh connectivity */
	nm_device_set_dhcp_timeout (NM_DEVICE (self), 20);
	return 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;
	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);
}
static void
update_connection (NMDevice *device, NMConnection *connection)
{
	NMDeviceTun *self = NM_DEVICE_TUN (device);
	NMSettingTun *s_tun = nm_connection_get_setting_tun (connection);
	NMPlatformTunProperties props;
	NMSettingTunMode mode;
	gint64 user, group;
	char *str;

	if (!s_tun) {
		s_tun = (NMSettingTun *) nm_setting_tun_new ();
		nm_connection_add_setting (connection, (NMSetting *) s_tun);
	}

	if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) {
		_LOGW (LOGD_HW, "failed to get TUN interface info while updating connection.");
		return;
	}

	mode = tun_mode_from_string (props.mode);

	if (mode != nm_setting_tun_get_mode (s_tun))
		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MODE, mode, NULL);

	user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1);
	group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1);

	if (props.owner != user) {
		str = props.owner >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.owner) : NULL;
		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_OWNER, str, NULL);
		g_free (str);
	}

	if (props.group != group) {
		str = props.group >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.group) : NULL;
		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_GROUP, str, NULL);
		g_free (str);
	}

	if ((!props.no_pi) != nm_setting_tun_get_pi (s_tun))
		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_PI, !props.no_pi, NULL);
	if (props.vnet_hdr != nm_setting_tun_get_vnet_hdr (s_tun))
		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_VNET_HDR, props.vnet_hdr, NULL);
	if (props.multi_queue != nm_setting_tun_get_multi_queue (s_tun))
		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MULTI_QUEUE, props.multi_queue, NULL);
}
NMDevice *
nm_device_vlan_new_for_connection (NMConnection *connection, NMDevice *parent)
{
	NMDevice *device;
	NMSettingVlan *s_vlan;
	char *iface;

	g_return_val_if_fail (connection != NULL, NULL);
	g_return_val_if_fail (NM_IS_DEVICE (parent), NULL);

	s_vlan = nm_connection_get_setting_vlan (connection);
	g_return_val_if_fail (s_vlan != NULL, NULL);

	iface = g_strdup (nm_connection_get_interface_name (connection));
	if (!iface) {
		iface = nm_utils_new_vlan_name (nm_device_get_ip_iface (parent),
		                                nm_setting_vlan_get_id (s_vlan));
	}

	if (   !nm_platform_vlan_add (iface,
	                              nm_device_get_ifindex (parent),
	                              nm_setting_vlan_get_id (s_vlan),
	                              nm_setting_vlan_get_flags (s_vlan))
	    && nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) {
		nm_log_warn (LOGD_DEVICE | LOGD_VLAN, "(%s) failed to add VLAN interface for '%s'",
		             iface, nm_connection_get_id (connection));
		g_free (iface);
		return NULL;
	}

	device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_VLAN,
	                                    NM_DEVICE_IFACE, iface,
	                                    NM_DEVICE_VLAN_PARENT, parent,
	                                    NM_DEVICE_DRIVER, "8021q",
	                                    NM_DEVICE_TYPE_DESC, "VLAN",
	                                    NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN,
	                                    NULL);
	g_free (iface);
	if (NM_DEVICE_VLAN_GET_PRIVATE (device)->invalid) {
		g_object_unref (device);
		device = NULL;
	}

	return device;
}
static void
carrier_on (NMNetlinkMonitor *monitor,
            int idx,
            gpointer user_data)
{
	NMDevice *device = NM_DEVICE (user_data);
	NMDeviceWired *self = NM_DEVICE_WIRED (device);
	guint32 caps;

	/* Make sure signal is for us */
	if (idx == nm_device_get_ifindex (device)) {
		caps = nm_device_get_capabilities (device);
		g_return_if_fail (caps & NM_DEVICE_CAP_CARRIER_DETECT);

		set_carrier (self, TRUE, FALSE);
		set_speed (self, ethtool_get_speed (self));
	}
}
static void
constructed (GObject *object)
{
	NMDeviceVlan *self = NM_DEVICE_VLAN (object);
	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
	int ifindex = nm_device_get_ifindex (NM_DEVICE (self));
	int parent_ifindex = -1, itype;
	int vlan_id;

	if (G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed)
		G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed (object);

	if (!priv->parent) {
		_LOGE (LOGD_VLAN, "no parent specified.");
		priv->invalid = TRUE;
		return;
	}

	itype = nm_platform_link_get_type (ifindex);
	if (itype != NM_LINK_TYPE_VLAN) {
		_LOGE (LOGD_VLAN, "failed to get VLAN interface type.");
		priv->invalid = TRUE;
		return;
	}

	if (!nm_platform_vlan_get_info (ifindex, &parent_ifindex, &vlan_id)) {
		_LOGW (LOGD_VLAN, "failed to get VLAN interface info.");
		priv->invalid = TRUE;
		return;
	}

	if (   parent_ifindex < 0
	    || parent_ifindex != nm_device_get_ip_ifindex (priv->parent)
	    || vlan_id < 0) {
		_LOGW (LOGD_VLAN, "VLAN parent ifindex (%d) or VLAN ID (%d) invalid.",
		       parent_ifindex, priv->vlan_id);
		priv->invalid = TRUE;
		return;
	}

	priv->vlan_id = vlan_id;
	_LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s",
	       priv->vlan_id, nm_device_get_iface (priv->parent));
}
static void
reload_tun_properties (NMDeviceTun *self)
{
	NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self);
	GObject *object = G_OBJECT (self);
	NMPlatformTunProperties props;
	int ifindex;

	ifindex = nm_device_get_ifindex (NM_DEVICE (self));
	if (ifindex > 0) {
		if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET, ifindex, &props)) {
			_LOGD (LOGD_DEVICE, "tun-properties: cannot loading tun properties from platform for ifindex %d", ifindex);
			ifindex = 0;
		} else if (g_strcmp0 (priv->mode, props.mode) != 0) {
			/* if the mode differs, we ignore what we loaded. A NMDeviceTun cannot
			 * change the mode after construction. */
			_LOGD (LOGD_DEVICE, "tun-properties: loading tun properties yielded tun-mode %s%s%s, but %s%s%s expected (ifindex %d)",
			       NM_PRINT_FMT_QUOTE_STRING (props.mode),
			       NM_PRINT_FMT_QUOTE_STRING (priv->mode),
			       ifindex);
			ifindex = 0;
		}
	} else
		_LOGD (LOGD_DEVICE, "tun-properties: ignore loading properties due to missing ifindex");
	if (ifindex <= 0)
		memset (&props, 0, sizeof (props));

	g_object_freeze_notify (object);

	if (priv->props.owner != props.owner)
		g_object_notify (object, NM_DEVICE_TUN_OWNER);
	if (priv->props.group != props.group)
		g_object_notify (object, NM_DEVICE_TUN_GROUP);
	if (priv->props.no_pi != props.no_pi)
		g_object_notify (object, NM_DEVICE_TUN_NO_PI);
	if (priv->props.vnet_hdr != props.vnet_hdr)
		g_object_notify (object, NM_DEVICE_TUN_VNET_HDR);
	if (priv->props.multi_queue != props.multi_queue)
		g_object_notify (object, NM_DEVICE_TUN_MULTI_QUEUE);

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

	g_object_thaw_notify (object);
}