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