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