示例#1
0
/*
 * Create a new ppp interface
 */
static dbus_bool_t
ni_objectmodel_ppp_device_new(ni_dbus_object_t *factory_object, const ni_dbus_method_t *method,
			unsigned int argc, const ni_dbus_variant_t *argv,
			ni_dbus_message_t *reply, DBusError *error)
{
	ni_dbus_server_t *server = ni_dbus_object_get_server(factory_object);
	ni_netdev_t *dev, *cfg;
	const char *ifname = NULL;

	if (argc != 2)
		goto error;

	if (!ni_dbus_variant_get_string(&argv[0], &ifname))
		goto error;

	if (!(cfg = ni_objectmodel_ppp_device_arg(&argv[1])))
		goto error;

	dev = ni_objectmodel_ppp_device_create(cfg, ifname, error);
	ni_netdev_put(cfg);

	if (dev)
		return ni_objectmodel_netif_factory_result(server, reply, dev, NULL, error);
	else
		return FALSE;

error:
	return ni_dbus_error_invalid_args(error, factory_object->path, method->name);
}
示例#2
0
文件: ethtool.c 项目: openSUSE/wicked
/*
 * ethtool.changeDevice method
 */
static dbus_bool_t
ni_objectmodel_ethtool_setup(ni_dbus_object_t *object, const ni_dbus_method_t *method,
		unsigned int argc, const ni_dbus_variant_t *argv,
		ni_dbus_message_t *reply, DBusError *error)
{
	ni_netdev_t *dev, *cfg;

	/* we've already checked that argv matches our signature */
	ni_assert(argc == 1);

	if (!(dev = ni_objectmodel_unwrap_netif(object, error)))
		return FALSE;

	if (!(cfg = ni_objectmodel_ethtool_request_arg(&argv[0]))) {
		ni_dbus_error_invalid_args(error, object->path, method->name);
		return FALSE;
	}

	if (ni_system_ethtool_setup(NULL, dev, cfg) < 0)  {
		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to apply ethtool settings");
		ni_netdev_put(cfg);
		return FALSE;
	}

	ni_netdev_put(cfg);
	return TRUE;
}
示例#3
0
/*
 * Filesystem.getInfo(path)
 *
 */
static dbus_bool_t
__ni_Testbus_Agent_Filesystem_getInfo(ni_dbus_object_t *object, const ni_dbus_method_t *method,
		unsigned int argc, const ni_dbus_variant_t *argv,
		ni_dbus_message_t *reply, DBusError *error)
{
	ni_dbus_variant_t res = NI_DBUS_VARIANT_INIT;
	struct stat stb;
	const char *path;
	dbus_bool_t rv;

	if (argc != 1 || !ni_dbus_variant_get_string(&argv[0], &path) || path[0] != '/')
		return ni_dbus_error_invalid_args(error, object->path, method->name);

	if (stat(path, &stb) < 0) {
		ni_dbus_set_error_from_errno(error, errno, "unable to stat file \"%s\"", path);
		return FALSE;
	}
	if (!S_ISREG(stb.st_mode)) {
		dbus_set_error(error, DBUS_ERROR_FAILED, "not a regular file");
		return FALSE;
	}

	ni_dbus_variant_init_dict(&res);
	ni_dbus_dict_add_uint64(&res, "size", stb.st_size);

	rv = ni_dbus_message_serialize_variants(reply, 1, &res, error);
	ni_dbus_variant_destroy(&res);
	return rv;
}
示例#4
0
/*
 * PPP.changeDevice method
 */
static dbus_bool_t
ni_objectmodel_ppp_device_change(ni_dbus_object_t *object, const ni_dbus_method_t *method,
			unsigned int argc, const ni_dbus_variant_t *argv,
			ni_dbus_message_t *reply, DBusError *error)
{
	ni_netconfig_t *nc = ni_global_state_handle(0);
	ni_netdev_t *ifp, *cfg;
	dbus_bool_t rv = FALSE;

	/* we've already checked that argv matches our signature */
	ni_assert(argc == 1);

	if (!(ifp = ni_objectmodel_unwrap_netif(object, error)))
		return FALSE;

	if (!(cfg = ni_objectmodel_ppp_device_arg(&argv[0]))) {
		ni_dbus_error_invalid_args(error, object->path, method->name);
		goto out;
	}

	if (ni_system_ppp_setup(nc, ifp, cfg) < 0) {
		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to set up ppp device");
		goto out;
	}

	rv = TRUE;
out:
	if (cfg)
		ni_netdev_put(cfg);
	return rv;
}
示例#5
0
文件: ppp.c 项目: mchf/wicked
/*
 * Create a new PPP interface
 * We're given two arguments, the interface name and the <ppp> configuration data.
 * However, we ignore all the config data at this point and just create the
 * device. The configuration data is consumed by a subsequent call to changeDevice
 * (where we build a config file from it).
 */
dbus_bool_t
ni_objectmodel_ppp_newlink(ni_dbus_object_t *factory_object, const ni_dbus_method_t *method,
			unsigned int argc, const ni_dbus_variant_t *argv,
			ni_dbus_message_t *reply, DBusError *error,
			__get_device_arg_fn_t get_device_arg_fn)
{
	ni_dbus_server_t *server = ni_dbus_object_get_server(factory_object);
	const char *ifname = NULL;
	ni_netdev_t *dev, *dev_cfg;

	NI_TRACE_ENTER();

	ni_assert(argc == 2);
	if (!ni_dbus_variant_get_string(&argv[0], &ifname))
		return ni_dbus_error_invalid_args(error, factory_object->path, method->name);
	if (!(dev_cfg = get_device_arg_fn(&argv[1], error)))
		return FALSE;

	dev = __ni_objectmodel_ppp_newlink(dev_cfg, ifname, error);
	ni_netdev_put(dev_cfg);

	if (dev == NULL)
		return FALSE;

	return ni_objectmodel_netif_factory_result(server, reply, dev, NULL, error);
}
示例#6
0
/*
 * Eventlog.purge(seqno)
 */
static dbus_bool_t
__ni_Testbus_Eventlog_purge(ni_dbus_object_t *object, const ni_dbus_method_t *method,
		unsigned int argc, const ni_dbus_variant_t *argv,
		ni_dbus_message_t *reply, DBusError *error)
{
	ni_eventlog_t *log;
	uint32_t upto_seq;

	if (!(log = __ni_objectmodel_get_eventlog(object, TRUE, error)))
		return FALSE;

	if (argc != 1
	 || !ni_dbus_variant_get_uint32(&argv[0], &upto_seq))
		return ni_dbus_error_invalid_args(error, object->path, method->name);

	if (upto_seq == 0) {
		/* Means: really flush all events */
		ni_eventlog_flush(log);
	} else {
		/* Mark all events up to and including upto_seq as consumed.
		 */
		ni_eventlog_consume_upto(log, upto_seq);
	}

	return TRUE;
}
示例#7
0
文件: macvlan.c 项目: gsanso/wicked
dbus_bool_t
ni_objectmodel_macvtap_newlink(ni_dbus_object_t *factory_object,
			const ni_dbus_method_t *method,
			unsigned int argc, const ni_dbus_variant_t *argv,
			ni_dbus_message_t *reply, DBusError *error)
{
	ni_dbus_server_t *server = ni_dbus_object_get_server(factory_object);
	ni_netdev_t *dev;
	const char *ifname = NULL;

	NI_TRACE_ENTER();

	ni_assert(argc == 2);
	if (!ni_dbus_variant_get_string(&argv[0], &ifname) ||
		!(dev = __ni_objectmodel_macvlan_device_arg(&argv[1], NI_IFTYPE_MACVTAP))) {
		return ni_dbus_error_invalid_args(error,
						factory_object->path,
						method->name);
	}

	if (!(dev = __ni_objectmodel_macvlan_newlink(dev, ifname, error)))
		return FALSE;

	return ni_objectmodel_netif_factory_result(server, reply, dev, NULL, error);
}
示例#8
0
文件: tuntap.c 项目: mijos/wicked
static dbus_bool_t
__ni_objectmodel_tuntap_newlink(ni_iftype_t iftype, ni_dbus_object_t *factory_object,
			const ni_dbus_method_t *method,
			unsigned int argc, const ni_dbus_variant_t *argv,
			ni_dbus_message_t *reply, DBusError *error)
{
	ni_dbus_server_t *server = ni_dbus_object_get_server(factory_object);
	const char *ifname = NULL;
	ni_netdev_t *dev;
	ni_netdev_t *cfg;

	NI_TRACE_ENTER();
	ni_assert(argc == 2);

	if (!ni_dbus_variant_get_string(&argv[0], &ifname) ||
	    !(cfg = __ni_objectmodel_tuntap_device_arg(&argv[1], iftype))) {
		return ni_dbus_error_invalid_args(error,
						factory_object->path,
						method->name);
	}

	ni_string_dup(&cfg->name, ifname);
	dev = __ni_objectmodel_tuntap_create(cfg, error);

	ni_netdev_put(cfg);
	if (!dev)
		return FALSE;
	return ni_objectmodel_netif_factory_result(server, reply, dev, NULL, error);
}
示例#9
0
/*
 * Filesystem.download(path, offset, count)
 *
 */
static dbus_bool_t
__ni_Testbus_Agent_Filesystem_download(ni_dbus_object_t *object, const ni_dbus_method_t *method,
		unsigned int argc, const ni_dbus_variant_t *argv,
		ni_dbus_message_t *reply, DBusError *error)
{
	ni_dbus_variant_t res = NI_DBUS_VARIANT_INIT;
	const char *path;
	uint64_t offset;
	uint32_t count;
	dbus_bool_t rv;
	ni_buffer_t *bp = NULL;
	int fd = -1;

	if (argc != 3
	 || !ni_dbus_variant_get_string(&argv[0], &path) || path[0] != '/'
	 || !ni_dbus_variant_get_uint64(&argv[1], &offset)
	 || !ni_dbus_variant_get_uint32(&argv[2], &count)
	 || count > 1024 * 1024
	 || offset + count < offset)
		return ni_dbus_error_invalid_args(error, object->path, method->name);

	if ((fd = open(path, O_RDONLY)) < 0) {
		ni_dbus_set_error_from_errno(error, errno, "unable to open file \"%s\"", path);
		return FALSE;
	}
	if (lseek(fd, offset, SEEK_SET) < 0) {
		ni_dbus_set_error_from_errno(error, errno, "seek faile");
		goto out_fail;
	}

	bp = ni_buffer_new(count);
	while (count) {
		int n;

		n = read(fd, ni_buffer_tail(bp), ni_buffer_tailroom(bp));
		if (n < 0) {
			ni_dbus_set_error_from_errno(error, errno, "read failed");
			goto out_fail;
		}
		if (n == 0)
			break;
		ni_buffer_push_tail(bp, n);
	}

	ni_dbus_variant_init_dict(&res);
	ni_dbus_variant_set_byte_array(&res, ni_buffer_head(bp), ni_buffer_count(bp));

	rv = ni_dbus_message_serialize_variants(reply, 1, &res, error);

	ni_dbus_variant_destroy(&res);
	ni_buffer_free(bp);
	close(fd);
	return rv;

out_fail:
	if (fd >= 0)
		close(fd);
	return FALSE;
}
示例#10
0
/*
 * Tmpfile.upload(path, offset, data)
 */
static dbus_bool_t
__ni_Testbus_Agent_Filesystem_upload(ni_dbus_object_t *object, const ni_dbus_method_t *method,
		unsigned int argc, const ni_dbus_variant_t *argv,
		ni_dbus_message_t *reply, DBusError *error)
{
	ni_buffer_t wbuf;
	const char *path;
	uint64_t offset;
	unsigned int written = 0;
	int fd;

	if (argc != 3
	 || !ni_dbus_variant_get_string(&argv[0], &path) || path[0] != '/'
	 || !ni_dbus_variant_get_uint64(&argv[1], &offset)
	 || !ni_dbus_variant_is_byte_array(&argv[2]))
		return ni_dbus_error_invalid_args(error, object->path, method->name);

	if (offset == 0)
		fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644);
	else
		fd = open(path, O_WRONLY);
	if (fd < 0) {
		ni_dbus_set_error_from_errno(error, errno, "unable to open file \"%s\"", path);
		return FALSE;
	}
	if (lseek(fd, offset, SEEK_SET) < 0) {
		ni_dbus_set_error_from_errno(error, errno, "seek faile");
		goto out_fail;
	}

	ni_buffer_init_reader(&wbuf, argv[2].byte_array_value, argv[2].array.len);
	while (ni_buffer_count(&wbuf)) {
		int n;

		n = write(fd, ni_buffer_head(&wbuf), ni_buffer_count(&wbuf));
		if (n < 0) {
			ni_dbus_set_error_from_errno(error, errno,
						"error writing to \"%s\" at offset %Lu",
						path, (unsigned long long) offset + written);
			goto out_fail;
		}

		ni_buffer_pull_head(&wbuf, n);
		written += n;
	}

	close(fd);

	ni_debug_testbus("%s: wrote %u bytes at offset %Lu",
			path, written, (unsigned long long) offset);
	return TRUE;

out_fail:
	if (fd >= 0)
		close(fd);
	return FALSE;
}
示例#11
0
static dbus_bool_t
ni_objectmodel_gre_change(ni_dbus_object_t *object, const ni_dbus_method_t *method,
			unsigned int argc, const ni_dbus_variant_t *argv,
			ni_dbus_message_t *reply, DBusError *error)
{
	ni_netconfig_t *nc = ni_global_state_handle(0);
	ni_netdev_t *dev, *cfg;
	ni_gre_t *gre;
	const char *err;

	/* we've already checked that argv matches our signature */
	ni_assert(argc == 1);

	if (!(dev = ni_objectmodel_unwrap_netif(object, error)) ||
		!(cfg = __ni_objectmodel_gre_device_arg(&argv[0])) ||
		!(ni_netdev_get_gre(dev))) {
		ni_dbus_error_invalid_args(error, object->path, method->name);
		return FALSE;
	}

	gre = ni_netdev_get_gre(cfg);
	if ((err = ni_gre_validate(gre))) {
		dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s", err);
		return FALSE;
	}

	cfg->link.ifindex = dev->link.ifindex;
	if (ni_string_empty(cfg->name))
		ni_string_dup(&cfg->name, dev->name);

	if (ni_netdev_device_is_up(dev)) {
		ni_debug_objectmodel("Skipping gre changeDevice call on %s: "
				"device is up", dev->name);
		return TRUE;
	}

	if (!ni_string_empty(cfg->link.lowerdev.name) &&
	    !ni_objectmodel_bind_netdev_ref_index(cfg->name, "gre tunnel",
					&cfg->link.lowerdev, nc, error))
		return FALSE;

	if (ni_system_tunnel_change(nc, dev, cfg) < 0) {
		dbus_set_error(error,
			DBUS_ERROR_FAILED,
			"Unable to change gre properties on interface %s",
			dev->name);
		return FALSE;
	}

	return TRUE;
}
示例#12
0
/*
 * Infiniband(Child).changeDevice method
 */
static dbus_bool_t
ni_objectmodel_ib_setup(ni_dbus_object_t *object, const ni_dbus_method_t *method,
				unsigned int argc, const ni_dbus_variant_t *argv,
				ni_dbus_message_t *reply, DBusError *error)
{
	ni_netconfig_t *nc = ni_global_state_handle(0);
	ni_netdev_t *ifp, *cfg;
	dbus_bool_t rv = FALSE;

	/* we've already checked that argv matches our signature */
	if (argc != 1 || !(ifp = ni_objectmodel_unwrap_netif(object, error)))
		return FALSE;

	if (ifp->link.type == NI_IFTYPE_INFINIBAND) {
		cfg = __ni_objectmodel_ibparent_device_arg(&argv[0]);
	} else
	if (ifp->link.type == NI_IFTYPE_INFINIBAND_CHILD) {
		cfg = __ni_objectmodel_ibchild_device_arg(&argv[0]);
	} else {
		cfg = NULL;
	}
	if (!cfg) {
		ni_dbus_error_invalid_args(error, object->path, method->name);
		goto out;
	}

	/* when <infiniband/> node is empty (defaults only), skip setup */
	if (cfg->infiniband) {
		const char *err;

		if ((err = ni_infiniband_validate(ifp->link.type, cfg->infiniband,
							&cfg->link.lowerdev))) {
			dbus_set_error(error, DBUS_ERROR_FAILED, "%s", err);
			goto out;
		}

		if (ni_system_infiniband_setup(nc, ifp, cfg) < 0) {
			dbus_set_error(error, DBUS_ERROR_FAILED,
					"failed to configure infiniband device %s",
					ifp->name);
			goto out;
		}
	}

	rv = TRUE;
out:
	if (cfg)
		ni_netdev_put(cfg);
	return rv;
}
示例#13
0
static dbus_bool_t
ni_objectmodel_dummy_change(ni_dbus_object_t *object, const ni_dbus_method_t *method,
			unsigned int argc, const ni_dbus_variant_t *argv,
			ni_dbus_message_t *reply, DBusError *error)
{
	ni_netconfig_t *nc = ni_global_state_handle(0);
	ni_netdev_t *dev, *cfg;

	/* we've already checked that argv matches our signature */
	ni_assert(argc == 1);

	if (!(dev = ni_objectmodel_unwrap_netif(object, error)) ||
	    !(cfg = __ni_objectmodel_dummy_device_arg(&argv[0]))) {
		ni_dbus_error_invalid_args(error, object->path, method->name);
		return FALSE;
	}

	cfg->link.ifindex = dev->link.ifindex;
	if (ni_string_empty(cfg->name))
		ni_string_dup(&cfg->name, dev->name);

	if (ni_netdev_device_is_up(dev)) {
		ni_debug_objectmodel("Skipping dummy changeDevice call on %s: "
				"device is up", dev->name);
		return TRUE;
	}

	if (ni_system_dummy_change(nc, dev, cfg) < 0) {
		dbus_set_error(error,
				DBUS_ERROR_FAILED,
				"Unable to change dummy properties on interface %s",
				dev->name);
		return FALSE;
	}

	if (cfg->link.hwaddr.type == ARPHRD_VOID)
		cfg->link.hwaddr.type = ARPHRD_ETHER;
	if (!ni_link_address_is_invalid(&cfg->link.hwaddr) &&
	    ni_system_hwaddr_change(nc, dev, &cfg->link.hwaddr) < 0) {
		ni_error("Unable to change hwaddr on dummy interface %s",
				dev->name);
		/* fail? */
	}

	return TRUE;
}
示例#14
0
文件: macvlan.c 项目: gsanso/wicked
static dbus_bool_t
ni_objectmodel_macvtap_change(ni_dbus_object_t *object, const ni_dbus_method_t *method,
			unsigned int argc, const ni_dbus_variant_t *argv,
			ni_dbus_message_t *reply, DBusError *error)
{
	ni_netdev_t *dev, *cfg;

	/* we've already checked that argv matches our signature */
	ni_assert(argc == 1);

	if (!(dev = ni_objectmodel_unwrap_netif(object, error)) ||
		!(cfg = __ni_objectmodel_macvlan_device_arg(&argv[0], NI_IFTYPE_MACVTAP)) ||
		!(ni_netdev_get_macvlan(dev))) {
		ni_dbus_error_invalid_args(error, object->path, method->name);
		return FALSE;
	}

	return __ni_objectmodel_macvlan_change(cfg, dev, error);
}
示例#15
0
/*
 * Create a new ovs bridge interface
 */
static dbus_bool_t
__ni_objectmodel_ovs_bridge_create(ni_dbus_object_t *factory_object, const ni_dbus_method_t *method,
			unsigned int argc, const ni_dbus_variant_t *argv,
			ni_dbus_message_t *reply, DBusError *error)
{
	ni_dbus_server_t *server = ni_dbus_object_get_server(factory_object);
	ni_netdev_t *ifp;
	const char *ifname = NULL;

	ni_assert(argc == 2);
	if (!ni_dbus_variant_get_string(&argv[0], &ifname)
	 || !(ifp = __ni_objectmodel_ovs_bridge_device_arg(&argv[1])))
		return ni_dbus_error_invalid_args(error, factory_object->path, method->name);

	if (!(ifp = __ni_objectmodel_ovs_bridge_newlink(ifp, ifname, error)))
		return FALSE;

	return ni_objectmodel_netif_factory_result(server, reply, ifp, NULL, error);
}
示例#16
0
文件: lldp.c 项目: mchf/wicked
/*
 * LLDP.lldpUp
 */
static dbus_bool_t
ni_objectmodel_lldp_up(ni_dbus_object_t *object, const ni_dbus_method_t *method,
			unsigned int argc, const ni_dbus_variant_t *argv,
			ni_dbus_message_t *reply, DBusError *error)
{
	ni_netdev_t *dev, *cfg;
	dbus_bool_t rv = FALSE;

	/* we've already checked that argv matches our signature */
	ni_assert(argc == 1);

	if (!(dev = ni_objectmodel_unwrap_netif(object, error)))
		return FALSE;

	ni_debug_lldp("ni_objectmodel_lldp_up(%s -> %s)", object->path, dev->name);

	if (!ni_system_lldp_available(dev)) {
		ni_error("Cannot enable LLDP for device %s: incompatible layer 2 protocol", dev->name);
		return TRUE;
	}

	if (!(cfg = __ni_objectmodel_protocol_arg(&argv[0], &ni_objectmodel_lldp_service))) {
		ni_dbus_error_invalid_args(error, object->path, method->name);
		goto out;
	}

	if (cfg->lldp
	 && !__ni_objectmodel_lldp_verify(object, method, dev, cfg->lldp, error))
		goto out;

	if (ni_system_lldp_up(dev, cfg->lldp) < 0) {
		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to set up LLDP on device %s", dev->name);
		goto out;
	}

	rv = TRUE;

out:
	if (cfg)
		ni_netdev_put(cfg);
	return rv;
}
示例#17
0
/*
 * Eventlog.add(event)
 */
static dbus_bool_t
__ni_Testbus_Eventlog_add(ni_dbus_object_t *object, const ni_dbus_method_t *method,
		unsigned int argc, const ni_dbus_variant_t *argv,
		ni_dbus_message_t *reply, DBusError *error)
{
	ni_eventlog_t *log;
	const ni_event_t *last;
	ni_event_t *ev;
	uint32_t last_seq = 0;

	if (!(log = __ni_objectmodel_get_eventlog(object, TRUE, error)))
		return FALSE;

	if ((last = ni_eventlog_last(log)) != NULL)
		last_seq = last->sequence;

	if (argc != 1)
		goto invalid_args;

	ev = ni_event_array_add(&log->events);
	if (!ni_testbus_event_deserialize(&argv[0], ev)) {
		/* Dispose of the incomplete event. Would be nice if there were
		 * a proper function for this. */
		ni_event_destroy(ev);
		log->events.count -= 1;

		goto invalid_args;
	}

	if (last_seq && ev->sequence != last_seq + 1)
		ni_warn("%s: lost event(s): expected seq %u, got seq %u",
				object->path, last_seq + 1, ev->sequence);

	ni_debug_dbus("%s: adding %s-%s event from %s to log",
			object->path, ev->class, ev->type, ev->source);

	ni_testbus_eventlog_signal_eventsAdded(object, ev->sequence);
	return TRUE;

invalid_args:
	return ni_dbus_error_invalid_args(error, object->path, method->name);
}
示例#18
0
static dbus_bool_t
ni_objectmodel_ib_newchild(ni_dbus_object_t *factory_object, const ni_dbus_method_t *method,
				unsigned int argc, const ni_dbus_variant_t *argv,
				ni_dbus_message_t *reply, DBusError *error)
{
	ni_dbus_server_t *server = ni_dbus_object_get_server(factory_object);
	ni_netdev_t *cfg, *dev;
	const char *ifname = NULL;

	NI_TRACE_ENTER();

	if (argc != 2 || !ni_dbus_variant_get_string(&argv[0], &ifname) || !ifname ||
	    !(cfg = __ni_objectmodel_ibchild_device_arg(&argv[1]))) {
		return ni_dbus_error_invalid_args(error, factory_object->path, method->name);
	}

	if (!(dev = __ni_objectmodel_ib_newchild(cfg, ifname, error))) {
		ni_netdev_put(cfg);
		return FALSE;
	}
	ni_netdev_put(cfg);

	return ni_objectmodel_netif_factory_result(server, reply, dev, NULL, error);
}
示例#19
0
文件: tuntap.c 项目: mijos/wicked
static dbus_bool_t
ni_objectmodel_tuntap_change(ni_dbus_object_t *object, const ni_dbus_method_t *method,
				unsigned int argc, const ni_dbus_variant_t *argv,
				ni_dbus_message_t *reply, DBusError *error)
{
	ni_netconfig_t *nc = ni_global_state_handle(0);
	ni_netdev_t *dev, *cfg;
	ni_tuntap_t *tuntap;
	const char *err;
	const char *iftype_name;

	/* we've already checked that argv matches our signature */
	ni_assert(argc == 1);

	if (!(dev = ni_objectmodel_unwrap_netif(object, error)) ||
	    !(cfg = __ni_objectmodel_tuntap_device_arg(&argv[0], dev->link.type)) ||
	    !(ni_netdev_get_tuntap(dev))) {
		ni_dbus_error_invalid_args(error, object->path, method->name);
		return FALSE;
	}

	/* changeDevice method is only needed in case of TAP devices */
	if (dev->link.type != NI_IFTYPE_TAP)
		return TRUE;

	iftype_name = ni_linktype_type_to_name(dev->link.type);

	tuntap = ni_netdev_get_tuntap(cfg);
	if ((err = ni_tuntap_validate(tuntap))) {
		dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s", err);
		return FALSE;
	}

	cfg->link.ifindex = dev->link.ifindex;
	if (ni_string_empty(cfg->name))
		ni_string_dup(&cfg->name, dev->name);

	if (ni_netdev_device_is_up(dev)) {
		ni_debug_objectmodel("Skipping %s changeDevice call on %s: "
				"device is up", iftype_name, dev->name);
		return TRUE;
	}

	if (ni_system_tap_change(nc, dev, cfg) < 0) {
		dbus_set_error(error,
				DBUS_ERROR_FAILED,
				"Unable to change %s properties on interface %s",
				iftype_name, dev->name);
		return FALSE;
	}

	if (cfg->link.hwaddr.type == ARPHRD_VOID)
		cfg->link.hwaddr.type = ARPHRD_ETHER;
	if (ni_system_hwaddr_change(nc, dev, &cfg->link.hwaddr) < 0) {
		ni_error("Unable to change hwaddr on %s interface %s",
				iftype_name, dev->name);
		/* fail? */
	}

	return TRUE;
}