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 <string.h> 27 #include <glib.h> 28 29 #include <stdio.h> 30 31 #include <bluetooth/bluetooth.h> 32 #include <bluetooth/uuid.h> 33 34 #include "att.h" 35 #include "btio.h" 36 #include "gattrib.h" 37 38 #define GATT_TIMEOUT 30 39 40 struct _GAttrib { 41 GIOChannel *io; 42 gint refs; 43 uint8_t *buf; 44 int buflen; 45 guint read_watch; 46 guint write_watch; 47 guint timeout_watch; 48 GQueue *queue; 49 GSList *events; 50 guint next_cmd_id; 51 guint next_evt_id; 52 GDestroyNotify destroy; 53 GAttribDisconnectFunc disconnect; 54 gpointer destroy_user_data; 55 gpointer disc_user_data; 56 }; 57 58 struct command { 59 guint id; 60 guint8 opcode; 61 guint8 *pdu; 62 guint16 len; 63 guint8 expected; 64 gboolean sent; 65 GAttribResultFunc func; 66 gpointer user_data; 67 GDestroyNotify notify; 68 }; 69 70 struct event { 71 guint id; 72 guint8 expected; 73 GAttribNotifyFunc func; 74 gpointer user_data; 75 GDestroyNotify notify; 76 }; 77 78 static guint8 opcode2expected(guint8 opcode) 79 { 80 switch (opcode) { 81 case ATT_OP_MTU_REQ: 82 return ATT_OP_MTU_RESP; 83 84 case ATT_OP_FIND_INFO_REQ: 85 return ATT_OP_FIND_INFO_RESP; 86 87 case ATT_OP_FIND_BY_TYPE_REQ: 88 return ATT_OP_FIND_BY_TYPE_RESP; 89 90 case ATT_OP_READ_BY_TYPE_REQ: 91 return ATT_OP_READ_BY_TYPE_RESP; 92 93 case ATT_OP_READ_REQ: 94 return ATT_OP_READ_RESP; 95 96 case ATT_OP_READ_BLOB_REQ: 97 return ATT_OP_READ_BLOB_RESP; 98 99 case ATT_OP_READ_MULTI_REQ: 100 return ATT_OP_READ_MULTI_RESP; 101 102 case ATT_OP_READ_BY_GROUP_REQ: 103 return ATT_OP_READ_BY_GROUP_RESP; 104 105 case ATT_OP_WRITE_REQ: 106 return ATT_OP_WRITE_RESP; 107 108 case ATT_OP_PREP_WRITE_REQ: 109 return ATT_OP_PREP_WRITE_RESP; 110 111 case ATT_OP_EXEC_WRITE_REQ: 112 return ATT_OP_EXEC_WRITE_RESP; 113 114 case ATT_OP_HANDLE_IND: 115 return ATT_OP_HANDLE_CNF; 116 } 117 118 return 0; 119 } 120 121 static gboolean is_response(guint8 opcode) 122 { 123 switch (opcode) { 124 case ATT_OP_ERROR: 125 case ATT_OP_MTU_RESP: 126 case ATT_OP_FIND_INFO_RESP: 127 case ATT_OP_FIND_BY_TYPE_RESP: 128 case ATT_OP_READ_BY_TYPE_RESP: 129 case ATT_OP_READ_RESP: 130 case ATT_OP_READ_BLOB_RESP: 131 case ATT_OP_READ_MULTI_RESP: 132 case ATT_OP_READ_BY_GROUP_RESP: 133 case ATT_OP_WRITE_RESP: 134 case ATT_OP_PREP_WRITE_RESP: 135 case ATT_OP_EXEC_WRITE_RESP: 136 case ATT_OP_HANDLE_CNF: 137 return TRUE; 138 } 139 140 return FALSE; 141 } 142 143 GAttrib *g_attrib_ref(GAttrib *attrib) 144 { 145 if (!attrib) 146 return NULL; 147 148 g_atomic_int_inc(&attrib->refs); 149 150 return attrib; 151 } 152 153 static void command_destroy(struct command *cmd) 154 { 155 if (cmd->notify) 156 cmd->notify(cmd->user_data); 157 158 g_free(cmd->pdu); 159 g_free(cmd); 160 } 161 162 static void event_destroy(struct event *evt) 163 { 164 if (evt->notify) 165 evt->notify(evt->user_data); 166 167 g_free(evt); 168 } 169 170 static void attrib_destroy(GAttrib *attrib) 171 { 172 GSList *l; 173 struct command *c; 174 175 while ((c = g_queue_pop_head(attrib->queue))) 176 command_destroy(c); 177 178 g_queue_free(attrib->queue); 179 attrib->queue = NULL; 180 181 for (l = attrib->events; l; l = l->next) 182 event_destroy(l->data); 183 184 g_slist_free(attrib->events); 185 attrib->events = NULL; 186 187 if (attrib->timeout_watch > 0) 188 g_source_remove(attrib->timeout_watch); 189 190 if (attrib->write_watch > 0) 191 g_source_remove(attrib->write_watch); 192 193 if (attrib->read_watch > 0) { 194 g_source_remove(attrib->read_watch); 195 g_io_channel_unref(attrib->io); 196 } 197 198 g_free(attrib->buf); 199 200 if (attrib->destroy) 201 attrib->destroy(attrib->destroy_user_data); 202 203 g_free(attrib); 204 } 205 206 void g_attrib_unref(GAttrib *attrib) 207 { 208 if (!attrib) 209 return; 210 211 if (g_atomic_int_dec_and_test(&attrib->refs) == FALSE) 212 return; 213 214 attrib_destroy(attrib); 215 } 216 217 GIOChannel *g_attrib_get_channel(GAttrib *attrib) 218 { 219 if (!attrib) 220 return NULL; 221 222 return attrib->io; 223 } 224 225 gboolean g_attrib_set_disconnect_function(GAttrib *attrib, 226 GAttribDisconnectFunc disconnect, gpointer user_data) 227 { 228 if (attrib == NULL) 229 return FALSE; 230 231 attrib->disconnect = disconnect; 232 attrib->disc_user_data = user_data; 233 234 return TRUE; 235 } 236 237 gboolean g_attrib_set_destroy_function(GAttrib *attrib, 238 GDestroyNotify destroy, gpointer user_data) 239 { 240 if (attrib == NULL) 241 return FALSE; 242 243 attrib->destroy = destroy; 244 attrib->destroy_user_data = user_data; 245 246 return TRUE; 247 } 248 249 static gboolean disconnect_timeout(gpointer data) 250 { 251 struct _GAttrib *attrib = data; 252 253 attrib_destroy(attrib); 254 255 return FALSE; 256 } 257 258 static gboolean can_write_data(GIOChannel *io, GIOCondition cond, 259 gpointer data) 260 { 261 struct _GAttrib *attrib = data; 262 struct command *cmd; 263 GError *gerr = NULL; 264 gsize len; 265 GIOStatus iostat; 266 267 if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) { 268 if (attrib->disconnect) 269 attrib->disconnect(attrib->disc_user_data); 270 271 return FALSE; 272 } 273 274 cmd = g_queue_peek_head(attrib->queue); 275 if (cmd == NULL) 276 return FALSE; 277 278 iostat = g_io_channel_write_chars(io, (gchar *) cmd->pdu, cmd->len, 279 &len, &gerr); 280 if (iostat != G_IO_STATUS_NORMAL) 281 return FALSE; 282 283 if (cmd->expected == 0) { 284 g_queue_pop_head(attrib->queue); 285 command_destroy(cmd); 286 287 return TRUE; 288 } 289 290 cmd->sent = TRUE; 291 292 if (attrib->timeout_watch == 0) 293 attrib->timeout_watch = g_timeout_add_seconds(GATT_TIMEOUT, 294 disconnect_timeout, attrib); 295 296 return FALSE; 297 } 298 299 static void destroy_sender(gpointer data) 300 { 301 struct _GAttrib *attrib = data; 302 303 attrib->write_watch = 0; 304 } 305 306 static void wake_up_sender(struct _GAttrib *attrib) 307 { 308 if (attrib->write_watch == 0) 309 attrib->write_watch = g_io_add_watch_full(attrib->io, 310 G_PRIORITY_DEFAULT, G_IO_OUT, can_write_data, 311 attrib, destroy_sender); 312 } 313 314 static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data) 315 { 316 struct _GAttrib *attrib = data; 317 struct command *cmd = NULL; 318 GSList *l; 319 uint8_t buf[512], status; 320 gsize len; 321 GIOStatus iostat; 322 gboolean qempty; 323 324 if (attrib->timeout_watch > 0) { 325 g_source_remove(attrib->timeout_watch); 326 attrib->timeout_watch = 0; 327 } 328 329 if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) { 330 attrib->read_watch = 0; 331 if (attrib->disconnect) 332 attrib->disconnect(attrib->disc_user_data); 333 return FALSE; 334 } 335 336 memset(buf, 0, sizeof(buf)); 337 338 iostat = g_io_channel_read_chars(io, (gchar *) buf, sizeof(buf), 339 &len, NULL); 340 if (iostat != G_IO_STATUS_NORMAL) { 341 status = ATT_ECODE_IO; 342 goto done; 343 } 344 345 for (l = attrib->events; l; l = l->next) { 346 struct event *evt = l->data; 347 348 if (evt->expected == buf[0] || 349 evt->expected == GATTRIB_ALL_EVENTS) 350 evt->func(buf, len, evt->user_data); 351 } 352 353 if (is_response(buf[0]) == FALSE) 354 return TRUE; 355 356 cmd = g_queue_pop_head(attrib->queue); 357 if (cmd == NULL) { 358 /* Keep the watch if we have events to report */ 359 return attrib->events != NULL; 360 } 361 362 if (buf[0] == ATT_OP_ERROR) { 363 status = buf[4]; 364 goto done; 365 } 366 367 if (cmd->expected != buf[0]) { 368 status = ATT_ECODE_IO; 369 goto done; 370 } 371 372 status = 0; 373 374 done: 375 qempty = attrib->queue == NULL || g_queue_is_empty(attrib->queue); 376 377 if (cmd) { 378 if (cmd->func) 379 cmd->func(status, buf, len, cmd->user_data); 380 381 command_destroy(cmd); 382 } 383 384 if (!qempty) 385 wake_up_sender(attrib); 386 387 return TRUE; 388 } 389 390 GAttrib *g_attrib_new(GIOChannel *io) 391 { 392 struct _GAttrib *attrib; 393 uint16_t omtu; 394 395 g_io_channel_set_encoding(io, NULL, NULL); 396 g_io_channel_set_buffered(io, FALSE); 397 398 attrib = g_try_new0(struct _GAttrib, 1); 399 if (attrib == NULL) 400 return NULL; 401 402 attrib->io = g_io_channel_ref(io); 403 attrib->queue = g_queue_new(); 404 405 attrib->read_watch = g_io_add_watch(attrib->io, 406 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, 407 received_data, attrib); 408 409 if (bt_io_get(attrib->io, BT_IO_L2CAP, NULL, 410 BT_IO_OPT_OMTU, &omtu, 411 BT_IO_OPT_INVALID)) { 412 if (omtu == 0 || omtu > ATT_MAX_MTU) 413 omtu = ATT_MAX_MTU; 414 } else 415 omtu = ATT_DEFAULT_LE_MTU; 416 417 attrib->buf = g_malloc0(omtu); 418 attrib->buflen = omtu; 419 420 return g_attrib_ref(attrib); 421 } 422 423 guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode, 424 const guint8 *pdu, guint16 len, GAttribResultFunc func, 425 gpointer user_data, GDestroyNotify notify) 426 { 427 struct command *c; 428 429 c = g_try_new0(struct command, 1); 430 if (c == NULL) 431 return 0; 432 433 c->opcode = opcode; 434 c->expected = opcode2expected(opcode); 435 c->pdu = g_malloc(len); 436 memcpy(c->pdu, pdu, len); 437 c->len = len; 438 c->func = func; 439 c->user_data = user_data; 440 c->notify = notify; 441 442 if (id) { 443 c->id = id; 444 g_queue_push_head(attrib->queue, c); 445 } else { 446 c->id = ++attrib->next_cmd_id; 447 g_queue_push_tail(attrib->queue, c); 448 } 449 450 if (g_queue_get_length(attrib->queue) == 1) 451 wake_up_sender(attrib); 452 453 return c->id; 454 } 455 456 static gint command_cmp_by_id(gconstpointer a, gconstpointer b) 457 { 458 const struct command *cmd = a; 459 guint id = GPOINTER_TO_UINT(b); 460 461 return cmd->id - id; 462 } 463 464 gboolean g_attrib_cancel(GAttrib *attrib, guint id) 465 { 466 GList *l; 467 struct command *cmd; 468 469 if (attrib == NULL || attrib->queue == NULL) 470 return FALSE; 471 472 l = g_queue_find_custom(attrib->queue, GUINT_TO_POINTER(id), 473 command_cmp_by_id); 474 if (l == NULL) 475 return FALSE; 476 477 cmd = l->data; 478 479 if (cmd == g_queue_peek_head(attrib->queue) && cmd->sent) 480 cmd->func = NULL; 481 else { 482 g_queue_remove(attrib->queue, cmd); 483 command_destroy(cmd); 484 } 485 486 return TRUE; 487 } 488 489 gboolean g_attrib_cancel_all(GAttrib *attrib) 490 { 491 struct command *c, *head = NULL; 492 gboolean first = TRUE; 493 494 if (attrib == NULL || attrib->queue == NULL) 495 return FALSE; 496 497 while ((c = g_queue_pop_head(attrib->queue))) { 498 if (first && c->sent) { 499 /* If the command was sent ignore its callback ... */ 500 c->func = NULL; 501 head = c; 502 continue; 503 } 504 505 first = FALSE; 506 command_destroy(c); 507 } 508 509 if (head) { 510 /* ... and put it back in the queue */ 511 g_queue_push_head(attrib->queue, head); 512 } 513 514 return TRUE; 515 } 516 517 gboolean g_attrib_set_debug(GAttrib *attrib, 518 GAttribDebugFunc func, gpointer user_data) 519 { 520 return TRUE; 521 } 522 523 uint8_t *g_attrib_get_buffer(GAttrib *attrib, int *len) 524 { 525 if (len == NULL) 526 return NULL; 527 528 *len = attrib->buflen; 529 530 return attrib->buf; 531 } 532 533 gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu) 534 { 535 if (mtu < ATT_DEFAULT_LE_MTU) 536 mtu = ATT_DEFAULT_LE_MTU; 537 538 if (mtu > ATT_MAX_MTU) 539 mtu = ATT_MAX_MTU; 540 541 if (!bt_io_set(attrib->io, BT_IO_L2CAP, NULL, 542 BT_IO_OPT_OMTU, mtu, 543 BT_IO_OPT_INVALID)) 544 return FALSE; 545 546 attrib->buf = g_realloc(attrib->buf, mtu); 547 548 attrib->buflen = mtu; 549 550 return TRUE; 551 } 552 553 guint g_attrib_register(GAttrib *attrib, guint8 opcode, 554 GAttribNotifyFunc func, gpointer user_data, 555 GDestroyNotify notify) 556 { 557 struct event *event; 558 559 event = g_try_new0(struct event, 1); 560 if (event == NULL) 561 return 0; 562 563 event->expected = opcode; 564 event->func = func; 565 event->user_data = user_data; 566 event->notify = notify; 567 event->id = ++attrib->next_evt_id; 568 569 attrib->events = g_slist_append(attrib->events, event); 570 571 return event->id; 572 } 573 574 static gint event_cmp_by_id(gconstpointer a, gconstpointer b) 575 { 576 const struct event *evt = a; 577 guint id = GPOINTER_TO_UINT(b); 578 579 return evt->id - id; 580 } 581 582 gboolean g_attrib_is_encrypted(GAttrib *attrib) 583 { 584 BtIOSecLevel sec_level; 585 586 if (!bt_io_get(attrib->io, BT_IO_L2CAP, NULL, 587 BT_IO_OPT_SEC_LEVEL, &sec_level, 588 BT_IO_OPT_INVALID)) 589 return FALSE; 590 591 return sec_level > BT_IO_SEC_LOW; 592 } 593 594 gboolean g_attrib_unregister(GAttrib *attrib, guint id) 595 { 596 struct event *evt; 597 GSList *l; 598 599 l = g_slist_find_custom(attrib->events, GUINT_TO_POINTER(id), 600 event_cmp_by_id); 601 if (l == NULL) 602 return FALSE; 603 604 evt = l->data; 605 606 attrib->events = g_slist_remove(attrib->events, evt); 607 608 if (evt->notify) 609 evt->notify(evt->user_data); 610 611 g_free(evt); 612 613 return TRUE; 614 } 615 616 gboolean g_attrib_unregister_all(GAttrib *attrib) 617 { 618 GSList *l; 619 620 if (attrib->events == NULL) 621 return FALSE; 622 623 for (l = attrib->events; l; l = l->next) { 624 struct event *evt = l->data; 625 626 if (evt->notify) 627 evt->notify(evt->user_data); 628 629 g_free(evt); 630 } 631 632 g_slist_free(attrib->events); 633 attrib->events = NULL; 634 635 return TRUE; 636 } 637