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