hdp_util.c revision b571d6d32701493af6493f90cf0cd4b3870f6606
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 39typedef gboolean (*parse_item_f)(DBusMessageIter *iter, gpointer user_data, 40 GError **err); 41 42struct dict_entry_func { 43 char *key; 44 parse_item_f func; 45}; 46 47struct get_mdep_data { 48 struct hdp_application *app; 49 gpointer data; 50 hdp_continue_mdep_f func; 51 GDestroyNotify destroy; 52}; 53 54static gboolean parse_dict_entry(struct dict_entry_func dict_context[], 55 DBusMessageIter *iter, 56 GError **err, 57 gpointer user_data) 58{ 59 DBusMessageIter entry; 60 char *key; 61 int ctype, i; 62 struct dict_entry_func df; 63 64 dbus_message_iter_recurse(iter, &entry); 65 ctype = dbus_message_iter_get_arg_type(&entry); 66 if (ctype != DBUS_TYPE_STRING) { 67 g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, 68 "Dictionary entries should have a string as key"); 69 return FALSE; 70 } 71 72 dbus_message_iter_get_basic(&entry, &key); 73 dbus_message_iter_next(&entry); 74 /* Find function and call it */ 75 for (i = 0, df = dict_context[0]; df.key; i++, df = dict_context[i]) { 76 if (g_ascii_strcasecmp(df.key, key) == 0) 77 return df.func(&entry, user_data, err); 78 } 79 80 g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, 81 "No function found for parsing value for key %s", key); 82 return FALSE; 83} 84 85static gboolean parse_dict(struct dict_entry_func dict_context[], 86 DBusMessageIter *iter, 87 GError **err, 88 gpointer user_data) 89{ 90 int ctype; 91 DBusMessageIter dict; 92 93 ctype = dbus_message_iter_get_arg_type(iter); 94 if (ctype != DBUS_TYPE_ARRAY) { 95 g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR, 96 "Dictionary should be an array"); 97 return FALSE; 98 } 99 100 dbus_message_iter_recurse(iter, &dict); 101 while ((ctype = dbus_message_iter_get_arg_type(&dict)) != 102 DBUS_TYPE_INVALID) { 103 if (ctype != DBUS_TYPE_DICT_ENTRY) { 104 g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR, 105 "Dictionary array should " 106 "contain dict entries"); 107 return FALSE; 108 } 109 110 /* Start parsing entry */ 111 if (!parse_dict_entry(dict_context, &dict, err, 112 user_data)) 113 return FALSE; 114 /* Finish entry parsing */ 115 116 dbus_message_iter_next(&dict); 117 } 118 119 return TRUE; 120} 121 122static gboolean parse_data_type(DBusMessageIter *iter, gpointer data, 123 GError **err) 124{ 125 struct hdp_application *app = data; 126 DBusMessageIter *value, variant; 127 int ctype; 128 129 ctype = dbus_message_iter_get_arg_type(iter); 130 value = iter; 131 if (ctype == DBUS_TYPE_VARIANT) { 132 /* Get value inside the variable */ 133 dbus_message_iter_recurse(iter, &variant); 134 ctype = dbus_message_iter_get_arg_type(&variant); 135 value = &variant; 136 } 137 138 if (ctype != DBUS_TYPE_UINT16) { 139 g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, 140 "Final value for data type should be uint16"); 141 return FALSE; 142 } 143 144 dbus_message_iter_get_basic(value, &app->data_type); 145 app->data_type_set = TRUE; 146 return TRUE; 147} 148 149static gboolean parse_role(DBusMessageIter *iter, gpointer data, GError **err) 150{ 151 struct hdp_application *app = data; 152 DBusMessageIter value; 153 DBusMessageIter *string; 154 int ctype; 155 const char *role; 156 157 ctype = dbus_message_iter_get_arg_type(iter); 158 if (ctype == DBUS_TYPE_VARIANT) { 159 /* Get value inside the variable */ 160 dbus_message_iter_recurse(iter, &value); 161 ctype = dbus_message_iter_get_arg_type(&value); 162 string = &value; 163 } else 164 string = iter; 165 166 if (ctype != DBUS_TYPE_STRING) { 167 g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR, 168 "Value data spec should be variable or string"); 169 return FALSE; 170 } 171 172 dbus_message_iter_get_basic(string, &role); 173 if (g_ascii_strcasecmp(role, HDP_SINK_ROLE_AS_STRING) == 0) 174 app->role = HDP_SINK; 175 else if (g_ascii_strcasecmp(role, HDP_SOURCE_ROLE_AS_STRING) == 0) 176 app->role = HDP_SOURCE; 177 else { 178 g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR, 179 "Role value should be \"source\" or \"sink\""); 180 return FALSE; 181 } 182 183 app->role_set = TRUE; 184 return TRUE; 185} 186 187static gboolean parse_desc(DBusMessageIter *iter, gpointer data, GError **err) 188{ 189 struct hdp_application *app = data; 190 DBusMessageIter *string, variant; 191 int ctype; 192 const char *desc; 193 194 ctype = dbus_message_iter_get_arg_type(iter); 195 if (ctype == DBUS_TYPE_VARIANT) { 196 /* Get value inside the variable */ 197 dbus_message_iter_recurse(iter, &variant); 198 ctype = dbus_message_iter_get_arg_type(&variant); 199 string = &variant; 200 } else 201 string = iter; 202 203 if (ctype != DBUS_TYPE_STRING) { 204 g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, 205 "Value data spec should be variable or string"); 206 return FALSE; 207 } 208 209 dbus_message_iter_get_basic(string, &desc); 210 app->description = g_strdup(desc); 211 return TRUE; 212} 213 214static gboolean parse_chan_type(DBusMessageIter *iter, gpointer data, 215 GError **err) 216{ 217 struct hdp_application *app = data; 218 DBusMessageIter *value, variant; 219 int ctype; 220 221 ctype = dbus_message_iter_get_arg_type(iter); 222 value = iter; 223 if (ctype == DBUS_TYPE_VARIANT) { 224 /* Get value inside the variable */ 225 dbus_message_iter_recurse(iter, &variant); 226 ctype = dbus_message_iter_get_arg_type(&variant); 227 value = &variant; 228 } 229 230 if (ctype != DBUS_TYPE_UINT16) { 231 g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, 232 "Final value for channel type should be a uint16"); 233 return FALSE; 234 } 235 236 dbus_message_iter_get_basic(value, &app->data_type); 237 if (app->data_type < HDP_RELIABLE_DC || 238 app->data_type > HDP_STREAMING_DC) { 239 g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, 240 "Invalid value for data type"); 241 return FALSE; 242 } 243 244 app->data_type_set = TRUE; 245 return TRUE; 246} 247 248static struct dict_entry_func dict_parser[] = { 249 {"DataType", parse_data_type}, 250 {"Role", parse_role}, 251 {"Description", parse_desc}, 252 {"ChannelType", parse_chan_type}, 253 {NULL, NULL} 254}; 255 256struct hdp_application *hdp_get_app_config(DBusMessageIter *iter, GError **err) 257{ 258 struct hdp_application *app; 259 260 app = g_new0(struct hdp_application, 1); 261 if (!parse_dict(dict_parser, iter, err, app)) 262 goto fail; 263 if (!app->data_type_set || !app->role_set) { 264 g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR, 265 "Mandatory fields aren't set"); 266 goto fail; 267 } 268 return app; 269 270fail: 271 g_free(app); 272 return NULL; 273} 274 275static gboolean is_app_role(GSList *app_list, HdpRole role) 276{ 277 struct hdp_application *app; 278 GSList *l; 279 280 for (l = app_list; l; l = l->next) { 281 app = l->data; 282 if (app->role == role) 283 return TRUE; 284 } 285 286 return FALSE; 287} 288 289static gboolean set_sdp_services_uuid(sdp_record_t *record, HdpRole role) 290{ 291 uuid_t svc_uuid_source, svc_uuid_sink; 292 sdp_list_t *svc_list = NULL; 293 294 sdp_uuid16_create(&svc_uuid_sink, HDP_SINK_SVCLASS_ID); 295 sdp_uuid16_create(&svc_uuid_source, HDP_SOURCE_SVCLASS_ID); 296 297 sdp_get_service_classes(record, &svc_list); 298 299 if (role == HDP_SOURCE) { 300 if (!sdp_list_find(svc_list, &svc_uuid_source, sdp_uuid_cmp)) 301 svc_list = sdp_list_append(svc_list, &svc_uuid_source); 302 } else if (role == HDP_SINK) { 303 if (!sdp_list_find(svc_list, &svc_uuid_sink, sdp_uuid_cmp)) 304 svc_list = sdp_list_append(svc_list, &svc_uuid_sink); 305 } 306 307 if (sdp_set_service_classes(record, svc_list) < 0) { 308 sdp_list_free(svc_list, NULL); 309 return FALSE; 310 } 311 312 sdp_list_free(svc_list, NULL); 313 return TRUE; 314} 315 316static gboolean register_service_protocols(struct hdp_adapter *adapter, 317 sdp_record_t *sdp_record) 318{ 319 gboolean ret; 320 uuid_t l2cap_uuid, mcap_c_uuid; 321 sdp_list_t *l2cap_list, *proto_list, *mcap_list, *access_proto_list; 322 sdp_data_t *psm, *mcap_ver; 323 uint16_t version = MCAP_VERSION; 324 325 /* set l2cap information */ 326 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); 327 l2cap_list = sdp_list_append(NULL, &l2cap_uuid); 328 if (!l2cap_list) { 329 ret = FALSE; 330 goto end; 331 } 332 333 psm = sdp_data_alloc(SDP_UINT16, &adapter->ccpsm); 334 if (!psm) { 335 ret = FALSE; 336 goto end; 337 } 338 339 if (!sdp_list_append(l2cap_list, psm)) { 340 ret = FALSE; 341 goto end; 342 } 343 344 proto_list = sdp_list_append(NULL, l2cap_list); 345 if (!proto_list) { 346 ret = FALSE; 347 goto end; 348 } 349 350 /* set mcap information */ 351 sdp_uuid16_create(&mcap_c_uuid, MCAP_CTRL_UUID); 352 mcap_list = sdp_list_append(NULL, &mcap_c_uuid); 353 if (!mcap_list) { 354 ret = FALSE; 355 goto end; 356 } 357 358 mcap_ver = sdp_data_alloc(SDP_UINT16, &version); 359 if (!mcap_ver) { 360 ret = FALSE; 361 goto end; 362 } 363 364 if (!sdp_list_append( mcap_list, mcap_ver)) { 365 ret = FALSE; 366 goto end; 367 } 368 369 if (!sdp_list_append( proto_list, mcap_list)) { 370 ret = FALSE; 371 goto end; 372 } 373 374 /* attach protocol information to service record */ 375 access_proto_list = sdp_list_append(NULL, proto_list); 376 if (!access_proto_list) { 377 ret = FALSE; 378 goto end; 379 } 380 381 if (sdp_set_access_protos(sdp_record, access_proto_list) < 0) { 382 ret = FALSE; 383 goto end; 384 } 385 ret = TRUE; 386 387end: 388 if (l2cap_list) 389 sdp_list_free(l2cap_list, NULL); 390 if (mcap_list) 391 sdp_list_free(mcap_list, NULL); 392 if (proto_list) 393 sdp_list_free(proto_list, NULL); 394 if (access_proto_list) 395 sdp_list_free(access_proto_list, NULL); 396 if (psm) 397 sdp_data_free(psm); 398 if (mcap_ver) 399 sdp_data_free(mcap_ver); 400 401 return ret; 402} 403 404static gboolean register_service_profiles(sdp_record_t *sdp_record) 405{ 406 gboolean ret; 407 sdp_list_t *profile_list; 408 sdp_profile_desc_t hdp_profile; 409 410 /* set hdp information */ 411 sdp_uuid16_create( &hdp_profile.uuid, HDP_SVCLASS_ID); 412 hdp_profile.version = HDP_VERSION; 413 profile_list = sdp_list_append(NULL, &hdp_profile); 414 if (!profile_list) 415 return FALSE; 416 417 /* set profile descriptor list */ 418 if (sdp_set_profile_descs(sdp_record, profile_list) < 0) 419 ret = FALSE; 420 else 421 ret = TRUE; 422 423 sdp_list_free(profile_list, NULL); 424 return ret; 425} 426 427static gboolean register_service_aditional_protocols( 428 struct hdp_adapter *adapter, 429 sdp_record_t *sdp_record) 430{ 431 gboolean ret; 432 uuid_t l2cap_uuid, mcap_d_uuid; 433 sdp_list_t *l2cap_list, *proto_list, *mcap_list, *access_proto_list; 434 sdp_data_t *psm = NULL; 435 436 /* set l2cap information */ 437 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); 438 l2cap_list = sdp_list_append(NULL, &l2cap_uuid); 439 if (!l2cap_list) { 440 ret = FALSE; 441 goto end; 442 } 443 444 psm = sdp_data_alloc(SDP_UINT16, &adapter->dcpsm); 445 if (!psm) { 446 ret = FALSE; 447 goto end; 448 } 449 450 if (!sdp_list_append(l2cap_list, psm)) { 451 ret = FALSE; 452 goto end; 453 } 454 455 proto_list = sdp_list_append(NULL, l2cap_list); 456 if (!proto_list) { 457 ret = FALSE; 458 goto end; 459 } 460 461 /* set mcap information */ 462 sdp_uuid16_create(&mcap_d_uuid, MCAP_DATA_UUID); 463 mcap_list = sdp_list_append(NULL, &mcap_d_uuid); 464 if (!mcap_list) { 465 ret = FALSE; 466 goto end; 467 } 468 469 if (!sdp_list_append( proto_list, mcap_list)) { 470 ret = FALSE; 471 goto end; 472 } 473 474 /* attach protocol information to service record */ 475 access_proto_list = sdp_list_append(NULL, proto_list); 476 if (!access_proto_list) { 477 ret = FALSE; 478 goto end; 479 } 480 481 if (sdp_set_add_access_protos(sdp_record, access_proto_list) < 0) 482 ret = FALSE; 483 else 484 ret = TRUE; 485 486end: 487 if (l2cap_list) 488 sdp_list_free(l2cap_list, NULL); 489 if (mcap_list) 490 sdp_list_free(mcap_list, NULL); 491 if (proto_list) 492 sdp_list_free(proto_list, NULL); 493 if (access_proto_list) 494 sdp_list_free(access_proto_list, NULL); 495 if (psm) 496 sdp_data_free(psm); 497 498 return ret; 499} 500 501static sdp_list_t *app_to_sdplist(struct hdp_application *app) 502{ 503 sdp_data_t *mdepid, *dtype, *role, *desc; 504 sdp_list_t *f_list; 505 506 mdepid = sdp_data_alloc(SDP_UINT8, &app->id); 507 if (!mdepid) 508 return NULL; 509 510 dtype = sdp_data_alloc(SDP_UINT16, &app->data_type); 511 if (!dtype) 512 goto fail; 513 514 role = sdp_data_alloc(SDP_UINT8, &app->role); 515 if (!role) 516 goto fail; 517 518 if (app->description) { 519 desc = sdp_data_alloc(SDP_TEXT_STR8, app->description); 520 if (!desc) 521 goto fail; 522 } 523 524 f_list = sdp_list_append(NULL, mdepid); 525 if (!f_list) 526 goto fail; 527 528 if (!sdp_list_append(f_list, dtype)) 529 goto fail; 530 531 if (!sdp_list_append(f_list, role)) 532 goto fail; 533 534 if (desc) 535 if (!sdp_list_append(f_list, desc)) 536 goto fail; 537 538 return f_list; 539 540fail: 541 if (f_list) 542 sdp_list_free(f_list, NULL); 543 if (mdepid) 544 sdp_data_free(mdepid); 545 if (dtype) 546 sdp_data_free(dtype); 547 if (role) 548 sdp_data_free(role); 549 if (desc) 550 sdp_data_free(desc); 551 552 return NULL; 553} 554 555static gboolean register_features(struct hdp_application *app, 556 sdp_list_t **sup_features) 557{ 558 sdp_list_t *hdp_feature; 559 560 hdp_feature = app_to_sdplist(app); 561 if (!hdp_feature) 562 goto fail; 563 564 if (!*sup_features) { 565 *sup_features = sdp_list_append(NULL, hdp_feature); 566 if (!*sup_features) 567 goto fail; 568 } else if (!sdp_list_append(*sup_features, hdp_feature)) { 569 goto fail; 570 } 571 572 return TRUE; 573 574fail: 575 if (hdp_feature) 576 sdp_list_free(hdp_feature, (sdp_free_func_t)sdp_data_free); 577 return FALSE; 578} 579 580static void free_hdp_list(void *list) 581{ 582 sdp_list_t *hdp_list = list; 583 584 sdp_list_free(hdp_list, (sdp_free_func_t)sdp_data_free); 585} 586 587static gboolean register_service_sup_features(GSList *app_list, 588 sdp_record_t *sdp_record) 589{ 590 GSList *l; 591 sdp_list_t *sup_features = NULL; 592 593 for (l = app_list; l; l = l->next) { 594 if (!register_features(l->data, &sup_features)) 595 return FALSE; 596 } 597 598 if (sdp_set_supp_feat(sdp_record, sup_features) < 0) { 599 sdp_list_free(sup_features, free_hdp_list); 600 return FALSE; 601 } 602 603 return TRUE; 604} 605 606static gboolean register_data_exchange_spec(sdp_record_t *record) 607{ 608 sdp_data_t *spec; 609 uint8_t data_spec = DATA_EXCHANGE_SPEC_11073; 610 /* As by now 11073 is the only supported we set it by default */ 611 612 spec = sdp_data_alloc(SDP_UINT8, &data_spec); 613 if (!spec) 614 return FALSE; 615 616 if (sdp_attr_add(record, SDP_ATTR_DATA_EXCHANGE_SPEC, spec) < 0) { 617 sdp_data_free(spec); 618 return FALSE; 619 } 620 621 return TRUE; 622} 623 624static gboolean register_mcap_features(sdp_record_t *sdp_record) 625{ 626 sdp_data_t *mcap_proc; 627 uint8_t mcap_sup_proc = MCAP_SUP_PROC; 628 629 mcap_proc = sdp_data_alloc(SDP_UINT8, &mcap_sup_proc); 630 if (!mcap_proc) 631 return FALSE; 632 633 if (sdp_attr_add(sdp_record, SDP_ATTR_MCAP_SUPPORTED_PROCEDURES, 634 mcap_proc) < 0) { 635 sdp_data_free(mcap_proc); 636 return FALSE; 637 } 638 639 return TRUE; 640} 641 642gboolean hdp_update_sdp_record(struct hdp_adapter *adapter, GSList *app_list) 643{ 644 sdp_record_t *sdp_record; 645 bdaddr_t addr; 646 647 if (adapter->sdp_handler) 648 remove_record_from_server(adapter->sdp_handler); 649 650 if (!app_list) { 651 adapter->sdp_handler = 0; 652 return TRUE; 653 } 654 655 sdp_record = sdp_record_alloc(); 656 if (!sdp_record) 657 return FALSE; 658 659 if (adapter->sdp_handler) 660 sdp_record->handle = adapter->sdp_handler; 661 else 662 sdp_record->handle = 0xffffffff; /* Set automatically */ 663 664 if (is_app_role(app_list, HDP_SINK)) 665 set_sdp_services_uuid(sdp_record, HDP_SINK); 666 if (is_app_role(app_list, HDP_SOURCE)) 667 set_sdp_services_uuid(sdp_record, HDP_SOURCE); 668 669 if (!register_service_protocols(adapter, sdp_record)) 670 goto fail; 671 if (!register_service_profiles(sdp_record)) 672 goto fail; 673 if (!register_service_aditional_protocols(adapter, sdp_record)) 674 goto fail; 675 676 sdp_set_info_attr(sdp_record, HDP_SERVICE_NAME, HDP_SERVICE_PROVIDER, 677 HDP_SERVICE_DSC); 678 if (!register_service_sup_features(app_list, sdp_record)) 679 goto fail; 680 if (!register_data_exchange_spec(sdp_record)) 681 goto fail; 682 683 register_mcap_features(sdp_record); 684 685 if (sdp_set_record_state(sdp_record, adapter->record_state++)) 686 goto fail; 687 688 adapter_get_address(adapter->btd_adapter, &addr); 689 690 if (add_record_to_server(&addr, sdp_record) < 0) 691 goto fail; 692 adapter->sdp_handler = sdp_record->handle; 693 return TRUE; 694 695fail: 696 if (sdp_record) 697 sdp_record_free(sdp_record); 698 return FALSE; 699} 700 701static void get_mdep_cb(sdp_list_t *recs, int err, gpointer user_data) 702{ 703 struct get_mdep_data *mdep_data = user_data; 704 GError *gerr = NULL; 705 706 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, 707 "Not implemented yet"); 708 mdep_data->func(0, mdep_data->data, gerr); 709 g_error_free(gerr); 710} 711 712static void free_mdep_data(gpointer data) 713{ 714 struct get_mdep_data *mdep_data = data; 715 716 if (mdep_data->destroy) 717 mdep_data->destroy(mdep_data->data); 718 719 g_free(mdep_data); 720} 721 722gboolean hdp_get_mdep(struct hdp_device *device, struct hdp_application *app, 723 hdp_continue_mdep_f func, gpointer data, 724 GDestroyNotify destroy, GError **err) 725{ 726 struct get_mdep_data *mdep_data; 727 bdaddr_t dst, src; 728 uuid_t uuid; 729 730 device_get_address(device->dev, &dst); 731 adapter_get_address(device_get_adapter(device->dev), &src); 732 733 mdep_data = g_new0(struct get_mdep_data, 1); 734 mdep_data->app = app; 735 mdep_data->func = func; 736 mdep_data->data = data; 737 mdep_data->destroy = destroy; 738 739 bt_string2uuid(&uuid, HDP_UUID); 740 if (bt_search_service(&src, &dst, &uuid, get_mdep_cb, mdep_data, 741 free_mdep_data)) { 742 g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR, 743 "Can't get remote SDP record"); 744 g_free(mdep_data); 745 return FALSE; 746 } 747 748 return TRUE; 749} 750