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