1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2010 Nokia Corporation 6 * Copyright (C) 2010 Marcel Holtmann <marcel (at) holtmann.org> 7 * 8 * 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. 13 * 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. 18 * 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 22 * 23 */ 24 25 #include <stdint.h> 26 #include <stdlib.h> 27 #include <glib.h> 28 #include <bluetooth/uuid.h> 29 #include <bluetooth/sdp.h> 30 #include <bluetooth/sdp_lib.h> 31 32 #include "att.h" 33 #include "gattrib.h" 34 #include "gatt.h" 35 36 struct discover_primary { 37 GAttrib *attrib; 38 bt_uuid_t uuid; 39 GSList *primaries; 40 gatt_cb_t cb; 41 void *user_data; 42 }; 43 44 struct discover_char { 45 GAttrib *attrib; 46 bt_uuid_t *uuid; 47 uint16_t end; 48 GSList *characteristics; 49 gatt_cb_t cb; 50 void *user_data; 51 }; 52 53 static void discover_primary_free(struct discover_primary *dp) 54 { 55 g_slist_free(dp->primaries); 56 g_attrib_unref(dp->attrib); 57 g_free(dp); 58 } 59 60 static void discover_char_free(struct discover_char *dc) 61 { 62 g_slist_foreach(dc->characteristics, (GFunc) g_free, NULL); 63 g_slist_free(dc->characteristics); 64 g_attrib_unref(dc->attrib); 65 g_free(dc->uuid); 66 g_free(dc); 67 } 68 69 static guint16 encode_discover_primary(uint16_t start, uint16_t end, 70 bt_uuid_t *uuid, uint8_t *pdu, size_t len) 71 { 72 bt_uuid_t prim; 73 guint16 plen; 74 75 bt_uuid16_create(&prim, GATT_PRIM_SVC_UUID); 76 77 if (uuid == NULL) { 78 /* Discover all primary services */ 79 plen = enc_read_by_grp_req(start, end, &prim, pdu, len); 80 } else { 81 uint16_t u16; 82 uint128_t u128; 83 const void *value; 84 int vlen; 85 86 /* Discover primary service by service UUID */ 87 88 if (uuid->type == BT_UUID16) { 89 u16 = htobs(uuid->value.u16); 90 value = &u16; 91 vlen = sizeof(u16); 92 } else { 93 htob128(&uuid->value.u128, &u128); 94 value = &u128; 95 vlen = sizeof(u128); 96 } 97 98 plen = enc_find_by_type_req(start, end, &prim, value, vlen, 99 pdu, len); 100 } 101 102 return plen; 103 } 104 105 static void primary_by_uuid_cb(guint8 status, const guint8 *ipdu, 106 guint16 iplen, gpointer user_data) 107 108 { 109 struct discover_primary *dp = user_data; 110 GSList *ranges, *last; 111 struct att_range *range; 112 uint8_t *buf; 113 guint16 oplen; 114 int err = 0, buflen; 115 116 if (status) { 117 err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status; 118 goto done; 119 } 120 121 ranges = dec_find_by_type_resp(ipdu, iplen); 122 if (ranges == NULL) 123 goto done; 124 125 dp->primaries = g_slist_concat(dp->primaries, ranges); 126 127 last = g_slist_last(ranges); 128 range = last->data; 129 130 if (range->end == 0xffff) 131 goto done; 132 133 buf = g_attrib_get_buffer(dp->attrib, &buflen); 134 oplen = encode_discover_primary(range->end + 1, 0xffff, &dp->uuid, 135 buf, buflen); 136 137 if (oplen == 0) 138 goto done; 139 140 g_attrib_send(dp->attrib, 0, buf[0], buf, oplen, primary_by_uuid_cb, 141 dp, NULL); 142 return; 143 144 done: 145 dp->cb(dp->primaries, err, dp->user_data); 146 discover_primary_free(dp); 147 } 148 149 static void primary_all_cb(guint8 status, const guint8 *ipdu, guint16 iplen, 150 gpointer user_data) 151 { 152 struct discover_primary *dp = user_data; 153 struct att_data_list *list; 154 unsigned int i, err; 155 uint16_t start, end; 156 157 if (status) { 158 err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status; 159 goto done; 160 } 161 162 list = dec_read_by_grp_resp(ipdu, iplen); 163 if (list == NULL) { 164 err = ATT_ECODE_IO; 165 goto done; 166 } 167 168 for (i = 0, end = 0; i < list->num; i++) { 169 const uint8_t *data = list->data[i]; 170 struct att_primary *primary; 171 bt_uuid_t uuid; 172 173 start = att_get_u16(&data[0]); 174 end = att_get_u16(&data[2]); 175 176 if (list->len == 6) { 177 bt_uuid_t uuid16 = att_get_uuid16(&data[4]); 178 bt_uuid_to_uuid128(&uuid16, &uuid); 179 } else if (list->len == 20) { 180 uuid = att_get_uuid128(&data[4]); 181 } else { 182 /* Skipping invalid data */ 183 continue; 184 } 185 186 primary = g_try_new0(struct att_primary, 1); 187 if (!primary) { 188 err = ATT_ECODE_INSUFF_RESOURCES; 189 goto done; 190 } 191 primary->start = start; 192 primary->end = end; 193 bt_uuid_to_string(&uuid, primary->uuid, sizeof(primary->uuid)); 194 dp->primaries = g_slist_append(dp->primaries, primary); 195 } 196 197 att_data_list_free(list); 198 err = 0; 199 200 if (end != 0xffff) { 201 int buflen; 202 uint8_t *buf = g_attrib_get_buffer(dp->attrib, &buflen); 203 guint16 oplen = encode_discover_primary(end + 1, 0xffff, NULL, 204 buf, buflen); 205 206 g_attrib_send(dp->attrib, 0, buf[0], buf, oplen, primary_all_cb, 207 dp, NULL); 208 209 return; 210 } 211 212 done: 213 dp->cb(dp->primaries, err, dp->user_data); 214 discover_primary_free(dp); 215 } 216 217 guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func, 218 gpointer user_data) 219 { 220 struct discover_primary *dp; 221 int buflen; 222 uint8_t *buf = g_attrib_get_buffer(attrib, &buflen); 223 GAttribResultFunc cb; 224 guint16 plen; 225 226 plen = encode_discover_primary(0x0001, 0xffff, uuid, buf, buflen); 227 if (plen == 0) 228 return 0; 229 230 dp = g_try_new0(struct discover_primary, 1); 231 if (dp == NULL) 232 return 0; 233 234 dp->attrib = g_attrib_ref(attrib); 235 dp->cb = func; 236 dp->user_data = user_data; 237 238 if (uuid) { 239 memcpy(&dp->uuid, uuid, sizeof(bt_uuid_t)); 240 cb = primary_by_uuid_cb; 241 } else 242 cb = primary_all_cb; 243 244 return g_attrib_send(attrib, 0, buf[0], buf, plen, cb, dp, NULL); 245 } 246 247 static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen, 248 gpointer user_data) 249 { 250 struct discover_char *dc = user_data; 251 struct att_data_list *list; 252 unsigned int i, err; 253 int buflen; 254 uint8_t *buf; 255 guint16 oplen; 256 bt_uuid_t uuid; 257 uint16_t last = 0; 258 259 if (status) { 260 err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status; 261 goto done; 262 } 263 264 list = dec_read_by_type_resp(ipdu, iplen); 265 if (list == NULL) { 266 err = ATT_ECODE_IO; 267 goto done; 268 } 269 270 for (i = 0; i < list->num; i++) { 271 uint8_t *value = list->data[i]; 272 struct att_char *chars; 273 bt_uuid_t uuid; 274 275 last = att_get_u16(value); 276 277 if (list->len == 7) { 278 bt_uuid_t uuid16 = att_get_uuid16(&value[5]); 279 bt_uuid_to_uuid128(&uuid16, &uuid); 280 } else 281 uuid = att_get_uuid128(&value[5]); 282 283 chars = g_try_new0(struct att_char, 1); 284 if (!chars) { 285 err = ATT_ECODE_INSUFF_RESOURCES; 286 goto done; 287 } 288 289 if (dc->uuid && bt_uuid_cmp(dc->uuid, &uuid)) 290 break; 291 292 chars->handle = last; 293 chars->properties = value[2]; 294 chars->value_handle = att_get_u16(&value[3]); 295 bt_uuid_to_string(&uuid, chars->uuid, sizeof(chars->uuid)); 296 dc->characteristics = g_slist_append(dc->characteristics, 297 chars); 298 } 299 300 att_data_list_free(list); 301 err = 0; 302 303 if (last != 0) { 304 buf = g_attrib_get_buffer(dc->attrib, &buflen); 305 306 bt_uuid16_create(&uuid, GATT_CHARAC_UUID); 307 308 oplen = enc_read_by_type_req(last + 1, dc->end, &uuid, buf, 309 buflen); 310 311 if (oplen == 0) 312 return; 313 314 g_attrib_send(dc->attrib, 0, buf[0], buf, oplen, 315 char_discovered_cb, dc, NULL); 316 317 return; 318 } 319 320 done: 321 dc->cb(dc->characteristics, err, dc->user_data); 322 discover_char_free(dc); 323 } 324 325 guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end, 326 bt_uuid_t *uuid, gatt_cb_t func, 327 gpointer user_data) 328 { 329 int buflen; 330 uint8_t *buf = g_attrib_get_buffer(attrib, &buflen); 331 struct discover_char *dc; 332 bt_uuid_t type_uuid; 333 guint16 plen; 334 335 bt_uuid16_create(&type_uuid, GATT_CHARAC_UUID); 336 337 plen = enc_read_by_type_req(start, end, &type_uuid, buf, buflen); 338 if (plen == 0) 339 return 0; 340 341 dc = g_try_new0(struct discover_char, 1); 342 if (dc == NULL) 343 return 0; 344 345 dc->attrib = g_attrib_ref(attrib); 346 dc->cb = func; 347 dc->user_data = user_data; 348 dc->end = end; 349 dc->uuid = g_memdup(uuid, sizeof(bt_uuid_t)); 350 351 return g_attrib_send(attrib, 0, buf[0], buf, plen, char_discovered_cb, 352 dc, NULL); 353 } 354 355 guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end, 356 bt_uuid_t *uuid, GAttribResultFunc func, 357 gpointer user_data) 358 { 359 int buflen; 360 uint8_t *buf = g_attrib_get_buffer(attrib, &buflen); 361 guint16 plen; 362 363 plen = enc_read_by_type_req(start, end, uuid, buf, buflen); 364 if (plen == 0) 365 return 0; 366 367 return g_attrib_send(attrib, 0, ATT_OP_READ_BY_TYPE_REQ, 368 buf, plen, func, user_data, NULL); 369 } 370 371 struct read_long_data { 372 GAttrib *attrib; 373 GAttribResultFunc func; 374 gpointer user_data; 375 guint8 *buffer; 376 guint16 size; 377 guint16 handle; 378 guint id; 379 gint ref; 380 }; 381 382 static void read_long_destroy(gpointer user_data) 383 { 384 struct read_long_data *long_read = user_data; 385 386 if (g_atomic_int_dec_and_test(&long_read->ref) == FALSE) 387 return; 388 389 if (long_read->buffer != NULL) 390 g_free(long_read->buffer); 391 392 g_free(long_read); 393 } 394 395 static void read_blob_helper(guint8 status, const guint8 *rpdu, guint16 rlen, 396 gpointer user_data) 397 { 398 struct read_long_data *long_read = user_data; 399 uint8_t *buf; 400 int buflen; 401 guint8 *tmp; 402 guint16 plen; 403 guint id; 404 405 if (status != 0 || rlen == 1) { 406 status = 0; 407 goto done; 408 } 409 410 tmp = g_try_realloc(long_read->buffer, long_read->size + rlen - 1); 411 412 if (tmp == NULL) { 413 status = ATT_ECODE_INSUFF_RESOURCES; 414 goto done; 415 } 416 417 memcpy(&tmp[long_read->size], &rpdu[1], rlen - 1); 418 long_read->buffer = tmp; 419 long_read->size += rlen - 1; 420 421 buf = g_attrib_get_buffer(long_read->attrib, &buflen); 422 if (rlen < buflen) 423 goto done; 424 425 plen = enc_read_blob_req(long_read->handle, long_read->size - 1, 426 buf, buflen); 427 id = g_attrib_send(long_read->attrib, long_read->id, 428 ATT_OP_READ_BLOB_REQ, buf, plen, 429 read_blob_helper, long_read, read_long_destroy); 430 431 if (id != 0) { 432 g_atomic_int_inc(&long_read->ref); 433 return; 434 } 435 436 status = ATT_ECODE_IO; 437 438 done: 439 long_read->func(status, long_read->buffer, long_read->size, 440 long_read->user_data); 441 } 442 443 static void read_char_helper(guint8 status, const guint8 *rpdu, 444 guint16 rlen, gpointer user_data) 445 { 446 struct read_long_data *long_read = user_data; 447 int buflen; 448 uint8_t *buf = g_attrib_get_buffer(long_read->attrib, &buflen); 449 guint16 plen; 450 guint id; 451 452 if (status != 0 || rlen < buflen) 453 goto done; 454 455 long_read->buffer = g_malloc(rlen); 456 457 if (long_read->buffer == NULL) 458 goto done; 459 460 memcpy(long_read->buffer, rpdu, rlen); 461 long_read->size = rlen; 462 463 plen = enc_read_blob_req(long_read->handle, rlen - 1, buf, buflen); 464 id = g_attrib_send(long_read->attrib, long_read->id, 465 ATT_OP_READ_BLOB_REQ, buf, plen, read_blob_helper, 466 long_read, read_long_destroy); 467 468 if (id != 0) { 469 g_atomic_int_inc(&long_read->ref); 470 return; 471 } 472 473 status = ATT_ECODE_IO; 474 475 done: 476 long_read->func(status, rpdu, rlen, long_read->user_data); 477 } 478 479 guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset, 480 GAttribResultFunc func, gpointer user_data) 481 { 482 uint8_t *buf; 483 int buflen; 484 guint16 plen; 485 guint id; 486 struct read_long_data *long_read; 487 488 long_read = g_try_new0(struct read_long_data, 1); 489 490 if (long_read == NULL) 491 return 0; 492 493 long_read->attrib = attrib; 494 long_read->func = func; 495 long_read->user_data = user_data; 496 long_read->handle = handle; 497 498 buf = g_attrib_get_buffer(attrib, &buflen); 499 if (offset > 0) { 500 plen = enc_read_blob_req(long_read->handle, offset, buf, 501 buflen); 502 id = g_attrib_send(attrib, 0, ATT_OP_READ_BLOB_REQ, buf, plen, 503 read_blob_helper, long_read, read_long_destroy); 504 } else { 505 plen = enc_read_req(handle, buf, buflen); 506 id = g_attrib_send(attrib, 0, ATT_OP_READ_REQ, buf, plen, 507 read_char_helper, long_read, read_long_destroy); 508 } 509 510 if (id == 0) 511 g_free(long_read); 512 else { 513 g_atomic_int_inc(&long_read->ref); 514 long_read->id = id; 515 } 516 517 return id; 518 } 519 520 guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value, 521 int vlen, GAttribResultFunc func, gpointer user_data) 522 { 523 uint8_t *buf; 524 int buflen; 525 guint16 plen; 526 527 buf = g_attrib_get_buffer(attrib, &buflen); 528 if (func) 529 plen = enc_write_req(handle, value, vlen, buf, buflen); 530 else 531 plen = enc_write_cmd(handle, value, vlen, buf, buflen); 532 533 return g_attrib_send(attrib, 0, buf[0], buf, plen, func, 534 user_data, NULL); 535 } 536 537 guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func, 538 gpointer user_data) 539 { 540 uint8_t *buf; 541 int buflen; 542 guint16 plen; 543 544 buf = g_attrib_get_buffer(attrib, &buflen); 545 plen = enc_mtu_req(mtu, buf, buflen); 546 return g_attrib_send(attrib, 0, ATT_OP_MTU_REQ, buf, plen, func, 547 user_data, NULL); 548 } 549 550 guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end, 551 GAttribResultFunc func, gpointer user_data) 552 { 553 uint8_t *buf; 554 int buflen; 555 guint16 plen; 556 557 buf = g_attrib_get_buffer(attrib, &buflen); 558 plen = enc_find_info_req(start, end, buf, buflen); 559 if (plen == 0) 560 return 0; 561 562 return g_attrib_send(attrib, 0, ATT_OP_FIND_INFO_REQ, buf, plen, func, 563 user_data, NULL); 564 } 565 566 guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen, 567 GDestroyNotify notify, gpointer user_data) 568 { 569 uint8_t *buf; 570 int buflen; 571 guint16 plen; 572 573 buf = g_attrib_get_buffer(attrib, &buflen); 574 plen = enc_write_cmd(handle, value, vlen, buf, buflen); 575 return g_attrib_send(attrib, 0, ATT_OP_WRITE_CMD, buf, plen, NULL, 576 user_data, notify); 577 } 578 579 static sdp_data_t *proto_seq_find(sdp_list_t *proto_list) 580 { 581 sdp_list_t *list; 582 uuid_t proto; 583 584 sdp_uuid16_create(&proto, ATT_UUID); 585 586 for (list = proto_list; list; list = list->next) { 587 sdp_list_t *p; 588 for (p = list->data; p; p = p->next) { 589 sdp_data_t *seq = p->data; 590 if (seq && seq->dtd == SDP_UUID16 && 591 sdp_uuid16_cmp(&proto, &seq->val.uuid) == 0) 592 return seq->next; 593 } 594 } 595 596 return NULL; 597 } 598 599 static gboolean parse_proto_params(sdp_list_t *proto_list, uint16_t *psm, 600 uint16_t *start, uint16_t *end) 601 { 602 sdp_data_t *seq1, *seq2; 603 604 if (psm) 605 *psm = sdp_get_proto_port(proto_list, L2CAP_UUID); 606 607 /* Getting start and end handle */ 608 seq1 = proto_seq_find(proto_list); 609 if (!seq1 || seq1->dtd != SDP_UINT16) 610 return FALSE; 611 612 seq2 = seq1->next; 613 if (!seq2 || seq2->dtd != SDP_UINT16) 614 return FALSE; 615 616 if (start) 617 *start = seq1->val.uint16; 618 619 if (end) 620 *end = seq2->val.uint16; 621 622 return TRUE; 623 } 624 625 gboolean gatt_parse_record(const sdp_record_t *rec, 626 uuid_t *prim_uuid, uint16_t *psm, 627 uint16_t *start, uint16_t *end) 628 { 629 sdp_list_t *list; 630 uuid_t uuid; 631 gboolean ret; 632 633 if (sdp_get_service_classes(rec, &list) < 0) 634 return FALSE; 635 636 memcpy(&uuid, list->data, sizeof(uuid)); 637 sdp_list_free(list, free); 638 639 if (sdp_get_access_protos(rec, &list) < 0) 640 return FALSE; 641 642 ret = parse_proto_params(list, psm, start, end); 643 644 sdp_list_foreach(list, (sdp_list_func_t) sdp_list_free, NULL); 645 sdp_list_free(list, NULL); 646 647 /* FIXME: replace by bt_uuid_t after uuid_t/sdp code cleanup */ 648 if (ret && prim_uuid) 649 memcpy(prim_uuid, &uuid, sizeof(uuid_t)); 650 651 return ret; 652 } 653