diff options
| -rw-r--r-- | hcid/dbus-adapter.c | 204 | ||||
| -rw-r--r-- | hcid/dbus-api.txt | 27 | ||||
| -rw-r--r-- | hcid/dbus.c | 85 | ||||
| -rw-r--r-- | hcid/dbus.h | 4 | ||||
| -rw-r--r-- | hcid/hcid.h | 2 | ||||
| -rw-r--r-- | hcid/storage.c | 49 | 
6 files changed, 299 insertions, 72 deletions
| diff --git a/hcid/dbus-adapter.c b/hcid/dbus-adapter.c index 7a995e83..106c6152 100644 --- a/hcid/dbus-adapter.c +++ b/hcid/dbus-adapter.c @@ -55,6 +55,19 @@ static const char *service_cls[] = {  	"information"  }; +static const char *major_cls[] = { +	"miscellaneous", +	"computer", +	"phone", +	"access point", +	"audio/video", +	"peripheral", +	"imaging", +	"wearable", +	"toy", +	"uncategorized" +}; +  static const char *computer_minor_cls[] = {  	"uncategorized",  	"desktop", @@ -1051,6 +1064,132 @@ static DBusHandlerResult handle_dev_get_remote_company_req(DBusConnection *conn,  	return send_reply_and_unref(conn, reply);  } +static int get_remote_class(DBusConnection *conn, DBusMessage *msg, void *data, uint32_t *class) +{ +	struct hci_dbus_data *dbus_data = data; +	char addr_local[18], *addr_peer; +	DBusError err; +	bdaddr_t local, peer; +	int ecode; + +	dbus_error_init(&err); +	dbus_message_get_args(msg, &err, +				DBUS_TYPE_STRING, &addr_peer, +				DBUS_TYPE_INVALID); + +	if (dbus_error_is_set(&err)) { +		error("Can't extract message arguments:%s", err.message); +		dbus_error_free(&err); +		error_invalid_arguments(conn, msg); +		return -1; +	} + +	if (check_address(addr_peer) < 0) { +		error_invalid_arguments(conn, msg); +		return -1; +	} + +	ecode = get_device_address(dbus_data->dev_id, addr_local, sizeof(addr_local)); +	if (ecode < 0) { +		error_failed(conn, msg, -ecode); +		return -1; +	} + +	str2ba(addr_peer, &peer); +	str2ba(addr_local, &local); + +	ecode = read_remote_class(&local, &peer, class); +	if (ecode < 0) { +		error_failed(conn, msg, -ecode); +		return -1; +	} + +	return 0; +} + +static DBusHandlerResult handle_dev_get_remote_major_class_req(DBusConnection *conn, +								DBusMessage *msg, +								void *data) +{ +	DBusMessage *reply; +	const char *major_class; +	uint32_t class; + +	if (get_remote_class(conn, msg, data, &class) < 0) +		return DBUS_HANDLER_RESULT_HANDLED; + +	major_class = major_class_str(class); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return DBUS_HANDLER_RESULT_NEED_MEMORY; + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &major_class, +					DBUS_TYPE_INVALID); + +	return send_reply_and_unref(conn, reply); +} + +static DBusHandlerResult handle_dev_get_remote_minor_class_req(DBusConnection *conn, +								DBusMessage *msg, +								void *data) +{ +	DBusMessage *reply; +	const char *major_class; +	uint32_t class; + +	if (get_remote_class(conn, msg, data, &class) < 0) +		return DBUS_HANDLER_RESULT_HANDLED; + +	major_class = minor_class_str(class); + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return DBUS_HANDLER_RESULT_NEED_MEMORY; + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &major_class, +					DBUS_TYPE_INVALID); + +	return send_reply_and_unref(conn, reply); +} + +static DBusHandlerResult handle_dev_get_remote_service_cls_req(DBusConnection *conn, +								DBusMessage *msg, +								void *data) +{ +	DBusMessage *reply; +	DBusMessageIter iter, array_iter; +	const char **service_classes; +	int i; +	uint32_t class; + +	if (get_remote_class(conn, msg, data, &class) < 0) +		return DBUS_HANDLER_RESULT_HANDLED; + +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return DBUS_HANDLER_RESULT_NEED_MEMORY; + +	service_classes = service_classes_str(class); +	if (!service_classes) { +		error("Unable to create service classes list"); +		return error_failed(conn,msg, ENOMEM); +	} + +	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; service_classes[i] != NULL; i++) +		dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &service_classes[i]); + +	dbus_message_iter_close_container(&iter, &array_iter); + +	free(service_classes); + +	return send_reply_and_unref(conn, reply); +} +  static DBusHandlerResult handle_dev_get_remote_name_req(DBusConnection *conn, DBusMessage *msg, void *data)  {  	char filename[PATH_MAX + 1], addr[18]; @@ -2030,6 +2169,68 @@ static DBusHandlerResult handle_dev_cancel_discovery_req(DBusConnection *conn, D  	return send_reply_and_unref(conn, reply);  } +const char *major_class_str(uint32_t class) +{ +	uint8_t index = (class >> 8) & 0x1F; + +	if (index > 8) +		return major_cls[9]; /* uncategorized */ + +	return major_cls[index]; +} + +const char *minor_class_str(uint32_t class) +{ +	uint8_t major_index = (class >> 8) & 0x1F; +	uint8_t minor_index = (class >> 2) & 0x3F; + +	switch (major_index) { +	case 1: /* computer */ +		return computer_minor_cls[minor_index]; +	case 2: /* phone */ +		return phone_minor_cls[minor_index]; +	} + +	return ""; +} + +/* Return NULL terminated array of strings */ +const char **service_classes_str(uint32_t class) +{ +	uint8_t services = class >> 16; +	const char **classes; +	int i, class_count = 0; + +	classes = malloc(sizeof(const char *)); +	if (!classes) +		return NULL; + +	classes[0] = NULL; + +	for (i = 0; i < (sizeof(service_cls) / sizeof(*service_cls)); i++) { +		const char **tmp; + +		if (!(services & (1 << i))) +			continue; + +		class_count++; + +		tmp = realloc(classes, sizeof(const char *) * (class_count + 1)); +		if (!tmp) { +			free(classes); +			return NULL; +		} + +		classes = tmp; + +		classes[class_count - 1] = service_cls[i]; +		classes[class_count] = NULL; +	} + +	return classes; +} + +  static struct service_data dev_services[] = {  	{ "GetAddress",					handle_dev_get_address_req		},  	{ "GetVersion",					handle_dev_get_version_req		}, @@ -2056,6 +2257,9 @@ static struct service_data dev_services[] = {  	{ "GetRemoteRevision",				handle_dev_get_remote_revision_req	},  	{ "GetRemoteManufacturer",			handle_dev_get_remote_manufacturer_req	},  	{ "GetRemoteCompany",				handle_dev_get_remote_company_req	}, +	{ "GetRemoteMajorClass",			handle_dev_get_remote_major_class_req	}, +	{ "GetRemoteMinorClass",			handle_dev_get_remote_minor_class_req	}, +	{ "GetRemoteServiceClasses",			handle_dev_get_remote_service_cls_req	},  	{ "GetRemoteName",				handle_dev_get_remote_name_req		},  	{ "GetRemoteAlias",				handle_dev_get_remote_alias_req		},  	{ "SetRemoteAlias",				handle_dev_set_remote_alias_req		}, diff --git a/hcid/dbus-api.txt b/hcid/dbus-api.txt index 51081424..a5f30101 100644 --- a/hcid/dbus-api.txt +++ b/hcid/dbus-api.txt @@ -416,6 +416,33 @@ Methods		string GetAddress()  			Possible errors: org.bluez.Error.UnknownAddress  			                 org.bluez.Error.NotAvailable +		string GetRemoteMajorClass(string address) + +			Get the major device class of the specified device. + +			Example: "computer" + +			Possible errors: org.bluez.Error.UnknownAddress +			                 org.bluez.Error.NotAvailable + +		string GetRemoteMinorClass(string address) + +			Get the minor device class of the specified device. + +			Example: "laptop" + +			Possible errors: org.bluez.Error.UnknownAddress +			                 org.bluez.Error.NotAvailable + +		array{string] GetRemoteServiceClasses(string address) + +			Get the service classes of the specified device. + +			Example: ["networking", "object transfer"] + +			Possible errors: org.bluez.Error.UnknownAddress +			                 org.bluez.Error.NotAvailable +  		string GetRemoteName(string address)  			Get adapter name for a remote device. This request diff --git a/hcid/dbus.c b/hcid/dbus.c index c1abd71b..a74b0309 100644 --- a/hcid/dbus.c +++ b/hcid/dbus.c @@ -52,50 +52,6 @@ static int default_dev = -1;  #define MAX_CONN_NUMBER			10  #define RECONNECT_RETRY_TIMEOUT		5000 -static const char *services_cls[] = { -	"positioning", -	"networking", -	"rendering", -	"capturing", -	"object transfer", -	"audio", -	"telephony", -	"information" -}; - -static const char *major_cls[] = { -	"miscellaneous", -	"computer", -	"phone", -	"access point", -	"audio/video", -	"peripheral", -	"imaging", -	"wearable", -	"toy", -	"uncategorized" -}; - -static const char *computer_minor_cls[] = { -	"uncategorized", -	"desktop", -	"server", -	"laptop", -	"handheld", -	"palm", -	"wearable" -}; - -static const char *phone_minor_cls[] = { -	"uncategorized", -	"cellular", -	"cordless", -	"smart phone", -	"modem", -	"isdn" -}; - -  void disc_device_info_free(void *data, void *user_data)  {  	struct discovered_dev_info *dev = data; @@ -958,13 +914,11 @@ void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, i  	struct slist *l = NULL;  	struct discovered_dev_info *dev;  	char *local_addr, *peer_addr, *name = NULL; -	const char *major_ptr; -	char invalid_minor_class[] = ""; -	const char *minor_ptr = invalid_minor_class; +	const char *major_ptr, *minor_ptr; +	const char **service_classes;  	const dbus_int16_t tmp_rssi = rssi;  	bdaddr_t tmp;  	int id, i; -	uint8_t service_index, major_index, minor_index;  	name_status_t name_status = NAME_PENDING;  	baswap(&tmp, local); local_addr = batostr(&tmp); @@ -983,6 +937,8 @@ void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, i  		goto failed;  	} +	write_remote_class(local, peer, class); +  	/* send the device found signal */  	signal_device = dbus_message_new_signal(path, ADAPTER_INTERFACE,  						"RemoteDeviceFound"); @@ -991,23 +947,8 @@ void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, i  		goto failed;  	} -	/* get the major class */ -	major_index = (class >> 8) & 0x1F; -	if (major_index > 8) -		major_ptr = major_cls[9]; /* set to uncategorized */ -	else -		major_ptr = major_cls[major_index]; - -	/* get the minor class */ -	minor_index = (class >> 2) & 0x3F; -	switch (major_index) { -	case 1: /* computer */ -		minor_ptr = computer_minor_cls[minor_index]; -		break; -	case 2: /* phone */ -		minor_ptr = phone_minor_cls[minor_index]; -		break; -	} +	major_ptr = major_class_str(class); +	minor_ptr = minor_class_str(class);  	dbus_message_iter_init_append(signal_device, &iter);  	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &peer_addr); @@ -1015,17 +956,23 @@ void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, i  	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &major_ptr);  	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor_ptr); +	service_classes = service_classes_str(class); +	if (!service_classes) { +		error("Unable to create service class strings"); +		goto failed; +	} +  	/* add the service classes */  	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,  	 					DBUS_TYPE_STRING_AS_STRING, &array_iter); -	service_index = class >> 16; -	for (i = 0; i < (sizeof(services_cls) / sizeof(*services_cls)); i++) -		if (service_index & (1 << i)) -			dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &services_cls[i]); +	for (i = 0; service_classes[i] != NULL; i++) +		dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &service_classes[i]);  	dbus_message_iter_close_container(&iter, &array_iter); +	free(service_classes); +  	if (dbus_connection_send(connection, signal_device, NULL) == FALSE) {  		error("Can't send D-Bus remote device found signal");  		goto failed; diff --git a/hcid/dbus.h b/hcid/dbus.h index f6f0b6d8..663394b6 100644 --- a/hcid/dbus.h +++ b/hcid/dbus.h @@ -129,6 +129,10 @@ typedef int unregister_function_t(DBusConnection *conn, uint16_t id);  DBusHandlerResult msg_func_device(DBusConnection *conn, DBusMessage *msg, void *data);  DBusHandlerResult msg_func_manager(DBusConnection *conn, DBusMessage *msg, void *data); +const char *major_class_str(uint32_t class); +const char *minor_class_str(uint32_t class); +const char **service_classes_str(uint32_t class); +  DBusHandlerResult bluez_new_failure_msg(DBusConnection *conn, DBusMessage *msg, const uint32_t ecode);  DBusMessage *dev_signal_factory(const int devid, const char *prop_name, const int first, ...); diff --git a/hcid/hcid.h b/hcid/hcid.h index 1bd64130..2f5d74c1 100644 --- a/hcid/hcid.h +++ b/hcid/hcid.h @@ -158,6 +158,8 @@ int write_local_name(bdaddr_t *bdaddr, char *name);  int read_local_name(bdaddr_t *bdaddr, char *name);  int write_local_class(bdaddr_t *bdaddr, uint8_t *class);  int read_local_class(bdaddr_t *bdaddr, uint8_t *class); +int write_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class); +int read_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t *class);  int write_device_name(bdaddr_t *local, bdaddr_t *peer, char *name);  int read_device_name(bdaddr_t *local, bdaddr_t *peer, char *name);  int write_version_info(bdaddr_t *local, bdaddr_t *peer, uint16_t manufacturer, uint8_t lmp_ver, uint16_t lmp_subver); diff --git a/hcid/storage.c b/hcid/storage.c index 17f0744a..e3781278 100644 --- a/hcid/storage.c +++ b/hcid/storage.c @@ -122,6 +122,44 @@ int read_local_class(bdaddr_t *bdaddr, uint8_t *class)  	return 0;  } +int write_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class) +{ +	char filename[PATH_MAX + 1], addr[18], str[9]; + +	ba2str(local, addr); +	snprintf(filename, PATH_MAX, "%s/%s/classes", STORAGEDIR, addr); + +	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +	ba2str(peer, addr); +	sprintf(str, "0x%6.6x", class); + +	return textfile_put(filename, addr, str); +} + +int read_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t *class) +{ +	char filename[PATH_MAX + 1], addr[18], *str; + +	ba2str(local, addr); +	snprintf(filename, PATH_MAX, "%s/%s/classes", STORAGEDIR, addr); + +	ba2str(peer, addr); + +	str = textfile_get(filename, addr); +	if (!str) +		return -ENOENT; + +	if (sscanf(str, "%x", class) != 1) { +		free(str); +		return -ENOENT; +	} + +	free(str); + +	return 0; +} +  int write_device_name(bdaddr_t *local, bdaddr_t *peer, char *name)  {  	char filename[PATH_MAX + 1], addr[18], str[249]; @@ -251,8 +289,11 @@ int write_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, int type  	if (length < 0) {  		char *tmp = textfile_get(filename, addr); -		if (tmp && strlen(tmp) > 34) -			memcpy(str + 34, tmp + 34, 3); +		if (tmp) { +			if (strlen(tmp) > 34) +				memcpy(str + 34, tmp + 34, 3); +			free(tmp); +		}  	}  	return textfile_put(filename, addr, str); @@ -295,8 +336,10 @@ int read_pin_length(bdaddr_t *local, bdaddr_t *peer)  	if (!str)  		return -ENOENT; -	if (strlen(str) < 36) +	if (strlen(str) < 36) { +		free(str);  		return -ENOENT; +	}  	len = atoi(str + 35); | 
