aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2011-01-14 23:14:13 +0200
committerJohan Hedberg <johan.hedberg@nokia.com>2011-01-16 23:09:40 +0200
commit006301ab40fc71da92f593ddfb2dba70202bd061 (patch)
tree7e2a2c773d46f20e04641a4caf4049af2e662120
parent24dbc52388f1ef2e759d24d74cd32f93531c8857 (diff)
downloadbluez-006301ab40fc71da92f593ddfb2dba70202bd061.tar.gz
Update Class of Device handling to the latest management interface
This patch updates the class of device handling code to match the latest management interface. A notable feature is that UUID to service class mapping policy remains in user space with the help of the svc_hint parameter of the add_uuid command. This is to make it easy to update the mapping table when new profiles come along.
-rw-r--r--doc/mgmt-api.txt20
-rw-r--r--lib/mgmt.h23
-rw-r--r--plugins/hciops.c81
-rw-r--r--plugins/mgmtops.c77
-rw-r--r--src/adapter.c51
-rw-r--r--src/adapter.h2
6 files changed, 171 insertions, 83 deletions
diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index 24c7070a..d964a702 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -122,6 +122,7 @@ Add UUID Command
Command Code: 0x0009
Command Parameters: Controller_Index (2 Octets)
UUID (16 Octets)
+ SVC_Hint (1 octet)
Return Paramters: Controller_Index (2 Octets)
@@ -134,6 +135,25 @@ Remove UUID Command
Return Paramters: Controller_Index (2 Octets)
+Set Device Class
+================
+
+ Command Code: 0x000B
+ Command Parameters: Controller_Index (2 Octets)
+ Major_Class (1 octet)
+ Minor_Class (1 octed)
+ Return Paramters: Controller_Index (2 Octets)
+
+
+Set Service Cache Command
+=========================
+
+ Command Code: 0x000C
+ Command Parameters: Controller_Index (2 Octets)
+ Enable (1 octet)
+ Return Paramters: Controller_Index (2 Octets)
+
+
Read Tracing Buffer Size Command
================================
diff --git a/lib/mgmt.h b/lib/mgmt.h
index a382c53a..6bdefab4 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -81,14 +81,31 @@ struct mgmt_mode {
#define MGMT_OP_SET_PAIRABLE 0x0008
-struct mgmt_cp_uuid {
+#define MGMT_OP_ADD_UUID 0x0009
+struct mgmt_cp_add_uuid {
uint16_t index;
uint8_t uuid[16];
+ uint8_t svc_hint;
} __packed;
-#define MGMT_OP_ADD_UUID 0x0009
-
#define MGMT_OP_REMOVE_UUID 0x000A
+struct mgmt_cp_remove_uuid {
+ uint16_t index;
+ uint8_t uuid[16];
+} __packed;
+
+#define MGMT_OP_SET_DEV_CLASS 0x000B
+struct mgmt_cp_set_dev_class {
+ uint16_t index;
+ uint8_t major;
+ uint8_t minor;
+} __packed;
+
+#define MGMT_OP_SET_SERVICE_CACHE 0x000C
+struct mgmt_cp_set_service_cache {
+ uint16_t index;
+ uint8_t enable;
+} __packed;
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
diff --git a/plugins/hciops.c b/plugins/hciops.c
index 4d8850fa..fec7e166 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -63,6 +63,11 @@ enum {
PENDING_NAME,
};
+struct uuid_info {
+ uuid_t uuid;
+ uint8_t svc_hint;
+};
+
static int max_dev = -1;
static struct dev_info {
int sk;
@@ -1037,10 +1042,10 @@ static void eir_generate_uuid128(GSList *list, uint8_t *ptr, uint16_t *eir_len)
uuid128 = ptr + 2;
for (; list; list = list->next) {
- uuid_t *uuid = list->data;
- uint8_t *uuid128_data = uuid->value.uuid128.data;
+ struct uuid_info *uuid = list->data;
+ uint8_t *uuid128_data = uuid->uuid.value.uuid128.data;
- if (uuid->type != SDP_UUID128)
+ if (uuid->uuid.type != SDP_UUID128)
continue;
/* Stop if not enough space to put next UUID128 */
@@ -1136,15 +1141,15 @@ static void create_ext_inquiry_response(int index, uint8_t *data)
/* Group all UUID16 types */
for (l = dev->uuids; l != NULL; l = g_slist_next(l)) {
- uuid_t *uuid = l->data;
+ struct uuid_info *uuid = l->data;
- if (uuid->type != SDP_UUID16)
+ if (uuid->uuid.type != SDP_UUID16)
continue;
- if (uuid->value.uuid16 < 0x1100)
+ if (uuid->uuid.value.uuid16 < 0x1100)
continue;
- if (uuid->value.uuid16 == PNP_INFO_SVCLASS_ID)
+ if (uuid->uuid.value.uuid16 == PNP_INFO_SVCLASS_ID)
continue;
/* Stop if not enough space to put next UUID16 */
@@ -1155,13 +1160,13 @@ static void create_ext_inquiry_response(int index, uint8_t *data)
/* Check for duplicates */
for (i = 0; i < uuid_count; i++)
- if (uuid16[i] == uuid->value.uuid16)
+ if (uuid16[i] == uuid->uuid.value.uuid16)
break;
if (i < uuid_count)
continue;
- uuid16[uuid_count++] = uuid->value.uuid16;
+ uuid16[uuid_count++] = uuid->uuid.value.uuid16;
eir_len += sizeof(uint16_t);
}
@@ -3021,48 +3026,6 @@ static int hciops_enable_le(int index)
return 0;
}
-static uint8_t get_uuid_mask(uint16_t uuid16)
-{
- switch (uuid16) {
- case DIALUP_NET_SVCLASS_ID:
- case CIP_SVCLASS_ID:
- return 0x42; /* Telephony & Networking */
- case IRMC_SYNC_SVCLASS_ID:
- case OBEX_OBJPUSH_SVCLASS_ID:
- case OBEX_FILETRANS_SVCLASS_ID:
- case IRMC_SYNC_CMD_SVCLASS_ID:
- case PBAP_PSE_SVCLASS_ID:
- return 0x10; /* Object Transfer */
- case HEADSET_SVCLASS_ID:
- case HANDSFREE_SVCLASS_ID:
- return 0x20; /* Audio */
- case CORDLESS_TELEPHONY_SVCLASS_ID:
- case INTERCOM_SVCLASS_ID:
- case FAX_SVCLASS_ID:
- case SAP_SVCLASS_ID:
- /*
- * Setting the telephony bit for the handsfree audio gateway
- * role is not required by the HFP specification, but the
- * Nokia 616 carkit is just plain broken! It will refuse
- * pairing without this bit set.
- */
- case HANDSFREE_AGW_SVCLASS_ID:
- return 0x40; /* Telephony */
- case AUDIO_SOURCE_SVCLASS_ID:
- case VIDEO_SOURCE_SVCLASS_ID:
- return 0x08; /* Capturing */
- case AUDIO_SINK_SVCLASS_ID:
- case VIDEO_SINK_SVCLASS_ID:
- return 0x04; /* Rendering */
- case PANU_SVCLASS_ID:
- case NAP_SVCLASS_ID:
- case GN_SVCLASS_ID:
- return 0x02; /* Networking */
- default:
- return 0;
- }
-}
-
static uint8_t generate_service_class(int index)
{
struct dev_info *dev = &devs[index];
@@ -3070,12 +3033,9 @@ static uint8_t generate_service_class(int index)
uint8_t val = 0;
for (l = dev->uuids; l != NULL; l = g_slist_next(l)) {
- uuid_t *uuid = l->data;
+ struct uuid_info *uuid = l->data;
- if (uuid->type != SDP_UUID16)
- continue;
-
- val |= get_uuid_mask(uuid->value.uuid16);
+ val |= uuid->svc_hint;
}
return val;
@@ -3117,13 +3077,18 @@ static int update_service_classes(int index)
return err;
}
-static int hciops_add_uuid(int index, uuid_t *uuid)
+static int hciops_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint)
{
struct dev_info *dev = &devs[index];
+ struct uuid_info *info;
DBG("hci%d", index);
- dev->uuids = g_slist_append(dev->uuids, g_memdup(uuid, sizeof(*uuid)));
+ info = g_new0(struct uuid_info, 1);
+ memcpy(&info->uuid, uuid, sizeof(*uuid));
+ info->svc_hint = svc_hint;
+
+ dev->uuids = g_slist_append(dev->uuids, info);
return update_service_classes(index);
}
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index 28b42bbe..e33c0496 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -410,17 +410,44 @@ static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid)
memcpy(uuid128, uuid, sizeof(*uuid));
}
-static int mgmt_uuid_op(int index, uint16_t op, uuid_t *uuid)
+static int mgmt_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint)
{
- char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_uuid)];
+ char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_add_uuid)];
struct mgmt_hdr *hdr = (void *) buf;
- struct mgmt_cp_uuid *cp = (void *) &buf[sizeof(*hdr)];
+ struct mgmt_cp_add_uuid *cp = (void *) &buf[sizeof(*hdr)];
uuid_t uuid128;
+ DBG("index %d", index);
+
uuid_to_uuid128(&uuid128, uuid);
memset(buf, 0, sizeof(buf));
- hdr->opcode = htobs(op);
+ hdr->opcode = htobs(MGMT_OP_ADD_UUID);
+ hdr->len = htobs(sizeof(*cp));
+
+ cp->index = htobs(index);
+ memcpy(cp->uuid, uuid128.value.uuid128.data, 16);
+ cp->svc_hint = svc_hint;
+
+ if (write(mgmt_sock, buf, sizeof(buf)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int mgmt_remove_uuid(int index, uuid_t *uuid)
+{
+ char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_remove_uuid)];
+ struct mgmt_hdr *hdr = (void *) buf;
+ struct mgmt_cp_remove_uuid *cp = (void *) &buf[sizeof(*hdr)];
+ uuid_t uuid128;
+
+ DBG("index %d", index);
+
+ uuid_to_uuid128(&uuid128, uuid);
+
+ memset(buf, 0, sizeof(buf));
+ hdr->opcode = htobs(MGMT_OP_REMOVE_UUID);
hdr->len = htobs(sizeof(*cp));
cp->index = htobs(index);
@@ -439,7 +466,7 @@ static int clear_uuids(int index)
memset(&uuid_any, 0, sizeof(uuid_any));
uuid_any.type = SDP_UUID128;
- return mgmt_uuid_op(index, MGMT_OP_REMOVE_UUID, &uuid_any);
+ return mgmt_remove_uuid(index, &uuid_any);
}
static void read_index_list_complete(int sk, void *buf, size_t len)
@@ -497,6 +524,8 @@ static void read_info_complete(int sk, void *buf, size_t len)
return;
}
+ mgmt_set_mode(index, MGMT_OP_SET_SERVICE_CACHE, 1);
+
info = &controllers[index];
info->type = rp->type;
info->enabled = rp->powered;
@@ -701,6 +730,12 @@ static void mgmt_cmd_complete(int sk, void *buf, size_t len)
case MGMT_OP_REMOVE_UUID:
DBG("remove_uuid complete");
break;
+ case MGMT_OP_SET_DEV_CLASS:
+ DBG("set_dev_class complete");
+ break;
+ case MGMT_OP_SET_SERVICE_CACHE:
+ DBG("set_service_cache complete");
+ break;
default:
error("Unknown command complete for opcode %u", opcode);
break;
@@ -879,8 +914,24 @@ static void mgmt_cleanup(void)
static int mgmt_set_dev_class(int index, uint8_t major, uint8_t minor)
{
+ char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_dev_class)];
+ struct mgmt_hdr *hdr = (void *) buf;
+ struct mgmt_cp_set_dev_class *cp = (void *) &buf[sizeof(*hdr)];
+
DBG("index %d major %u minor %u", index, major, minor);
- return -ENOSYS;
+
+ memset(buf, 0, sizeof(buf));
+ hdr->opcode = htobs(MGMT_OP_SET_DEV_CLASS);
+ hdr->len = htobs(sizeof(*cp));
+
+ cp->index = htobs(index);
+ cp->major = major;
+ cp->minor = minor;
+
+ if (write(mgmt_sock, buf, sizeof(buf)) < 0)
+ return -errno;
+
+ return 0;
}
static int mgmt_set_limited_discoverable(int index, gboolean limited)
@@ -1123,22 +1174,10 @@ static int mgmt_set_did(int index, uint16_t vendor, uint16_t product,
return -ENOSYS;
}
-static int mgmt_add_uuid(int index, uuid_t *uuid)
-{
- DBG("index %d", index);
- return mgmt_uuid_op(index, MGMT_OP_ADD_UUID, uuid);
-}
-
-static int mgmt_remove_uuid(int index, uuid_t *uuid)
-{
- DBG("index %d", index);
- return mgmt_uuid_op(index, MGMT_OP_REMOVE_UUID, uuid);
-}
-
static int mgmt_disable_cod_cache(int index)
{
DBG("index %d", index);
- return -ENOSYS;
+ return mgmt_set_mode(index, MGMT_OP_SET_SERVICE_CACHE, 0);
}
static int mgmt_restore_powered(int index)
diff --git a/src/adapter.c b/src/adapter.c
index 87a8bebc..ab4791c6 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1004,6 +1004,51 @@ static void adapter_emit_uuids_updated(struct btd_adapter *adapter)
g_strfreev(uuids);
}
+static uint8_t get_uuid_mask(uuid_t *uuid)
+{
+ if (uuid->type != SDP_UUID16)
+ return 0;
+
+ switch (uuid->value.uuid16) {
+ case DIALUP_NET_SVCLASS_ID:
+ case CIP_SVCLASS_ID:
+ return 0x42; /* Telephony & Networking */
+ case IRMC_SYNC_SVCLASS_ID:
+ case OBEX_OBJPUSH_SVCLASS_ID:
+ case OBEX_FILETRANS_SVCLASS_ID:
+ case IRMC_SYNC_CMD_SVCLASS_ID:
+ case PBAP_PSE_SVCLASS_ID:
+ return 0x10; /* Object Transfer */
+ case HEADSET_SVCLASS_ID:
+ case HANDSFREE_SVCLASS_ID:
+ return 0x20; /* Audio */
+ case CORDLESS_TELEPHONY_SVCLASS_ID:
+ case INTERCOM_SVCLASS_ID:
+ case FAX_SVCLASS_ID:
+ case SAP_SVCLASS_ID:
+ /*
+ * Setting the telephony bit for the handsfree audio gateway
+ * role is not required by the HFP specification, but the
+ * Nokia 616 carkit is just plain broken! It will refuse
+ * pairing without this bit set.
+ */
+ case HANDSFREE_AGW_SVCLASS_ID:
+ return 0x40; /* Telephony */
+ case AUDIO_SOURCE_SVCLASS_ID:
+ case VIDEO_SOURCE_SVCLASS_ID:
+ return 0x08; /* Capturing */
+ case AUDIO_SINK_SVCLASS_ID:
+ case VIDEO_SINK_SVCLASS_ID:
+ return 0x04; /* Rendering */
+ case PANU_SVCLASS_ID:
+ case NAP_SVCLASS_ID:
+ case GN_SVCLASS_ID:
+ return 0x02; /* Networking */
+ default:
+ return 0;
+ }
+}
+
static int uuid_cmp(const void *a, const void *b)
{
const sdp_record_t *rec = a;
@@ -1025,8 +1070,10 @@ void adapter_service_insert(struct btd_adapter *adapter, void *r)
adapter->services = sdp_list_insert_sorted(adapter->services, rec,
record_sort);
- if (new_uuid)
- adapter_ops->add_uuid(adapter->dev_id, &rec->svclass);
+ if (new_uuid) {
+ uint8_t svc_hint = get_uuid_mask(&rec->svclass);
+ adapter_ops->add_uuid(adapter->dev_id, &rec->svclass, svc_hint);
+ }
adapter_emit_uuids_updated(adapter);
}
diff --git a/src/adapter.h b/src/adapter.h
index 250c65e5..b66be9a8 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -234,7 +234,7 @@ struct btd_adapter_ops {
gpointer user_data);
int (*set_did) (int index, uint16_t vendor, uint16_t product,
uint16_t version);
- int (*add_uuid) (int index, uuid_t *uuid);
+ int (*add_uuid) (int index, uuid_t *uuid, uint8_t svc_hint);
int (*remove_uuid) (int index, uuid_t *uuid);
int (*disable_cod_cache) (int index);
int (*restore_powered) (int index);