summaryrefslogtreecommitdiff
path: root/attrib/gatt.c
diff options
context:
space:
mode:
Diffstat (limited to 'attrib/gatt.c')
-rw-r--r--attrib/gatt.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/attrib/gatt.c b/attrib/gatt.c
index f5917db1c..f76661773 100644
--- a/attrib/gatt.c
+++ b/attrib/gatt.c
@@ -73,6 +73,16 @@ struct discover_char {
void *user_data;
};
+struct discover_desc {
+ int ref;
+ GAttrib *attrib;
+ bt_uuid_t *uuid;
+ uint16_t end;
+ GSList *descriptors;
+ gatt_cb_t cb;
+ void *user_data;
+};
+
static void discover_primary_unref(void *data)
{
struct discover_primary *dp = data;
@@ -139,6 +149,28 @@ static struct discover_char *discover_char_ref(struct discover_char *dc)
return dc;
}
+static void discover_desc_unref(void *data)
+{
+ struct discover_desc *dd = data;
+
+ dd->ref--;
+
+ if (dd->ref > 0)
+ return;
+
+ g_slist_free_full(dd->descriptors, g_free);
+ g_attrib_unref(dd->attrib);
+ g_free(dd->uuid);
+ g_free(dd);
+}
+
+static struct discover_desc *discover_desc_ref(struct discover_desc *dd)
+{
+ dd->ref++;
+
+ return dd;
+}
+
static void put_uuid_le(const bt_uuid_t *uuid, void *dst)
{
if (uuid->type == BT_UUID16)
@@ -907,6 +939,120 @@ guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func,
return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
}
+
+static void desc_discovered_cb(guint8 status, const guint8 *ipdu,
+ guint16 iplen, gpointer user_data)
+{
+ struct discover_desc *dd = user_data;
+ struct att_data_list *list;
+ unsigned int i, err = ATT_ECODE_ATTR_NOT_FOUND;
+ guint8 format;
+ uint16_t last = 0xffff;
+ uint8_t type;
+ gboolean uuid_found = FALSE;
+
+ if (status) {
+ err = status;
+ goto done;
+ }
+
+ list = dec_find_info_resp(ipdu, iplen, &format);
+ if (!list) {
+ err = ATT_ECODE_IO;
+ goto done;
+ }
+
+ if (format == ATT_FIND_INFO_RESP_FMT_16BIT)
+ type = BT_UUID16;
+ else
+ type = BT_UUID128;
+
+ for (i = 0; i < list->num; i++) {
+ uint8_t *value = list->data[i];
+ struct gatt_desc *desc;
+ bt_uuid_t uuid128;
+
+ last = get_le16(value);
+
+ get_uuid128(type, &value[2], &uuid128);
+
+ if (dd->uuid) {
+ if (bt_uuid_cmp(dd->uuid, &uuid128))
+ continue;
+ else
+ uuid_found = TRUE;
+ }
+
+ desc = g_try_new0(struct gatt_desc, 1);
+ if (!desc) {
+ att_data_list_free(list);
+ err = ATT_ECODE_INSUFF_RESOURCES;
+ goto done;
+ }
+
+ bt_uuid_to_string(&uuid128, desc->uuid, sizeof(desc->uuid));
+ desc->handle = last;
+
+ if (type == BT_UUID16)
+ desc->uuid16 = get_le16(&value[2]);
+
+ dd->descriptors = g_slist_append(dd->descriptors, desc);
+
+ if (uuid_found)
+ break;
+ }
+
+ att_data_list_free(list);
+
+ if (last + 1 < dd->end && !uuid_found) {
+ guint16 oplen;
+ size_t buflen;
+ uint8_t *buf;
+
+ buf = g_attrib_get_buffer(dd->attrib, &buflen);
+
+ oplen = enc_find_info_req(last + 1, dd->end, buf, buflen);
+ if (oplen == 0)
+ return;
+
+ g_attrib_send(dd->attrib, 0, buf, oplen, desc_discovered_cb,
+ discover_desc_ref(dd), discover_desc_unref);
+
+ return;
+ }
+
+done:
+ err = (dd->descriptors ? 0 : err);
+ dd->cb(err, dd->descriptors, dd->user_data);
+}
+
+guint gatt_discover_desc(GAttrib *attrib, uint16_t start, uint16_t end,
+ bt_uuid_t *uuid, gatt_cb_t func,
+ gpointer user_data)
+{
+ size_t buflen;
+ uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
+ struct discover_desc *dd;
+ guint16 plen;
+
+ plen = enc_find_info_req(start, end, buf, buflen);
+ if (plen == 0)
+ return 0;
+
+ dd = g_try_new0(struct discover_desc, 1);
+ if (dd == NULL)
+ return 0;
+
+ dd->attrib = g_attrib_ref(attrib);
+ dd->cb = func;
+ dd->user_data = user_data;
+ dd->end = end;
+ dd->uuid = g_memdup(uuid, sizeof(bt_uuid_t));
+
+ return g_attrib_send(attrib, 0, buf, plen, desc_discovered_cb,
+ discover_desc_ref(dd), discover_desc_unref);
+}
+
guint gatt_discover_char_desc(GAttrib *attrib, uint16_t start, uint16_t end,
GAttribResultFunc func, gpointer user_data)
{