summaryrefslogtreecommitdiffstats
path: root/hcid
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2006-04-09 00:12:36 +0000
committerJohan Hedberg <johan.hedberg@nokia.com>2006-04-09 00:12:36 +0000
commite0d05942e436393256b61f111d5924add57840c7 (patch)
tree3657026fe793e6e051022d90728369578a7bec9b /hcid
parent8fa8629fa44075dfa41b1bff96a7951dd40cfb0a (diff)
* Add D-Bus methods for getting remote device class information
* Fix a couple of memory leaks where result of textfile_get wasn't free'd
Diffstat (limited to 'hcid')
-rw-r--r--hcid/dbus-adapter.c204
-rw-r--r--hcid/dbus-api.txt27
-rw-r--r--hcid/dbus.c85
-rw-r--r--hcid/dbus.h4
-rw-r--r--hcid/hcid.h2
-rw-r--r--hcid/storage.c49
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);