diff options
| -rw-r--r-- | hcid/Makefile.am | 3 | ||||
| -rw-r--r-- | hcid/dbus-adapter.c | 1342 | ||||
| -rw-r--r-- | hcid/dbus-device.c | 1313 | 
3 files changed, 1344 insertions, 1314 deletions
| diff --git a/hcid/Makefile.am b/hcid/Makefile.am index 0f9b81df..8d35463f 100644 --- a/hcid/Makefile.am +++ b/hcid/Makefile.am @@ -18,7 +18,8 @@ sbin_PROGRAMS = hcid  noinst_SCRIPTS = dbus-test  if DBUS -dbus_hcid_sources = dbus.h dbus.c dbus-error.c dbus-manager.c dbus-device.c +dbus_hcid_sources = dbus.h dbus.c dbus-error.c \ +			dbus-manager.c dbus-adapter.c dbus-device.c  dbus_hcid_libs    = @DBUS_LIBS@  dbus_hcid_cflags  = -DENABLE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE  else diff --git a/hcid/dbus-adapter.c b/hcid/dbus-adapter.c new file mode 100644 index 00000000..050aab69 --- /dev/null +++ b/hcid/dbus-adapter.c @@ -0,0 +1,1342 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2004-2006  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <sys/socket.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> + +#include <dbus/dbus.h> + +#include "hcid.h" +#include "dbus.h" + +#include "textfile.h" +#include "oui.h" + +static const char *service_cls[] = { +	"positioning", +	"networking", +	"rendering", +	"capturing", +	"object transfer", +	"audio", +	"telephony", +	"information" +}; + +static const char *computer_minor_cls[] = { +	"uncategorized", +	"desktop", +	"server", +	"laptop", +	"handheld", +	"palm", +	"wearable" +}; + +static char *get_peer_name(const bdaddr_t *local, const bdaddr_t *peer) +{ +	char filename[PATH_MAX + 1], addr[18]; + +	ba2str(local, addr); +	snprintf(filename, PATH_MAX, "%s/%s/names", STORAGEDIR, addr); + +	ba2str(peer, addr); +	return textfile_get(filename, addr); +} + +static DBusMessage *handle_dev_get_address_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	char str[18], *str_ptr = str; +	int err; + +	err = get_device_address(dbus_data->dev_id, str, sizeof(str)); +	if (err < 0) +		return error_generic(msg, -err); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_get_version_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	char str[20], *str_ptr = str; +	int err; + +	err = get_device_version(dbus_data->dev_id, str, sizeof(str)); +	if (err < 0) +		return error_generic(msg, -err); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_get_revision_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	char str[64], *str_ptr = str; +	int err; + +	err = get_device_revision(dbus_data->dev_id, str, sizeof(str)); +	if (err < 0) +		return error_generic(msg, -err); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_get_manufacturer_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	char str[64], *str_ptr = str; +	int err; + +	err = get_device_manufacturer(dbus_data->dev_id, str, sizeof(str)); +	if (err < 0) +		return error_generic(msg, -err); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_get_company_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	char str[64], *str_ptr = str; +	int err; + +	err = get_device_company(dbus_data->dev_id, str, sizeof(str)); +	if (err < 0) +		return error_generic(msg, -err); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_get_features_req(DBusMessage *msg, void *data) +{ +	DBusMessage *reply; +	DBusMessageIter iter; +	DBusMessageIter array_iter; + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	dbus_message_iter_init_append(reply, &iter); + +	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, +				DBUS_TYPE_STRING_AS_STRING, &array_iter); + +	dbus_message_iter_close_container(&iter, &array_iter); + +	return reply; +} + +static DBusMessage *handle_dev_get_mode_req(DBusMessage *msg, void *data) +{ +	const struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply = NULL; +	const uint8_t hci_mode = dbus_data->mode; +	const char *scan_mode; + +	switch (hci_mode) { +	case SCAN_DISABLED: +		scan_mode = MODE_OFF; +		break; +	case SCAN_PAGE: +		scan_mode = MODE_CONNECTABLE; +		break; +	case (SCAN_PAGE | SCAN_INQUIRY): +		scan_mode = MODE_DISCOVERABLE; +		break; +	case SCAN_INQUIRY: +	/* inquiry scan mode is not handled, return unknown */ +	default: +		/* reserved */ +		scan_mode = MODE_UNKNOWN; +	} + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &scan_mode, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_set_mode_req(DBusMessage *msg, void *data) +{ +	const struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	const char* scan_mode; +	uint8_t hci_mode; +	const uint8_t current_mode = dbus_data->mode; +	int dd; + +	dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &scan_mode, +							DBUS_TYPE_INVALID); + +	if (!scan_mode) +		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); + +	if (strcasecmp(MODE_OFF, scan_mode) == 0) +		hci_mode = SCAN_DISABLED; +	else if (strcasecmp(MODE_CONNECTABLE, scan_mode) == 0) +		hci_mode = SCAN_PAGE; +	else if (strcasecmp(MODE_DISCOVERABLE, scan_mode) == 0) +		hci_mode = (SCAN_PAGE | SCAN_INQUIRY); +	else +		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); + +	dd = hci_open_dev(dbus_data->dev_id); +	if (dd < 0) +		return error_no_such_device(msg); + +	/* Check if the new requested mode is different from the current */ +	if (current_mode != hci_mode) { +		struct hci_request rq; +		uint8_t status = 0; + +		memset(&rq, 0, sizeof(rq)); +		rq.ogf    = OGF_HOST_CTL; +		rq.ocf    = OCF_WRITE_SCAN_ENABLE; +		rq.cparam = &hci_mode; +		rq.clen   = sizeof(hci_mode); +		rq.rparam = &status; +		rq.rlen   = sizeof(status); + +		if (hci_send_req(dd, &rq, 100) < 0) { +			syslog(LOG_ERR, "Sending write scan enable command failed: %s (%d)", +							strerror(errno), errno); +			hci_close_dev(dd); +			return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | errno); +		} + +		if (status) { +			syslog(LOG_ERR, "Setting scan enable failed with status 0x%02x", status); +			hci_close_dev(dd); +			return bluez_new_failure_msg(msg, BLUEZ_EBT_OFFSET | status); +		} +	} + +	hci_close_dev(dd); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	return reply; +} + +static DBusMessage *handle_dev_get_discoverable_to_req(DBusMessage *msg, void *data) +{ +	const struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_UINT32, &dbus_data->discoverable_timeout, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_set_discoverable_to_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	DBusMessageIter iter; +	uint32_t timeout; + +	dbus_message_iter_init(msg, &iter); +	dbus_message_iter_get_basic(&iter, &timeout); + +	dbus_data->discoverable_timeout = timeout; + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	return reply; +} + +static DBusMessage *handle_dev_is_connectable_req(DBusMessage *msg, void *data) +{ +	const struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	const uint8_t hci_mode = dbus_data->mode; +	dbus_bool_t connectable = FALSE; + +	if (hci_mode & SCAN_PAGE) +		connectable = TRUE; + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connectable, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_is_discoverable_req(DBusMessage *msg, void *data) +{ +	const struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	const uint8_t hci_mode = dbus_data->mode; +	dbus_bool_t discoverable = FALSE; + +	if (hci_mode & SCAN_INQUIRY) +		discoverable = TRUE; + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &discoverable, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_get_major_class_req(DBusMessage *msg, void *data) +{ +	DBusMessage *reply; +	const char *str_ptr = "computer"; + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	/*FIXME: Check the real device major class */ +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_get_minor_class_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	const char *str_ptr = ""; +	uint8_t cls[3]; +	uint8_t minor_class; +	int dd; + +	dd = hci_open_dev(dbus_data->dev_id); +	if (dd < 0) +		return error_no_such_device(msg); + +	if (hci_read_class_of_dev(dd, cls, 1000) < 0) { +		syslog(LOG_ERR, "Can't read class of device on hci%d: %s(%d)", +				dbus_data->dev_id, strerror(errno), errno); +		hci_close_dev(dd); +		return error_generic(msg, -errno); +	} + +	hci_close_dev(dd); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	/* FIXME: Currently, only computer major class is supported */ +	if ((cls[1] & 0x1f) != 1) +		goto failed; + +	minor_class = cls[0] >> 2; + +	/* Validate computer minor class */ +	if (minor_class > (sizeof(computer_minor_cls) / sizeof(*computer_minor_cls))) +		goto failed; + +	str_ptr = computer_minor_cls[minor_class]; + +failed: +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_set_minor_class_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusConnection *connection = get_dbus_connection(); +	DBusMessageIter iter; +	DBusMessage *reply, *signal; +	bdaddr_t bdaddr; +	const char *minor; +	uint8_t cls[3]; +	uint32_t dev_class = 0xFFFFFFFF; +	int i, dd; + +	dbus_message_iter_init(msg, &iter); +	dbus_message_iter_get_basic(&iter, &minor); + +	if (!minor) +		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); + +	/* FIXME: currently, only computer minor classes are allowed */ +	for (i = 0; i < sizeof(computer_minor_cls) / sizeof(*computer_minor_cls); i++) +		if (!strcasecmp(minor, computer_minor_cls[i])) { +			/* Remove the format type */ +			dev_class = i << 2; +			break; +		} + +	/* Check if it's a valid minor class */ +	if (dev_class == 0xFFFFFFFF) +		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); + +	dd = hci_open_dev(dbus_data->dev_id); +	if (dd < 0) { +		syslog(LOG_ERR, "HCI device open failed: hci%d", dbus_data->dev_id); +		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_ENODEV); +	} + +	if (hci_read_class_of_dev(dd, cls, 1000) < 0) { +		syslog(LOG_ERR, "Can't read class of device on hci%d: %s(%d)", +				dbus_data->dev_id, strerror(errno), errno); +		reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | errno); +		goto failed; +	} + +	dev_class |= (cls[2] << 16) | (cls[1] << 8); + +	cls[2] = 0x00;	/* no service classes */ +	cls[1] = 0x01;	/* major class computer */ +	cls[0] = (dev_class & 0xff); + +	hci_devba(dbus_data->dev_id, &bdaddr); + +	write_local_class(&bdaddr, cls); + +	if (hci_write_class_of_dev(dd, dev_class, 2000) < 0) { +		syslog(LOG_ERR, "Can't write class of device on hci%d: %s(%d)", +				dbus_data->dev_id, strerror(errno), errno); +		reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | errno); +		goto failed; +	} + +	signal = dev_signal_factory(dbus_data->dev_id, DEV_SIG_MINOR_CLASS_CHANGED, +						DBUS_TYPE_STRING, &minor, +						DBUS_TYPE_INVALID); +	if (signal) { +		dbus_connection_send(connection, signal, NULL); +		dbus_connection_flush(connection); +		dbus_message_unref(signal); +	} + +	reply = dbus_message_new_method_return(msg); + +failed: +	hci_close_dev(dd); + +	return reply; +} + +static DBusMessage *handle_dev_get_service_classes_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	DBusMessageIter iter; +	DBusMessageIter array_iter; +	const char *str_ptr; +	uint8_t cls[3]; +	int dd, i; + +	dd = hci_open_dev(dbus_data->dev_id); +	if (dd < 0) { +		syslog(LOG_ERR, "HCI device open failed: hci%d", dbus_data->dev_id); +		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_ENODEV); +	} + +	if (hci_read_class_of_dev(dd, cls, 1000) < 0) { +		syslog(LOG_ERR, "Can't read class of device on hci%d: %s(%d)", +				dbus_data->dev_id, strerror(errno), errno); +		hci_close_dev(dd); +		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | errno); +	} + +	reply = dbus_message_new_method_return(msg); + +	dbus_message_iter_init_append(reply, &iter); + +	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, +				DBUS_TYPE_STRING_AS_STRING, &array_iter); + +	for (i = 0; i < (sizeof(service_cls) / sizeof(*service_cls)); i++) { +		if (cls[2] & (1 << i)) { +			str_ptr = service_cls[i]; +			dbus_message_iter_append_basic(&array_iter, +						DBUS_TYPE_STRING, &str_ptr); +		} +	} + +	dbus_message_iter_close_container(&iter, &array_iter); + +	hci_close_dev(dd); + +	return reply; +} + +static DBusMessage *handle_dev_get_name_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	char str[249], *str_ptr = str; +	int err; + +	err = get_device_name(dbus_data->dev_id, str, sizeof(str)); +	if (err < 0) +		return error_generic(msg, -err); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_set_name_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessageIter iter; +	DBusMessage *reply; +	bdaddr_t bdaddr; +	char *str_ptr; +	int err; + +	dbus_message_iter_init(msg, &iter); +	dbus_message_iter_get_basic(&iter, &str_ptr); + +	if (strlen(str_ptr) == 0) { +		syslog(LOG_ERR, "Name change failed: Invalid parameter"); +		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); +	} + +	hci_devba(dbus_data->dev_id, &bdaddr); + +	write_local_name(&bdaddr, str_ptr); + +	err = set_device_name(dbus_data->dev_id, str_ptr); +	if (err < 0) +		return error_generic(msg, -err); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	return reply; +} + +static DBusMessage *handle_dev_get_remote_version_req(DBusMessage *msg, void *data) +{ +	/*FIXME: */ +	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage *handle_dev_get_remote_revision_req(DBusMessage *msg, void *data) +{ +	/*FIXME: */ +	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage *handle_dev_get_remote_manufacturer_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessageIter iter; +	DBusMessage *reply; +	char filename[PATH_MAX + 1]; +	char addr[18], *addr_ptr, *str; +	int compid; + +	get_device_address(dbus_data->dev_id, addr, sizeof(addr)); + +	snprintf(filename, PATH_MAX, "%s/%s/manufacturers", STORAGEDIR, addr); + +	dbus_message_iter_init(msg, &iter); +	dbus_message_iter_get_basic(&iter, &addr_ptr); + +	str = textfile_get(filename, addr_ptr); +	if (!str) +		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | ENXIO); + +	compid = atoi(str); + +	free(str); + +	str = bt_compidtostr(compid); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_get_remote_company_req(DBusMessage *msg, void *data) +{ +	DBusMessage *reply; +	bdaddr_t bdaddr; +	char oui[9], *str_bdaddr, *tmp; + +	dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str_bdaddr, +							DBUS_TYPE_INVALID); + + +	str2ba(str_bdaddr, &bdaddr); +	ba2oui(&bdaddr, oui); + +	tmp = ouitocomp(oui); +	if (!tmp) +		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_RECORD_NOT_FOUND); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) { +		reply = error_out_of_memory(msg); +		goto done; +	} + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &tmp, +					DBUS_TYPE_INVALID); + +done: +	free(tmp); + +	return reply; +} + +static DBusMessage *handle_dev_get_remote_name_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply = NULL; +	const char *str_bdaddr; +	char *name; +	bdaddr_t bdaddr; +	struct hci_dev_info di; + +	dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str_bdaddr, +							DBUS_TYPE_INVALID); + +	str2ba(str_bdaddr, &bdaddr); + +	if (hci_devinfo(dbus_data->dev_id, &di) < 0) { +		syslog(LOG_ERR, "Can't get device info"); +		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_ENODEV); +	} + +	name = get_peer_name(&di.bdaddr, &bdaddr); +	if (!name) +		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_RECORD_NOT_FOUND); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) { +		reply = error_out_of_memory(msg); +		goto done; +	} + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &name, +					DBUS_TYPE_INVALID); + +done: +	free(name); + +	return reply; +} + +static DBusMessage *handle_dev_get_remote_alias_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessageIter iter; +	DBusMessage *reply; +	char str[249], *str_ptr = str, *addr_ptr; +	bdaddr_t bdaddr; +	int err; + +	dbus_message_iter_init(msg, &iter); +	dbus_message_iter_get_basic(&iter, &addr_ptr); + +	str2ba(addr_ptr, &bdaddr); + +	err = get_device_alias(dbus_data->dev_id, &bdaddr, str, sizeof(str)); +	if (err < 0) +		return error_generic(msg, -err); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_set_remote_alias_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusConnection *connection = get_dbus_connection(); +	DBusMessageIter iter; +	DBusMessage *reply, *signal; +	char *str_ptr, *addr_ptr; +	bdaddr_t bdaddr; +	int err; + +	dbus_message_iter_init(msg, &iter); +	dbus_message_iter_get_basic(&iter, &addr_ptr); +	dbus_message_iter_next(&iter); +	dbus_message_iter_get_basic(&iter, &str_ptr); + +	if (strlen(str_ptr) == 0) { +		syslog(LOG_ERR, "Alias change failed: Invalid parameter"); +		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); +	} + +	str2ba(addr_ptr, &bdaddr); + +	err = set_device_alias(dbus_data->dev_id, &bdaddr, str_ptr); +	if (err < 0) +		return error_generic(msg, -err); + +	signal = dev_signal_factory(dbus_data->dev_id, DEV_SIG_REMOTE_ALIAS_CHANGED, +						DBUS_TYPE_STRING, &addr_ptr, +						DBUS_TYPE_STRING, &str_ptr, +						DBUS_TYPE_INVALID); +	if (signal) { +		dbus_connection_send(connection, signal, NULL); +		dbus_connection_flush(connection); +		dbus_message_unref(signal); +	} + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return error_out_of_memory(msg); + +	return reply; +} + +static DBusMessage *handle_dev_last_seen_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessageIter iter; +	DBusMessage *reply; +	char filename[PATH_MAX + 1]; +	char addr[18], *addr_ptr, *str; + +	get_device_address(dbus_data->dev_id, addr, sizeof(addr)); + +	snprintf(filename, PATH_MAX, "%s/%s/lastseen", STORAGEDIR, addr); + +	dbus_message_iter_init(msg, &iter); +	dbus_message_iter_get_basic(&iter, &addr_ptr); + +	str = textfile_get(filename, addr_ptr); +	if (!str) +		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | ENXIO); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) { +		reply = error_out_of_memory(msg); +		goto done; +	} + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str, +					DBUS_TYPE_INVALID); + +done: +	free(str); + +	return reply; +} + +static DBusMessage *handle_dev_last_used_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessageIter iter; +	DBusMessage *reply; +	char filename[PATH_MAX + 1]; +	char addr[18], *addr_ptr, *str; + +	get_device_address(dbus_data->dev_id, addr, sizeof(addr)); + +	snprintf(filename, PATH_MAX, "%s/%s/lastused", STORAGEDIR, addr); + +	dbus_message_iter_init(msg, &iter); +	dbus_message_iter_get_basic(&iter, &addr_ptr); + +	str = textfile_get(filename, addr_ptr); +	if (!str) +		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | ENXIO); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) { +		reply = error_out_of_memory(msg); +		goto done; +	} + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str, +					DBUS_TYPE_INVALID); + +done: +	free(str); + +	return reply; +} + +static DBusMessage *handle_dev_create_bonding_req(DBusMessage *msg, void *data) +{ +	struct hci_request rq; +	auth_requested_cp cp; +	evt_cmd_status rp; +	DBusMessage *reply; +	char *str_bdaddr; +	struct hci_dbus_data *dbus_data = data; +	struct hci_conn_info_req *cr; +	bdaddr_t bdaddr; +	int dd, dev_id; + +	dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str_bdaddr, +							DBUS_TYPE_INVALID); + +	str2ba(str_bdaddr, &bdaddr); + +	dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + +	if (dev_id < 0) +		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_CONN_NOT_FOUND); + +	if (dbus_data->dev_id != dev_id) +		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_CONN_NOT_FOUND); + +	dd = hci_open_dev(dev_id); +	if (dd < 0) +		return error_no_such_device(msg); + +	cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); +	if (!cr) { +		reply = bluez_new_failure_msg(msg, BLUEZ_EDBUS_NO_MEM); +		goto failed; +	} + +	bacpy(&cr->bdaddr, &bdaddr); +	cr->type = ACL_LINK; + +	if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { +		reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); +		goto done; +	} + +	memset(&cp, 0, sizeof(cp)); +	cp.handle = cr->conn_info->handle; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_LINK_CTL; +	rq.ocf    = OCF_AUTH_REQUESTED; +	rq.cparam = &cp; +	rq.clen   = AUTH_REQUESTED_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = EVT_CMD_STATUS_SIZE; +	rq.event  = EVT_CMD_STATUS; + +	if (hci_send_req(dd, &rq, 100) < 0) { +		syslog(LOG_ERR, "Unable to send authentication request: %s (%d)", +							strerror(errno), errno); +		reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); +		goto done; +	} + +	reply = dbus_message_new_method_return(msg); + +done: +	free(cr); + +failed: +	close(dd); + +	return reply; +} + +static DBusMessage *handle_dev_remove_bonding_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusConnection *connection = get_dbus_connection(); +	DBusMessageIter iter; +	DBusMessage *reply; +	DBusMessage *signal; +	char filename[PATH_MAX + 1]; +	char addr[18], *addr_ptr; +	struct hci_conn_info_req *cr; +	bdaddr_t bdaddr; +	int dd; + +	dd = hci_open_dev(dbus_data->dev_id); +	if (dd < 0) +		return error_no_such_device(msg); + +	get_device_address(dbus_data->dev_id, addr, sizeof(addr)); + +	snprintf(filename, PATH_MAX, "%s/%s/linkkeys", STORAGEDIR, addr); + +	dbus_message_iter_init(msg, &iter); +	dbus_message_iter_get_basic(&iter, &addr_ptr); + +	/* Delete the link key from storage */ +	textfile_del(filename, addr_ptr); + +	str2ba(addr_ptr, &bdaddr); + +	/* Delete the link key from the Bluetooth chip */ +	hci_delete_stored_link_key(dd, &bdaddr, 0, 1000); + +	/* Close active connections for the remote device */ +	cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); +	if (!cr) { +		syslog(LOG_ERR, "Can't allocate memory"); +		hci_close_dev(dd); +		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NO_MEM); +	} + +	bacpy(&cr->bdaddr, &bdaddr); +	cr->type = ACL_LINK; +	if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { +		/* Ignore when there isn't active connections, return success */ +		reply = dbus_message_new_method_return(msg); +		goto failed; +	} + +	/* Send the HCI disconnect command */ +	if (hci_disconnect(dd, htobs(cr->conn_info->handle), HCI_OE_USER_ENDED_CONNECTION, 1000) < 0) { +		syslog(LOG_ERR, "Disconnect failed"); +		reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | errno); +		goto failed; +	} + +	/* FIXME: which condition must be verified before send the signal */ +	signal = dev_signal_factory(dbus_data->dev_id, +					DEV_SIG_BONDING_REMOVED, +					DBUS_TYPE_STRING, &addr_ptr, +					DBUS_TYPE_INVALID); +	if (signal) { +		dbus_connection_send(connection, signal, NULL); +		dbus_connection_flush(connection); +		dbus_message_unref(signal); +	} + +	reply = dbus_message_new_method_return(msg); + +failed: +	free(cr); + +	close(dd); + +	return reply; +} + +static DBusMessage *handle_dev_has_bonding_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessageIter iter; +	DBusMessage *reply; +	char filename[PATH_MAX + 1]; +	char addr[18], *addr_ptr, *str; +	dbus_bool_t result; + +	get_device_address(dbus_data->dev_id, addr, sizeof(addr)); + +	snprintf(filename, PATH_MAX, "%s/%s/linkkeys", STORAGEDIR, addr); + +	dbus_message_iter_init(msg, &iter); +	dbus_message_iter_get_basic(&iter, &addr_ptr); + +	str = textfile_get(filename, addr_ptr); +	if (str) { +		result = TRUE; +		free(str); +	} else +		result = FALSE; + +	reply = dbus_message_new_method_return(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &result, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_list_bondings_req(DBusMessage *msg, void *data) +{ +	void do_append(char *key, char *value, void *data) +	{ +		DBusMessageIter *iter = data; + +		dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key); +	} + +	struct hci_dbus_data *dbus_data = data; +	DBusMessageIter iter; +	DBusMessageIter array_iter; +	DBusMessage *reply; +	char filename[PATH_MAX + 1]; +	char addr[18]; + +	get_device_address(dbus_data->dev_id, addr, sizeof(addr)); + +	snprintf(filename, PATH_MAX, "%s/%s/linkkeys", STORAGEDIR, addr); + +	reply = dbus_message_new_method_return(msg); + +	dbus_message_iter_init_append(reply, &iter); + +	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, +				DBUS_TYPE_STRING_AS_STRING, &array_iter); + +	textfile_foreach(filename, do_append, &array_iter); + +	dbus_message_iter_close_container(&iter, &array_iter); + +	return reply; +} + +static DBusMessage *handle_dev_pin_code_length_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessageIter iter; +	DBusMessage *reply; +	bdaddr_t local, peer; +	char addr[18], *addr_ptr; +	uint8_t length; +	int len; + +	get_device_address(dbus_data->dev_id, addr, sizeof(addr)); + +	str2ba(addr, &local); + +	dbus_message_iter_init(msg, &iter); +	dbus_message_iter_get_basic(&iter, &addr_ptr); + +	str2ba(addr_ptr, &peer); + +	len = read_pin_length(&local, &peer); +	if (len < 0) +		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | -len); + +	reply = dbus_message_new_method_return(msg); + +	length = len; + +	dbus_message_append_args(reply, DBUS_TYPE_BYTE, &length, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_encryption_key_size_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessageIter iter; +	DBusMessage *reply; +	bdaddr_t bdaddr; +	char *addr_ptr; +	uint8_t size; +	int val; + +	dbus_message_iter_init(msg, &iter); +	dbus_message_iter_get_basic(&iter, &addr_ptr); + +	str2ba(addr_ptr, &bdaddr); + +	val = get_encryption_key_size(dbus_data->dev_id, &bdaddr); +	if (val < 0) +		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | -val); + +	reply = dbus_message_new_method_return(msg); + +	size = val; + +	dbus_message_append_args(reply, DBUS_TYPE_BYTE, &size, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage *handle_dev_discover_req(DBusMessage *msg, void *data) +{ +	DBusMessage *reply = NULL; +	inquiry_cp cp; +	evt_cmd_status rp; +	struct hci_request rq; +	struct hci_dbus_data *dbus_data = data; +	uint8_t length = 8, num_rsp = 0; +	uint32_t lap = 0x9e8b33; +	int dd; + +	dd = hci_open_dev(dbus_data->dev_id); +	if (dd < 0) +		return error_no_such_device(msg); + +	memset(&cp, 0, sizeof(cp)); +	cp.lap[0]  = lap & 0xff; +	cp.lap[1]  = (lap >> 8) & 0xff; +	cp.lap[2]  = (lap >> 16) & 0xff; +	cp.length  = length; +	cp.num_rsp = num_rsp; + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_LINK_CTL; +	rq.ocf    = OCF_INQUIRY; +	rq.cparam = &cp; +	rq.clen   = INQUIRY_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = EVT_CMD_STATUS_SIZE; +	rq.event  = EVT_CMD_STATUS; + +	if (hci_send_req(dd, &rq, 100) < 0) { +		syslog(LOG_ERR, "Unable to start inquiry: %s (%d)", +							strerror(errno), errno); +		reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); +		goto failed; +	} + +	reply = dbus_message_new_method_return(msg); + +failed: +	hci_close_dev(dd); + +	return reply; +} + +static DBusMessage *handle_dev_discover_cancel_req(DBusMessage *msg, void *data) +{ +	DBusMessage *reply = NULL; +	struct hci_request rq; +	struct hci_dbus_data *dbus_data = data; +	uint8_t status; +	int dd; + +	dd = hci_open_dev(dbus_data->dev_id); +	if (dd < 0) +		return error_no_such_device(msg); + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_LINK_CTL; +	rq.ocf    = OCF_INQUIRY_CANCEL; +	rq.rparam = &status; +	rq.rlen   = sizeof(status); + +	if (hci_send_req(dd, &rq, 100) < 0) { +		syslog(LOG_ERR, "Sending cancel inquiry failed: %s (%d)", +							strerror(errno), errno); +		reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); +		goto failed; +	} + +	if (status) { +		syslog(LOG_ERR, "Cancel inquiry failed with status 0x%02x", status); +		reply = bluez_new_failure_msg(msg, BLUEZ_EBT_OFFSET + status); +		goto failed; +	} + +	reply = dbus_message_new_method_return(msg); + +failed: +	hci_close_dev(dd); + +	return reply; +} + +static DBusMessage *handle_dev_discover_cache_req(DBusMessage *msg, void *data) +{ +	/*FIXME: */ +	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage *handle_dev_discover_service_req(DBusMessage *msg, void *data) +{ +	/*FIXME: */ +	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static const struct service_data dev_services[] = { +	{ DEV_GET_ADDRESS,		handle_dev_get_address_req,		DEV_GET_ADDRESS_SIGNATURE		}, +	{ DEV_GET_VERSION,		handle_dev_get_version_req,		DEV_GET_VERSION_SIGNATURE		}, +	{ DEV_GET_REVISION,		handle_dev_get_revision_req,		DEV_GET_REVISION_SIGNATURE		}, +	{ DEV_GET_MANUFACTURER,		handle_dev_get_manufacturer_req,	DEV_GET_MANUFACTURER_SIGNATURE		}, +	{ DEV_GET_COMPANY,		handle_dev_get_company_req,		DEV_GET_COMPANY_SIGNATURE		}, +	{ DEV_GET_FEATURES,		handle_dev_get_features_req,		DEV_GET_FEATURES_SIGNATURE		}, +	{ DEV_GET_MODE,			handle_dev_get_mode_req,		DEV_GET_MODE_SIGNATURE			}, +	{ DEV_SET_MODE,			handle_dev_set_mode_req,		DEV_SET_MODE_SIGNATURE			}, +	{ DEV_GET_DISCOVERABLE_TO,	handle_dev_get_discoverable_to_req,	DEV_GET_DISCOVERABLE_TO_SIGNATURE	}, +	{ DEV_SET_DISCOVERABLE_TO,	handle_dev_set_discoverable_to_req,	DEV_SET_DISCOVERABLE_TO_SIGNATURE	}, +	{ DEV_IS_CONNECTABLE,		handle_dev_is_connectable_req,		DEV_IS_CONNECTABLE_SIGNATURE		}, +	{ DEV_IS_DISCOVERABLE,		handle_dev_is_discoverable_req,		DEV_IS_DISCOVERABLE_SIGNATURE		}, +	{ DEV_GET_MAJOR_CLASS,		handle_dev_get_major_class_req,		DEV_GET_MAJOR_CLASS_SIGNATURE		}, +	{ DEV_GET_MINOR_CLASS,		handle_dev_get_minor_class_req,		DEV_GET_MINOR_CLASS_SIGNATURE		}, +	{ DEV_SET_MINOR_CLASS,		handle_dev_set_minor_class_req,		DEV_SET_MINOR_CLASS_SIGNATURE		}, +	{ DEV_GET_SERVICE_CLASSES,	handle_dev_get_service_classes_req,	DEV_GET_SERVICE_CLASSES_SIGNATURE	}, +	{ DEV_GET_NAME,			handle_dev_get_name_req,		DEV_GET_NAME_SIGNATURE			}, +	{ DEV_SET_NAME,			handle_dev_set_name_req,		DEV_SET_NAME_SIGNATURE			}, + +	{ DEV_GET_REMOTE_VERSION,	handle_dev_get_remote_version_req,	DEV_GET_REMOTE_VERSION_SIGNATURE	}, +	{ DEV_GET_REMOTE_REVISION,	handle_dev_get_remote_revision_req,	DEV_GET_REMOTE_REVISION_SIGNATURE	}, +	{ DEV_GET_REMOTE_MANUFACTURER,	handle_dev_get_remote_manufacturer_req,	DEV_GET_REMOTE_MANUFACTURER_SIGNATURE	}, +	{ DEV_GET_REMOTE_COMPANY,	handle_dev_get_remote_company_req,	DEV_GET_REMOTE_COMPANY_SIGNATURE	}, +	{ DEV_GET_REMOTE_NAME,		handle_dev_get_remote_name_req,		DEV_GET_REMOTE_NAME_SIGNATURE		}, +	{ DEV_GET_REMOTE_ALIAS,		handle_dev_get_remote_alias_req,	DEV_GET_REMOTE_ALIAS_SIGNATURE		}, +	{ DEV_SET_REMOTE_ALIAS,		handle_dev_set_remote_alias_req,	DEV_SET_REMOTE_ALIAS_SIGNATURE		}, + +	{ DEV_LAST_SEEN,		handle_dev_last_seen_req,		DEV_LAST_SEEN_SIGNATURE			}, +	{ DEV_LAST_USED,		handle_dev_last_used_req,		DEV_LAST_USED_SIGNATURE			}, + +	{ DEV_CREATE_BONDING,		handle_dev_create_bonding_req,		DEV_CREATE_BONDING_SIGNATURE		}, +	{ DEV_REMOVE_BONDING,		handle_dev_remove_bonding_req,		DEV_REMOVE_BONDING_SIGNATURE		}, +	{ DEV_HAS_BONDING_NAME,		handle_dev_has_bonding_req,		DEV_HAS_BONDING_SIGNATURE		}, +	{ DEV_LIST_BONDINGS,		handle_dev_list_bondings_req,		DEV_LIST_BONDINGS_SIGNATURE		}, +	{ DEV_PIN_CODE_LENGTH,		handle_dev_pin_code_length_req,		DEV_PIN_CODE_LENGTH_SIGNATURE		}, +	{ DEV_ENCRYPTION_KEY_SIZE,	handle_dev_encryption_key_size_req,	DEV_ENCRYPTION_KEY_SIZE_SIGNATURE	}, + +	{ DEV_DISCOVER,			handle_dev_discover_req,		DEV_DISCOVER_SIGNATURE			}, +	{ DEV_DISCOVER_CANCEL,		handle_dev_discover_cancel_req,		DEV_DISCOVER_CANCEL_SIGNATURE		}, +	{ DEV_DISCOVER_CACHE,		handle_dev_discover_cache_req,		DEV_DISCOVER_CACHE_SIGNATURE		}, +	{ DEV_DISCOVER_SERVICE,		handle_dev_discover_service_req,	DEV_DISCOVER_SERVICE_SIGNATURE		}, + +	{ NULL, NULL, NULL} +}; + +DBusHandlerResult msg_func_device(DBusConnection *conn, DBusMessage *msg, void *data) +{ +	const struct service_data *handlers = dev_services; +	DBusMessage *reply = NULL; +	struct hci_dbus_data *dbus_data = data; +	const char *method; +	const char *signature; +	const char *iface; +	uint32_t error = BLUEZ_EDBUS_UNKNOWN_METHOD; + +	method = dbus_message_get_member(msg); +	signature = dbus_message_get_signature(msg); +	iface = dbus_message_get_interface(msg); + +	syslog(LOG_INFO, "Adapter path:%s method:%s", +					dbus_message_get_path(msg), method); + +	if (strcmp(ADAPTER_INTERFACE, iface)) +		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + +	if (dbus_data->path_id == ADAPTER_ROOT_ID) { +		/* Adapter is down(path unregistered) or the path is wrong */ +		error = BLUEZ_EDBUS_UNKNOWN_PATH; +		goto failed; +	} + +	/* It's a device path id */ +	for (; handlers->name != NULL; handlers++) { +		if (strcmp(handlers->name, method)) +			continue; + +		if (!strcmp(handlers->signature, signature)) { +			reply = handlers->handler_func(msg, data); +			error = 0; +			break; +		} else { +			/* Set the error, but continue looping incase there is +			 * another method with the same name but a different +			 * signature */ +			error = BLUEZ_EDBUS_WRONG_SIGNATURE; +			continue; +		} +	} + +failed: +	if (error) +		reply = bluez_new_failure_msg(msg, error); + +	if (reply) { +		if (!dbus_connection_send (conn, reply, NULL)) +			syslog(LOG_ERR, "Can't send reply message"); + +		dbus_message_unref(reply); +	} + +	return DBUS_HANDLER_RESULT_HANDLED; +} diff --git a/hcid/dbus-device.c b/hcid/dbus-device.c index 050aab69..f3bf47c4 100644 --- a/hcid/dbus-device.c +++ b/hcid/dbus-device.c @@ -27,1316 +27,3 @@  #include <stdio.h>  #include <errno.h> -#include <unistd.h> -#include <sys/socket.h> - -#include <bluetooth/bluetooth.h> -#include <bluetooth/hci.h> -#include <bluetooth/hci_lib.h> - -#include <dbus/dbus.h> - -#include "hcid.h" -#include "dbus.h" - -#include "textfile.h" -#include "oui.h" - -static const char *service_cls[] = { -	"positioning", -	"networking", -	"rendering", -	"capturing", -	"object transfer", -	"audio", -	"telephony", -	"information" -}; - -static const char *computer_minor_cls[] = { -	"uncategorized", -	"desktop", -	"server", -	"laptop", -	"handheld", -	"palm", -	"wearable" -}; - -static char *get_peer_name(const bdaddr_t *local, const bdaddr_t *peer) -{ -	char filename[PATH_MAX + 1], addr[18]; - -	ba2str(local, addr); -	snprintf(filename, PATH_MAX, "%s/%s/names", STORAGEDIR, addr); - -	ba2str(peer, addr); -	return textfile_get(filename, addr); -} - -static DBusMessage *handle_dev_get_address_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply; -	char str[18], *str_ptr = str; -	int err; - -	err = get_device_address(dbus_data->dev_id, str, sizeof(str)); -	if (err < 0) -		return error_generic(msg, -err); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_get_version_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply; -	char str[20], *str_ptr = str; -	int err; - -	err = get_device_version(dbus_data->dev_id, str, sizeof(str)); -	if (err < 0) -		return error_generic(msg, -err); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_get_revision_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply; -	char str[64], *str_ptr = str; -	int err; - -	err = get_device_revision(dbus_data->dev_id, str, sizeof(str)); -	if (err < 0) -		return error_generic(msg, -err); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_get_manufacturer_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply; -	char str[64], *str_ptr = str; -	int err; - -	err = get_device_manufacturer(dbus_data->dev_id, str, sizeof(str)); -	if (err < 0) -		return error_generic(msg, -err); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_get_company_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply; -	char str[64], *str_ptr = str; -	int err; - -	err = get_device_company(dbus_data->dev_id, str, sizeof(str)); -	if (err < 0) -		return error_generic(msg, -err); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_get_features_req(DBusMessage *msg, void *data) -{ -	DBusMessage *reply; -	DBusMessageIter iter; -	DBusMessageIter array_iter; - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	dbus_message_iter_init_append(reply, &iter); - -	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, -				DBUS_TYPE_STRING_AS_STRING, &array_iter); - -	dbus_message_iter_close_container(&iter, &array_iter); - -	return reply; -} - -static DBusMessage *handle_dev_get_mode_req(DBusMessage *msg, void *data) -{ -	const struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply = NULL; -	const uint8_t hci_mode = dbus_data->mode; -	const char *scan_mode; - -	switch (hci_mode) { -	case SCAN_DISABLED: -		scan_mode = MODE_OFF; -		break; -	case SCAN_PAGE: -		scan_mode = MODE_CONNECTABLE; -		break; -	case (SCAN_PAGE | SCAN_INQUIRY): -		scan_mode = MODE_DISCOVERABLE; -		break; -	case SCAN_INQUIRY: -	/* inquiry scan mode is not handled, return unknown */ -	default: -		/* reserved */ -		scan_mode = MODE_UNKNOWN; -	} - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &scan_mode, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_set_mode_req(DBusMessage *msg, void *data) -{ -	const struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply; -	const char* scan_mode; -	uint8_t hci_mode; -	const uint8_t current_mode = dbus_data->mode; -	int dd; - -	dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &scan_mode, -							DBUS_TYPE_INVALID); - -	if (!scan_mode) -		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); - -	if (strcasecmp(MODE_OFF, scan_mode) == 0) -		hci_mode = SCAN_DISABLED; -	else if (strcasecmp(MODE_CONNECTABLE, scan_mode) == 0) -		hci_mode = SCAN_PAGE; -	else if (strcasecmp(MODE_DISCOVERABLE, scan_mode) == 0) -		hci_mode = (SCAN_PAGE | SCAN_INQUIRY); -	else -		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); - -	dd = hci_open_dev(dbus_data->dev_id); -	if (dd < 0) -		return error_no_such_device(msg); - -	/* Check if the new requested mode is different from the current */ -	if (current_mode != hci_mode) { -		struct hci_request rq; -		uint8_t status = 0; - -		memset(&rq, 0, sizeof(rq)); -		rq.ogf    = OGF_HOST_CTL; -		rq.ocf    = OCF_WRITE_SCAN_ENABLE; -		rq.cparam = &hci_mode; -		rq.clen   = sizeof(hci_mode); -		rq.rparam = &status; -		rq.rlen   = sizeof(status); - -		if (hci_send_req(dd, &rq, 100) < 0) { -			syslog(LOG_ERR, "Sending write scan enable command failed: %s (%d)", -							strerror(errno), errno); -			hci_close_dev(dd); -			return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | errno); -		} - -		if (status) { -			syslog(LOG_ERR, "Setting scan enable failed with status 0x%02x", status); -			hci_close_dev(dd); -			return bluez_new_failure_msg(msg, BLUEZ_EBT_OFFSET | status); -		} -	} - -	hci_close_dev(dd); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	return reply; -} - -static DBusMessage *handle_dev_get_discoverable_to_req(DBusMessage *msg, void *data) -{ -	const struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply; - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	dbus_message_append_args(reply, DBUS_TYPE_UINT32, &dbus_data->discoverable_timeout, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_set_discoverable_to_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply; -	DBusMessageIter iter; -	uint32_t timeout; - -	dbus_message_iter_init(msg, &iter); -	dbus_message_iter_get_basic(&iter, &timeout); - -	dbus_data->discoverable_timeout = timeout; - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	return reply; -} - -static DBusMessage *handle_dev_is_connectable_req(DBusMessage *msg, void *data) -{ -	const struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply; -	const uint8_t hci_mode = dbus_data->mode; -	dbus_bool_t connectable = FALSE; - -	if (hci_mode & SCAN_PAGE) -		connectable = TRUE; - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connectable, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_is_discoverable_req(DBusMessage *msg, void *data) -{ -	const struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply; -	const uint8_t hci_mode = dbus_data->mode; -	dbus_bool_t discoverable = FALSE; - -	if (hci_mode & SCAN_INQUIRY) -		discoverable = TRUE; - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &discoverable, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_get_major_class_req(DBusMessage *msg, void *data) -{ -	DBusMessage *reply; -	const char *str_ptr = "computer"; - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	/*FIXME: Check the real device major class */ -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_get_minor_class_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply; -	const char *str_ptr = ""; -	uint8_t cls[3]; -	uint8_t minor_class; -	int dd; - -	dd = hci_open_dev(dbus_data->dev_id); -	if (dd < 0) -		return error_no_such_device(msg); - -	if (hci_read_class_of_dev(dd, cls, 1000) < 0) { -		syslog(LOG_ERR, "Can't read class of device on hci%d: %s(%d)", -				dbus_data->dev_id, strerror(errno), errno); -		hci_close_dev(dd); -		return error_generic(msg, -errno); -	} - -	hci_close_dev(dd); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	/* FIXME: Currently, only computer major class is supported */ -	if ((cls[1] & 0x1f) != 1) -		goto failed; - -	minor_class = cls[0] >> 2; - -	/* Validate computer minor class */ -	if (minor_class > (sizeof(computer_minor_cls) / sizeof(*computer_minor_cls))) -		goto failed; - -	str_ptr = computer_minor_cls[minor_class]; - -failed: -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_set_minor_class_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusConnection *connection = get_dbus_connection(); -	DBusMessageIter iter; -	DBusMessage *reply, *signal; -	bdaddr_t bdaddr; -	const char *minor; -	uint8_t cls[3]; -	uint32_t dev_class = 0xFFFFFFFF; -	int i, dd; - -	dbus_message_iter_init(msg, &iter); -	dbus_message_iter_get_basic(&iter, &minor); - -	if (!minor) -		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); - -	/* FIXME: currently, only computer minor classes are allowed */ -	for (i = 0; i < sizeof(computer_minor_cls) / sizeof(*computer_minor_cls); i++) -		if (!strcasecmp(minor, computer_minor_cls[i])) { -			/* Remove the format type */ -			dev_class = i << 2; -			break; -		} - -	/* Check if it's a valid minor class */ -	if (dev_class == 0xFFFFFFFF) -		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); - -	dd = hci_open_dev(dbus_data->dev_id); -	if (dd < 0) { -		syslog(LOG_ERR, "HCI device open failed: hci%d", dbus_data->dev_id); -		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_ENODEV); -	} - -	if (hci_read_class_of_dev(dd, cls, 1000) < 0) { -		syslog(LOG_ERR, "Can't read class of device on hci%d: %s(%d)", -				dbus_data->dev_id, strerror(errno), errno); -		reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | errno); -		goto failed; -	} - -	dev_class |= (cls[2] << 16) | (cls[1] << 8); - -	cls[2] = 0x00;	/* no service classes */ -	cls[1] = 0x01;	/* major class computer */ -	cls[0] = (dev_class & 0xff); - -	hci_devba(dbus_data->dev_id, &bdaddr); - -	write_local_class(&bdaddr, cls); - -	if (hci_write_class_of_dev(dd, dev_class, 2000) < 0) { -		syslog(LOG_ERR, "Can't write class of device on hci%d: %s(%d)", -				dbus_data->dev_id, strerror(errno), errno); -		reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | errno); -		goto failed; -	} - -	signal = dev_signal_factory(dbus_data->dev_id, DEV_SIG_MINOR_CLASS_CHANGED, -						DBUS_TYPE_STRING, &minor, -						DBUS_TYPE_INVALID); -	if (signal) { -		dbus_connection_send(connection, signal, NULL); -		dbus_connection_flush(connection); -		dbus_message_unref(signal); -	} - -	reply = dbus_message_new_method_return(msg); - -failed: -	hci_close_dev(dd); - -	return reply; -} - -static DBusMessage *handle_dev_get_service_classes_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply; -	DBusMessageIter iter; -	DBusMessageIter array_iter; -	const char *str_ptr; -	uint8_t cls[3]; -	int dd, i; - -	dd = hci_open_dev(dbus_data->dev_id); -	if (dd < 0) { -		syslog(LOG_ERR, "HCI device open failed: hci%d", dbus_data->dev_id); -		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_ENODEV); -	} - -	if (hci_read_class_of_dev(dd, cls, 1000) < 0) { -		syslog(LOG_ERR, "Can't read class of device on hci%d: %s(%d)", -				dbus_data->dev_id, strerror(errno), errno); -		hci_close_dev(dd); -		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | errno); -	} - -	reply = dbus_message_new_method_return(msg); - -	dbus_message_iter_init_append(reply, &iter); - -	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, -				DBUS_TYPE_STRING_AS_STRING, &array_iter); - -	for (i = 0; i < (sizeof(service_cls) / sizeof(*service_cls)); i++) { -		if (cls[2] & (1 << i)) { -			str_ptr = service_cls[i]; -			dbus_message_iter_append_basic(&array_iter, -						DBUS_TYPE_STRING, &str_ptr); -		} -	} - -	dbus_message_iter_close_container(&iter, &array_iter); - -	hci_close_dev(dd); - -	return reply; -} - -static DBusMessage *handle_dev_get_name_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply; -	char str[249], *str_ptr = str; -	int err; - -	err = get_device_name(dbus_data->dev_id, str, sizeof(str)); -	if (err < 0) -		return error_generic(msg, -err); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_set_name_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessageIter iter; -	DBusMessage *reply; -	bdaddr_t bdaddr; -	char *str_ptr; -	int err; - -	dbus_message_iter_init(msg, &iter); -	dbus_message_iter_get_basic(&iter, &str_ptr); - -	if (strlen(str_ptr) == 0) { -		syslog(LOG_ERR, "Name change failed: Invalid parameter"); -		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); -	} - -	hci_devba(dbus_data->dev_id, &bdaddr); - -	write_local_name(&bdaddr, str_ptr); - -	err = set_device_name(dbus_data->dev_id, str_ptr); -	if (err < 0) -		return error_generic(msg, -err); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	return reply; -} - -static DBusMessage *handle_dev_get_remote_version_req(DBusMessage *msg, void *data) -{ -	/*FIXME: */ -	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); -} - -static DBusMessage *handle_dev_get_remote_revision_req(DBusMessage *msg, void *data) -{ -	/*FIXME: */ -	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); -} - -static DBusMessage *handle_dev_get_remote_manufacturer_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessageIter iter; -	DBusMessage *reply; -	char filename[PATH_MAX + 1]; -	char addr[18], *addr_ptr, *str; -	int compid; - -	get_device_address(dbus_data->dev_id, addr, sizeof(addr)); - -	snprintf(filename, PATH_MAX, "%s/%s/manufacturers", STORAGEDIR, addr); - -	dbus_message_iter_init(msg, &iter); -	dbus_message_iter_get_basic(&iter, &addr_ptr); - -	str = textfile_get(filename, addr_ptr); -	if (!str) -		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | ENXIO); - -	compid = atoi(str); - -	free(str); - -	str = bt_compidtostr(compid); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_get_remote_company_req(DBusMessage *msg, void *data) -{ -	DBusMessage *reply; -	bdaddr_t bdaddr; -	char oui[9], *str_bdaddr, *tmp; - -	dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str_bdaddr, -							DBUS_TYPE_INVALID); - - -	str2ba(str_bdaddr, &bdaddr); -	ba2oui(&bdaddr, oui); - -	tmp = ouitocomp(oui); -	if (!tmp) -		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_RECORD_NOT_FOUND); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) { -		reply = error_out_of_memory(msg); -		goto done; -	} - -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &tmp, -					DBUS_TYPE_INVALID); - -done: -	free(tmp); - -	return reply; -} - -static DBusMessage *handle_dev_get_remote_name_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessage *reply = NULL; -	const char *str_bdaddr; -	char *name; -	bdaddr_t bdaddr; -	struct hci_dev_info di; - -	dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str_bdaddr, -							DBUS_TYPE_INVALID); - -	str2ba(str_bdaddr, &bdaddr); - -	if (hci_devinfo(dbus_data->dev_id, &di) < 0) { -		syslog(LOG_ERR, "Can't get device info"); -		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_ENODEV); -	} - -	name = get_peer_name(&di.bdaddr, &bdaddr); -	if (!name) -		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_RECORD_NOT_FOUND); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) { -		reply = error_out_of_memory(msg); -		goto done; -	} - -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &name, -					DBUS_TYPE_INVALID); - -done: -	free(name); - -	return reply; -} - -static DBusMessage *handle_dev_get_remote_alias_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessageIter iter; -	DBusMessage *reply; -	char str[249], *str_ptr = str, *addr_ptr; -	bdaddr_t bdaddr; -	int err; - -	dbus_message_iter_init(msg, &iter); -	dbus_message_iter_get_basic(&iter, &addr_ptr); - -	str2ba(addr_ptr, &bdaddr); - -	err = get_device_alias(dbus_data->dev_id, &bdaddr, str, sizeof(str)); -	if (err < 0) -		return error_generic(msg, -err); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_set_remote_alias_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusConnection *connection = get_dbus_connection(); -	DBusMessageIter iter; -	DBusMessage *reply, *signal; -	char *str_ptr, *addr_ptr; -	bdaddr_t bdaddr; -	int err; - -	dbus_message_iter_init(msg, &iter); -	dbus_message_iter_get_basic(&iter, &addr_ptr); -	dbus_message_iter_next(&iter); -	dbus_message_iter_get_basic(&iter, &str_ptr); - -	if (strlen(str_ptr) == 0) { -		syslog(LOG_ERR, "Alias change failed: Invalid parameter"); -		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); -	} - -	str2ba(addr_ptr, &bdaddr); - -	err = set_device_alias(dbus_data->dev_id, &bdaddr, str_ptr); -	if (err < 0) -		return error_generic(msg, -err); - -	signal = dev_signal_factory(dbus_data->dev_id, DEV_SIG_REMOTE_ALIAS_CHANGED, -						DBUS_TYPE_STRING, &addr_ptr, -						DBUS_TYPE_STRING, &str_ptr, -						DBUS_TYPE_INVALID); -	if (signal) { -		dbus_connection_send(connection, signal, NULL); -		dbus_connection_flush(connection); -		dbus_message_unref(signal); -	} - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return error_out_of_memory(msg); - -	return reply; -} - -static DBusMessage *handle_dev_last_seen_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessageIter iter; -	DBusMessage *reply; -	char filename[PATH_MAX + 1]; -	char addr[18], *addr_ptr, *str; - -	get_device_address(dbus_data->dev_id, addr, sizeof(addr)); - -	snprintf(filename, PATH_MAX, "%s/%s/lastseen", STORAGEDIR, addr); - -	dbus_message_iter_init(msg, &iter); -	dbus_message_iter_get_basic(&iter, &addr_ptr); - -	str = textfile_get(filename, addr_ptr); -	if (!str) -		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | ENXIO); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) { -		reply = error_out_of_memory(msg); -		goto done; -	} - -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str, -					DBUS_TYPE_INVALID); - -done: -	free(str); - -	return reply; -} - -static DBusMessage *handle_dev_last_used_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessageIter iter; -	DBusMessage *reply; -	char filename[PATH_MAX + 1]; -	char addr[18], *addr_ptr, *str; - -	get_device_address(dbus_data->dev_id, addr, sizeof(addr)); - -	snprintf(filename, PATH_MAX, "%s/%s/lastused", STORAGEDIR, addr); - -	dbus_message_iter_init(msg, &iter); -	dbus_message_iter_get_basic(&iter, &addr_ptr); - -	str = textfile_get(filename, addr_ptr); -	if (!str) -		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | ENXIO); - -	reply = dbus_message_new_method_return(msg); -	if (!reply) { -		reply = error_out_of_memory(msg); -		goto done; -	} - -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str, -					DBUS_TYPE_INVALID); - -done: -	free(str); - -	return reply; -} - -static DBusMessage *handle_dev_create_bonding_req(DBusMessage *msg, void *data) -{ -	struct hci_request rq; -	auth_requested_cp cp; -	evt_cmd_status rp; -	DBusMessage *reply; -	char *str_bdaddr; -	struct hci_dbus_data *dbus_data = data; -	struct hci_conn_info_req *cr; -	bdaddr_t bdaddr; -	int dd, dev_id; - -	dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str_bdaddr, -							DBUS_TYPE_INVALID); - -	str2ba(str_bdaddr, &bdaddr); - -	dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); - -	if (dev_id < 0) -		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_CONN_NOT_FOUND); - -	if (dbus_data->dev_id != dev_id) -		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_CONN_NOT_FOUND); - -	dd = hci_open_dev(dev_id); -	if (dd < 0) -		return error_no_such_device(msg); - -	cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); -	if (!cr) { -		reply = bluez_new_failure_msg(msg, BLUEZ_EDBUS_NO_MEM); -		goto failed; -	} - -	bacpy(&cr->bdaddr, &bdaddr); -	cr->type = ACL_LINK; - -	if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { -		reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); -		goto done; -	} - -	memset(&cp, 0, sizeof(cp)); -	cp.handle = cr->conn_info->handle; - -	memset(&rq, 0, sizeof(rq)); -	rq.ogf    = OGF_LINK_CTL; -	rq.ocf    = OCF_AUTH_REQUESTED; -	rq.cparam = &cp; -	rq.clen   = AUTH_REQUESTED_CP_SIZE; -	rq.rparam = &rp; -	rq.rlen   = EVT_CMD_STATUS_SIZE; -	rq.event  = EVT_CMD_STATUS; - -	if (hci_send_req(dd, &rq, 100) < 0) { -		syslog(LOG_ERR, "Unable to send authentication request: %s (%d)", -							strerror(errno), errno); -		reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); -		goto done; -	} - -	reply = dbus_message_new_method_return(msg); - -done: -	free(cr); - -failed: -	close(dd); - -	return reply; -} - -static DBusMessage *handle_dev_remove_bonding_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusConnection *connection = get_dbus_connection(); -	DBusMessageIter iter; -	DBusMessage *reply; -	DBusMessage *signal; -	char filename[PATH_MAX + 1]; -	char addr[18], *addr_ptr; -	struct hci_conn_info_req *cr; -	bdaddr_t bdaddr; -	int dd; - -	dd = hci_open_dev(dbus_data->dev_id); -	if (dd < 0) -		return error_no_such_device(msg); - -	get_device_address(dbus_data->dev_id, addr, sizeof(addr)); - -	snprintf(filename, PATH_MAX, "%s/%s/linkkeys", STORAGEDIR, addr); - -	dbus_message_iter_init(msg, &iter); -	dbus_message_iter_get_basic(&iter, &addr_ptr); - -	/* Delete the link key from storage */ -	textfile_del(filename, addr_ptr); - -	str2ba(addr_ptr, &bdaddr); - -	/* Delete the link key from the Bluetooth chip */ -	hci_delete_stored_link_key(dd, &bdaddr, 0, 1000); - -	/* Close active connections for the remote device */ -	cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); -	if (!cr) { -		syslog(LOG_ERR, "Can't allocate memory"); -		hci_close_dev(dd); -		return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NO_MEM); -	} - -	bacpy(&cr->bdaddr, &bdaddr); -	cr->type = ACL_LINK; -	if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { -		/* Ignore when there isn't active connections, return success */ -		reply = dbus_message_new_method_return(msg); -		goto failed; -	} - -	/* Send the HCI disconnect command */ -	if (hci_disconnect(dd, htobs(cr->conn_info->handle), HCI_OE_USER_ENDED_CONNECTION, 1000) < 0) { -		syslog(LOG_ERR, "Disconnect failed"); -		reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | errno); -		goto failed; -	} - -	/* FIXME: which condition must be verified before send the signal */ -	signal = dev_signal_factory(dbus_data->dev_id, -					DEV_SIG_BONDING_REMOVED, -					DBUS_TYPE_STRING, &addr_ptr, -					DBUS_TYPE_INVALID); -	if (signal) { -		dbus_connection_send(connection, signal, NULL); -		dbus_connection_flush(connection); -		dbus_message_unref(signal); -	} - -	reply = dbus_message_new_method_return(msg); - -failed: -	free(cr); - -	close(dd); - -	return reply; -} - -static DBusMessage *handle_dev_has_bonding_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessageIter iter; -	DBusMessage *reply; -	char filename[PATH_MAX + 1]; -	char addr[18], *addr_ptr, *str; -	dbus_bool_t result; - -	get_device_address(dbus_data->dev_id, addr, sizeof(addr)); - -	snprintf(filename, PATH_MAX, "%s/%s/linkkeys", STORAGEDIR, addr); - -	dbus_message_iter_init(msg, &iter); -	dbus_message_iter_get_basic(&iter, &addr_ptr); - -	str = textfile_get(filename, addr_ptr); -	if (str) { -		result = TRUE; -		free(str); -	} else -		result = FALSE; - -	reply = dbus_message_new_method_return(msg); - -	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &result, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_list_bondings_req(DBusMessage *msg, void *data) -{ -	void do_append(char *key, char *value, void *data) -	{ -		DBusMessageIter *iter = data; - -		dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key); -	} - -	struct hci_dbus_data *dbus_data = data; -	DBusMessageIter iter; -	DBusMessageIter array_iter; -	DBusMessage *reply; -	char filename[PATH_MAX + 1]; -	char addr[18]; - -	get_device_address(dbus_data->dev_id, addr, sizeof(addr)); - -	snprintf(filename, PATH_MAX, "%s/%s/linkkeys", STORAGEDIR, addr); - -	reply = dbus_message_new_method_return(msg); - -	dbus_message_iter_init_append(reply, &iter); - -	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, -				DBUS_TYPE_STRING_AS_STRING, &array_iter); - -	textfile_foreach(filename, do_append, &array_iter); - -	dbus_message_iter_close_container(&iter, &array_iter); - -	return reply; -} - -static DBusMessage *handle_dev_pin_code_length_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessageIter iter; -	DBusMessage *reply; -	bdaddr_t local, peer; -	char addr[18], *addr_ptr; -	uint8_t length; -	int len; - -	get_device_address(dbus_data->dev_id, addr, sizeof(addr)); - -	str2ba(addr, &local); - -	dbus_message_iter_init(msg, &iter); -	dbus_message_iter_get_basic(&iter, &addr_ptr); - -	str2ba(addr_ptr, &peer); - -	len = read_pin_length(&local, &peer); -	if (len < 0) -		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | -len); - -	reply = dbus_message_new_method_return(msg); - -	length = len; - -	dbus_message_append_args(reply, DBUS_TYPE_BYTE, &length, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_encryption_key_size_req(DBusMessage *msg, void *data) -{ -	struct hci_dbus_data *dbus_data = data; -	DBusMessageIter iter; -	DBusMessage *reply; -	bdaddr_t bdaddr; -	char *addr_ptr; -	uint8_t size; -	int val; - -	dbus_message_iter_init(msg, &iter); -	dbus_message_iter_get_basic(&iter, &addr_ptr); - -	str2ba(addr_ptr, &bdaddr); - -	val = get_encryption_key_size(dbus_data->dev_id, &bdaddr); -	if (val < 0) -		return bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | -val); - -	reply = dbus_message_new_method_return(msg); - -	size = val; - -	dbus_message_append_args(reply, DBUS_TYPE_BYTE, &size, -					DBUS_TYPE_INVALID); - -	return reply; -} - -static DBusMessage *handle_dev_discover_req(DBusMessage *msg, void *data) -{ -	DBusMessage *reply = NULL; -	inquiry_cp cp; -	evt_cmd_status rp; -	struct hci_request rq; -	struct hci_dbus_data *dbus_data = data; -	uint8_t length = 8, num_rsp = 0; -	uint32_t lap = 0x9e8b33; -	int dd; - -	dd = hci_open_dev(dbus_data->dev_id); -	if (dd < 0) -		return error_no_such_device(msg); - -	memset(&cp, 0, sizeof(cp)); -	cp.lap[0]  = lap & 0xff; -	cp.lap[1]  = (lap >> 8) & 0xff; -	cp.lap[2]  = (lap >> 16) & 0xff; -	cp.length  = length; -	cp.num_rsp = num_rsp; - -	memset(&rq, 0, sizeof(rq)); -	rq.ogf    = OGF_LINK_CTL; -	rq.ocf    = OCF_INQUIRY; -	rq.cparam = &cp; -	rq.clen   = INQUIRY_CP_SIZE; -	rq.rparam = &rp; -	rq.rlen   = EVT_CMD_STATUS_SIZE; -	rq.event  = EVT_CMD_STATUS; - -	if (hci_send_req(dd, &rq, 100) < 0) { -		syslog(LOG_ERR, "Unable to start inquiry: %s (%d)", -							strerror(errno), errno); -		reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); -		goto failed; -	} - -	reply = dbus_message_new_method_return(msg); - -failed: -	hci_close_dev(dd); - -	return reply; -} - -static DBusMessage *handle_dev_discover_cancel_req(DBusMessage *msg, void *data) -{ -	DBusMessage *reply = NULL; -	struct hci_request rq; -	struct hci_dbus_data *dbus_data = data; -	uint8_t status; -	int dd; - -	dd = hci_open_dev(dbus_data->dev_id); -	if (dd < 0) -		return error_no_such_device(msg); - -	memset(&rq, 0, sizeof(rq)); -	rq.ogf    = OGF_LINK_CTL; -	rq.ocf    = OCF_INQUIRY_CANCEL; -	rq.rparam = &status; -	rq.rlen   = sizeof(status); - -	if (hci_send_req(dd, &rq, 100) < 0) { -		syslog(LOG_ERR, "Sending cancel inquiry failed: %s (%d)", -							strerror(errno), errno); -		reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); -		goto failed; -	} - -	if (status) { -		syslog(LOG_ERR, "Cancel inquiry failed with status 0x%02x", status); -		reply = bluez_new_failure_msg(msg, BLUEZ_EBT_OFFSET + status); -		goto failed; -	} - -	reply = dbus_message_new_method_return(msg); - -failed: -	hci_close_dev(dd); - -	return reply; -} - -static DBusMessage *handle_dev_discover_cache_req(DBusMessage *msg, void *data) -{ -	/*FIXME: */ -	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); -} - -static DBusMessage *handle_dev_discover_service_req(DBusMessage *msg, void *data) -{ -	/*FIXME: */ -	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); -} - -static const struct service_data dev_services[] = { -	{ DEV_GET_ADDRESS,		handle_dev_get_address_req,		DEV_GET_ADDRESS_SIGNATURE		}, -	{ DEV_GET_VERSION,		handle_dev_get_version_req,		DEV_GET_VERSION_SIGNATURE		}, -	{ DEV_GET_REVISION,		handle_dev_get_revision_req,		DEV_GET_REVISION_SIGNATURE		}, -	{ DEV_GET_MANUFACTURER,		handle_dev_get_manufacturer_req,	DEV_GET_MANUFACTURER_SIGNATURE		}, -	{ DEV_GET_COMPANY,		handle_dev_get_company_req,		DEV_GET_COMPANY_SIGNATURE		}, -	{ DEV_GET_FEATURES,		handle_dev_get_features_req,		DEV_GET_FEATURES_SIGNATURE		}, -	{ DEV_GET_MODE,			handle_dev_get_mode_req,		DEV_GET_MODE_SIGNATURE			}, -	{ DEV_SET_MODE,			handle_dev_set_mode_req,		DEV_SET_MODE_SIGNATURE			}, -	{ DEV_GET_DISCOVERABLE_TO,	handle_dev_get_discoverable_to_req,	DEV_GET_DISCOVERABLE_TO_SIGNATURE	}, -	{ DEV_SET_DISCOVERABLE_TO,	handle_dev_set_discoverable_to_req,	DEV_SET_DISCOVERABLE_TO_SIGNATURE	}, -	{ DEV_IS_CONNECTABLE,		handle_dev_is_connectable_req,		DEV_IS_CONNECTABLE_SIGNATURE		}, -	{ DEV_IS_DISCOVERABLE,		handle_dev_is_discoverable_req,		DEV_IS_DISCOVERABLE_SIGNATURE		}, -	{ DEV_GET_MAJOR_CLASS,		handle_dev_get_major_class_req,		DEV_GET_MAJOR_CLASS_SIGNATURE		}, -	{ DEV_GET_MINOR_CLASS,		handle_dev_get_minor_class_req,		DEV_GET_MINOR_CLASS_SIGNATURE		}, -	{ DEV_SET_MINOR_CLASS,		handle_dev_set_minor_class_req,		DEV_SET_MINOR_CLASS_SIGNATURE		}, -	{ DEV_GET_SERVICE_CLASSES,	handle_dev_get_service_classes_req,	DEV_GET_SERVICE_CLASSES_SIGNATURE	}, -	{ DEV_GET_NAME,			handle_dev_get_name_req,		DEV_GET_NAME_SIGNATURE			}, -	{ DEV_SET_NAME,			handle_dev_set_name_req,		DEV_SET_NAME_SIGNATURE			}, - -	{ DEV_GET_REMOTE_VERSION,	handle_dev_get_remote_version_req,	DEV_GET_REMOTE_VERSION_SIGNATURE	}, -	{ DEV_GET_REMOTE_REVISION,	handle_dev_get_remote_revision_req,	DEV_GET_REMOTE_REVISION_SIGNATURE	}, -	{ DEV_GET_REMOTE_MANUFACTURER,	handle_dev_get_remote_manufacturer_req,	DEV_GET_REMOTE_MANUFACTURER_SIGNATURE	}, -	{ DEV_GET_REMOTE_COMPANY,	handle_dev_get_remote_company_req,	DEV_GET_REMOTE_COMPANY_SIGNATURE	}, -	{ DEV_GET_REMOTE_NAME,		handle_dev_get_remote_name_req,		DEV_GET_REMOTE_NAME_SIGNATURE		}, -	{ DEV_GET_REMOTE_ALIAS,		handle_dev_get_remote_alias_req,	DEV_GET_REMOTE_ALIAS_SIGNATURE		}, -	{ DEV_SET_REMOTE_ALIAS,		handle_dev_set_remote_alias_req,	DEV_SET_REMOTE_ALIAS_SIGNATURE		}, - -	{ DEV_LAST_SEEN,		handle_dev_last_seen_req,		DEV_LAST_SEEN_SIGNATURE			}, -	{ DEV_LAST_USED,		handle_dev_last_used_req,		DEV_LAST_USED_SIGNATURE			}, - -	{ DEV_CREATE_BONDING,		handle_dev_create_bonding_req,		DEV_CREATE_BONDING_SIGNATURE		}, -	{ DEV_REMOVE_BONDING,		handle_dev_remove_bonding_req,		DEV_REMOVE_BONDING_SIGNATURE		}, -	{ DEV_HAS_BONDING_NAME,		handle_dev_has_bonding_req,		DEV_HAS_BONDING_SIGNATURE		}, -	{ DEV_LIST_BONDINGS,		handle_dev_list_bondings_req,		DEV_LIST_BONDINGS_SIGNATURE		}, -	{ DEV_PIN_CODE_LENGTH,		handle_dev_pin_code_length_req,		DEV_PIN_CODE_LENGTH_SIGNATURE		}, -	{ DEV_ENCRYPTION_KEY_SIZE,	handle_dev_encryption_key_size_req,	DEV_ENCRYPTION_KEY_SIZE_SIGNATURE	}, - -	{ DEV_DISCOVER,			handle_dev_discover_req,		DEV_DISCOVER_SIGNATURE			}, -	{ DEV_DISCOVER_CANCEL,		handle_dev_discover_cancel_req,		DEV_DISCOVER_CANCEL_SIGNATURE		}, -	{ DEV_DISCOVER_CACHE,		handle_dev_discover_cache_req,		DEV_DISCOVER_CACHE_SIGNATURE		}, -	{ DEV_DISCOVER_SERVICE,		handle_dev_discover_service_req,	DEV_DISCOVER_SERVICE_SIGNATURE		}, - -	{ NULL, NULL, NULL} -}; - -DBusHandlerResult msg_func_device(DBusConnection *conn, DBusMessage *msg, void *data) -{ -	const struct service_data *handlers = dev_services; -	DBusMessage *reply = NULL; -	struct hci_dbus_data *dbus_data = data; -	const char *method; -	const char *signature; -	const char *iface; -	uint32_t error = BLUEZ_EDBUS_UNKNOWN_METHOD; - -	method = dbus_message_get_member(msg); -	signature = dbus_message_get_signature(msg); -	iface = dbus_message_get_interface(msg); - -	syslog(LOG_INFO, "Adapter path:%s method:%s", -					dbus_message_get_path(msg), method); - -	if (strcmp(ADAPTER_INTERFACE, iface)) -		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - -	if (dbus_data->path_id == ADAPTER_ROOT_ID) { -		/* Adapter is down(path unregistered) or the path is wrong */ -		error = BLUEZ_EDBUS_UNKNOWN_PATH; -		goto failed; -	} - -	/* It's a device path id */ -	for (; handlers->name != NULL; handlers++) { -		if (strcmp(handlers->name, method)) -			continue; - -		if (!strcmp(handlers->signature, signature)) { -			reply = handlers->handler_func(msg, data); -			error = 0; -			break; -		} else { -			/* Set the error, but continue looping incase there is -			 * another method with the same name but a different -			 * signature */ -			error = BLUEZ_EDBUS_WRONG_SIGNATURE; -			continue; -		} -	} - -failed: -	if (error) -		reply = bluez_new_failure_msg(msg, error); - -	if (reply) { -		if (!dbus_connection_send (conn, reply, NULL)) -			syslog(LOG_ERR, "Can't send reply message"); - -		dbus_message_unref(reply); -	} - -	return DBUS_HANDLER_RESULT_HANDLED; -} | 
