Git init
[framework/connectivity/bluez.git] / health / hdp_util.c
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 <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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
999 static void destroy_con_mcl_data(gpointer data)
1000 {
1001         con_mcl_data_unref(data);
1002 }
1003
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
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
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
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
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
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
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
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
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
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 }