3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2010 Nokia Corporation
6 * Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 #include <bluetooth/uuid.h>
33 struct discover_primary {
41 struct discover_char {
45 GSList *characteristics;
50 static void discover_primary_free(struct discover_primary *dp)
52 g_slist_free(dp->primaries);
53 g_attrib_unref(dp->attrib);
57 static void discover_char_free(struct discover_char *dc)
59 g_slist_foreach(dc->characteristics, (GFunc) g_free, NULL);
60 g_slist_free(dc->characteristics);
61 g_attrib_unref(dc->attrib);
65 static guint16 encode_discover_primary(uint16_t start, uint16_t end,
66 bt_uuid_t *uuid, uint8_t *pdu, size_t len)
72 bt_uuid16_create(&prim, GATT_PRIM_SVC_UUID);
75 /* Discover all primary services */
76 op = ATT_OP_READ_BY_GROUP_REQ;
77 plen = enc_read_by_grp_req(start, end, &prim, pdu, len);
84 /* Discover primary service by service UUID */
85 op = ATT_OP_FIND_BY_TYPE_REQ;
87 if (uuid->type == BT_UUID16) {
88 u16 = htobs(uuid->value.u16);
92 htob128(&uuid->value.u128, &u128);
97 plen = enc_find_by_type_req(start, end, &prim, value, vlen,
104 static void primary_by_uuid_cb(guint8 status, const guint8 *ipdu,
105 guint16 iplen, gpointer user_data)
108 struct discover_primary *dp = user_data;
109 GSList *ranges, *last;
110 struct att_range *range;
111 uint8_t opdu[ATT_DEFAULT_LE_MTU];
116 err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status;
120 ranges = dec_find_by_type_resp(ipdu, iplen);
124 dp->primaries = g_slist_concat(dp->primaries, ranges);
126 last = g_slist_last(ranges);
129 if (range->end == 0xffff)
132 oplen = encode_discover_primary(range->end + 1, 0xffff, &dp->uuid,
138 g_attrib_send(dp->attrib, 0, opdu[0], opdu, oplen, primary_by_uuid_cb,
143 dp->cb(dp->primaries, err, dp->user_data);
144 discover_primary_free(dp);
147 static void primary_all_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
150 struct discover_primary *dp = user_data;
151 struct att_data_list *list;
156 err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status;
160 list = dec_read_by_grp_resp(ipdu, iplen);
166 for (i = 0, end = 0; i < list->num; i++) {
167 const uint8_t *data = list->data[i];
168 struct att_primary *primary;
171 start = att_get_u16(&data[0]);
172 end = att_get_u16(&data[2]);
174 if (list->len == 6) {
175 bt_uuid_t uuid16 = att_get_uuid16(&data[4]);
176 bt_uuid_to_uuid128(&uuid16, &uuid);
177 } else if (list->len == 20) {
178 uuid = att_get_uuid128(&data[4]);
180 /* Skipping invalid data */
184 primary = g_try_new0(struct att_primary, 1);
186 err = ATT_ECODE_INSUFF_RESOURCES;
189 primary->start = start;
191 bt_uuid_to_string(&uuid, primary->uuid, sizeof(primary->uuid));
192 dp->primaries = g_slist_append(dp->primaries, primary);
195 att_data_list_free(list);
199 uint8_t opdu[ATT_DEFAULT_LE_MTU];
200 guint16 oplen = encode_discover_primary(end + 1, 0xffff, NULL,
203 g_attrib_send(dp->attrib, 0, opdu[0], opdu, oplen,
204 primary_all_cb, dp, NULL);
210 dp->cb(dp->primaries, err, dp->user_data);
211 discover_primary_free(dp);
214 guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
217 struct discover_primary *dp;
218 uint8_t pdu[ATT_DEFAULT_LE_MTU];
219 GAttribResultFunc cb;
222 plen = encode_discover_primary(0x0001, 0xffff, uuid, pdu, sizeof(pdu));
226 dp = g_try_new0(struct discover_primary, 1);
230 dp->attrib = g_attrib_ref(attrib);
232 dp->user_data = user_data;
235 memcpy(&dp->uuid, uuid, sizeof(bt_uuid_t));
236 cb = primary_by_uuid_cb;
240 return g_attrib_send(attrib, 0, pdu[0], pdu, plen, cb, dp, NULL);
243 static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
246 struct discover_char *dc = user_data;
247 struct att_data_list *list;
249 uint8_t opdu[ATT_DEFAULT_LE_MTU];
255 err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status;
259 list = dec_read_by_type_resp(ipdu, iplen);
265 for (i = 0; i < list->num; i++) {
266 uint8_t *value = list->data[i];
267 struct att_char *chars;
270 last = att_get_u16(value);
272 if (list->len == 7) {
273 bt_uuid_t uuid16 = att_get_uuid16(&value[5]);
274 bt_uuid_to_uuid128(&uuid16, &uuid);
276 uuid = att_get_uuid128(&value[5]);
278 chars = g_try_new0(struct att_char, 1);
280 err = ATT_ECODE_INSUFF_RESOURCES;
284 chars->handle = last;
285 chars->properties = value[2];
286 chars->value_handle = att_get_u16(&value[3]);
287 bt_uuid_to_string(&uuid, chars->uuid, sizeof(chars->uuid));
288 dc->characteristics = g_slist_append(dc->characteristics,
292 att_data_list_free(list);
296 bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
298 oplen = enc_read_by_type_req(last + 1, dc->end, &uuid, opdu,
304 g_attrib_send(dc->attrib, 0, opdu[0], opdu, oplen,
305 char_discovered_cb, dc, NULL);
311 dc->cb(dc->characteristics, err, dc->user_data);
312 discover_char_free(dc);
315 guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
316 gatt_cb_t func, gpointer user_data)
318 uint8_t pdu[ATT_DEFAULT_LE_MTU];
319 struct discover_char *dc;
323 bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
325 plen = enc_read_by_type_req(start, end, &uuid, pdu, sizeof(pdu));
329 dc = g_try_new0(struct discover_char, 1);
333 dc->attrib = g_attrib_ref(attrib);
335 dc->user_data = user_data;
338 return g_attrib_send(attrib, 0, pdu[0], pdu, plen, char_discovered_cb,
342 guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end,
343 bt_uuid_t *uuid, GAttribResultFunc func,
346 uint8_t pdu[ATT_DEFAULT_LE_MTU];
349 plen = enc_read_by_type_req(start, end, uuid, pdu, sizeof(pdu));
353 return g_attrib_send(attrib, 0, ATT_OP_READ_BY_TYPE_REQ,
354 pdu, plen, func, user_data, NULL);
357 struct read_long_data {
359 GAttribResultFunc func;
368 static void read_long_destroy(gpointer user_data)
370 struct read_long_data *long_read = user_data;
372 if (g_atomic_int_dec_and_test(&long_read->ref) == FALSE)
375 if (long_read->buffer != NULL)
376 g_free(long_read->buffer);
381 static void read_blob_helper(guint8 status, const guint8 *rpdu, guint16 rlen,
384 struct read_long_data *long_read = user_data;
385 uint8_t pdu[ATT_DEFAULT_LE_MTU];
390 if (status != 0 || rlen == 1) {
395 tmp = g_try_realloc(long_read->buffer, long_read->size + rlen - 1);
398 status = ATT_ECODE_INSUFF_RESOURCES;
402 memcpy(&tmp[long_read->size], &rpdu[1], rlen - 1);
403 long_read->buffer = tmp;
404 long_read->size += rlen - 1;
406 if (rlen < ATT_DEFAULT_LE_MTU)
409 plen = enc_read_blob_req(long_read->handle, long_read->size - 1,
411 id = g_attrib_send(long_read->attrib, long_read->id,
412 ATT_OP_READ_BLOB_REQ, pdu, plen,
413 read_blob_helper, long_read, read_long_destroy);
416 g_atomic_int_inc(&long_read->ref);
420 status = ATT_ECODE_IO;
423 long_read->func(status, long_read->buffer, long_read->size,
424 long_read->user_data);
427 static void read_char_helper(guint8 status, const guint8 *rpdu,
428 guint16 rlen, gpointer user_data)
430 struct read_long_data *long_read = user_data;
431 uint8_t pdu[ATT_DEFAULT_LE_MTU];
435 if (status != 0 || rlen < ATT_DEFAULT_LE_MTU)
438 long_read->buffer = g_malloc(rlen);
440 if (long_read->buffer == NULL)
443 memcpy(long_read->buffer, rpdu, rlen);
444 long_read->size = rlen;
446 plen = enc_read_blob_req(long_read->handle, rlen - 1, pdu, sizeof(pdu));
447 id = g_attrib_send(long_read->attrib, long_read->id,
448 ATT_OP_READ_BLOB_REQ, pdu, plen, read_blob_helper,
449 long_read, read_long_destroy);
452 g_atomic_int_inc(&long_read->ref);
456 status = ATT_ECODE_IO;
459 long_read->func(status, rpdu, rlen, long_read->user_data);
462 guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset,
463 GAttribResultFunc func, gpointer user_data)
465 uint8_t pdu[ATT_DEFAULT_LE_MTU];
468 struct read_long_data *long_read;
470 long_read = g_try_new0(struct read_long_data, 1);
472 if (long_read == NULL)
475 long_read->attrib = attrib;
476 long_read->func = func;
477 long_read->user_data = user_data;
478 long_read->handle = handle;
481 plen = enc_read_blob_req(long_read->handle, offset, pdu,
483 id = g_attrib_send(attrib, 0, ATT_OP_READ_BLOB_REQ, pdu, plen,
484 read_blob_helper, long_read, read_long_destroy);
486 plen = enc_read_req(handle, pdu, sizeof(pdu));
487 id = g_attrib_send(attrib, 0, ATT_OP_READ_REQ, pdu, plen,
488 read_char_helper, long_read, read_long_destroy);
494 g_atomic_int_inc(&long_read->ref);
501 guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
502 int vlen, GAttribResultFunc func, gpointer user_data)
504 uint8_t pdu[ATT_DEFAULT_LE_MTU];
508 plen = enc_write_req(handle, value, vlen, pdu, sizeof(pdu));
510 plen = enc_write_cmd(handle, value, vlen, pdu, sizeof(pdu));
512 return g_attrib_send(attrib, 0, pdu[0], pdu, plen, func,
516 guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
517 GAttribResultFunc func, gpointer user_data)
519 uint8_t pdu[ATT_DEFAULT_LE_MTU];
522 plen = enc_find_info_req(start, end, pdu, sizeof(pdu));
526 return g_attrib_send(attrib, 0, ATT_OP_FIND_INFO_REQ, pdu, plen, func,
530 guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,
531 GDestroyNotify notify, gpointer user_data)
533 uint8_t pdu[ATT_DEFAULT_LE_MTU];
536 plen = enc_write_cmd(handle, value, vlen, pdu, sizeof(pdu));
537 return g_attrib_send(attrib, 0, ATT_OP_WRITE_CMD, pdu, plen, NULL,