mcap.c revision f47ef246ff038ee8ec823bb7a0329135b32b9513
1/* 2 * 3 * MCAP for BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. 6 * 7 * Authors: 8 * Santiago Carot-Nemesio <sancane at gmail.com> 9 * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com> 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 * 25 */ 26 27#include "log.h" 28#include "error.h" 29 30#include <netinet/in.h> 31#include <stdlib.h> 32#include <errno.h> 33#include <unistd.h> 34 35#include "btio.h" 36#include <bluetooth/bluetooth.h> 37#include <bluetooth/l2cap.h> 38#include "mcap.h" 39#include "mcap_lib.h" 40#include "mcap_internal.h" 41 42#define RESPONSE_TIMER 6 /* seconds */ 43#define MAX_CACHED 10 /* 10 devices */ 44 45#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark") 46 47#define RELEASE_TIMER(__mcl) do { \ 48 g_source_remove(__mcl->tid); \ 49 __mcl->tid = 0; \ 50} while(0) 51 52struct connect_mcl { 53 struct mcap_mcl *mcl; /* MCL for this operation */ 54 mcap_mcl_connect_cb connect_cb; /* Connect callback */ 55 gpointer user_data; /* Callback user data */ 56}; 57 58typedef union { 59 mcap_mdl_operation_cb op; 60 mcap_mdl_operation_conf_cb op_conf; 61 mcap_mdl_notify_cb notify; 62} mcap_cb_type; 63 64struct mcap_mdl_op_cb { 65 struct mcap_mdl *mdl; /* MDL for this operation */ 66 mcap_cb_type cb; /* Operation callback */ 67 gpointer user_data; /* Callback user data */ 68}; 69 70/* MCAP finite state machine functions */ 71static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l); 72static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l); 73static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l); 74 75static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = { 76 proc_req_connected, 77 proc_req_pending, 78 proc_req_active 79}; 80 81static void mcap_cache_mcl(struct mcap_mcl *mcl); 82 83static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data) 84{ 85 DBG("MCAP Unmanaged mdl connection"); 86} 87 88static void default_mdl_closed_cb(struct mcap_mdl *mdl, gpointer data) 89{ 90 DBG("MCAP Unmanaged mdl closed"); 91} 92 93static void default_mdl_deleted_cb(struct mcap_mdl *mdl, gpointer data) 94{ 95 DBG("MCAP Unmanaged mdl deleted"); 96} 97 98static void default_mdl_aborted_cb(struct mcap_mdl *mdl, gpointer data) 99{ 100 DBG("MCAP Unmanaged mdl aborted"); 101} 102 103static uint8_t default_mdl_conn_req_cb(struct mcap_mcl *mcl, 104 uint8_t mdepid, uint16_t mdlid, 105 uint8_t *conf, gpointer data) 106{ 107 DBG("MCAP mdl remote connection aborted"); 108 /* Due to this callback isn't managed this request won't be supported */ 109 return MCAP_REQUEST_NOT_SUPPORTED; 110} 111 112static uint8_t default_mdl_reconn_req_cb(struct mcap_mdl *mdl, 113 gpointer data) 114{ 115 DBG("MCAP mdl remote reconnection aborted"); 116 /* Due to this callback isn't managed this request won't be supported */ 117 return MCAP_REQUEST_NOT_SUPPORTED; 118} 119 120static void set_default_cb(struct mcap_mcl *mcl) 121{ 122 if (!mcl->cb) 123 mcl->cb = g_new0(struct mcap_mdl_cb, 1); 124 125 mcl->cb->mdl_connected = default_mdl_connected_cb; 126 mcl->cb->mdl_closed = default_mdl_closed_cb; 127 mcl->cb->mdl_deleted = default_mdl_deleted_cb; 128 mcl->cb->mdl_aborted = default_mdl_aborted_cb; 129 mcl->cb->mdl_conn_req = default_mdl_conn_req_cb; 130 mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb; 131} 132 133static char *error2str(uint8_t rc) 134{ 135 switch (rc) { 136 case MCAP_SUCCESS: 137 return "Success"; 138 case MCAP_INVALID_OP_CODE: 139 return "Invalid Op Code"; 140 case MCAP_INVALID_PARAM_VALUE: 141 return "Invalid Parameter Value"; 142 case MCAP_INVALID_MDEP: 143 return "Invalid MDEP"; 144 case MCAP_MDEP_BUSY: 145 return "MDEP Busy"; 146 case MCAP_INVALID_MDL: 147 return "Invalid MDL"; 148 case MCAP_MDL_BUSY: 149 return "MDL Busy"; 150 case MCAP_INVALID_OPERATION: 151 return "Invalid Operation"; 152 case MCAP_RESOURCE_UNAVAILABLE: 153 return "Resource Unavailable"; 154 case MCAP_UNSPECIFIED_ERROR: 155 return "Unspecified Error"; 156 case MCAP_REQUEST_NOT_SUPPORTED: 157 return "Request Not Supported"; 158 case MCAP_CONFIGURATION_REJECTED: 159 return "Configuration Rejected"; 160 default: 161 return "Unknown Response Code"; 162 } 163} 164 165static gboolean mcap_send_std_opcode(struct mcap_mcl *mcl, void *cmd, 166 uint32_t size, GError **err) 167{ 168 if (mcl->state == MCL_IDLE) { 169 g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED, 170 "MCL is not connected"); 171 return FALSE; 172 } 173 174 if (mcl->req != MCL_AVAILABLE) { 175 g_set_error(err, MCAP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE, 176 "Pending request"); 177 return FALSE; 178 } 179 180 if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) { 181 g_set_error(err, MCAP_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED, 182 "Remote does not support standard opcodes"); 183 return FALSE; 184 } 185 186 if (mcl->state == MCL_PENDING) { 187 g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_OPERATION, 188 "Not Std Op. Codes can be sent in PENDING State"); 189 return FALSE; 190 } 191 192 if (mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), cmd, size) < 0) { 193 g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED, 194 "Command can't be sent, write error"); 195 return FALSE; 196 } 197 198 mcl->lcmd = cmd; 199 mcl->req = MCL_WAITING_RSP; 200 201 return TRUE; 202} 203 204static void update_mcl_state(struct mcap_mcl *mcl) 205{ 206 GSList *l; 207 struct mcap_mdl *mdl; 208 209 if (mcl->state == MCL_PENDING) 210 return; 211 212 for (l = mcl->mdls; l; l = l->next) { 213 mdl = l->data; 214 215 if (mdl->state == MDL_CONNECTED) { 216 mcl->state = MCL_ACTIVE; 217 return; 218 } 219 } 220 221 mcl->state = MCL_CONNECTED; 222} 223 224static void shutdown_mdl(struct mcap_mdl *mdl) 225{ 226 mdl->state = MDL_CLOSED; 227 228 g_source_remove(mdl->wid); 229 230 if (mdl->dc) { 231 g_io_channel_shutdown(mdl->dc, TRUE, NULL); 232 g_io_channel_unref(mdl->dc); 233 mdl->dc = NULL; 234 } 235} 236 237static gint cmp_mdl_state(gconstpointer a, gconstpointer b) 238{ 239 const struct mcap_mdl *mdl = a; 240 const MDLState *st = b; 241 242 if (mdl->state == *st) 243 return 0; 244 else if (mdl->state < *st) 245 return -1; 246 else 247 return 1; 248} 249 250static void mcap_notify_error(struct mcap_mcl *mcl, GError *err) 251{ 252 struct mcap_mdl_op_cb *con = mcl->priv_data; 253 struct mcap_mdl *mdl; 254 MDLState st; 255 GSList *l; 256 257 if (!con || !mcl->lcmd) 258 return; 259 260 switch (mcl->lcmd[0]) { 261 case MCAP_MD_CREATE_MDL_REQ: 262 st = MDL_WAITING; 263 l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state); 264 mdl = l->data; 265 mcl->mdls = g_slist_remove(mcl->mdls, mdl); 266 g_free(mdl); 267 update_mcl_state(mcl); 268 con->cb.op_conf(NULL, 0, err, con->user_data); 269 break; 270 case MCAP_MD_ABORT_MDL_REQ: 271 st = MDL_WAITING; 272 l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state); 273 shutdown_mdl(l->data); 274 update_mcl_state(mcl); 275 con->cb.notify(err, con->user_data); 276 break; 277 case MCAP_MD_DELETE_MDL_REQ: 278 for (l = mcl->mdls; l; l = l->next) { 279 mdl = l->data; 280 if (mdl->state == MDL_DELETING) 281 mdl->state = (mdl->dc) ? MDL_CONNECTED : 282 MDL_CLOSED; 283 } 284 update_mcl_state(mcl); 285 con->cb.notify(err, con->user_data); 286 break; 287 case MCAP_MD_RECONNECT_MDL_REQ: 288 st = MDL_WAITING; 289 l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state); 290 shutdown_mdl(l->data); 291 update_mcl_state(mcl); 292 con->cb.op(NULL, err, con->user_data); 293 break; 294 } 295 296 g_free(mcl->priv_data); 297 mcl->priv_data = NULL; 298 299 g_free(mcl->lcmd); 300 mcl->lcmd = NULL; 301} 302 303int mcap_send_data(int sock, const uint8_t *buf, uint32_t size) 304{ 305 uint32_t sent = 0; 306 307 while (sent < size) { 308 int n = write(sock, buf + sent, size - sent); 309 if (n < 0) 310 return -1; 311 sent += n; 312 } 313 314 return 0; 315} 316 317static int mcap_send_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc, 318 uint16_t mdl, uint8_t *data, size_t len) 319{ 320 mcap_rsp *cmd; 321 uint8_t *rsp; 322 int sock, sent; 323 324 if (mcl->cc == NULL) 325 return -1; 326 327 sock = g_io_channel_unix_get_fd(mcl->cc); 328 329 rsp = g_malloc(sizeof(mcap_rsp) + len); 330 cmd = (mcap_rsp *) rsp; 331 cmd->op = oc; 332 cmd->rc = rc; 333 cmd->mdl = htons(mdl); 334 335 if (data && len > 0) 336 memcpy(rsp + sizeof(mcap_rsp), data, len); 337 338 sent = mcap_send_data(sock, rsp, sizeof(mcap_rsp) + len); 339 g_free(rsp); 340 341 return sent; 342} 343 344static struct mcap_mdl *get_mdl(struct mcap_mcl *mcl, uint16_t mdlid) 345{ 346 GSList *l; 347 struct mcap_mdl *mdl; 348 349 for (l = mcl->mdls; l; l = l->next) { 350 mdl = l->data; 351 if (mdlid == mdl->mdlid) 352 return mdl; 353 } 354 355 return NULL; 356} 357 358static uint16_t generate_mdlid(struct mcap_mcl *mcl) 359{ 360 uint16_t mdlid = mcl->next_mdl; 361 struct mcap_mdl *mdl; 362 363 do { 364 mdl = get_mdl(mcl, mdlid); 365 if (!mdl) { 366 mcl->next_mdl = (mdlid % MCAP_MDLID_FINAL) + 1; 367 return mdlid; 368 } else 369 mdlid = (mdlid % MCAP_MDLID_FINAL) + 1; 370 } while (mdlid != mcl->next_mdl); 371 372 /* No more mdlids availables */ 373 return 0; 374} 375 376static mcap_md_req *create_req(uint8_t op, uint16_t mdl_id) 377{ 378 mcap_md_req *req_cmd; 379 380 req_cmd = g_new0(mcap_md_req, 1); 381 382 req_cmd->op = op; 383 req_cmd->mdl = htons(mdl_id); 384 385 return req_cmd; 386} 387 388static mcap_md_create_mdl_req *create_mdl_req(uint16_t mdl_id, uint8_t mdep, 389 uint8_t conf) 390{ 391 mcap_md_create_mdl_req *req_mdl; 392 393 req_mdl = g_new0(mcap_md_create_mdl_req, 1); 394 395 req_mdl->op = MCAP_MD_CREATE_MDL_REQ; 396 req_mdl->mdl = htons(mdl_id); 397 req_mdl->mdep = mdep; 398 req_mdl->conf = conf; 399 400 return req_mdl; 401} 402 403static gint compare_mdl(gconstpointer a, gconstpointer b) 404{ 405 const struct mcap_mdl *mdla = a; 406 const struct mcap_mdl *mdlb = b; 407 408 if (mdla->mdlid == mdlb->mdlid) 409 return 0; 410 else if (mdla->mdlid < mdlb->mdlid) 411 return -1; 412 else 413 return 1; 414} 415 416static gboolean wait_response_timer(gpointer data) 417{ 418 struct mcap_mcl *mcl = data; 419 420 GError *gerr = NULL; 421 422 RELEASE_TIMER(mcl); 423 424 g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED, 425 "Timeout waiting response"); 426 427 mcap_notify_error(mcl, gerr); 428 429 g_error_free(gerr); 430 mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data); 431 mcap_cache_mcl(mcl); 432 433 return FALSE; 434} 435 436gboolean mcap_create_mdl(struct mcap_mcl *mcl, 437 uint8_t mdepid, 438 uint8_t conf, 439 mcap_mdl_operation_conf_cb connect_cb, 440 gpointer user_data, 441 GError **err) 442{ 443 struct mcap_mdl *mdl; 444 struct mcap_mdl_op_cb *con; 445 mcap_md_create_mdl_req *cmd; 446 uint16_t id; 447 448 id = generate_mdlid(mcl); 449 if (!id) { 450 g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED, 451 "Not more mdlids available"); 452 return FALSE; 453 } 454 455 mdl = g_new0(struct mcap_mdl, 1); 456 mdl->mcl = mcl; 457 mdl->mdlid = id; 458 mdl->mdep_id = mdepid; 459 mdl->state = MDL_WAITING; 460 461 con = g_new0(struct mcap_mdl_op_cb, 1); 462 con->mdl = mdl; 463 con->cb.op_conf = connect_cb; 464 con->user_data = user_data; 465 466 cmd = create_mdl_req(id, mdepid, conf); 467 if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_create_mdl_req), 468 err)) { 469 g_free(mdl); 470 g_free(con); 471 g_free(cmd); 472 return FALSE; 473 } 474 475 mcl->state = MCL_ACTIVE; 476 mcl->priv_data = con; 477 478 mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl); 479 mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer, 480 mcl); 481 return TRUE; 482} 483 484gboolean mcap_reconnect_mdl(struct mcap_mdl *mdl, 485 mcap_mdl_operation_cb reconnect_cb, 486 gpointer user_data, 487 GError **err) 488{ 489 struct mcap_mdl_op_cb *con; 490 struct mcap_mcl *mcl = mdl->mcl; 491 mcap_md_req *cmd; 492 493 if (mdl->state != MDL_CLOSED) { 494 g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED, 495 "MDL is not closed"); 496 return FALSE; 497 } 498 con = g_new0(struct mcap_mdl_op_cb, 1); 499 500 cmd = create_req(MCAP_MD_RECONNECT_MDL_REQ, mdl->mdlid); 501 if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) { 502 g_free(con); 503 g_free(cmd); 504 return FALSE; 505 } 506 507 mdl->state = MDL_WAITING; 508 509 con->mdl = mdl; 510 con->cb.op = reconnect_cb; 511 con->user_data = user_data; 512 513 mcl->state = MCL_ACTIVE; 514 mcl->priv_data = con; 515 516 mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer, 517 mcl); 518 return TRUE; 519} 520 521static gboolean send_delete_req(struct mcap_mcl *mcl, 522 struct mcap_mdl_op_cb *con, 523 uint16_t mdlid, 524 GError **err) 525{ 526 mcap_md_req *cmd; 527 528 cmd = create_req(MCAP_MD_DELETE_MDL_REQ, mdlid); 529 if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) { 530 g_free(cmd); 531 return FALSE; 532 } 533 534 mcl->priv_data = con; 535 536 mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer, 537 mcl); 538 return TRUE; 539} 540 541gboolean mcap_delete_all_mdls(struct mcap_mcl *mcl, 542 mcap_mdl_notify_cb delete_cb, 543 gpointer user_data, GError **err) 544{ 545 GSList *l; 546 struct mcap_mdl *mdl; 547 struct mcap_mdl_op_cb *con; 548 549 DBG("MCL in state: %d", mcl->state); 550 if (!mcl->mdls) { 551 g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED, 552 "There are not MDLs created"); 553 return FALSE; 554 } 555 556 for (l = mcl->mdls; l; l = l->next) { 557 mdl = l->data; 558 if (mdl->state != MDL_WAITING) 559 mdl->state = MDL_DELETING; 560 } 561 562 con = g_new0(struct mcap_mdl_op_cb, 1); 563 con->mdl = NULL; 564 con->cb.notify = delete_cb; 565 con->user_data = user_data; 566 567 568 if (!send_delete_req(mcl, con, MCAP_ALL_MDLIDS, err)) { 569 g_free(con); 570 return FALSE; 571 } 572 573 return TRUE; 574} 575 576gboolean mcap_delete_mdl(struct mcap_mdl *mdl, mcap_mdl_notify_cb delete_cb, 577 gpointer user_data, GError **err) 578{ 579 struct mcap_mcl *mcl= mdl->mcl; 580 struct mcap_mdl_op_cb *con; 581 GSList *l; 582 583 l = g_slist_find(mcl->mdls, mdl); 584 585 if (!l) { 586 g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL, 587 "%s" , error2str(MCAP_INVALID_MDEP)); 588 return FALSE; 589 } 590 591 if (mdl->state == MDL_WAITING) { 592 g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED, 593 "Mdl is not created"); 594 return FALSE; 595 } 596 597 mdl->state = MDL_DELETING; 598 599 con = g_new0(struct mcap_mdl_op_cb, 1); 600 con->mdl = mdl; 601 con->cb.notify = delete_cb; 602 con->user_data = user_data; 603 604 if (!send_delete_req(mcl, con, mdl->mdlid, err)) { 605 g_free(con); 606 return FALSE; 607 } 608 609 return TRUE; 610} 611 612gboolean mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb, 613 gpointer user_data, GError **err) 614{ 615 struct mcap_mdl_op_cb *con; 616 struct mcap_mcl *mcl = mdl->mcl; 617 mcap_md_req *cmd; 618 619 if (mdl->state != MDL_WAITING) { 620 g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED, 621 "Mdl in invalid state"); 622 return FALSE; 623 } 624 625 con = g_new0(struct mcap_mdl_op_cb, 1); 626 cmd = create_req(MCAP_MD_ABORT_MDL_REQ, mdl->mdlid); 627 if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) { 628 g_free(con); 629 g_free(cmd); 630 return FALSE; 631 } 632 633 con->mdl = mdl; 634 con->cb.notify = abort_cb; 635 con->user_data = user_data; 636 637 mcl->priv_data = con; 638 639 mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer, 640 mcl); 641 return TRUE; 642} 643 644static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr) 645{ 646 GSList *l; 647 struct mcap_mcl *mcl; 648 649 for (l = list; l; l = l->next) { 650 mcl = l->data; 651 652 if (!bacmp(&mcl->addr, addr)) 653 return mcl; 654 } 655 656 return NULL; 657} 658 659int mcap_mdl_get_fd(struct mcap_mdl *mdl) 660{ 661 if (!mdl || mdl->state != MDL_CONNECTED) 662 return -ENOTCONN; 663 664 return g_io_channel_unix_get_fd(mdl->dc); 665} 666 667uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl) 668{ 669 if (!mdl) 670 return MCAP_MDLID_RESERVED; 671 672 return mdl->mdlid; 673} 674 675static void close_mcl(struct mcap_mcl *mcl, gboolean cache_requested) 676{ 677 gboolean save = ((!(mcl->ctrl & MCAP_CTRL_FREE)) && cache_requested); 678 679 if (mcl->tid) { 680 RELEASE_TIMER(mcl); 681 } 682 683 if (mcl->cc) { 684 g_io_channel_shutdown(mcl->cc, TRUE, NULL); 685 g_io_channel_unref(mcl->cc); 686 mcl->cc = NULL; 687 } 688 689 g_source_remove(mcl->wid); 690 if (mcl->lcmd) { 691 g_free(mcl->lcmd); 692 mcl->lcmd = NULL; 693 } 694 695 if (mcl->priv_data) { 696 g_free(mcl->priv_data); 697 mcl->priv_data = NULL; 698 } 699 700 g_slist_foreach(mcl->mdls, (GFunc) shutdown_mdl, NULL); 701 702 mcl->state = MCL_IDLE; 703 704 if (save) 705 return; 706 707 g_slist_foreach(mcl->mdls, (GFunc) g_free, NULL); 708 g_slist_free(mcl->mdls); 709 710 g_free(mcl->cb); 711 712 g_free(mcl); 713} 714 715static void mcap_mcl_shutdown(struct mcap_mcl *mcl) 716{ 717 close_mcl(mcl, TRUE); 718} 719 720static void mcap_mcl_release(struct mcap_mcl *mcl) 721{ 722 close_mcl(mcl, FALSE); 723} 724 725static void mcap_mcl_check_del(struct mcap_mcl *mcl) 726{ 727 if (mcl->ctrl & MCAP_CTRL_CACHED) 728 mcap_mcl_shutdown(mcl); 729 else 730 mcap_mcl_unref(mcl); 731} 732 733static void mcap_cache_mcl(struct mcap_mcl *mcl) 734{ 735 GSList *l; 736 struct mcap_mcl *last; 737 int len; 738 739 if (mcl->ctrl & MCAP_CTRL_CACHED) 740 return; 741 742 mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl); 743 744 if ((mcl->ctrl & MCAP_CTRL_NOCACHE) || (mcl->ref < 2)) { 745 mcap_mcl_unref(mcl); 746 return; 747 } 748 749 DBG("Caching MCL"); 750 751 len = g_slist_length(mcl->ms->cached); 752 if (len == MAX_CACHED) { 753 /* Remove the latest cached mcl */ 754 l = g_slist_last(mcl->ms->cached); 755 last = l->data; 756 mcl->ms->cached = g_slist_remove(mcl->ms->cached, last); 757 last->ctrl &= ~MCAP_CTRL_CACHED; 758 if (last->ctrl & MCAP_CTRL_CONN) { 759 /* If connection process is not success this MCL will be 760 * freed next time that close_mcl is invoked */ 761 last->ctrl |= MCAP_CTRL_FREE; 762 } else { 763 last->ms->mcl_uncached_cb(last, last->ms->user_data); 764 mcap_mcl_unref(last); 765 } 766 } 767 768 mcl->ms->cached = g_slist_prepend(mcl->ms->cached, mcl); 769 mcl->ctrl |= MCAP_CTRL_CACHED; 770 mcap_mcl_shutdown(mcl); 771} 772 773static void mcap_uncache_mcl(struct mcap_mcl *mcl) 774{ 775 if (!(mcl->ctrl & MCAP_CTRL_CACHED)) 776 return; 777 778 DBG("Got MCL from cache"); 779 780 mcl->ms->cached = g_slist_remove(mcl->ms->cached, mcl); 781 mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl); 782 mcl->ctrl &= ~MCAP_CTRL_CACHED; 783 mcl->ctrl &= ~MCAP_CTRL_FREE; 784} 785 786void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache) 787{ 788 if (!mcl) 789 return; 790 791 if (mcl->cc) { 792 g_io_channel_shutdown(mcl->cc, TRUE, NULL); 793 g_io_channel_unref(mcl->cc); 794 mcl->cc = NULL; 795 } 796 797 mcl->state = MCL_IDLE; 798 799 if (!cache) 800 mcl->ctrl |= MCAP_CTRL_NOCACHE; 801} 802 803struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl) 804{ 805 mcl->ref++; 806 807 DBG("mcap_mcl_ref(%p): ref=%d", mcl, mcl->ref); 808 809 return mcl; 810} 811 812void mcap_mcl_unref(struct mcap_mcl *mcl) 813{ 814 mcl->ref--; 815 816 DBG("mcap_mcl_unref(%p): ref=%d", mcl, mcl->ref); 817 818 if ((mcl->ctrl & MCAP_CTRL_CACHED) && (mcl->ref < 2)) { 819 /* Free space in cache memory due any other profile has a local 820 * copy of current MCL stored in cache */ 821 DBG("Remove from cache (%p): ref=%d", mcl, mcl->ref); 822 mcl->ms->cached = g_slist_remove(mcl->ms->cached, mcl); 823 mcap_mcl_release(mcl); 824 return; 825 } 826 827 if (mcl->ref > 0) 828 return; 829 830 mcap_mcl_release(mcl); 831} 832 833static gboolean parse_set_opts(struct mcap_mdl_cb *mdl_cb, GError **err, 834 McapMclCb cb1, va_list args) 835{ 836 McapMclCb cb = cb1; 837 struct mcap_mdl_cb *c; 838 839 c = g_new0(struct mcap_mdl_cb, 1); 840 841 while (cb != MCAP_MDL_CB_INVALID) { 842 switch (cb) { 843 case MCAP_MDL_CB_CONNECTED: 844 c->mdl_connected = va_arg(args, mcap_mdl_event_cb); 845 break; 846 case MCAP_MDL_CB_CLOSED: 847 c->mdl_closed = va_arg(args, mcap_mdl_event_cb); 848 break; 849 case MCAP_MDL_CB_DELETED: 850 c->mdl_deleted = va_arg(args, mcap_mdl_event_cb); 851 break; 852 case MCAP_MDL_CB_ABORTED: 853 c->mdl_aborted = va_arg(args, mcap_mdl_event_cb); 854 break; 855 case MCAP_MDL_CB_REMOTE_CONN_REQ: 856 c->mdl_conn_req = va_arg(args, 857 mcap_remote_mdl_conn_req_cb); 858 break; 859 case MCAP_MDL_CB_REMOTE_RECONN_REQ: 860 c->mdl_reconn_req = va_arg(args, 861 mcap_remote_mdl_reconn_req_cb); 862 break; 863 default: 864 g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS, 865 "Unknown option %d", cb); 866 return FALSE; 867 } 868 cb = va_arg(args, int); 869 } 870 871 /* Set new callbacks */ 872 if (c->mdl_connected) 873 mdl_cb->mdl_connected = c->mdl_connected; 874 if (c->mdl_closed) 875 mdl_cb->mdl_closed = c->mdl_closed; 876 if (c->mdl_deleted) 877 mdl_cb->mdl_deleted = c->mdl_deleted; 878 if (c->mdl_aborted) 879 mdl_cb->mdl_aborted = c->mdl_aborted; 880 if (c->mdl_conn_req) 881 mdl_cb->mdl_conn_req = c->mdl_conn_req; 882 if (c->mdl_reconn_req) 883 mdl_cb->mdl_reconn_req = c->mdl_reconn_req; 884 885 g_free(c); 886 887 return TRUE; 888} 889 890gboolean mcap_mcl_set_cb(struct mcap_mcl *mcl, gpointer user_data, 891 GError **gerr, McapMclCb cb1, ...) 892{ 893 va_list args; 894 gboolean ret; 895 896 va_start(args, cb1); 897 ret = parse_set_opts(mcl->cb, gerr, cb1, args); 898 va_end(args); 899 900 if (!ret) 901 return FALSE; 902 903 mcl->cb->user_data = user_data; 904 return TRUE; 905} 906 907void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr) 908{ 909 bacpy(addr, &mcl->addr); 910} 911 912static void mcap_del_mdl(gpointer elem, gpointer user_data) 913{ 914 struct mcap_mdl *mdl = elem; 915 gboolean notify = *(gboolean *) user_data; 916 917 shutdown_mdl(mdl); 918 if (notify) 919 mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data); 920 921 g_free(mdl); 922} 923 924static gboolean check_cmd_req_length(struct mcap_mcl *mcl, void *cmd, 925 uint32_t rlen, uint32_t explen, uint8_t rspcod) 926{ 927 mcap_md_req *req; 928 uint16_t mdl_id; 929 930 if (rlen != explen) { 931 if (rlen >= sizeof(mcap_md_req)) { 932 req = cmd; 933 mdl_id = ntohs(req->mdl); 934 } else { 935 /* We can't get mdlid */ 936 mdl_id = MCAP_MDLID_RESERVED; 937 } 938 mcap_send_cmd(mcl, rspcod, MCAP_INVALID_PARAM_VALUE, mdl_id, 939 NULL, 0); 940 return FALSE; 941 } 942 return TRUE; 943} 944 945static void process_md_create_mdl_req(struct mcap_mcl *mcl, void *cmd, 946 uint32_t len) 947{ 948 mcap_md_create_mdl_req *req; 949 struct mcap_mdl *mdl; 950 uint16_t mdl_id; 951 uint8_t mdep_id; 952 uint8_t cfga, conf; 953 uint8_t rsp; 954 955 if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_create_mdl_req), 956 MCAP_MD_CREATE_MDL_RSP)) 957 return; 958 959 req = cmd; 960 mdl_id = ntohs(req->mdl); 961 if (mdl_id < MCAP_MDLID_INITIAL || mdl_id > MCAP_MDLID_FINAL) { 962 mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL, 963 mdl_id, NULL, 0); 964 return; 965 } 966 967 mdep_id = req->mdep; 968 if (mdep_id > MCAP_MDEPID_FINAL) { 969 mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDEP, 970 mdl_id, NULL, 0); 971 return; 972 } 973 974 mdl = get_mdl(mcl, mdl_id); 975 if (mdl && (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING )) { 976 /* Creation request arrives for a MDL that is being managed 977 * at current moment */ 978 mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY, 979 mdl_id, NULL, 0); 980 return; 981 } 982 983 cfga = conf = req->conf; 984 /* Callback to upper layer */ 985 rsp = mcl->cb->mdl_conn_req(mcl, mdep_id, mdl_id, &conf, 986 mcl->cb->user_data); 987 if (mcl->state == MCL_IDLE) { 988 /* MCL has been closed int the callback */ 989 return; 990 } 991 992 if (cfga != 0 && cfga != conf) { 993 /* Remote device set default configuration but upper profile */ 994 /* has changed it. Protocol Error: force closing the MCL by */ 995 /* remote device using UNSPECIFIED_ERROR response */ 996 mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, 997 MCAP_UNSPECIFIED_ERROR, mdl_id, NULL, 0); 998 return; 999 } 1000 if (rsp != MCAP_SUCCESS) { 1001 mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id, 1002 NULL, 0); 1003 return; 1004 } 1005 1006 if (!mdl) { 1007 mdl = g_new0(struct mcap_mdl, 1); 1008 mdl->mcl = mcl; 1009 mdl->mdlid = mdl_id; 1010 mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl); 1011 } else if (mdl->state == MDL_CONNECTED) { 1012 /* MCAP specification says that we should close the MCL if 1013 * it is open when we receive a MD_CREATE_MDL_REQ */ 1014 shutdown_mdl(mdl); 1015 } 1016 1017 mdl->mdep_id = mdep_id; 1018 mdl->state = MDL_WAITING; 1019 1020 mcl->state = MCL_PENDING; 1021 mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id, 1022 &conf, 1); 1023} 1024 1025static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, void *cmd, 1026 uint32_t len) 1027{ 1028 mcap_md_req *req; 1029 struct mcap_mdl *mdl; 1030 uint16_t mdl_id; 1031 uint8_t rsp; 1032 1033 if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req), 1034 MCAP_MD_RECONNECT_MDL_RSP)) 1035 return; 1036 1037 req = cmd; 1038 mdl_id = ntohs(req->mdl); 1039 1040 mdl = get_mdl(mcl, mdl_id); 1041 if (!mdl) { 1042 mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_INVALID_MDL, 1043 mdl_id, NULL, 0); 1044 return; 1045 } else if (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING ) { 1046 /* Creation request arrives for a MDL that is being managed 1047 * at current moment */ 1048 mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_MDL_BUSY, 1049 mdl_id, NULL, 0); 1050 return; 1051 } 1052 1053 /* Callback to upper layer */ 1054 rsp = mcl->cb->mdl_reconn_req(mdl, mcl->cb->user_data); 1055 if (mcl->state == MCL_IDLE) 1056 return; 1057 1058 if (rsp != MCAP_SUCCESS) { 1059 mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, rsp, mdl_id, 1060 NULL, 0); 1061 return; 1062 } 1063 1064 if (mdl->state == MDL_CONNECTED) 1065 shutdown_mdl(mdl); 1066 1067 mdl->state = MDL_WAITING; 1068 mcl->state = MCL_PENDING; 1069 mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id, 1070 NULL, 0); 1071} 1072 1073static void process_md_abort_mdl_req(struct mcap_mcl *mcl, void *cmd, 1074 uint32_t len) 1075{ 1076 mcap_md_req *req; 1077 GSList *l; 1078 struct mcap_mdl *mdl, *abrt; 1079 uint16_t mdl_id; 1080 1081 if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req), 1082 MCAP_MD_ABORT_MDL_RSP)) 1083 return; 1084 1085 req = cmd; 1086 mdl_id = ntohs(req->mdl); 1087 mcl->state = MCL_CONNECTED; 1088 for (l = mcl->mdls; l; l = l->next) { 1089 mdl = l->data; 1090 if (mdl_id == mdl->mdlid && mdl->state == MDL_WAITING) { 1091 abrt = mdl; 1092 if (mcl->state != MCL_CONNECTED) 1093 break; 1094 continue; 1095 } 1096 if (mdl->state == MDL_CONNECTED && mcl->state != MCL_ACTIVE) 1097 mcl->state = MCL_ACTIVE; 1098 1099 if (abrt && mcl->state == MCL_ACTIVE) 1100 break; 1101 } 1102 1103 if (!abrt) { 1104 mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL, 1105 mdl_id, NULL, 0); 1106 return; 1107 } 1108 1109 mcl->cb->mdl_aborted(abrt, mcl->cb->user_data); 1110 abrt->state = MDL_CLOSED; 1111 mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_SUCCESS, mdl_id, 1112 NULL, 0); 1113} 1114 1115static void process_md_delete_mdl_req(struct mcap_mcl *mcl, void *cmd, 1116 uint32_t len) 1117{ 1118 mcap_md_req *req; 1119 struct mcap_mdl *mdl, *aux; 1120 uint16_t mdlid; 1121 gboolean notify; 1122 GSList *l; 1123 1124 if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req), 1125 MCAP_MD_DELETE_MDL_RSP)) 1126 return; 1127 1128 req = cmd; 1129 mdlid = ntohs(req->mdl); 1130 if (mdlid == MCAP_ALL_MDLIDS) { 1131 notify = FALSE; 1132 g_slist_foreach(mcl->mdls, mcap_del_mdl, ¬ify); 1133 g_slist_free(mcl->mdls); 1134 mcl->mdls = NULL; 1135 mcl->state = MCL_CONNECTED; 1136 /* NULL mdl means ALL_MDLS */ 1137 mcl->cb->mdl_deleted(NULL, mcl->cb->user_data); 1138 goto resp; 1139 } 1140 1141 if (mdlid < MCAP_MDLID_INITIAL || mdlid > MCAP_MDLID_FINAL) { 1142 mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL, 1143 mdlid, NULL, 0); 1144 return; 1145 } 1146 1147 for (l = mcl->mdls, mdl = NULL; l; l = l->next) { 1148 aux = l->data; 1149 if (aux->mdlid == mdlid) { 1150 mdl = aux; 1151 break; 1152 } 1153 } 1154 1155 if (!mdl || mdl->state == MDL_WAITING) { 1156 mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL, 1157 mdlid, NULL, 0); 1158 return; 1159 } 1160 1161 mcl->mdls = g_slist_remove(mcl->mdls, mdl); 1162 update_mcl_state(mcl); 1163 notify = TRUE; 1164 mcap_del_mdl(mdl, ¬ify); 1165 1166resp: 1167 mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid, 1168 NULL, 0); 1169} 1170 1171static void invalid_req_state(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) 1172{ 1173 uint16_t mdlr; 1174 1175 error("Invalid cmd received (op code = %d) in state %d", cmd[0], 1176 mcl->state); 1177 /* Get previously mdlid sent to generate an appropriate 1178 * response if it is possible */ 1179 mdlr = len < sizeof(mcap_md_req) ? MCAP_MDLID_RESERVED : 1180 ntohs(((mcap_md_req *) cmd)->mdl); 1181 mcap_send_cmd(mcl, cmd[0]+1, MCAP_INVALID_OPERATION, mdlr, NULL, 0); 1182} 1183 1184/* Function used to process commands depending of MCL state */ 1185static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) 1186{ 1187 switch (cmd[0]) { 1188 case MCAP_MD_CREATE_MDL_REQ: 1189 process_md_create_mdl_req(mcl, cmd, len); 1190 break; 1191 case MCAP_MD_RECONNECT_MDL_REQ: 1192 process_md_reconnect_mdl_req(mcl, cmd, len); 1193 break; 1194 case MCAP_MD_DELETE_MDL_REQ: 1195 process_md_delete_mdl_req(mcl, cmd, len); 1196 break; 1197 default: 1198 invalid_req_state(mcl, cmd, len); 1199 } 1200} 1201 1202static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) 1203{ 1204 if (cmd[0] == MCAP_MD_ABORT_MDL_REQ) 1205 process_md_abort_mdl_req(mcl, cmd, len); 1206 else 1207 invalid_req_state(mcl, cmd, len); 1208} 1209 1210static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) 1211{ 1212 switch (cmd[0]) { 1213 case MCAP_MD_CREATE_MDL_REQ: 1214 process_md_create_mdl_req(mcl, cmd, len); 1215 break; 1216 case MCAP_MD_RECONNECT_MDL_REQ: 1217 process_md_reconnect_mdl_req(mcl, cmd, len); 1218 break; 1219 case MCAP_MD_DELETE_MDL_REQ: 1220 process_md_delete_mdl_req(mcl, cmd, len); 1221 break; 1222 default: 1223 invalid_req_state(mcl, cmd, len); 1224 } 1225} 1226 1227/* Function used to process replies */ 1228static gboolean check_err_rsp(struct mcap_mcl *mcl, uint8_t *cmd, 1229 uint32_t rlen, uint32_t len, GError **gerr) 1230{ 1231 mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd; 1232 gint err = MCAP_ERROR_FAILED; 1233 gboolean close = FALSE; 1234 uint16_t rmdl, smdl; 1235 mcap_rsp *rsp; 1236 char *msg; 1237 1238 if (cmd[0] == MCAP_ERROR_RSP) { 1239 msg = "MCAP_ERROR_RSP received"; 1240 close = FALSE; 1241 goto fail; 1242 } 1243 1244 /* Check if the response matches with the last request */ 1245 if (rlen < sizeof(mcap_rsp) || (mcl->lcmd[0] + 1) != cmd[0]) { 1246 msg = "Protocol error"; 1247 close = FALSE; 1248 goto fail; 1249 } 1250 1251 if (rlen < len) { 1252 msg = "Protocol error"; 1253 close = FALSE; 1254 goto fail; 1255 } 1256 1257 rsp = (mcap_rsp *) cmd; 1258 smdl = ntohs(cmdlast->mdl); 1259 rmdl = ntohs(rsp->mdl); 1260 if (rmdl != smdl) { 1261 msg = "MDLID received doesn't match with MDLID sent"; 1262 close = TRUE; 1263 goto fail; 1264 } 1265 1266 if (rsp->rc == MCAP_REQUEST_NOT_SUPPORTED) { 1267 msg = "Remote does not support opcodes"; 1268 mcl->ctrl &= ~MCAP_CTRL_STD_OP; 1269 goto fail; 1270 } 1271 1272 if (rsp->rc == MCAP_UNSPECIFIED_ERROR) { 1273 msg = "Unspecified error"; 1274 close = TRUE; 1275 goto fail; 1276 } 1277 1278 if (rsp->rc != MCAP_SUCCESS) { 1279 msg = error2str(rsp->rc); 1280 err = rsp->rc; 1281 goto fail; 1282 } 1283 1284 return FALSE; 1285 1286fail: 1287 g_set_error(gerr, MCAP_ERROR, err, "%s", msg); 1288 return close; 1289} 1290 1291static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl, 1292 uint8_t *cmd, uint32_t len) 1293{ 1294 mcap_md_create_mdl_req *cmdlast = (mcap_md_create_mdl_req *) mcl->lcmd; 1295 struct mcap_mdl_op_cb *conn = mcl->priv_data; 1296 mcap_mdl_operation_conf_cb connect_cb = conn->cb.op_conf; 1297 gpointer user_data = conn->user_data; 1298 struct mcap_mdl *mdl = conn->mdl; 1299 uint8_t conf = cmdlast->conf; 1300 gboolean close; 1301 GError *gerr = NULL; 1302 uint8_t *param; 1303 1304 g_free(mcl->priv_data); 1305 mcl->priv_data = NULL; 1306 1307 close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp) + 1, &gerr); 1308 g_free(mcl->lcmd); 1309 mcl->lcmd = NULL; 1310 mcl->req = MCL_AVAILABLE; 1311 1312 if (gerr) 1313 goto fail; 1314 1315 param = cmd + sizeof(mcap_rsp); 1316 /* Check if preferences changed */ 1317 if (conf != 0x00 && *param != conf) { 1318 g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED, 1319 "Configuration changed"); 1320 close = TRUE; 1321 goto fail; 1322 } 1323 1324 connect_cb(mdl, *param, gerr, user_data); 1325 return close; 1326 1327fail: 1328 connect_cb(NULL, 0, gerr, user_data); 1329 mcl->mdls = g_slist_remove(mcl->mdls, mdl); 1330 g_free(mdl); 1331 g_error_free(gerr); 1332 update_mcl_state(mcl); 1333 return close; 1334} 1335 1336static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl, 1337 uint8_t *cmd, uint32_t len) 1338{ 1339 struct mcap_mdl_op_cb *reconn = mcl->priv_data; 1340 mcap_mdl_operation_cb reconn_cb = reconn->cb.op; 1341 gpointer user_data = reconn->user_data; 1342 struct mcap_mdl *mdl = reconn->mdl; 1343 mcap_rsp *rsp = (mcap_rsp *) cmd; 1344 GError *gerr = NULL; 1345 gboolean close; 1346 1347 g_free(mcl->priv_data); 1348 mcl->priv_data = NULL; 1349 1350 close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp), &gerr); 1351 1352 g_free(mcl->lcmd); 1353 mcl->lcmd = NULL; 1354 mcl->req = MCL_AVAILABLE; 1355 1356 reconn_cb(mdl, gerr, user_data); 1357 if (!gerr) 1358 return close; 1359 1360 g_error_free(gerr); 1361 shutdown_mdl(mdl); 1362 update_mcl_state(mcl); 1363 1364 if (rsp->rc != MCAP_INVALID_MDL) 1365 return close; 1366 1367 /* Remove cached mdlid */ 1368 mcl->mdls = g_slist_remove(mcl->mdls, mdl); 1369 mcl->cb->mdl_deleted(mdl, mcl->cb->user_data); 1370 g_free(mdl); 1371 1372 return close; 1373} 1374 1375static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl, 1376 uint8_t *cmd, uint32_t len) 1377{ 1378 struct mcap_mdl_op_cb *abrt = mcl->priv_data; 1379 mcap_mdl_notify_cb abrt_cb = abrt->cb.notify; 1380 gpointer user_data = abrt->user_data; 1381 struct mcap_mdl *mdl = abrt->mdl; 1382 mcap_rsp *rsp = (mcap_rsp *) cmd; 1383 GError *gerr = NULL; 1384 gboolean close; 1385 1386 g_free(mcl->priv_data); 1387 mcl->priv_data = NULL; 1388 1389 close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp), &gerr); 1390 1391 g_free(mcl->lcmd); 1392 mcl->lcmd = NULL; 1393 mcl->req = MCL_AVAILABLE; 1394 1395 abrt_cb(gerr, user_data); 1396 shutdown_mdl(mdl); 1397 1398 if (len >= sizeof(mcap_rsp) && rsp->rc == MCAP_INVALID_MDL) { 1399 mcl->mdls = g_slist_remove(mcl->mdls, mdl); 1400 g_free(mdl); 1401 } 1402 1403 if (!gerr) 1404 g_error_free(gerr); 1405 1406 update_mcl_state(mcl); 1407 1408 return close; 1409} 1410 1411static void restore_mdl(gpointer elem, gpointer data) 1412{ 1413 struct mcap_mdl *mdl = elem; 1414 1415 if (mdl->state == MDL_DELETING) { 1416 if (mdl->dc) 1417 mdl->state = MDL_CONNECTED; 1418 else 1419 mdl->state = MDL_CLOSED; 1420 } else if (mdl->state == MDL_CLOSED) 1421 mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data); 1422} 1423 1424static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd, 1425 uint32_t len) 1426{ 1427 struct mcap_mdl_op_cb *del = mcl->priv_data; 1428 struct mcap_mdl *mdl = del->mdl; 1429 mcap_mdl_notify_cb deleted_cb = del->cb.notify; 1430 gpointer user_data = del->user_data; 1431 mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd; 1432 uint16_t mdlid = ntohs(cmdlast->mdl); 1433 GError *gerr = NULL; 1434 gboolean close; 1435 gboolean notify = FALSE; 1436 1437 g_free(mcl->priv_data); 1438 mcl->priv_data = NULL; 1439 1440 close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp), &gerr); 1441 1442 g_free(mcl->lcmd); 1443 mcl->lcmd = NULL; 1444 mcl->req = MCL_AVAILABLE; 1445 1446 if (gerr) { 1447 if (mdl) 1448 restore_mdl(mdl, NULL); 1449 else 1450 g_slist_foreach(mcl->mdls, restore_mdl, NULL); 1451 deleted_cb(gerr, user_data); 1452 g_error_free(gerr); 1453 return close; 1454 } 1455 1456 if (mdlid == MCAP_ALL_MDLIDS) { 1457 g_slist_foreach(mcl->mdls, mcap_del_mdl, ¬ify); 1458 g_slist_free(mcl->mdls); 1459 mcl->mdls = NULL; 1460 mcl->state = MCL_CONNECTED; 1461 } else { 1462 mcl->mdls = g_slist_remove(mcl->mdls, mdl); 1463 update_mcl_state(mcl); 1464 mcap_del_mdl(mdl, ¬ify); 1465 } 1466 1467 deleted_cb(gerr, user_data); 1468 1469 return close; 1470} 1471 1472static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) 1473{ 1474 gboolean close; 1475 RELEASE_TIMER(mcl); 1476 1477 switch (mcl->lcmd[0] + 1) { 1478 case MCAP_MD_CREATE_MDL_RSP: 1479 close = process_md_create_mdl_rsp(mcl, cmd, len); 1480 break; 1481 case MCAP_MD_RECONNECT_MDL_RSP: 1482 close = process_md_reconnect_mdl_rsp(mcl, cmd, len); 1483 break; 1484 case MCAP_MD_ABORT_MDL_RSP: 1485 close = process_md_abort_mdl_rsp(mcl, cmd, len); 1486 break; 1487 case MCAP_MD_DELETE_MDL_RSP: 1488 close = process_md_delete_mdl_rsp(mcl, cmd, len); 1489 break; 1490 default: 1491 DBG("Unknown cmd response received (op code = %d)",cmd[0]); 1492 close = TRUE; 1493 break; 1494 } 1495 1496 if (close) { 1497 mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data); 1498 mcap_cache_mcl(mcl); 1499 } 1500} 1501 1502static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) 1503{ 1504 GError *gerr = NULL; 1505 1506 if (cmd[0] > MCAP_MD_SYNC_INFO_IND || 1507 (cmd[0] > MCAP_MD_DELETE_MDL_RSP && 1508 cmd[0] < MCAP_MD_SYNC_CAP_REQ)) { 1509 error("Unknown cmd received (op code = %d)", cmd[0]); 1510 mcap_send_cmd(mcl, MCAP_ERROR_RSP, MCAP_INVALID_OP_CODE, 1511 MCAP_MDLID_RESERVED, NULL, 0); 1512 return; 1513 } 1514 1515 if (cmd[0] >= MCAP_MD_SYNC_CAP_REQ && 1516 cmd[0] <= MCAP_MD_SYNC_INFO_IND) { 1517 proc_sync_cmd(mcl, cmd, len); 1518 return; 1519 } 1520 1521 if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) { 1522 /* In case the remote device doesn't work correctly */ 1523 error("Remote device does not support opcodes, cmd ignored"); 1524 return; 1525 } 1526 1527 if (mcl->req == MCL_WAITING_RSP) { 1528 if (cmd[0] & 0x01) { 1529 /* Request arrived when a response is expected */ 1530 if (mcl->role == MCL_INITIATOR) 1531 /* ignore */ 1532 return; 1533 /* Initiator will ignore our last request */ 1534 RELEASE_TIMER(mcl); 1535 mcl->req = MCL_AVAILABLE; 1536 g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_REQ_IGNORED, 1537 "Initiator sent a request with more priority"); 1538 mcap_notify_error(mcl, gerr); 1539 proc_req[mcl->state](mcl, cmd, len); 1540 return; 1541 } 1542 proc_response(mcl, cmd, len); 1543 } else if (cmd[0] & 0x01) 1544 proc_req[mcl->state](mcl, cmd, len); 1545} 1546 1547static gboolean mdl_event_cb(GIOChannel *chan, GIOCondition cond, gpointer data) 1548{ 1549 1550 struct mcap_mdl *mdl = data; 1551 gboolean notify; 1552 1553 DBG("Close MDL %d", mdl->mdlid); 1554 1555 notify = (mdl->state == MDL_CONNECTED); 1556 shutdown_mdl(mdl); 1557 1558 update_mcl_state(mdl->mcl); 1559 1560 if (notify) { 1561 /*Callback to upper layer */ 1562 mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data); 1563 } 1564 1565 return FALSE; 1566} 1567 1568static void mcap_connect_mdl_cb(GIOChannel *chan, GError *conn_err, 1569 gpointer data) 1570{ 1571 struct mcap_mdl_op_cb *con = data; 1572 struct mcap_mdl *mdl = con->mdl; 1573 mcap_mdl_operation_cb cb = con->cb.op; 1574 gpointer user_data = con->user_data; 1575 1576 g_free(con); 1577 DBG("mdl connect callback"); 1578 1579 if (conn_err) { 1580 DBG("ERROR: mdl connect callback"); 1581 mdl->state = MDL_CLOSED; 1582 g_io_channel_unref(mdl->dc); 1583 mdl->dc = NULL; 1584 cb(mdl, conn_err, user_data); 1585 return; 1586 } 1587 1588 mdl->state = MDL_CONNECTED; 1589 mdl->wid = g_io_add_watch(mdl->dc, G_IO_ERR | G_IO_HUP | G_IO_NVAL, 1590 (GIOFunc) mdl_event_cb, mdl); 1591 1592 cb(mdl, conn_err, user_data); 1593} 1594 1595gboolean mcap_connect_mdl(struct mcap_mdl *mdl, BtIOType BtType, 1596 uint16_t dcpsm, 1597 mcap_mdl_operation_cb connect_cb, 1598 gpointer user_data, GError **err) 1599{ 1600 struct mcap_mdl_op_cb *con; 1601 1602 if (mdl->state != MDL_WAITING) { 1603 g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL, 1604 "%s", error2str(MCAP_INVALID_MDL)); 1605 return FALSE; 1606 } 1607 1608 con = g_new0(struct mcap_mdl_op_cb, 1); 1609 con->mdl = mdl; 1610 con->cb.op = connect_cb; 1611 con->user_data = user_data; 1612 1613 /* TODO: Check if BtIOType is ERTM or Streaming before continue */ 1614 1615 mdl->dc = bt_io_connect(BtType, mcap_connect_mdl_cb, con, 1616 NULL, err, 1617 BT_IO_OPT_SOURCE_BDADDR, &mdl->mcl->ms->src, 1618 BT_IO_OPT_DEST_BDADDR, &mdl->mcl->addr, 1619 BT_IO_OPT_PSM, dcpsm, 1620 BT_IO_OPT_MTU, MCAP_DC_MTU, 1621 BT_IO_OPT_SEC_LEVEL, mdl->mcl->ms->sec, 1622 BT_IO_OPT_INVALID); 1623 if (!mdl->dc) { 1624 DBG("MDL Connection error"); 1625 mdl->state = MDL_CLOSED; 1626 g_free(con); 1627 return FALSE; 1628 } 1629 1630 return TRUE; 1631} 1632 1633static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond, 1634 gpointer data) 1635{ 1636 GError *gerr = NULL; 1637 struct mcap_mcl *mcl = data; 1638 int sk, len; 1639 uint8_t buf[MCAP_CC_MTU]; 1640 1641 if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) 1642 goto fail; 1643 1644 sk = g_io_channel_unix_get_fd(chan); 1645 len = read(sk, buf, sizeof(buf)); 1646 if (len < 0) 1647 goto fail; 1648 1649 proc_cmd(mcl, buf, (uint32_t) len); 1650 return TRUE; 1651 1652fail: 1653 if (mcl->state != MCL_IDLE) { 1654 if (mcl->req == MCL_WAITING_RSP) { 1655 /* notify error in pending callback */ 1656 g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_MCL_CLOSED, 1657 "MCL closed"); 1658 mcap_notify_error(mcl, gerr); 1659 g_error_free(gerr); 1660 } 1661 mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data); 1662 } 1663 mcap_cache_mcl(mcl); 1664 return FALSE; 1665} 1666 1667static void mcap_connect_mcl_cb(GIOChannel *chan, GError *conn_err, 1668 gpointer user_data) 1669{ 1670 char dstaddr[18]; 1671 struct connect_mcl *con = user_data; 1672 struct mcap_mcl *aux, *mcl = con->mcl; 1673 mcap_mcl_connect_cb connect_cb = con->connect_cb; 1674 gpointer data = con->user_data; 1675 GError *gerr = NULL; 1676 1677 g_free(con); 1678 1679 mcl->ctrl &= ~MCAP_CTRL_CONN; 1680 1681 if (conn_err) { 1682 if (mcl->ctrl & MCAP_CTRL_FREE) 1683 mcl->ms->mcl_uncached_cb(mcl, mcl->ms->user_data); 1684 mcap_mcl_check_del(mcl); 1685 connect_cb(NULL, conn_err, data); 1686 return; 1687 } 1688 1689 ba2str(&mcl->addr, dstaddr); 1690 1691 aux = find_mcl(mcl->ms->mcls, &mcl->addr); 1692 if (aux) { 1693 /* Double MCL connection case */ 1694 if (aux != mcl) { 1695 /* This MCL was not in cache */ 1696 mcap_mcl_unref(mcl); 1697 } 1698 error("MCL error: Device %s is already connected", dstaddr); 1699 g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS, 1700 "MCL %s is already connected", dstaddr); 1701 connect_cb(NULL, gerr, data); 1702 g_error_free(gerr); 1703 return; 1704 } 1705 1706 mcl->state = MCL_CONNECTED; 1707 mcl->role = MCL_INITIATOR; 1708 mcl->req = MCL_AVAILABLE; 1709 mcl->ctrl |= MCAP_CTRL_STD_OP; 1710 1711 if (mcl->ctrl & MCAP_CTRL_CACHED) 1712 mcap_uncache_mcl(mcl); 1713 else 1714 mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl); 1715 1716 mcl->wid = g_io_add_watch(mcl->cc, 1717 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, 1718 (GIOFunc) mcl_control_cb, mcl); 1719 connect_cb(mcl, gerr, data); 1720 1721 if (mcl->ref == 1) { 1722 mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl); 1723 mcap_mcl_unref(mcl); 1724 } 1725} 1726 1727static void connect_dc_event_cb(GIOChannel *chan, GError *err, 1728 gpointer user_data) 1729{ 1730 struct mcap_mdl *mdl = user_data; 1731 struct mcap_mcl *mcl = mdl->mcl; 1732 1733 mdl->state = MDL_CONNECTED; 1734 mdl->dc = g_io_channel_ref(chan); 1735 mdl->wid = g_io_add_watch(mdl->dc, G_IO_ERR | G_IO_HUP | G_IO_NVAL, 1736 (GIOFunc) mdl_event_cb, mdl); 1737 1738 mcl->state = MCL_ACTIVE; 1739 mcl->cb->mdl_connected(mdl, mcl->cb->user_data); 1740} 1741 1742gboolean mcap_create_mcl(struct mcap_instance *ms, 1743 const bdaddr_t *addr, 1744 uint16_t ccpsm, 1745 mcap_mcl_connect_cb connect_cb, 1746 gpointer user_data, 1747 GError **err) 1748{ 1749 struct mcap_mcl *mcl; 1750 struct connect_mcl *con; 1751 1752 mcl = find_mcl(ms->mcls, addr); 1753 if (mcl) { 1754 g_set_error(err, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS, 1755 "MCL is already connected."); 1756 return FALSE; 1757 } 1758 1759 mcl = find_mcl(ms->cached, addr); 1760 if (!mcl) { 1761 mcl = g_new0(struct mcap_mcl, 1); 1762 mcl->ms = ms; 1763 mcl->state = MCL_IDLE; 1764 bacpy(&mcl->addr, addr); 1765 set_default_cb(mcl); 1766 mcl->next_mdl = (rand() % MCAP_MDLID_FINAL) + 1; 1767 mcl = mcap_mcl_ref(mcl); 1768 } else 1769 mcl->ctrl |= MCAP_CTRL_CONN; 1770 1771 con = g_new0(struct connect_mcl, 1); 1772 con->mcl = mcl; 1773 con->connect_cb = connect_cb; 1774 con->user_data = user_data; 1775 1776 mcl->cc = bt_io_connect(BT_IO_L2CAP, mcap_connect_mcl_cb, con, 1777 NULL, err, 1778 BT_IO_OPT_SOURCE_BDADDR, &ms->src, 1779 BT_IO_OPT_DEST_BDADDR, addr, 1780 BT_IO_OPT_PSM, ccpsm, 1781 BT_IO_OPT_MTU, MCAP_CC_MTU, 1782 BT_IO_OPT_SEC_LEVEL, ms->sec, 1783 BT_IO_OPT_INVALID); 1784 if (!mcl->cc) { 1785 g_free(con); 1786 mcl->ctrl &= ~MCAP_CTRL_CONN; 1787 if (mcl->ctrl & MCAP_CTRL_FREE) 1788 mcl->ms->mcl_uncached_cb(mcl, mcl->ms->user_data); 1789 mcap_mcl_check_del(mcl); 1790 return FALSE; 1791 } 1792 1793 return TRUE; 1794} 1795 1796static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data) 1797{ 1798 struct mcap_instance *ms = user_data; 1799 struct mcap_mcl *mcl; 1800 struct mcap_mdl *mdl; 1801 GError *err = NULL; 1802 bdaddr_t dst; 1803 GSList *l; 1804 1805 bt_io_get(chan, BT_IO_L2CAP, &err, 1806 BT_IO_OPT_DEST_BDADDR, &dst, 1807 BT_IO_OPT_INVALID); 1808 if (err) { 1809 error("%s", err->message); 1810 g_error_free(err); 1811 goto drop; 1812 } 1813 1814 mcl = find_mcl(ms->mcls, &dst); 1815 if (!mcl || mcl->state != MCL_PENDING) 1816 goto drop; 1817 1818 for (l = mcl->mdls; l; l = l->next) { 1819 mdl = l->data; 1820 if (mdl->state == MDL_WAITING) { 1821 if (!bt_io_accept(chan, connect_dc_event_cb, mdl, NULL, 1822 &err)) { 1823 error("MDL accept error %s", err->message); 1824 mdl->state = MDL_CLOSED; 1825 g_error_free(err); 1826 goto drop; 1827 } 1828 return; 1829 } 1830 } 1831 1832drop: 1833 g_io_channel_shutdown(chan, TRUE, NULL); 1834} 1835 1836static void connect_mcl_event_cb(GIOChannel *chan, GError *err, 1837 gpointer user_data) 1838{ 1839 struct mcap_mcl *mcl = user_data; 1840 gboolean reconn; 1841 1842 if (err) { 1843 mcap_mcl_check_del(mcl); 1844 return; 1845 } 1846 1847 mcl->state = MCL_CONNECTED; 1848 mcl->role = MCL_ACCEPTOR; 1849 mcl->req = MCL_AVAILABLE; 1850 mcl->cc = g_io_channel_ref(chan); 1851 mcl->ctrl |= MCAP_CTRL_STD_OP; 1852 1853 reconn = (mcl->ctrl & MCAP_CTRL_CACHED); 1854 if (reconn) 1855 mcap_uncache_mcl(mcl); 1856 else 1857 mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl); 1858 1859 mcl->wid = g_io_add_watch(mcl->cc, 1860 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, 1861 (GIOFunc) mcl_control_cb, mcl); 1862 1863 /* Callback to report new MCL */ 1864 if (reconn) 1865 mcl->ms->mcl_reconnected_cb(mcl, mcl->ms->user_data); 1866 else 1867 mcl->ms->mcl_connected_cb(mcl, mcl->ms->user_data); 1868 1869 if (mcl->ref == 1) { 1870 mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl); 1871 mcap_mcl_unref(mcl); 1872 } 1873} 1874 1875static void confirm_mcl_event_cb(GIOChannel *chan, gpointer user_data) 1876{ 1877 struct mcap_instance *ms = user_data; 1878 struct mcap_mcl *mcl; 1879 bdaddr_t dst; 1880 char address[18], srcstr[18]; 1881 GError *err = NULL; 1882 1883 bt_io_get(chan, BT_IO_L2CAP, &err, 1884 BT_IO_OPT_DEST_BDADDR, &dst, 1885 BT_IO_OPT_DEST, address, 1886 BT_IO_OPT_INVALID); 1887 if (err) { 1888 error("%s", err->message); 1889 g_error_free(err); 1890 goto drop; 1891 } 1892 1893 ba2str(&ms->src, srcstr); 1894 mcl = find_mcl(ms->mcls, &dst); 1895 if (mcl) { 1896 error("Control channel already created with %s on adapter %s", 1897 address, srcstr); 1898 goto drop; 1899 } 1900 1901 mcl = find_mcl(ms->cached, &dst); 1902 if (!mcl) { 1903 mcl = g_new0(struct mcap_mcl, 1); 1904 mcl->ms = ms; 1905 bacpy(&mcl->addr, &dst); 1906 set_default_cb(mcl); 1907 mcl->next_mdl = (rand() % MCAP_MDLID_FINAL) + 1; 1908 mcl = mcap_mcl_ref(mcl); 1909 } 1910 1911 if (!bt_io_accept(chan, connect_mcl_event_cb, mcl, NULL, &err)) { 1912 error("mcap accept error: %s", err->message); 1913 if (!(mcl->ctrl & MCAP_CTRL_CACHED)) 1914 mcap_mcl_unref(mcl); 1915 g_error_free(err); 1916 goto drop; 1917 } 1918 1919 return; 1920drop: 1921 g_io_channel_shutdown(chan, TRUE, NULL); 1922} 1923 1924struct mcap_instance *mcap_create_instance(bdaddr_t *src, 1925 BtIOSecLevel sec, 1926 uint16_t ccpsm, 1927 uint16_t dcpsm, 1928 mcap_mcl_event_cb mcl_connected, 1929 mcap_mcl_event_cb mcl_reconnected, 1930 mcap_mcl_event_cb mcl_disconnected, 1931 mcap_mcl_event_cb mcl_uncached, 1932 gpointer user_data, 1933 GError **gerr) 1934{ 1935 struct mcap_instance *ms; 1936 1937 if (sec < BT_IO_SEC_MEDIUM) { 1938 g_set_error(gerr, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS, 1939 "Security level can't be minor of %d", 1940 BT_IO_SEC_MEDIUM); 1941 return NULL; 1942 } 1943 1944 if (!(mcl_connected && mcl_reconnected && 1945 mcl_disconnected && mcl_uncached)) { 1946 g_set_error(gerr, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS, 1947 "The callbacks can't be null"); 1948 return NULL; 1949 } 1950 1951 ms = g_new0(struct mcap_instance, 1); 1952 1953 bacpy(&ms->src, src); 1954 1955 ms->sec = sec; 1956 ms->mcl_connected_cb = mcl_connected; 1957 ms->mcl_reconnected_cb = mcl_reconnected; 1958 ms->mcl_disconnected_cb = mcl_disconnected; 1959 ms->mcl_uncached_cb = mcl_uncached; 1960 ms->user_data = user_data; 1961 1962 /* Listen incoming connections in control channel */ 1963 ms->ccio = bt_io_listen(BT_IO_L2CAP, NULL, confirm_mcl_event_cb, ms, 1964 NULL, gerr, 1965 BT_IO_OPT_SOURCE_BDADDR, &ms->src, 1966 BT_IO_OPT_PSM, ccpsm, 1967 BT_IO_OPT_MTU, MCAP_CC_MTU, 1968 BT_IO_OPT_SEC_LEVEL, sec, 1969 BT_IO_OPT_INVALID); 1970 if (!ms->ccio) { 1971 error("%s", (*gerr)->message); 1972 g_free(ms); 1973 return NULL; 1974 } 1975 1976 /* Listen incoming connections in data channels */ 1977 ms->dcio = bt_io_listen(BT_IO_L2CAP, NULL, confirm_dc_event_cb, ms, 1978 NULL, gerr, 1979 BT_IO_OPT_SOURCE_BDADDR, &ms->src, 1980 BT_IO_OPT_PSM, dcpsm, 1981 BT_IO_OPT_MTU, MCAP_DC_MTU, 1982 BT_IO_OPT_SEC_LEVEL, sec, 1983 BT_IO_OPT_INVALID); 1984 if (!ms->dcio) { 1985 g_io_channel_shutdown(ms->ccio, TRUE, NULL); 1986 g_io_channel_unref(ms->ccio); 1987 ms->ccio = NULL; 1988 error("%s", (*gerr)->message); 1989 g_free(ms); 1990 return NULL; 1991 } 1992 1993 /* Initialize random seed to generate mdlids for this instance */ 1994 srand(time(NULL)); 1995 1996 return ms; 1997} 1998 1999void mcap_release_instance(struct mcap_instance *mi) 2000{ 2001 GSList *l; 2002 2003 if (!mi) 2004 return; 2005 2006 if (mi->ccio) { 2007 g_io_channel_shutdown(mi->ccio, TRUE, NULL); 2008 g_io_channel_unref(mi->ccio); 2009 mi->ccio = NULL; 2010 } 2011 2012 if (mi->dcio) { 2013 g_io_channel_shutdown(mi->dcio, TRUE, NULL); 2014 g_io_channel_unref(mi->dcio); 2015 mi->dcio = NULL; 2016 } 2017 2018 for (l = mi->mcls; l; l = l->next) { 2019 mcap_mcl_shutdown(l->data); 2020 mcap_mcl_unref(l->data); 2021 } 2022 g_slist_free(mi->mcls); 2023 mi->mcls = NULL; 2024 2025 for (l = mi->cached; l; l = l->next) 2026 mcap_mcl_unref(l->data); 2027 g_slist_free(mi->cached); 2028 mi->cached = NULL; 2029 2030 g_free(mi); 2031} 2032 2033uint16_t mcap_get_ctrl_psm(struct mcap_instance *mi, GError **err) 2034{ 2035 uint16_t lpsm; 2036 2037 if (!(mi && mi->ccio)) { 2038 g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS, 2039 "Invalid MCAP instance"); 2040 return 0; 2041 } 2042 2043 if (!bt_io_get(mi->ccio, BT_IO_L2CAP, err, 2044 BT_IO_OPT_PSM, &lpsm, 2045 BT_IO_OPT_INVALID)) 2046 return 0; 2047 2048 return lpsm; 2049} 2050 2051uint16_t mcap_get_data_psm(struct mcap_instance *mi, GError **err) 2052{ 2053 uint16_t lpsm; 2054 2055 if (!(mi && mi->dcio)) { 2056 g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS, 2057 "Invalid MCAP instance"); 2058 return 0; 2059 } 2060 2061 if (!bt_io_get(mi->dcio, BT_IO_L2CAP, err, 2062 BT_IO_OPT_PSM, &lpsm, 2063 BT_IO_OPT_INVALID)) 2064 return 0; 2065 2066 return lpsm; 2067} 2068