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