hdp_util.c revision 1c5538a22468fb29f6bcd59f679dee1e1fa96ad4
1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. 6 * Authors: 7 * Santiago Carot Nemesio <sancane at gmail.com> 8 * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 * 24 */ 25 26#include <gdbus.h> 27 28#include <adapter.h> 29#include <device.h> 30#include <stdint.h> 31#include <hdp_types.h> 32#include <hdp_util.h> 33#include <mcap.h> 34 35#include <sdpd.h> 36#include <sdp_lib.h> 37#include <glib-helper.h> 38 39#include <btio.h> 40#include <mcap_lib.h> 41 42typedef gboolean (*parse_item_f)(DBusMessageIter *iter, gpointer user_data, 43 GError **err); 44 45struct dict_entry_func { 46 char *key; 47 parse_item_f func; 48}; 49 50struct get_mdep_data { 51 struct hdp_application *app; 52 gpointer data; 53 hdp_continue_mdep_f func; 54 GDestroyNotify destroy; 55}; 56 57struct conn_mcl_data { 58 int refs; 59 struct hdp_application *app; 60 gpointer data; 61 hdp_continue_proc_f func; 62 GDestroyNotify destroy; 63 struct hdp_device *dev; 64}; 65 66struct get_dcpsm_data { 67 gpointer data; 68 hdp_continue_dcpsm_f func; 69 GDestroyNotify destroy; 70}; 71 72static gboolean parse_dict_entry(struct dict_entry_func dict_context[], 73 DBusMessageIter *iter, 74 GError **err, 75 gpointer user_data) 76{ 77 DBusMessageIter entry; 78 char *key; 79 int ctype, i; 80 struct dict_entry_func df; 81 82 dbus_message_iter_recurse(iter, &entry); 83 ctype = dbus_message_iter_get_arg_type(&entry); 84 if (ctype != DBUS_TYPE_STRING) { 85 g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, 86 "Dictionary entries should have a string as key"); 87 return FALSE; 88 } 89 90 dbus_message_iter_get_basic(&entry, &key); 91 dbus_message_iter_next(&entry); 92 /* Find function and call it */ 93 for (i = 0, df = dict_context[0]; df.key; i++, df = dict_context[i]) { 94 if (g_ascii_strcasecmp(df.key, key) == 0) 95 return df.func(&entry, user_data, err); 96 } 97 98 g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, 99 "No function found for parsing value for key %s", key); 100 return FALSE; 101} 102 103static gboolean parse_dict(struct dict_entry_func dict_context[], 104 DBusMessageIter *iter, 105 GError **err, 106 gpointer user_data) 107{ 108 int ctype; 109 DBusMessageIter dict; 110 111 ctype = dbus_message_iter_get_arg_type(iter); 112 if (ctype != DBUS_TYPE_ARRAY) { 113 g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR, 114 "Dictionary should be an array"); 115 return FALSE; 116 } 117 118 dbus_message_iter_recurse(iter, &dict); 119 while ((ctype = dbus_message_iter_get_arg_type(&dict)) != 120 DBUS_TYPE_INVALID) { 121 if (ctype != DBUS_TYPE_DICT_ENTRY) { 122 g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR, 123 "Dictionary array should " 124 "contain dict entries"); 125 return FALSE; 126 } 127 128 /* Start parsing entry */ 129 if (!parse_dict_entry(dict_context, &dict, err, 130 user_data)) 131 return FALSE; 132 /* Finish entry parsing */ 133 134 dbus_message_iter_next(&dict); 135 } 136 137 return TRUE; 138} 139 140static gboolean parse_data_type(DBusMessageIter *iter, gpointer data, 141 GError **err) 142{ 143 struct hdp_application *app = data; 144 DBusMessageIter *value, variant; 145 int ctype; 146 147 ctype = dbus_message_iter_get_arg_type(iter); 148 value = iter; 149 if (ctype == DBUS_TYPE_VARIANT) { 150 /* Get value inside the variable */ 151 dbus_message_iter_recurse(iter, &variant); 152 ctype = dbus_message_iter_get_arg_type(&variant); 153 value = &variant; 154 } 155 156 if (ctype != DBUS_TYPE_UINT16) { 157 g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, 158 "Final value for data type should be uint16"); 159 return FALSE; 160 } 161 162 dbus_message_iter_get_basic(value, &app->data_type); 163 app->data_type_set = TRUE; 164 return TRUE; 165} 166 167static gboolean parse_role(DBusMessageIter *iter, gpointer data, GError **err) 168{ 169 struct hdp_application *app = data; 170 DBusMessageIter value; 171 DBusMessageIter *string; 172 int ctype; 173 const char *role; 174 175 ctype = dbus_message_iter_get_arg_type(iter); 176 if (ctype == DBUS_TYPE_VARIANT) { 177 /* Get value inside the variable */ 178 dbus_message_iter_recurse(iter, &value); 179 ctype = dbus_message_iter_get_arg_type(&value); 180 string = &value; 181 } else 182 string = iter; 183 184 if (ctype != DBUS_TYPE_STRING) { 185 g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR, 186 "Value data spec should be variable or string"); 187 return FALSE; 188 } 189 190 dbus_message_iter_get_basic(string, &role); 191 if (g_ascii_strcasecmp(role, HDP_SINK_ROLE_AS_STRING) == 0) 192 app->role = HDP_SINK; 193 else if (g_ascii_strcasecmp(role, HDP_SOURCE_ROLE_AS_STRING) == 0) 194 app->role = HDP_SOURCE; 195 else { 196 g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR, 197 "Role value should be \"source\" or \"sink\""); 198 return FALSE; 199 } 200 201 app->role_set = TRUE; 202 return TRUE; 203} 204 205static gboolean parse_desc(DBusMessageIter *iter, gpointer data, GError **err) 206{ 207 struct hdp_application *app = data; 208 DBusMessageIter *string, variant; 209 int ctype; 210 const char *desc; 211 212 ctype = dbus_message_iter_get_arg_type(iter); 213 if (ctype == DBUS_TYPE_VARIANT) { 214 /* Get value inside the variable */ 215 dbus_message_iter_recurse(iter, &variant); 216 ctype = dbus_message_iter_get_arg_type(&variant); 217 string = &variant; 218 } else 219 string = iter; 220 221 if (ctype != DBUS_TYPE_STRING) { 222 g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, 223 "Value data spec should be variable or string"); 224 return FALSE; 225 } 226 227 dbus_message_iter_get_basic(string, &desc); 228 app->description = g_strdup(desc); 229 return TRUE; 230} 231 232static gboolean parse_chan_type(DBusMessageIter *iter, gpointer data, 233 GError **err) 234{ 235 struct hdp_application *app = data; 236 DBusMessageIter *value, variant; 237 int ctype; 238 239 ctype = dbus_message_iter_get_arg_type(iter); 240 value = iter; 241 if (ctype == DBUS_TYPE_VARIANT) { 242 /* Get value inside the variable */ 243 dbus_message_iter_recurse(iter, &variant); 244 ctype = dbus_message_iter_get_arg_type(&variant); 245 value = &variant; 246 } 247 248 if (ctype != DBUS_TYPE_UINT16) { 249 g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, 250 "Final value for channel type should be a uint16"); 251 return FALSE; 252 } 253 254 dbus_message_iter_get_basic(value, &app->data_type); 255 if (app->data_type < HDP_RELIABLE_DC || 256 app->data_type > HDP_STREAMING_DC) { 257 g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, 258 "Invalid value for data type"); 259 return FALSE; 260 } 261 262 app->data_type_set = TRUE; 263 return TRUE; 264} 265 266static struct dict_entry_func dict_parser[] = { 267 {"DataType", parse_data_type}, 268 {"Role", parse_role}, 269 {"Description", parse_desc}, 270 {"ChannelType", parse_chan_type}, 271 {NULL, NULL} 272}; 273 274struct hdp_application *hdp_get_app_config(DBusMessageIter *iter, GError **err) 275{ 276 struct hdp_application *app; 277 278 app = g_new0(struct hdp_application, 1); 279 if (!parse_dict(dict_parser, iter, err, app)) 280 goto fail; 281 if (!app->data_type_set || !app->role_set) { 282 g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR, 283 "Mandatory fields aren't set"); 284 goto fail; 285 } 286 return app; 287 288fail: 289 g_free(app); 290 return NULL; 291} 292 293static gboolean is_app_role(GSList *app_list, HdpRole role) 294{ 295 struct hdp_application *app; 296 GSList *l; 297 298 for (l = app_list; l; l = l->next) { 299 app = l->data; 300 if (app->role == role) 301 return TRUE; 302 } 303 304 return FALSE; 305} 306 307static gboolean set_sdp_services_uuid(sdp_record_t *record, HdpRole role) 308{ 309 uuid_t svc_uuid_source, svc_uuid_sink; 310 sdp_list_t *svc_list = NULL; 311 312 sdp_uuid16_create(&svc_uuid_sink, HDP_SINK_SVCLASS_ID); 313 sdp_uuid16_create(&svc_uuid_source, HDP_SOURCE_SVCLASS_ID); 314 315 sdp_get_service_classes(record, &svc_list); 316 317 if (role == HDP_SOURCE) { 318 if (!sdp_list_find(svc_list, &svc_uuid_source, sdp_uuid_cmp)) 319 svc_list = sdp_list_append(svc_list, &svc_uuid_source); 320 } else if (role == HDP_SINK) { 321 if (!sdp_list_find(svc_list, &svc_uuid_sink, sdp_uuid_cmp)) 322 svc_list = sdp_list_append(svc_list, &svc_uuid_sink); 323 } 324 325 if (sdp_set_service_classes(record, svc_list) < 0) { 326 sdp_list_free(svc_list, NULL); 327 return FALSE; 328 } 329 330 sdp_list_free(svc_list, NULL); 331 return TRUE; 332} 333 334static gboolean register_service_protocols(struct hdp_adapter *adapter, 335 sdp_record_t *sdp_record) 336{ 337 gboolean ret; 338 uuid_t l2cap_uuid, mcap_c_uuid; 339 sdp_list_t *l2cap_list, *proto_list, *mcap_list, *access_proto_list; 340 sdp_data_t *psm, *mcap_ver; 341 uint16_t version = MCAP_VERSION; 342 343 /* set l2cap information */ 344 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); 345 l2cap_list = sdp_list_append(NULL, &l2cap_uuid); 346 if (!l2cap_list) { 347 ret = FALSE; 348 goto end; 349 } 350 351 psm = sdp_data_alloc(SDP_UINT16, &adapter->ccpsm); 352 if (!psm) { 353 ret = FALSE; 354 goto end; 355 } 356 357 if (!sdp_list_append(l2cap_list, psm)) { 358 ret = FALSE; 359 goto end; 360 } 361 362 proto_list = sdp_list_append(NULL, l2cap_list); 363 if (!proto_list) { 364 ret = FALSE; 365 goto end; 366 } 367 368 /* set mcap information */ 369 sdp_uuid16_create(&mcap_c_uuid, MCAP_CTRL_UUID); 370 mcap_list = sdp_list_append(NULL, &mcap_c_uuid); 371 if (!mcap_list) { 372 ret = FALSE; 373 goto end; 374 } 375 376 mcap_ver = sdp_data_alloc(SDP_UINT16, &version); 377 if (!mcap_ver) { 378 ret = FALSE; 379 goto end; 380 } 381 382 if (!sdp_list_append( mcap_list, mcap_ver)) { 383 ret = FALSE; 384 goto end; 385 } 386 387 if (!sdp_list_append( proto_list, mcap_list)) { 388 ret = FALSE; 389 goto end; 390 } 391 392 /* attach protocol information to service record */ 393 access_proto_list = sdp_list_append(NULL, proto_list); 394 if (!access_proto_list) { 395 ret = FALSE; 396 goto end; 397 } 398 399 if (sdp_set_access_protos(sdp_record, access_proto_list) < 0) { 400 ret = FALSE; 401 goto end; 402 } 403 ret = TRUE; 404 405end: 406 if (l2cap_list) 407 sdp_list_free(l2cap_list, NULL); 408 if (mcap_list) 409 sdp_list_free(mcap_list, NULL); 410 if (proto_list) 411 sdp_list_free(proto_list, NULL); 412 if (access_proto_list) 413 sdp_list_free(access_proto_list, NULL); 414 if (psm) 415 sdp_data_free(psm); 416 if (mcap_ver) 417 sdp_data_free(mcap_ver); 418 419 return ret; 420} 421 422static gboolean register_service_profiles(sdp_record_t *sdp_record) 423{ 424 gboolean ret; 425 sdp_list_t *profile_list; 426 sdp_profile_desc_t hdp_profile; 427 428 /* set hdp information */ 429 sdp_uuid16_create( &hdp_profile.uuid, HDP_SVCLASS_ID); 430 hdp_profile.version = HDP_VERSION; 431 profile_list = sdp_list_append(NULL, &hdp_profile); 432 if (!profile_list) 433 return FALSE; 434 435 /* set profile descriptor list */ 436 if (sdp_set_profile_descs(sdp_record, profile_list) < 0) 437 ret = FALSE; 438 else 439 ret = TRUE; 440 441 sdp_list_free(profile_list, NULL); 442 return ret; 443} 444 445static gboolean register_service_aditional_protocols( 446 struct hdp_adapter *adapter, 447 sdp_record_t *sdp_record) 448{ 449 gboolean ret; 450 uuid_t l2cap_uuid, mcap_d_uuid; 451 sdp_list_t *l2cap_list, *proto_list, *mcap_list, *access_proto_list; 452 sdp_data_t *psm = NULL; 453 454 /* set l2cap information */ 455 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); 456 l2cap_list = sdp_list_append(NULL, &l2cap_uuid); 457 if (!l2cap_list) { 458 ret = FALSE; 459 goto end; 460 } 461 462 psm = sdp_data_alloc(SDP_UINT16, &adapter->dcpsm); 463 if (!psm) { 464 ret = FALSE; 465 goto end; 466 } 467 468 if (!sdp_list_append(l2cap_list, psm)) { 469 ret = FALSE; 470 goto end; 471 } 472 473 proto_list = sdp_list_append(NULL, l2cap_list); 474 if (!proto_list) { 475 ret = FALSE; 476 goto end; 477 } 478 479 /* set mcap information */ 480 sdp_uuid16_create(&mcap_d_uuid, MCAP_DATA_UUID); 481 mcap_list = sdp_list_append(NULL, &mcap_d_uuid); 482 if (!mcap_list) { 483 ret = FALSE; 484 goto end; 485 } 486 487 if (!sdp_list_append( proto_list, mcap_list)) { 488 ret = FALSE; 489 goto end; 490 } 491 492 /* attach protocol information to service record */ 493 access_proto_list = sdp_list_append(NULL, proto_list); 494 if (!access_proto_list) { 495 ret = FALSE; 496 goto end; 497 } 498 499 if (sdp_set_add_access_protos(sdp_record, access_proto_list) < 0) 500 ret = FALSE; 501 else 502 ret = TRUE; 503 504end: 505 if (l2cap_list) 506 sdp_list_free(l2cap_list, NULL); 507 if (mcap_list) 508 sdp_list_free(mcap_list, NULL); 509 if (proto_list) 510 sdp_list_free(proto_list, NULL); 511 if (access_proto_list) 512 sdp_list_free(access_proto_list, NULL); 513 if (psm) 514 sdp_data_free(psm); 515 516 return ret; 517} 518 519static sdp_list_t *app_to_sdplist(struct hdp_application *app) 520{ 521 sdp_data_t *mdepid, *dtype, *role, *desc; 522 sdp_list_t *f_list; 523 524 mdepid = sdp_data_alloc(SDP_UINT8, &app->id); 525 if (!mdepid) 526 return NULL; 527 528 dtype = sdp_data_alloc(SDP_UINT16, &app->data_type); 529 if (!dtype) 530 goto fail; 531 532 role = sdp_data_alloc(SDP_UINT8, &app->role); 533 if (!role) 534 goto fail; 535 536 if (app->description) { 537 desc = sdp_data_alloc(SDP_TEXT_STR8, app->description); 538 if (!desc) 539 goto fail; 540 } 541 542 f_list = sdp_list_append(NULL, mdepid); 543 if (!f_list) 544 goto fail; 545 546 if (!sdp_list_append(f_list, dtype)) 547 goto fail; 548 549 if (!sdp_list_append(f_list, role)) 550 goto fail; 551 552 if (desc) 553 if (!sdp_list_append(f_list, desc)) 554 goto fail; 555 556 return f_list; 557 558fail: 559 if (f_list) 560 sdp_list_free(f_list, NULL); 561 if (mdepid) 562 sdp_data_free(mdepid); 563 if (dtype) 564 sdp_data_free(dtype); 565 if (role) 566 sdp_data_free(role); 567 if (desc) 568 sdp_data_free(desc); 569 570 return NULL; 571} 572 573static gboolean register_features(struct hdp_application *app, 574 sdp_list_t **sup_features) 575{ 576 sdp_list_t *hdp_feature; 577 578 hdp_feature = app_to_sdplist(app); 579 if (!hdp_feature) 580 goto fail; 581 582 if (!*sup_features) { 583 *sup_features = sdp_list_append(NULL, hdp_feature); 584 if (!*sup_features) 585 goto fail; 586 } else if (!sdp_list_append(*sup_features, hdp_feature)) { 587 goto fail; 588 } 589 590 return TRUE; 591 592fail: 593 if (hdp_feature) 594 sdp_list_free(hdp_feature, (sdp_free_func_t)sdp_data_free); 595 return FALSE; 596} 597 598static void free_hdp_list(void *list) 599{ 600 sdp_list_t *hdp_list = list; 601 602 sdp_list_free(hdp_list, (sdp_free_func_t)sdp_data_free); 603} 604 605static gboolean register_service_sup_features(GSList *app_list, 606 sdp_record_t *sdp_record) 607{ 608 GSList *l; 609 sdp_list_t *sup_features = NULL; 610 611 for (l = app_list; l; l = l->next) { 612 if (!register_features(l->data, &sup_features)) 613 return FALSE; 614 } 615 616 if (sdp_set_supp_feat(sdp_record, sup_features) < 0) { 617 sdp_list_free(sup_features, free_hdp_list); 618 return FALSE; 619 } 620 621 return TRUE; 622} 623 624static gboolean register_data_exchange_spec(sdp_record_t *record) 625{ 626 sdp_data_t *spec; 627 uint8_t data_spec = DATA_EXCHANGE_SPEC_11073; 628 /* As by now 11073 is the only supported we set it by default */ 629 630 spec = sdp_data_alloc(SDP_UINT8, &data_spec); 631 if (!spec) 632 return FALSE; 633 634 if (sdp_attr_add(record, SDP_ATTR_DATA_EXCHANGE_SPEC, spec) < 0) { 635 sdp_data_free(spec); 636 return FALSE; 637 } 638 639 return TRUE; 640} 641 642static gboolean register_mcap_features(sdp_record_t *sdp_record) 643{ 644 sdp_data_t *mcap_proc; 645 uint8_t mcap_sup_proc = MCAP_SUP_PROC; 646 647 mcap_proc = sdp_data_alloc(SDP_UINT8, &mcap_sup_proc); 648 if (!mcap_proc) 649 return FALSE; 650 651 if (sdp_attr_add(sdp_record, SDP_ATTR_MCAP_SUPPORTED_PROCEDURES, 652 mcap_proc) < 0) { 653 sdp_data_free(mcap_proc); 654 return FALSE; 655 } 656 657 return TRUE; 658} 659 660gboolean hdp_update_sdp_record(struct hdp_adapter *adapter, GSList *app_list) 661{ 662 sdp_record_t *sdp_record; 663 bdaddr_t addr; 664 665 if (adapter->sdp_handler) 666 remove_record_from_server(adapter->sdp_handler); 667 668 if (!app_list) { 669 adapter->sdp_handler = 0; 670 return TRUE; 671 } 672 673 sdp_record = sdp_record_alloc(); 674 if (!sdp_record) 675 return FALSE; 676 677 if (adapter->sdp_handler) 678 sdp_record->handle = adapter->sdp_handler; 679 else 680 sdp_record->handle = 0xffffffff; /* Set automatically */ 681 682 if (is_app_role(app_list, HDP_SINK)) 683 set_sdp_services_uuid(sdp_record, HDP_SINK); 684 if (is_app_role(app_list, HDP_SOURCE)) 685 set_sdp_services_uuid(sdp_record, HDP_SOURCE); 686 687 if (!register_service_protocols(adapter, sdp_record)) 688 goto fail; 689 if (!register_service_profiles(sdp_record)) 690 goto fail; 691 if (!register_service_aditional_protocols(adapter, sdp_record)) 692 goto fail; 693 694 sdp_set_info_attr(sdp_record, HDP_SERVICE_NAME, HDP_SERVICE_PROVIDER, 695 HDP_SERVICE_DSC); 696 if (!register_service_sup_features(app_list, sdp_record)) 697 goto fail; 698 if (!register_data_exchange_spec(sdp_record)) 699 goto fail; 700 701 register_mcap_features(sdp_record); 702 703 if (sdp_set_record_state(sdp_record, adapter->record_state++)) 704 goto fail; 705 706 adapter_get_address(adapter->btd_adapter, &addr); 707 708 if (add_record_to_server(&addr, sdp_record) < 0) 709 goto fail; 710 adapter->sdp_handler = sdp_record->handle; 711 return TRUE; 712 713fail: 714 if (sdp_record) 715 sdp_record_free(sdp_record); 716 return FALSE; 717} 718 719static gboolean check_role(uint8_t rec_role, uint8_t app_role) 720{ 721 if ((rec_role == HDP_SINK && app_role == HDP_SOURCE) || 722 (rec_role == HDP_SOURCE && app_role == HDP_SINK)) 723 return TRUE; 724 725 return FALSE; 726} 727 728static gboolean get_mdep_from_rec(const sdp_record_t *rec, uint8_t role, 729 uint16_t d_type, uint8_t *mdep, char **desc) 730{ 731 sdp_data_t *list, *feat, *data_type, *mdepid, *role_t, *desc_t; 732 733 if (!desc && !mdep) 734 return TRUE; 735 736 list = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST); 737 738 if (list->dtd != SDP_SEQ8 && list->dtd != SDP_SEQ16 && 739 list->dtd != SDP_SEQ32) 740 return FALSE; 741 742 for (feat = list->val.dataseq; feat; feat = feat->next) { 743 if (feat->dtd != SDP_SEQ8 && feat->dtd != SDP_SEQ16 && 744 feat->dtd != SDP_SEQ32) 745 continue; 746 747 mdepid = feat->val.dataseq; 748 if (!mdepid) 749 continue; 750 751 data_type = mdepid->next; 752 if (!data_type) 753 continue; 754 755 role_t = data_type->next; 756 if (!role_t) 757 continue; 758 759 desc_t = role_t->next; 760 761 if (data_type->dtd != SDP_UINT16 || mdepid->dtd != SDP_UINT8 || 762 role_t->dtd != SDP_UINT8) 763 continue; 764 765 if (data_type->val.uint16 != d_type || 766 !check_role(role_t->val.uint8, role)) 767 continue; 768 769 if (mdep) 770 *mdep = mdepid->val.uint8; 771 772 if (desc && desc_t && (desc_t->dtd == SDP_TEXT_STR8 || 773 desc_t->dtd == SDP_TEXT_STR16 || 774 desc_t->dtd == SDP_TEXT_STR32)) 775 *desc = g_strdup(desc_t->val.str); 776 777 return TRUE; 778 } 779 780 return FALSE; 781} 782 783static void get_mdep_cb(sdp_list_t *recs, int err, gpointer user_data) 784{ 785 struct get_mdep_data *mdep_data = user_data; 786 GError *gerr = NULL; 787 uint8_t mdep; 788 789 if (err || !recs) { 790 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, 791 "Error getting remote SDP records"); 792 mdep_data->func(0, mdep_data->data, gerr); 793 g_error_free(gerr); 794 return; 795 } 796 797 if (!get_mdep_from_rec(recs->data, mdep_data->app->role, 798 mdep_data->app->data_type, &mdep, NULL)) { 799 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, 800 "No matching MDEP found"); 801 mdep_data->func(0, mdep_data->data, gerr); 802 g_error_free(gerr); 803 return; 804 } 805 806 mdep_data->func(mdep, mdep_data->data, NULL); 807} 808 809static void free_mdep_data(gpointer data) 810{ 811 struct get_mdep_data *mdep_data = data; 812 813 if (mdep_data->destroy) 814 mdep_data->destroy(mdep_data->data); 815 816 g_free(mdep_data); 817} 818 819gboolean hdp_get_mdep(struct hdp_device *device, struct hdp_application *app, 820 hdp_continue_mdep_f func, gpointer data, 821 GDestroyNotify destroy, GError **err) 822{ 823 struct get_mdep_data *mdep_data; 824 bdaddr_t dst, src; 825 uuid_t uuid; 826 827 device_get_address(device->dev, &dst); 828 adapter_get_address(device_get_adapter(device->dev), &src); 829 830 mdep_data = g_new0(struct get_mdep_data, 1); 831 mdep_data->app = app; 832 mdep_data->func = func; 833 mdep_data->data = data; 834 mdep_data->destroy = destroy; 835 836 bt_string2uuid(&uuid, HDP_UUID); 837 if (bt_search_service(&src, &dst, &uuid, get_mdep_cb, mdep_data, 838 free_mdep_data)) { 839 g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR, 840 "Can't get remote SDP record"); 841 g_free(mdep_data); 842 return FALSE; 843 } 844 845 return TRUE; 846} 847 848static gboolean get_prot_desc_entry(sdp_data_t *entry, int type, guint16 *val) 849{ 850 sdp_data_t *iter; 851 int proto; 852 853 if (!entry || (entry->dtd != SDP_SEQ8 && entry->dtd != SDP_SEQ16 && 854 entry->dtd != SDP_SEQ32)) 855 return FALSE; 856 857 iter = entry->val.dataseq; 858 if (!(iter->dtd & SDP_UUID_UNSPEC)) 859 return FALSE; 860 861 proto = sdp_uuid_to_proto(&iter->val.uuid); 862 if (proto != type) 863 return FALSE; 864 865 if (!val) 866 return TRUE; 867 868 iter = iter->next; 869 if (iter->dtd != SDP_UINT16) 870 return FALSE; 871 872 *val = iter->val.uint16; 873 return TRUE; 874} 875 876static gboolean hdp_get_prot_desc_list(const sdp_record_t *rec, guint16 *psm, 877 guint16 *version) 878{ 879 sdp_data_t *pdl, *p0, *p1; 880 881 if (!psm && !version) 882 return TRUE; 883 884 pdl = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST); 885 if (pdl->dtd != SDP_SEQ8 && pdl->dtd != SDP_SEQ16 && 886 pdl->dtd != SDP_SEQ32) 887 return FALSE; 888 889 p0 = pdl->val.dataseq; 890 if (!get_prot_desc_entry(p0, L2CAP_UUID, psm)) 891 return FALSE; 892 893 p1 = p0->next; 894 if (!get_prot_desc_entry(p1, MCAP_CTRL_UUID, version)) 895 return FALSE; 896 897 return TRUE; 898} 899 900static gboolean hdp_get_add_prot_desc_list(const sdp_record_t *rec, 901 guint16 *psm) 902{ 903 sdp_data_t *pdl, *p0, *p1; 904 905 if (!psm) 906 return TRUE; 907 908 pdl = sdp_data_get(rec, SDP_ATTR_ADD_PROTO_DESC_LIST); 909 if (pdl->dtd != SDP_SEQ8) 910 return FALSE; 911 pdl = pdl->val.dataseq; 912 if (pdl->dtd != SDP_SEQ8) 913 return FALSE; 914 915 p0 = pdl->val.dataseq; 916 917 if (!get_prot_desc_entry(p0, L2CAP_UUID, psm)) 918 return FALSE; 919 p1 = p0->next; 920 if (!get_prot_desc_entry(p1, MCAP_DATA_UUID, NULL)) 921 return FALSE; 922 923 return TRUE; 924} 925 926static gboolean get_ccpsm(sdp_list_t *recs, uint16_t *ccpsm) 927{ 928 sdp_list_t *l; 929 sdp_record_t *rec; 930 931 for (l = recs; l; l = l->next) { 932 rec = l->data; 933 934 if (hdp_get_prot_desc_list(rec, ccpsm, NULL)) 935 return TRUE; 936 } 937 938 return FALSE; 939} 940 941static gboolean get_dcpsm(sdp_list_t *recs, uint16_t *dcpsm) 942{ 943 sdp_list_t *l; 944 sdp_record_t *rec; 945 946 for (l = recs; l; l = l->next) { 947 rec = l->data; 948 949 if (hdp_get_add_prot_desc_list(rec, dcpsm)) 950 return TRUE; 951 } 952 953 return FALSE; 954} 955 956static void con_mcl_data_unref(struct conn_mcl_data *conn_data) 957{ 958 if (!conn_data) 959 return; 960 961 if (--conn_data->refs > 0) 962 return; 963 964 if (conn_data->destroy) 965 conn_data->destroy(conn_data->data); 966 967 g_free(conn_data); 968} 969 970static void destroy_con_mcl_data(gpointer data) 971{ 972 con_mcl_data_unref(data); 973} 974 975static struct conn_mcl_data *con_mcl_data_ref(struct conn_mcl_data *conn_data) 976{ 977 if (!conn_data) 978 return NULL; 979 980 conn_data->refs++; 981 return conn_data; 982} 983 984static void create_mcl_cb(struct mcap_mcl *mcl, GError *err, gpointer data) 985{ 986 struct conn_mcl_data *conn_data = data; 987 struct hdp_device *device = conn_data->dev; 988 989 if (err) { 990 conn_data->func(conn_data->data, err); 991 return; 992 } 993 994 if (!device->mcl) 995 device->mcl = mcap_mcl_ref(mcl); 996 device->mcl_conn = TRUE; 997 998 conn_data->func(conn_data->data, NULL); 999} 1000 1001static void search_cb(sdp_list_t *recs, int err, gpointer user_data) 1002{ 1003 struct conn_mcl_data *conn_data = user_data; 1004 GError *gerr = NULL; 1005 bdaddr_t dst; 1006 uint16_t ccpsm; 1007 1008 if (err || !recs) { 1009 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, 1010 "Error getting remote SDP records"); 1011 goto fail; 1012 } 1013 1014 if (!get_ccpsm(recs, &ccpsm)) { 1015 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, 1016 "Can't get remote PSM for control channel"); 1017 goto fail; 1018 } 1019 1020 conn_data = con_mcl_data_ref(conn_data); 1021 1022 device_get_address(conn_data->dev->dev, &dst); 1023 if (!mcap_create_mcl(conn_data->dev->hdp_adapter->mi, &dst, ccpsm, 1024 create_mcl_cb, conn_data, 1025 destroy_con_mcl_data, &gerr)) { 1026 con_mcl_data_unref(conn_data); 1027 goto fail; 1028 } 1029 return; 1030fail: 1031 conn_data->func(conn_data->data, gerr); 1032 g_error_free(gerr); 1033} 1034 1035gboolean hdp_establish_mcl(struct hdp_device *device, 1036 struct hdp_application *app, 1037 hdp_continue_proc_f func, 1038 gpointer data, 1039 GDestroyNotify destroy, 1040 GError **err) 1041{ 1042 struct conn_mcl_data *conn_data; 1043 bdaddr_t dst, src; 1044 uuid_t uuid; 1045 1046 device_get_address(device->dev, &dst); 1047 adapter_get_address(device_get_adapter(device->dev), &src); 1048 1049 conn_data = g_new0(struct conn_mcl_data, 1); 1050 conn_data->refs = 1; 1051 conn_data->app = app; 1052 conn_data->func = func; 1053 conn_data->data = data; 1054 conn_data->destroy = destroy; 1055 conn_data->dev = device; 1056 1057 bt_string2uuid(&uuid, HDP_UUID); 1058 if (bt_search_service(&src, &dst, &uuid, search_cb, conn_data, 1059 destroy_con_mcl_data)) { 1060 g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR, 1061 "Can't get remote SDP record"); 1062 g_free(conn_data); 1063 return FALSE; 1064 } 1065 return TRUE; 1066} 1067 1068static void get_dcpsm_cb(sdp_list_t *recs, int err, gpointer data) 1069{ 1070 struct get_dcpsm_data *dcpsm_data = data; 1071 GError *gerr = NULL; 1072 uint16_t dcpsm; 1073 1074 if (err || !recs) { 1075 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, 1076 "Error getting remote SDP records"); 1077 goto fail; 1078 } 1079 1080 if (!get_dcpsm(recs, &dcpsm)) { 1081 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, 1082 "Can't get remote PSM for data channel"); 1083 goto fail; 1084 } 1085 1086 dcpsm_data->func(dcpsm, dcpsm_data->data, NULL); 1087 return; 1088fail: 1089 dcpsm_data->func(0, dcpsm_data->data, gerr); 1090 g_error_free(gerr); 1091} 1092 1093static void free_dcpsm_data(gpointer data) 1094{ 1095 struct get_dcpsm_data *dcpsm_data = data; 1096 1097 if (!dcpsm_data) 1098 return; 1099 1100 if (dcpsm_data->destroy) 1101 dcpsm_data->destroy(dcpsm_data->data); 1102 1103 g_free(dcpsm_data); 1104} 1105 1106gboolean hdp_get_dcpsm(struct hdp_device *device, hdp_continue_dcpsm_f func, 1107 gpointer data, 1108 GDestroyNotify destroy, 1109 GError **err) 1110{ 1111 struct get_dcpsm_data *dcpsm_data; 1112 bdaddr_t dst, src; 1113 uuid_t uuid; 1114 1115 device_get_address(device->dev, &dst); 1116 adapter_get_address(device_get_adapter(device->dev), &src); 1117 1118 dcpsm_data = g_new0(struct get_dcpsm_data, 1); 1119 dcpsm_data->func = func; 1120 dcpsm_data->data = data; 1121 dcpsm_data->destroy = destroy; 1122 1123 bt_string2uuid(&uuid, HDP_UUID); 1124 if (bt_search_service(&src, &dst, &uuid, get_dcpsm_cb, dcpsm_data, 1125 free_dcpsm_data)) { 1126 g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR, 1127 "Can't get remote SDP record"); 1128 g_free(dcpsm_data); 1129 return FALSE; 1130 } 1131 return TRUE; 1132} 1133