mcap.c revision f47ef246ff038ee8ec823bb7a0329135b32b9513
1/*
2 *
3 *  MCAP for BlueZ - Bluetooth protocol stack for Linux
4 *
5 *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
6 *
7 *  Authors:
8 *  Santiago Carot-Nemesio <sancane at gmail.com>
9 *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
10 *
11 *  This program is free software; you can redistribute it and/or modify
12 *  it under the terms of the GNU General Public License as published by
13 *  the Free Software Foundation; either version 2 of the License, or
14 *  (at your option) any later version.
15 *
16 *  This program is distributed in the hope that it will be useful,
17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 *  GNU General Public License for more details.
20 *
21 *  You should have received a copy of the GNU General Public License
22 *  along with this program; if not, write to the Free Software
23 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24 *
25 */
26
27#include "log.h"
28#include "error.h"
29
30#include <netinet/in.h>
31#include <stdlib.h>
32#include <errno.h>
33#include <unistd.h>
34
35#include "btio.h"
36#include <bluetooth/bluetooth.h>
37#include <bluetooth/l2cap.h>
38#include "mcap.h"
39#include "mcap_lib.h"
40#include "mcap_internal.h"
41
42#define RESPONSE_TIMER	6	/* seconds */
43#define MAX_CACHED	10	/* 10 devices */
44
45#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
46
47#define RELEASE_TIMER(__mcl) do {	\
48	g_source_remove(__mcl->tid);	\
49	__mcl->tid = 0;			\
50} while(0)
51
52struct connect_mcl {
53	struct mcap_mcl		*mcl;		/* MCL for this operation */
54	mcap_mcl_connect_cb	connect_cb;	/* Connect callback */
55	gpointer		user_data;	/* Callback user data */
56};
57
58typedef union {
59	mcap_mdl_operation_cb		op;
60	mcap_mdl_operation_conf_cb	op_conf;
61	mcap_mdl_notify_cb		notify;
62} mcap_cb_type;
63
64struct mcap_mdl_op_cb {
65	struct mcap_mdl		*mdl;		/* MDL for this operation */
66	mcap_cb_type		cb;		/* Operation callback */
67	gpointer		user_data;	/* Callback user data */
68};
69
70/* MCAP finite state machine functions */
71static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
72static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
73static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
74
75static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = {
76	proc_req_connected,
77	proc_req_pending,
78	proc_req_active
79};
80
81static void mcap_cache_mcl(struct mcap_mcl *mcl);
82
83static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
84{
85	DBG("MCAP Unmanaged mdl connection");
86}
87
88static void default_mdl_closed_cb(struct mcap_mdl *mdl, gpointer data)
89{
90	DBG("MCAP Unmanaged mdl closed");
91}
92
93static void default_mdl_deleted_cb(struct mcap_mdl *mdl, gpointer data)
94{
95	DBG("MCAP Unmanaged mdl deleted");
96}
97
98static void default_mdl_aborted_cb(struct mcap_mdl *mdl, gpointer data)
99{
100	DBG("MCAP Unmanaged mdl aborted");
101}
102
103static uint8_t default_mdl_conn_req_cb(struct mcap_mcl *mcl,
104						uint8_t mdepid, uint16_t mdlid,
105						uint8_t *conf, gpointer data)
106{
107	DBG("MCAP mdl remote connection aborted");
108	/* Due to this callback isn't managed this request won't be supported */
109	return MCAP_REQUEST_NOT_SUPPORTED;
110}
111
112static uint8_t default_mdl_reconn_req_cb(struct mcap_mdl *mdl,
113						gpointer data)
114{
115	DBG("MCAP mdl remote reconnection aborted");
116	/* Due to this callback isn't managed this request won't be supported */
117	return MCAP_REQUEST_NOT_SUPPORTED;
118}
119
120static void set_default_cb(struct mcap_mcl *mcl)
121{
122	if (!mcl->cb)
123		mcl->cb = g_new0(struct mcap_mdl_cb, 1);
124
125	mcl->cb->mdl_connected = default_mdl_connected_cb;
126	mcl->cb->mdl_closed = default_mdl_closed_cb;
127	mcl->cb->mdl_deleted = default_mdl_deleted_cb;
128	mcl->cb->mdl_aborted = default_mdl_aborted_cb;
129	mcl->cb->mdl_conn_req = default_mdl_conn_req_cb;
130	mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
131}
132
133static char *error2str(uint8_t rc)
134{
135	switch (rc) {
136	case MCAP_SUCCESS:
137		return "Success";
138	case MCAP_INVALID_OP_CODE:
139		return "Invalid Op Code";
140	case MCAP_INVALID_PARAM_VALUE:
141		return "Invalid Parameter Value";
142	case MCAP_INVALID_MDEP:
143		return "Invalid MDEP";
144	case MCAP_MDEP_BUSY:
145		return "MDEP Busy";
146	case MCAP_INVALID_MDL:
147		return "Invalid MDL";
148	case MCAP_MDL_BUSY:
149		return "MDL Busy";
150	case MCAP_INVALID_OPERATION:
151		return "Invalid Operation";
152	case MCAP_RESOURCE_UNAVAILABLE:
153		return "Resource Unavailable";
154	case MCAP_UNSPECIFIED_ERROR:
155		return "Unspecified Error";
156	case MCAP_REQUEST_NOT_SUPPORTED:
157		return "Request Not Supported";
158	case MCAP_CONFIGURATION_REJECTED:
159		return "Configuration Rejected";
160	default:
161		return "Unknown Response Code";
162	}
163}
164
165static gboolean mcap_send_std_opcode(struct mcap_mcl *mcl, void *cmd,
166						uint32_t size, GError **err)
167{
168	if (mcl->state == MCL_IDLE) {
169		g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
170							"MCL is not connected");
171		return FALSE;
172	}
173
174	if (mcl->req != MCL_AVAILABLE) {
175		g_set_error(err, MCAP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE,
176							"Pending request");
177		return FALSE;
178	}
179
180	if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) {
181		g_set_error(err, MCAP_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED,
182				"Remote does not support standard opcodes");
183		return FALSE;
184	}
185
186	if (mcl->state == MCL_PENDING) {
187		g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_OPERATION,
188			"Not Std Op. Codes can be sent in PENDING State");
189		return FALSE;
190	}
191
192	if (mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), cmd, size) < 0) {
193		g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
194					"Command can't be sent, write error");
195		return FALSE;
196	}
197
198	mcl->lcmd = cmd;
199	mcl->req = MCL_WAITING_RSP;
200
201	return TRUE;
202}
203
204static void update_mcl_state(struct mcap_mcl *mcl)
205{
206	GSList *l;
207	struct mcap_mdl *mdl;
208
209	if (mcl->state == MCL_PENDING)
210		return;
211
212	for (l = mcl->mdls; l; l = l->next) {
213		mdl = l->data;
214
215		if (mdl->state == MDL_CONNECTED) {
216			mcl->state = MCL_ACTIVE;
217			return;
218		}
219	}
220
221	mcl->state = MCL_CONNECTED;
222}
223
224static void shutdown_mdl(struct mcap_mdl *mdl)
225{
226	mdl->state = MDL_CLOSED;
227
228	g_source_remove(mdl->wid);
229
230	if (mdl->dc) {
231		g_io_channel_shutdown(mdl->dc, TRUE, NULL);
232		g_io_channel_unref(mdl->dc);
233		mdl->dc = NULL;
234	}
235}
236
237static gint cmp_mdl_state(gconstpointer a, gconstpointer b)
238{
239	const struct mcap_mdl *mdl = a;
240	const MDLState *st = b;
241
242	if (mdl->state == *st)
243		return 0;
244	else if (mdl->state < *st)
245		return -1;
246	else
247		return 1;
248}
249
250static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
251{
252	struct mcap_mdl_op_cb *con = mcl->priv_data;
253	struct mcap_mdl *mdl;
254	MDLState st;
255	GSList *l;
256
257	if (!con || !mcl->lcmd)
258		return;
259
260	switch (mcl->lcmd[0]) {
261	case MCAP_MD_CREATE_MDL_REQ:
262		st = MDL_WAITING;
263		l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
264		mdl = l->data;
265		mcl->mdls = g_slist_remove(mcl->mdls, mdl);
266		g_free(mdl);
267		update_mcl_state(mcl);
268		con->cb.op_conf(NULL, 0, err, con->user_data);
269		break;
270	case MCAP_MD_ABORT_MDL_REQ:
271		st = MDL_WAITING;
272		l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
273		shutdown_mdl(l->data);
274		update_mcl_state(mcl);
275		con->cb.notify(err, con->user_data);
276		break;
277	case MCAP_MD_DELETE_MDL_REQ:
278		for (l = mcl->mdls; l; l = l->next) {
279			mdl = l->data;
280			if (mdl->state == MDL_DELETING)
281				mdl->state = (mdl->dc) ? MDL_CONNECTED :
282								MDL_CLOSED;
283		}
284		update_mcl_state(mcl);
285		con->cb.notify(err, con->user_data);
286		break;
287	case MCAP_MD_RECONNECT_MDL_REQ:
288		st = MDL_WAITING;
289		l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
290		shutdown_mdl(l->data);
291		update_mcl_state(mcl);
292		con->cb.op(NULL, err, con->user_data);
293		break;
294	}
295
296	g_free(mcl->priv_data);
297	mcl->priv_data = NULL;
298
299	g_free(mcl->lcmd);
300	mcl->lcmd = NULL;
301}
302
303int mcap_send_data(int sock, const uint8_t *buf, uint32_t size)
304{
305	uint32_t sent = 0;
306
307	while (sent < size) {
308		int n = write(sock, buf + sent, size - sent);
309		if (n < 0)
310			return -1;
311		sent += n;
312	}
313
314	return 0;
315}
316
317static int mcap_send_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
318					uint16_t mdl, uint8_t *data, size_t len)
319{
320	mcap_rsp *cmd;
321	uint8_t *rsp;
322	int sock, sent;
323
324	if (mcl->cc == NULL)
325		return -1;
326
327	sock = g_io_channel_unix_get_fd(mcl->cc);
328
329	rsp = g_malloc(sizeof(mcap_rsp) + len);
330	cmd = (mcap_rsp *) rsp;
331	cmd->op = oc;
332	cmd->rc = rc;
333	cmd->mdl = htons(mdl);
334
335	if (data && len > 0)
336		memcpy(rsp + sizeof(mcap_rsp), data, len);
337
338	sent = mcap_send_data(sock, rsp, sizeof(mcap_rsp) + len);
339	g_free(rsp);
340
341	return sent;
342}
343
344static struct mcap_mdl *get_mdl(struct mcap_mcl *mcl, uint16_t mdlid)
345{
346	GSList *l;
347	struct mcap_mdl *mdl;
348
349	for (l = mcl->mdls; l; l = l->next) {
350		mdl = l->data;
351		if (mdlid == mdl->mdlid)
352			return mdl;
353	}
354
355	return NULL;
356}
357
358static uint16_t generate_mdlid(struct mcap_mcl *mcl)
359{
360	uint16_t mdlid = mcl->next_mdl;
361	struct mcap_mdl *mdl;
362
363	do {
364		mdl = get_mdl(mcl, mdlid);
365		if (!mdl) {
366			mcl->next_mdl = (mdlid % MCAP_MDLID_FINAL) + 1;
367			return mdlid;
368		} else
369			mdlid = (mdlid % MCAP_MDLID_FINAL) + 1;
370	} while (mdlid != mcl->next_mdl);
371
372	/* No more mdlids availables */
373	return 0;
374}
375
376static mcap_md_req *create_req(uint8_t op, uint16_t mdl_id)
377{
378	mcap_md_req *req_cmd;
379
380	req_cmd = g_new0(mcap_md_req, 1);
381
382	req_cmd->op = op;
383	req_cmd->mdl = htons(mdl_id);
384
385	return req_cmd;
386}
387
388static mcap_md_create_mdl_req *create_mdl_req(uint16_t mdl_id, uint8_t mdep,
389								uint8_t conf)
390{
391	mcap_md_create_mdl_req *req_mdl;
392
393	req_mdl = g_new0(mcap_md_create_mdl_req, 1);
394
395	req_mdl->op = MCAP_MD_CREATE_MDL_REQ;
396	req_mdl->mdl = htons(mdl_id);
397	req_mdl->mdep = mdep;
398	req_mdl->conf = conf;
399
400	return req_mdl;
401}
402
403static gint compare_mdl(gconstpointer a, gconstpointer b)
404{
405	const struct mcap_mdl *mdla = a;
406	const struct mcap_mdl *mdlb = b;
407
408	if (mdla->mdlid == mdlb->mdlid)
409		return 0;
410	else if (mdla->mdlid < mdlb->mdlid)
411		return -1;
412	else
413		return 1;
414}
415
416static gboolean wait_response_timer(gpointer data)
417{
418	struct mcap_mcl *mcl = data;
419
420	GError *gerr = NULL;
421
422	RELEASE_TIMER(mcl);
423
424	g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
425					"Timeout waiting response");
426
427	mcap_notify_error(mcl, gerr);
428
429	g_error_free(gerr);
430	mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
431	mcap_cache_mcl(mcl);
432
433	return FALSE;
434}
435
436gboolean mcap_create_mdl(struct mcap_mcl *mcl,
437				uint8_t mdepid,
438				uint8_t conf,
439				mcap_mdl_operation_conf_cb connect_cb,
440				gpointer user_data,
441				GError **err)
442{
443	struct mcap_mdl *mdl;
444	struct mcap_mdl_op_cb *con;
445	mcap_md_create_mdl_req *cmd;
446	uint16_t id;
447
448	id = generate_mdlid(mcl);
449	if (!id) {
450		g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
451					"Not more mdlids available");
452		return FALSE;
453	}
454
455	mdl = g_new0(struct mcap_mdl, 1);
456	mdl->mcl = mcl;
457	mdl->mdlid = id;
458	mdl->mdep_id = mdepid;
459	mdl->state = MDL_WAITING;
460
461	con = g_new0(struct mcap_mdl_op_cb, 1);
462	con->mdl = mdl;
463	con->cb.op_conf = connect_cb;
464	con->user_data = user_data;
465
466	cmd = create_mdl_req(id, mdepid, conf);
467	if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_create_mdl_req),
468									err)) {
469		g_free(mdl);
470		g_free(con);
471		g_free(cmd);
472		return FALSE;
473	}
474
475	mcl->state = MCL_ACTIVE;
476	mcl->priv_data = con;
477
478	mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl);
479	mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
480									mcl);
481	return TRUE;
482}
483
484gboolean mcap_reconnect_mdl(struct mcap_mdl *mdl,
485				mcap_mdl_operation_cb reconnect_cb,
486				gpointer user_data,
487				GError **err)
488{
489	struct mcap_mdl_op_cb *con;
490	struct mcap_mcl *mcl = mdl->mcl;
491	mcap_md_req *cmd;
492
493	if (mdl->state != MDL_CLOSED) {
494		g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
495					"MDL is not closed");
496		return FALSE;
497	}
498	con = g_new0(struct mcap_mdl_op_cb, 1);
499
500	cmd = create_req(MCAP_MD_RECONNECT_MDL_REQ, mdl->mdlid);
501	if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
502		g_free(con);
503		g_free(cmd);
504		return FALSE;
505	}
506
507	mdl->state = MDL_WAITING;
508
509	con->mdl = mdl;
510	con->cb.op = reconnect_cb;
511	con->user_data = user_data;
512
513	mcl->state = MCL_ACTIVE;
514	mcl->priv_data = con;
515
516	mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
517									mcl);
518	return TRUE;
519}
520
521static gboolean send_delete_req(struct mcap_mcl *mcl,
522						struct mcap_mdl_op_cb *con,
523						uint16_t mdlid,
524						GError **err)
525{
526	mcap_md_req *cmd;
527
528	cmd = create_req(MCAP_MD_DELETE_MDL_REQ, mdlid);
529	if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
530		g_free(cmd);
531		return FALSE;
532	}
533
534	mcl->priv_data = con;
535
536	mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
537									mcl);
538	return TRUE;
539}
540
541gboolean mcap_delete_all_mdls(struct mcap_mcl *mcl,
542					mcap_mdl_notify_cb delete_cb,
543					gpointer user_data, GError **err)
544{
545	GSList *l;
546	struct mcap_mdl *mdl;
547	struct mcap_mdl_op_cb *con;
548
549	DBG("MCL in state: %d", mcl->state);
550	if (!mcl->mdls) {
551		g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
552				"There are not MDLs created");
553		return FALSE;
554	}
555
556	for (l = mcl->mdls; l; l = l->next) {
557		mdl = l->data;
558		if (mdl->state != MDL_WAITING)
559			mdl->state = MDL_DELETING;
560	}
561
562	con = g_new0(struct mcap_mdl_op_cb, 1);
563	con->mdl = NULL;
564	con->cb.notify = delete_cb;
565	con->user_data = user_data;
566
567
568	if (!send_delete_req(mcl, con, MCAP_ALL_MDLIDS, err)) {
569		g_free(con);
570		return FALSE;
571	}
572
573	return TRUE;
574}
575
576gboolean mcap_delete_mdl(struct mcap_mdl *mdl, mcap_mdl_notify_cb delete_cb,
577					gpointer user_data, GError **err)
578{
579	struct mcap_mcl *mcl= mdl->mcl;
580	struct mcap_mdl_op_cb *con;
581	GSList *l;
582
583	l = g_slist_find(mcl->mdls, mdl);
584
585	if (!l) {
586		g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL,
587					"%s" , error2str(MCAP_INVALID_MDEP));
588		return FALSE;
589	}
590
591	if (mdl->state == MDL_WAITING) {
592		g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
593							"Mdl is not created");
594		return FALSE;
595	}
596
597	mdl->state = MDL_DELETING;
598
599	con = g_new0(struct mcap_mdl_op_cb, 1);
600	con->mdl = mdl;
601	con->cb.notify = delete_cb;
602	con->user_data = user_data;
603
604	if (!send_delete_req(mcl, con, mdl->mdlid, err)) {
605		g_free(con);
606		return FALSE;
607	}
608
609	return TRUE;
610}
611
612gboolean mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb,
613					gpointer user_data, GError **err)
614{
615	struct mcap_mdl_op_cb *con;
616	struct mcap_mcl *mcl = mdl->mcl;
617	mcap_md_req *cmd;
618
619	if (mdl->state != MDL_WAITING) {
620		g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
621							"Mdl in invalid state");
622		return FALSE;
623	}
624
625	con = g_new0(struct mcap_mdl_op_cb, 1);
626	cmd = create_req(MCAP_MD_ABORT_MDL_REQ, mdl->mdlid);
627	if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
628		g_free(con);
629		g_free(cmd);
630		return FALSE;
631	}
632
633	con->mdl = mdl;
634	con->cb.notify = abort_cb;
635	con->user_data = user_data;
636
637	mcl->priv_data = con;
638
639	mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
640									mcl);
641	return TRUE;
642}
643
644static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
645{
646	GSList *l;
647	struct mcap_mcl *mcl;
648
649	for (l = list; l; l = l->next) {
650		mcl = l->data;
651
652		if (!bacmp(&mcl->addr, addr))
653			return mcl;
654	}
655
656	return NULL;
657}
658
659int mcap_mdl_get_fd(struct mcap_mdl *mdl)
660{
661	if (!mdl || mdl->state != MDL_CONNECTED)
662		return -ENOTCONN;
663
664	return g_io_channel_unix_get_fd(mdl->dc);
665}
666
667uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl)
668{
669	if (!mdl)
670		return MCAP_MDLID_RESERVED;
671
672	return mdl->mdlid;
673}
674
675static void close_mcl(struct mcap_mcl *mcl, gboolean cache_requested)
676{
677	gboolean save = ((!(mcl->ctrl & MCAP_CTRL_FREE)) && cache_requested);
678
679	if (mcl->tid) {
680		RELEASE_TIMER(mcl);
681	}
682
683	if (mcl->cc) {
684		g_io_channel_shutdown(mcl->cc, TRUE, NULL);
685		g_io_channel_unref(mcl->cc);
686		mcl->cc = NULL;
687	}
688
689	g_source_remove(mcl->wid);
690	if (mcl->lcmd) {
691		g_free(mcl->lcmd);
692		mcl->lcmd = NULL;
693	}
694
695	if (mcl->priv_data) {
696		g_free(mcl->priv_data);
697		mcl->priv_data = NULL;
698	}
699
700	g_slist_foreach(mcl->mdls, (GFunc) shutdown_mdl, NULL);
701
702	mcl->state = MCL_IDLE;
703
704	if (save)
705		return;
706
707	g_slist_foreach(mcl->mdls, (GFunc) g_free, NULL);
708	g_slist_free(mcl->mdls);
709
710	g_free(mcl->cb);
711
712	g_free(mcl);
713}
714
715static void mcap_mcl_shutdown(struct mcap_mcl *mcl)
716{
717	close_mcl(mcl, TRUE);
718}
719
720static void mcap_mcl_release(struct mcap_mcl *mcl)
721{
722	close_mcl(mcl, FALSE);
723}
724
725static void mcap_mcl_check_del(struct mcap_mcl *mcl)
726{
727	if (mcl->ctrl & MCAP_CTRL_CACHED)
728		mcap_mcl_shutdown(mcl);
729	else
730		mcap_mcl_unref(mcl);
731}
732
733static void mcap_cache_mcl(struct mcap_mcl *mcl)
734{
735	GSList *l;
736	struct mcap_mcl *last;
737	int len;
738
739	if (mcl->ctrl & MCAP_CTRL_CACHED)
740		return;
741
742	mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl);
743
744	if ((mcl->ctrl & MCAP_CTRL_NOCACHE) || (mcl->ref < 2)) {
745		mcap_mcl_unref(mcl);
746		return;
747	}
748
749	DBG("Caching MCL");
750
751	len = g_slist_length(mcl->ms->cached);
752	if (len == MAX_CACHED) {
753		/* Remove the latest cached mcl */
754		l = g_slist_last(mcl->ms->cached);
755		last = l->data;
756		mcl->ms->cached = g_slist_remove(mcl->ms->cached, last);
757		last->ctrl &= ~MCAP_CTRL_CACHED;
758		if (last->ctrl & MCAP_CTRL_CONN) {
759			/* If connection process is not success this MCL will be
760			 * freed next time that close_mcl is invoked */
761			last->ctrl |= MCAP_CTRL_FREE;
762		} else {
763			last->ms->mcl_uncached_cb(last, last->ms->user_data);
764			mcap_mcl_unref(last);
765		}
766	}
767
768	mcl->ms->cached = g_slist_prepend(mcl->ms->cached, mcl);
769	mcl->ctrl |= MCAP_CTRL_CACHED;
770	mcap_mcl_shutdown(mcl);
771}
772
773static void mcap_uncache_mcl(struct mcap_mcl *mcl)
774{
775	if (!(mcl->ctrl & MCAP_CTRL_CACHED))
776		return;
777
778	DBG("Got MCL from cache");
779
780	mcl->ms->cached = g_slist_remove(mcl->ms->cached, mcl);
781	mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl);
782	mcl->ctrl &= ~MCAP_CTRL_CACHED;
783	mcl->ctrl &= ~MCAP_CTRL_FREE;
784}
785
786void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache)
787{
788	if (!mcl)
789		return;
790
791	if (mcl->cc) {
792		g_io_channel_shutdown(mcl->cc, TRUE, NULL);
793		g_io_channel_unref(mcl->cc);
794		mcl->cc = NULL;
795	}
796
797	mcl->state = MCL_IDLE;
798
799	if (!cache)
800		mcl->ctrl |= MCAP_CTRL_NOCACHE;
801}
802
803struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl)
804{
805	mcl->ref++;
806
807	DBG("mcap_mcl_ref(%p): ref=%d", mcl, mcl->ref);
808
809	return mcl;
810}
811
812void mcap_mcl_unref(struct mcap_mcl *mcl)
813{
814	mcl->ref--;
815
816	DBG("mcap_mcl_unref(%p): ref=%d", mcl, mcl->ref);
817
818	if ((mcl->ctrl & MCAP_CTRL_CACHED) && (mcl->ref < 2)) {
819		/* Free space in cache memory due any other profile has a local
820		 * copy of current MCL stored in cache */
821		DBG("Remove from cache (%p): ref=%d", mcl, mcl->ref);
822		mcl->ms->cached = g_slist_remove(mcl->ms->cached, mcl);
823		mcap_mcl_release(mcl);
824		return;
825	}
826
827	if (mcl->ref > 0)
828		return;
829
830	mcap_mcl_release(mcl);
831}
832
833static gboolean parse_set_opts(struct mcap_mdl_cb *mdl_cb, GError **err,
834						McapMclCb cb1, va_list args)
835{
836	McapMclCb cb = cb1;
837	struct mcap_mdl_cb *c;
838
839	c = g_new0(struct mcap_mdl_cb, 1);
840
841	while (cb != MCAP_MDL_CB_INVALID) {
842		switch (cb) {
843		case MCAP_MDL_CB_CONNECTED:
844			c->mdl_connected = va_arg(args, mcap_mdl_event_cb);
845			break;
846		case MCAP_MDL_CB_CLOSED:
847			c->mdl_closed = va_arg(args, mcap_mdl_event_cb);
848			break;
849		case MCAP_MDL_CB_DELETED:
850			c->mdl_deleted = va_arg(args, mcap_mdl_event_cb);
851			break;
852		case MCAP_MDL_CB_ABORTED:
853			c->mdl_aborted = va_arg(args, mcap_mdl_event_cb);
854			break;
855		case MCAP_MDL_CB_REMOTE_CONN_REQ:
856			c->mdl_conn_req = va_arg(args,
857						mcap_remote_mdl_conn_req_cb);
858			break;
859		case MCAP_MDL_CB_REMOTE_RECONN_REQ:
860			c->mdl_reconn_req = va_arg(args,
861						mcap_remote_mdl_reconn_req_cb);
862			break;
863		default:
864			g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
865						"Unknown option %d", cb);
866			return FALSE;
867		}
868		cb = va_arg(args, int);
869	}
870
871	/* Set new callbacks */
872	if (c->mdl_connected)
873		mdl_cb->mdl_connected = c->mdl_connected;
874	if (c->mdl_closed)
875		mdl_cb->mdl_closed = c->mdl_closed;
876	if (c->mdl_deleted)
877		mdl_cb->mdl_deleted = c->mdl_deleted;
878	if (c->mdl_aborted)
879		mdl_cb->mdl_aborted = c->mdl_aborted;
880	if (c->mdl_conn_req)
881		mdl_cb->mdl_conn_req = c->mdl_conn_req;
882	if (c->mdl_reconn_req)
883		mdl_cb->mdl_reconn_req = c->mdl_reconn_req;
884
885	g_free(c);
886
887	return TRUE;
888}
889
890gboolean mcap_mcl_set_cb(struct mcap_mcl *mcl, gpointer user_data,
891					GError **gerr, McapMclCb cb1, ...)
892{
893	va_list args;
894	gboolean ret;
895
896	va_start(args, cb1);
897	ret = parse_set_opts(mcl->cb, gerr, cb1, args);
898	va_end(args);
899
900	if (!ret)
901		return FALSE;
902
903	mcl->cb->user_data = user_data;
904	return TRUE;
905}
906
907void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)
908{
909	bacpy(addr, &mcl->addr);
910}
911
912static void mcap_del_mdl(gpointer elem, gpointer user_data)
913{
914	struct mcap_mdl *mdl = elem;
915	gboolean notify = *(gboolean *) user_data;
916
917	shutdown_mdl(mdl);
918	if (notify)
919		mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data);
920
921	g_free(mdl);
922}
923
924static gboolean check_cmd_req_length(struct mcap_mcl *mcl, void *cmd,
925				uint32_t rlen, uint32_t explen, uint8_t rspcod)
926{
927	mcap_md_req *req;
928	uint16_t mdl_id;
929
930	if (rlen != explen) {
931		if (rlen >= sizeof(mcap_md_req)) {
932			req = cmd;
933			mdl_id = ntohs(req->mdl);
934		} else {
935			/* We can't get mdlid */
936			mdl_id = MCAP_MDLID_RESERVED;
937		}
938		mcap_send_cmd(mcl, rspcod, MCAP_INVALID_PARAM_VALUE, mdl_id,
939								NULL, 0);
940		return FALSE;
941	}
942	return TRUE;
943}
944
945static void process_md_create_mdl_req(struct mcap_mcl *mcl, void *cmd,
946								uint32_t len)
947{
948	mcap_md_create_mdl_req *req;
949	struct mcap_mdl *mdl;
950	uint16_t mdl_id;
951	uint8_t mdep_id;
952	uint8_t cfga, conf;
953	uint8_t rsp;
954
955	if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_create_mdl_req),
956							MCAP_MD_CREATE_MDL_RSP))
957		return;
958
959	req = cmd;
960	mdl_id = ntohs(req->mdl);
961	if (mdl_id < MCAP_MDLID_INITIAL || mdl_id > MCAP_MDLID_FINAL) {
962		mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL,
963							mdl_id, NULL, 0);
964		return;
965	}
966
967	mdep_id = req->mdep;
968	if (mdep_id > MCAP_MDEPID_FINAL) {
969		mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDEP,
970							mdl_id, NULL, 0);
971		return;
972	}
973
974	mdl = get_mdl(mcl, mdl_id);
975	if (mdl && (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING )) {
976		/* Creation request arrives for a MDL that is being managed
977		* at current moment */
978		mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY,
979							mdl_id, NULL, 0);
980		return;
981	}
982
983	cfga = conf = req->conf;
984	/* Callback to upper layer */
985	rsp = mcl->cb->mdl_conn_req(mcl, mdep_id, mdl_id, &conf,
986							mcl->cb->user_data);
987	if (mcl->state == MCL_IDLE) {
988		/* MCL has been closed int the callback */
989		return;
990	}
991
992	if (cfga != 0 && cfga != conf) {
993		/* Remote device set default configuration but upper profile */
994		/* has changed it. Protocol Error: force closing the MCL by */
995		/* remote device using UNSPECIFIED_ERROR response */
996		mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP,
997				MCAP_UNSPECIFIED_ERROR, mdl_id, NULL, 0);
998		return;
999	}
1000	if (rsp != MCAP_SUCCESS) {
1001		mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id,
1002								NULL, 0);
1003		return;
1004	}
1005
1006	if (!mdl) {
1007		mdl = g_new0(struct mcap_mdl, 1);
1008		mdl->mcl = mcl;
1009		mdl->mdlid = mdl_id;
1010		mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl);
1011	} else if (mdl->state == MDL_CONNECTED) {
1012		/* MCAP specification says that we should close the MCL if
1013		 * it is open when we receive a MD_CREATE_MDL_REQ */
1014		shutdown_mdl(mdl);
1015	}
1016
1017	mdl->mdep_id = mdep_id;
1018	mdl->state = MDL_WAITING;
1019
1020	mcl->state = MCL_PENDING;
1021	mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id,
1022								&conf, 1);
1023}
1024
1025static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, void *cmd,
1026								uint32_t len)
1027{
1028	mcap_md_req *req;
1029	struct mcap_mdl *mdl;
1030	uint16_t mdl_id;
1031	uint8_t rsp;
1032
1033	if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
1034						MCAP_MD_RECONNECT_MDL_RSP))
1035		return;
1036
1037	req = cmd;
1038	mdl_id = ntohs(req->mdl);
1039
1040	mdl = get_mdl(mcl, mdl_id);
1041	if (!mdl) {
1042		mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_INVALID_MDL,
1043							mdl_id, NULL, 0);
1044		return;
1045	} else if (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING ) {
1046		/* Creation request arrives for a MDL that is being managed
1047		* at current moment */
1048		mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_MDL_BUSY,
1049							mdl_id, NULL, 0);
1050		return;
1051	}
1052
1053	/* Callback to upper layer */
1054	rsp = mcl->cb->mdl_reconn_req(mdl, mcl->cb->user_data);
1055	if (mcl->state == MCL_IDLE)
1056		return;
1057
1058	if (rsp != MCAP_SUCCESS) {
1059		mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, rsp, mdl_id,
1060								NULL, 0);
1061		return;
1062	}
1063
1064	if (mdl->state == MDL_CONNECTED)
1065		shutdown_mdl(mdl);
1066
1067	mdl->state = MDL_WAITING;
1068	mcl->state = MCL_PENDING;
1069	mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id,
1070								NULL, 0);
1071}
1072
1073static void process_md_abort_mdl_req(struct mcap_mcl *mcl, void *cmd,
1074								uint32_t len)
1075{
1076	mcap_md_req *req;
1077	GSList *l;
1078	struct mcap_mdl *mdl, *abrt;
1079	uint16_t mdl_id;
1080
1081	if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
1082							MCAP_MD_ABORT_MDL_RSP))
1083		return;
1084
1085	req = cmd;
1086	mdl_id = ntohs(req->mdl);
1087	mcl->state = MCL_CONNECTED;
1088	for (l = mcl->mdls; l; l = l->next) {
1089		mdl = l->data;
1090		if (mdl_id == mdl->mdlid && mdl->state == MDL_WAITING) {
1091			abrt = mdl;
1092			if (mcl->state != MCL_CONNECTED)
1093				break;
1094			continue;
1095		}
1096		if (mdl->state == MDL_CONNECTED && mcl->state != MCL_ACTIVE)
1097			mcl->state = MCL_ACTIVE;
1098
1099		if (abrt && mcl->state == MCL_ACTIVE)
1100			break;
1101	}
1102
1103	if (!abrt) {
1104		mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL,
1105							mdl_id, NULL, 0);
1106		return;
1107	}
1108
1109	mcl->cb->mdl_aborted(abrt, mcl->cb->user_data);
1110	abrt->state = MDL_CLOSED;
1111	mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_SUCCESS, mdl_id,
1112								NULL, 0);
1113}
1114
1115static void process_md_delete_mdl_req(struct mcap_mcl *mcl, void *cmd,
1116								uint32_t len)
1117{
1118	mcap_md_req *req;
1119	struct mcap_mdl *mdl, *aux;
1120	uint16_t mdlid;
1121	gboolean notify;
1122	GSList *l;
1123
1124	if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
1125							MCAP_MD_DELETE_MDL_RSP))
1126		return;
1127
1128	req = cmd;
1129	mdlid = ntohs(req->mdl);
1130	if (mdlid == MCAP_ALL_MDLIDS) {
1131		notify = FALSE;
1132		g_slist_foreach(mcl->mdls, mcap_del_mdl, &notify);
1133		g_slist_free(mcl->mdls);
1134		mcl->mdls = NULL;
1135		mcl->state = MCL_CONNECTED;
1136		/* NULL mdl means ALL_MDLS */
1137		mcl->cb->mdl_deleted(NULL, mcl->cb->user_data);
1138		goto resp;
1139	}
1140
1141	if (mdlid < MCAP_MDLID_INITIAL || mdlid > MCAP_MDLID_FINAL) {
1142		mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL,
1143								mdlid, NULL, 0);
1144		return;
1145	}
1146
1147	for (l = mcl->mdls, mdl = NULL; l; l = l->next) {
1148		aux = l->data;
1149		if (aux->mdlid == mdlid) {
1150			mdl = aux;
1151			break;
1152		}
1153	}
1154
1155	if (!mdl || mdl->state == MDL_WAITING) {
1156		mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL,
1157								mdlid, NULL, 0);
1158		return;
1159	}
1160
1161	mcl->mdls = g_slist_remove(mcl->mdls, mdl);
1162	update_mcl_state(mcl);
1163	notify = TRUE;
1164	mcap_del_mdl(mdl, &notify);
1165
1166resp:
1167	mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid,
1168								NULL, 0);
1169}
1170
1171static void invalid_req_state(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1172{
1173	uint16_t mdlr;
1174
1175	error("Invalid cmd received (op code = %d) in state %d", cmd[0],
1176								mcl->state);
1177	/* Get previously mdlid sent to generate an appropriate
1178	 * response if it is possible */
1179	mdlr = len < sizeof(mcap_md_req) ? MCAP_MDLID_RESERVED :
1180					ntohs(((mcap_md_req *) cmd)->mdl);
1181	mcap_send_cmd(mcl, cmd[0]+1, MCAP_INVALID_OPERATION, mdlr, NULL, 0);
1182}
1183
1184/* Function used to process commands depending of MCL state */
1185static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1186{
1187	switch (cmd[0]) {
1188	case MCAP_MD_CREATE_MDL_REQ:
1189		process_md_create_mdl_req(mcl, cmd, len);
1190		break;
1191	case MCAP_MD_RECONNECT_MDL_REQ:
1192		process_md_reconnect_mdl_req(mcl, cmd, len);
1193		break;
1194	case MCAP_MD_DELETE_MDL_REQ:
1195		process_md_delete_mdl_req(mcl, cmd, len);
1196		break;
1197	default:
1198		invalid_req_state(mcl, cmd, len);
1199	}
1200}
1201
1202static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1203{
1204	if (cmd[0] == MCAP_MD_ABORT_MDL_REQ)
1205		process_md_abort_mdl_req(mcl, cmd, len);
1206	else
1207		invalid_req_state(mcl, cmd, len);
1208}
1209
1210static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1211{
1212	switch (cmd[0]) {
1213	case MCAP_MD_CREATE_MDL_REQ:
1214		process_md_create_mdl_req(mcl, cmd, len);
1215		break;
1216	case MCAP_MD_RECONNECT_MDL_REQ:
1217		process_md_reconnect_mdl_req(mcl, cmd, len);
1218		break;
1219	case MCAP_MD_DELETE_MDL_REQ:
1220		process_md_delete_mdl_req(mcl, cmd, len);
1221		break;
1222	default:
1223		invalid_req_state(mcl, cmd, len);
1224	}
1225}
1226
1227/* Function used to process replies */
1228static gboolean check_err_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
1229				uint32_t rlen, uint32_t len, GError **gerr)
1230{
1231	mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
1232	gint err = MCAP_ERROR_FAILED;
1233	gboolean close = FALSE;
1234	uint16_t rmdl, smdl;
1235	mcap_rsp *rsp;
1236	char *msg;
1237
1238	if (cmd[0] == MCAP_ERROR_RSP) {
1239		msg = "MCAP_ERROR_RSP received";
1240		close = FALSE;
1241		goto fail;
1242	}
1243
1244	/* Check if the response matches with the last request */
1245	if (rlen < sizeof(mcap_rsp) || (mcl->lcmd[0] + 1) != cmd[0]) {
1246		msg = "Protocol error";
1247		close = FALSE;
1248		goto fail;
1249	}
1250
1251	if (rlen < len) {
1252		msg = "Protocol error";
1253		close = FALSE;
1254		goto fail;
1255	}
1256
1257	rsp = (mcap_rsp *) cmd;
1258	smdl = ntohs(cmdlast->mdl);
1259	rmdl = ntohs(rsp->mdl);
1260	if (rmdl != smdl) {
1261		msg = "MDLID received doesn't match with MDLID sent";
1262		close = TRUE;
1263		goto fail;
1264	}
1265
1266	if (rsp->rc == MCAP_REQUEST_NOT_SUPPORTED) {
1267		msg = "Remote does not support opcodes";
1268		mcl->ctrl &= ~MCAP_CTRL_STD_OP;
1269		goto fail;
1270	}
1271
1272	if (rsp->rc == MCAP_UNSPECIFIED_ERROR) {
1273		msg = "Unspecified error";
1274		close = TRUE;
1275		goto fail;
1276	}
1277
1278	if (rsp->rc != MCAP_SUCCESS) {
1279		msg = error2str(rsp->rc);
1280		err = rsp->rc;
1281		goto fail;
1282	}
1283
1284	return FALSE;
1285
1286fail:
1287	g_set_error(gerr, MCAP_ERROR, err, "%s", msg);
1288	return close;
1289}
1290
1291static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl,
1292						uint8_t *cmd, uint32_t len)
1293{
1294	mcap_md_create_mdl_req *cmdlast = (mcap_md_create_mdl_req *) mcl->lcmd;
1295	struct mcap_mdl_op_cb *conn = mcl->priv_data;
1296	mcap_mdl_operation_conf_cb connect_cb = conn->cb.op_conf;
1297	gpointer user_data = conn->user_data;
1298	struct mcap_mdl *mdl = conn->mdl;
1299	uint8_t conf = cmdlast->conf;
1300	gboolean close;
1301	GError *gerr = NULL;
1302	uint8_t *param;
1303
1304	g_free(mcl->priv_data);
1305	mcl->priv_data = NULL;
1306
1307	close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp) + 1, &gerr);
1308	g_free(mcl->lcmd);
1309	mcl->lcmd = NULL;
1310	mcl->req = MCL_AVAILABLE;
1311
1312	if (gerr)
1313		goto fail;
1314
1315	param = cmd + sizeof(mcap_rsp);
1316	/* Check if preferences changed */
1317	if (conf != 0x00 && *param != conf) {
1318		g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
1319						"Configuration changed");
1320		close = TRUE;
1321		goto fail;
1322	}
1323
1324	connect_cb(mdl, *param, gerr, user_data);
1325	return close;
1326
1327fail:
1328	connect_cb(NULL, 0, gerr, user_data);
1329	mcl->mdls = g_slist_remove(mcl->mdls, mdl);
1330	g_free(mdl);
1331	g_error_free(gerr);
1332	update_mcl_state(mcl);
1333	return close;
1334}
1335
1336static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
1337						uint8_t *cmd, uint32_t len)
1338{
1339	struct mcap_mdl_op_cb *reconn = mcl->priv_data;
1340	mcap_mdl_operation_cb reconn_cb = reconn->cb.op;
1341	gpointer user_data = reconn->user_data;
1342	struct mcap_mdl *mdl = reconn->mdl;
1343	mcap_rsp *rsp = (mcap_rsp *) cmd;
1344	GError *gerr = NULL;
1345	gboolean close;
1346
1347	g_free(mcl->priv_data);
1348	mcl->priv_data = NULL;
1349
1350	close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp), &gerr);
1351
1352	g_free(mcl->lcmd);
1353	mcl->lcmd = NULL;
1354	mcl->req = MCL_AVAILABLE;
1355
1356	reconn_cb(mdl, gerr, user_data);
1357	if (!gerr)
1358		return close;
1359
1360	g_error_free(gerr);
1361	shutdown_mdl(mdl);
1362	update_mcl_state(mcl);
1363
1364	if (rsp->rc != MCAP_INVALID_MDL)
1365		return close;
1366
1367	/* Remove cached mdlid */
1368	mcl->mdls = g_slist_remove(mcl->mdls, mdl);
1369	mcl->cb->mdl_deleted(mdl, mcl->cb->user_data);
1370	g_free(mdl);
1371
1372	return close;
1373}
1374
1375static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
1376						uint8_t *cmd, uint32_t len)
1377{
1378	struct mcap_mdl_op_cb *abrt = mcl->priv_data;
1379	mcap_mdl_notify_cb abrt_cb = abrt->cb.notify;
1380	gpointer user_data = abrt->user_data;
1381	struct mcap_mdl *mdl = abrt->mdl;
1382	mcap_rsp *rsp = (mcap_rsp *) cmd;
1383	GError *gerr = NULL;
1384	gboolean close;
1385
1386	g_free(mcl->priv_data);
1387	mcl->priv_data = NULL;
1388
1389	close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp), &gerr);
1390
1391	g_free(mcl->lcmd);
1392	mcl->lcmd = NULL;
1393	mcl->req = MCL_AVAILABLE;
1394
1395	abrt_cb(gerr, user_data);
1396	shutdown_mdl(mdl);
1397
1398	if (len >= sizeof(mcap_rsp) && rsp->rc == MCAP_INVALID_MDL) {
1399		mcl->mdls = g_slist_remove(mcl->mdls, mdl);
1400		g_free(mdl);
1401	}
1402
1403	if (!gerr)
1404		g_error_free(gerr);
1405
1406	update_mcl_state(mcl);
1407
1408	return close;
1409}
1410
1411static void restore_mdl(gpointer elem, gpointer data)
1412{
1413	struct mcap_mdl *mdl = elem;
1414
1415	if (mdl->state == MDL_DELETING) {
1416		if (mdl->dc)
1417			mdl->state = MDL_CONNECTED;
1418		else
1419			mdl->state = MDL_CLOSED;
1420	} else if (mdl->state == MDL_CLOSED)
1421		mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data);
1422}
1423
1424static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
1425								uint32_t len)
1426{
1427	struct mcap_mdl_op_cb *del = mcl->priv_data;
1428	struct mcap_mdl *mdl = del->mdl;
1429	mcap_mdl_notify_cb deleted_cb = del->cb.notify;
1430	gpointer user_data = del->user_data;
1431	mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
1432	uint16_t mdlid = ntohs(cmdlast->mdl);
1433	GError *gerr = NULL;
1434	gboolean close;
1435	gboolean notify = FALSE;
1436
1437	g_free(mcl->priv_data);
1438	mcl->priv_data = NULL;
1439
1440	close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp), &gerr);
1441
1442	g_free(mcl->lcmd);
1443	mcl->lcmd = NULL;
1444	mcl->req = MCL_AVAILABLE;
1445
1446	if (gerr) {
1447		if (mdl)
1448			restore_mdl(mdl, NULL);
1449		else
1450			g_slist_foreach(mcl->mdls, restore_mdl, NULL);
1451		deleted_cb(gerr, user_data);
1452		g_error_free(gerr);
1453		return close;
1454	}
1455
1456	if (mdlid == MCAP_ALL_MDLIDS) {
1457		g_slist_foreach(mcl->mdls, mcap_del_mdl, &notify);
1458		g_slist_free(mcl->mdls);
1459		mcl->mdls = NULL;
1460		mcl->state = MCL_CONNECTED;
1461	} else {
1462		mcl->mdls = g_slist_remove(mcl->mdls, mdl);
1463		update_mcl_state(mcl);
1464		mcap_del_mdl(mdl, &notify);
1465	}
1466
1467	deleted_cb(gerr, user_data);
1468
1469	return close;
1470}
1471
1472static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1473{
1474	gboolean close;
1475	RELEASE_TIMER(mcl);
1476
1477	switch (mcl->lcmd[0] + 1) {
1478	case MCAP_MD_CREATE_MDL_RSP:
1479		close = process_md_create_mdl_rsp(mcl, cmd, len);
1480		break;
1481	case MCAP_MD_RECONNECT_MDL_RSP:
1482		close = process_md_reconnect_mdl_rsp(mcl, cmd, len);
1483		break;
1484	case MCAP_MD_ABORT_MDL_RSP:
1485		close = process_md_abort_mdl_rsp(mcl, cmd, len);
1486		break;
1487	case MCAP_MD_DELETE_MDL_RSP:
1488		close = process_md_delete_mdl_rsp(mcl, cmd, len);
1489		break;
1490	default:
1491		DBG("Unknown cmd response received (op code = %d)",cmd[0]);
1492		close = TRUE;
1493		break;
1494	}
1495
1496	if (close) {
1497		mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
1498		mcap_cache_mcl(mcl);
1499	}
1500}
1501
1502static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1503{
1504	GError *gerr = NULL;
1505
1506	if (cmd[0] > MCAP_MD_SYNC_INFO_IND ||
1507					(cmd[0] > MCAP_MD_DELETE_MDL_RSP &&
1508					cmd[0] < MCAP_MD_SYNC_CAP_REQ)) {
1509		error("Unknown cmd received (op code = %d)", cmd[0]);
1510		mcap_send_cmd(mcl, MCAP_ERROR_RSP, MCAP_INVALID_OP_CODE,
1511						MCAP_MDLID_RESERVED, NULL, 0);
1512		return;
1513	}
1514
1515	if (cmd[0] >= MCAP_MD_SYNC_CAP_REQ &&
1516					cmd[0] <= MCAP_MD_SYNC_INFO_IND) {
1517		proc_sync_cmd(mcl, cmd, len);
1518		return;
1519	}
1520
1521	if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) {
1522		/* In case the remote device doesn't work correctly */
1523		error("Remote device does not support opcodes, cmd ignored");
1524		return;
1525	}
1526
1527	if (mcl->req == MCL_WAITING_RSP) {
1528		if (cmd[0] & 0x01) {
1529			/* Request arrived when a response is expected */
1530			if (mcl->role == MCL_INITIATOR)
1531				/* ignore */
1532				return;
1533			/* Initiator will ignore our last request */
1534			RELEASE_TIMER(mcl);
1535			mcl->req = MCL_AVAILABLE;
1536			g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_REQ_IGNORED,
1537				"Initiator sent a request with more priority");
1538			mcap_notify_error(mcl, gerr);
1539			proc_req[mcl->state](mcl, cmd, len);
1540			return;
1541		}
1542		proc_response(mcl, cmd, len);
1543	} else if (cmd[0] & 0x01)
1544		proc_req[mcl->state](mcl, cmd, len);
1545}
1546
1547static gboolean mdl_event_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
1548{
1549
1550	struct mcap_mdl *mdl = data;
1551	gboolean notify;
1552
1553	DBG("Close MDL %d", mdl->mdlid);
1554
1555	notify = (mdl->state == MDL_CONNECTED);
1556	shutdown_mdl(mdl);
1557
1558	update_mcl_state(mdl->mcl);
1559
1560	if (notify) {
1561		/*Callback to upper layer */
1562		mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data);
1563	}
1564
1565	return FALSE;
1566}
1567
1568static void mcap_connect_mdl_cb(GIOChannel *chan, GError *conn_err,
1569								gpointer data)
1570{
1571	struct mcap_mdl_op_cb *con = data;
1572	struct mcap_mdl *mdl = con->mdl;
1573	mcap_mdl_operation_cb cb = con->cb.op;
1574	gpointer user_data = con->user_data;
1575
1576	g_free(con);
1577	DBG("mdl connect callback");
1578
1579	if (conn_err) {
1580		DBG("ERROR: mdl connect callback");
1581		mdl->state = MDL_CLOSED;
1582		g_io_channel_unref(mdl->dc);
1583		mdl->dc = NULL;
1584		cb(mdl, conn_err, user_data);
1585		return;
1586	}
1587
1588	mdl->state = MDL_CONNECTED;
1589	mdl->wid = g_io_add_watch(mdl->dc, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
1590						(GIOFunc) mdl_event_cb, mdl);
1591
1592	cb(mdl, conn_err, user_data);
1593}
1594
1595gboolean mcap_connect_mdl(struct mcap_mdl *mdl, BtIOType BtType,
1596					uint16_t dcpsm,
1597					mcap_mdl_operation_cb connect_cb,
1598					gpointer user_data, GError **err)
1599{
1600	struct mcap_mdl_op_cb *con;
1601
1602	if (mdl->state != MDL_WAITING) {
1603		g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL,
1604					"%s", error2str(MCAP_INVALID_MDL));
1605		return FALSE;
1606	}
1607
1608	con = g_new0(struct mcap_mdl_op_cb, 1);
1609	con->mdl = mdl;
1610	con->cb.op = connect_cb;
1611	con->user_data = user_data;
1612
1613	/* TODO: Check if BtIOType is ERTM or Streaming before continue */
1614
1615	mdl->dc = bt_io_connect(BtType, mcap_connect_mdl_cb, con,
1616				NULL, err,
1617				BT_IO_OPT_SOURCE_BDADDR, &mdl->mcl->ms->src,
1618				BT_IO_OPT_DEST_BDADDR, &mdl->mcl->addr,
1619				BT_IO_OPT_PSM, dcpsm,
1620				BT_IO_OPT_MTU, MCAP_DC_MTU,
1621				BT_IO_OPT_SEC_LEVEL, mdl->mcl->ms->sec,
1622				BT_IO_OPT_INVALID);
1623	if (!mdl->dc) {
1624		DBG("MDL Connection error");
1625		mdl->state = MDL_CLOSED;
1626		g_free(con);
1627		return FALSE;
1628	}
1629
1630	return TRUE;
1631}
1632
1633static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
1634								gpointer data)
1635{
1636	GError *gerr = NULL;
1637	struct mcap_mcl *mcl = data;
1638	int sk, len;
1639	uint8_t buf[MCAP_CC_MTU];
1640
1641	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
1642		goto fail;
1643
1644	sk = g_io_channel_unix_get_fd(chan);
1645	len = read(sk, buf, sizeof(buf));
1646	if (len < 0)
1647		goto fail;
1648
1649	proc_cmd(mcl, buf, (uint32_t) len);
1650	return TRUE;
1651
1652fail:
1653	if (mcl->state != MCL_IDLE) {
1654		if (mcl->req == MCL_WAITING_RSP) {
1655			/* notify error in pending callback */
1656			g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_MCL_CLOSED,
1657								"MCL closed");
1658			mcap_notify_error(mcl, gerr);
1659			g_error_free(gerr);
1660		}
1661		mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
1662	}
1663	mcap_cache_mcl(mcl);
1664	return FALSE;
1665}
1666
1667static void mcap_connect_mcl_cb(GIOChannel *chan, GError *conn_err,
1668							gpointer user_data)
1669{
1670	char dstaddr[18];
1671	struct connect_mcl *con = user_data;
1672	struct mcap_mcl *aux, *mcl = con->mcl;
1673	mcap_mcl_connect_cb connect_cb = con->connect_cb;
1674	gpointer data = con->user_data;
1675	GError *gerr = NULL;
1676
1677	g_free(con);
1678
1679	mcl->ctrl &= ~MCAP_CTRL_CONN;
1680
1681	if (conn_err) {
1682		if (mcl->ctrl & MCAP_CTRL_FREE)
1683			mcl->ms->mcl_uncached_cb(mcl, mcl->ms->user_data);
1684		mcap_mcl_check_del(mcl);
1685		connect_cb(NULL, conn_err, data);
1686		return;
1687	}
1688
1689	ba2str(&mcl->addr, dstaddr);
1690
1691	aux = find_mcl(mcl->ms->mcls, &mcl->addr);
1692	if (aux) {
1693		/* Double MCL connection case */
1694		if (aux != mcl) {
1695			/* This MCL was not in cache */
1696			mcap_mcl_unref(mcl);
1697		}
1698		error("MCL error: Device %s is already connected", dstaddr);
1699		g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS,
1700					"MCL %s is already connected", dstaddr);
1701		connect_cb(NULL, gerr, data);
1702		g_error_free(gerr);
1703		return;
1704	}
1705
1706	mcl->state = MCL_CONNECTED;
1707	mcl->role = MCL_INITIATOR;
1708	mcl->req = MCL_AVAILABLE;
1709	mcl->ctrl |= MCAP_CTRL_STD_OP;
1710
1711	if (mcl->ctrl & MCAP_CTRL_CACHED)
1712		mcap_uncache_mcl(mcl);
1713	else
1714		mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl);
1715
1716	mcl->wid = g_io_add_watch(mcl->cc,
1717				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
1718				(GIOFunc) mcl_control_cb, mcl);
1719	connect_cb(mcl, gerr, data);
1720
1721	if (mcl->ref == 1) {
1722		mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl);
1723		mcap_mcl_unref(mcl);
1724	}
1725}
1726
1727static void connect_dc_event_cb(GIOChannel *chan, GError *err,
1728							gpointer user_data)
1729{
1730	struct mcap_mdl *mdl = user_data;
1731	struct mcap_mcl *mcl = mdl->mcl;
1732
1733	mdl->state = MDL_CONNECTED;
1734	mdl->dc = g_io_channel_ref(chan);
1735	mdl->wid = g_io_add_watch(mdl->dc, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
1736						(GIOFunc) mdl_event_cb, mdl);
1737
1738	mcl->state = MCL_ACTIVE;
1739	mcl->cb->mdl_connected(mdl, mcl->cb->user_data);
1740}
1741
1742gboolean mcap_create_mcl(struct mcap_instance *ms,
1743				const bdaddr_t *addr,
1744				uint16_t ccpsm,
1745				mcap_mcl_connect_cb connect_cb,
1746				gpointer user_data,
1747				GError **err)
1748{
1749	struct mcap_mcl *mcl;
1750	struct connect_mcl *con;
1751
1752	mcl = find_mcl(ms->mcls, addr);
1753	if (mcl) {
1754		g_set_error(err, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS,
1755					"MCL is already connected.");
1756		return FALSE;
1757	}
1758
1759	mcl = find_mcl(ms->cached, addr);
1760	if (!mcl) {
1761		mcl = g_new0(struct mcap_mcl, 1);
1762		mcl->ms = ms;
1763		mcl->state = MCL_IDLE;
1764		bacpy(&mcl->addr, addr);
1765		set_default_cb(mcl);
1766		mcl->next_mdl = (rand() % MCAP_MDLID_FINAL) + 1;
1767		mcl = mcap_mcl_ref(mcl);
1768	} else
1769		mcl->ctrl |= MCAP_CTRL_CONN;
1770
1771	con = g_new0(struct connect_mcl, 1);
1772	con->mcl = mcl;
1773	con->connect_cb = connect_cb;
1774	con->user_data = user_data;
1775
1776	mcl->cc = bt_io_connect(BT_IO_L2CAP, mcap_connect_mcl_cb, con,
1777				NULL, err,
1778				BT_IO_OPT_SOURCE_BDADDR, &ms->src,
1779				BT_IO_OPT_DEST_BDADDR, addr,
1780				BT_IO_OPT_PSM, ccpsm,
1781				BT_IO_OPT_MTU, MCAP_CC_MTU,
1782				BT_IO_OPT_SEC_LEVEL, ms->sec,
1783				BT_IO_OPT_INVALID);
1784	if (!mcl->cc) {
1785		g_free(con);
1786		mcl->ctrl &= ~MCAP_CTRL_CONN;
1787		if (mcl->ctrl & MCAP_CTRL_FREE)
1788			mcl->ms->mcl_uncached_cb(mcl, mcl->ms->user_data);
1789		mcap_mcl_check_del(mcl);
1790		return FALSE;
1791	}
1792
1793	return TRUE;
1794}
1795
1796static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
1797{
1798	struct mcap_instance *ms = user_data;
1799	struct mcap_mcl *mcl;
1800	struct mcap_mdl *mdl;
1801	GError *err = NULL;
1802	bdaddr_t dst;
1803	GSList *l;
1804
1805	bt_io_get(chan, BT_IO_L2CAP, &err,
1806			BT_IO_OPT_DEST_BDADDR, &dst,
1807			BT_IO_OPT_INVALID);
1808	if (err) {
1809		error("%s", err->message);
1810		g_error_free(err);
1811		goto drop;
1812	}
1813
1814	mcl = find_mcl(ms->mcls, &dst);
1815	if (!mcl || mcl->state != MCL_PENDING)
1816		goto drop;
1817
1818	for (l = mcl->mdls; l; l = l->next) {
1819		mdl = l->data;
1820		if (mdl->state == MDL_WAITING) {
1821			if (!bt_io_accept(chan, connect_dc_event_cb, mdl, NULL,
1822									&err)) {
1823				error("MDL accept error %s", err->message);
1824				mdl->state = MDL_CLOSED;
1825				g_error_free(err);
1826				goto drop;
1827			}
1828			return;
1829		}
1830	}
1831
1832drop:
1833	g_io_channel_shutdown(chan, TRUE, NULL);
1834}
1835
1836static void connect_mcl_event_cb(GIOChannel *chan, GError *err,
1837							gpointer user_data)
1838{
1839	struct mcap_mcl *mcl = user_data;
1840	gboolean reconn;
1841
1842	if (err) {
1843		mcap_mcl_check_del(mcl);
1844		return;
1845	}
1846
1847	mcl->state = MCL_CONNECTED;
1848	mcl->role = MCL_ACCEPTOR;
1849	mcl->req = MCL_AVAILABLE;
1850	mcl->cc = g_io_channel_ref(chan);
1851	mcl->ctrl |= MCAP_CTRL_STD_OP;
1852
1853	reconn = (mcl->ctrl & MCAP_CTRL_CACHED);
1854	if (reconn)
1855		mcap_uncache_mcl(mcl);
1856	else
1857		mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl);
1858
1859	mcl->wid = g_io_add_watch(mcl->cc,
1860			G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
1861			(GIOFunc) mcl_control_cb, mcl);
1862
1863	/* Callback to report new MCL */
1864	if (reconn)
1865		mcl->ms->mcl_reconnected_cb(mcl, mcl->ms->user_data);
1866	else
1867		mcl->ms->mcl_connected_cb(mcl, mcl->ms->user_data);
1868
1869	if (mcl->ref == 1) {
1870		mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl);
1871		mcap_mcl_unref(mcl);
1872	}
1873}
1874
1875static void confirm_mcl_event_cb(GIOChannel *chan, gpointer user_data)
1876{
1877	struct mcap_instance *ms = user_data;
1878	struct mcap_mcl *mcl;
1879	bdaddr_t dst;
1880	char address[18], srcstr[18];
1881	GError *err = NULL;
1882
1883	bt_io_get(chan, BT_IO_L2CAP, &err,
1884			BT_IO_OPT_DEST_BDADDR, &dst,
1885			BT_IO_OPT_DEST, address,
1886			BT_IO_OPT_INVALID);
1887	if (err) {
1888		error("%s", err->message);
1889		g_error_free(err);
1890		goto drop;
1891	}
1892
1893	ba2str(&ms->src, srcstr);
1894	mcl = find_mcl(ms->mcls, &dst);
1895	if (mcl) {
1896		error("Control channel already created with %s on adapter %s",
1897				address, srcstr);
1898		goto drop;
1899	}
1900
1901	mcl = find_mcl(ms->cached, &dst);
1902	if (!mcl) {
1903		mcl = g_new0(struct mcap_mcl, 1);
1904		mcl->ms = ms;
1905		bacpy(&mcl->addr, &dst);
1906		set_default_cb(mcl);
1907		mcl->next_mdl = (rand() % MCAP_MDLID_FINAL) + 1;
1908		mcl = mcap_mcl_ref(mcl);
1909	}
1910
1911	if (!bt_io_accept(chan, connect_mcl_event_cb, mcl, NULL, &err)) {
1912		error("mcap accept error: %s", err->message);
1913		if (!(mcl->ctrl & MCAP_CTRL_CACHED))
1914			mcap_mcl_unref(mcl);
1915		g_error_free(err);
1916		goto drop;
1917	}
1918
1919	return;
1920drop:
1921	g_io_channel_shutdown(chan, TRUE, NULL);
1922}
1923
1924struct mcap_instance *mcap_create_instance(bdaddr_t *src,
1925					BtIOSecLevel sec,
1926					uint16_t ccpsm,
1927					uint16_t dcpsm,
1928					mcap_mcl_event_cb mcl_connected,
1929					mcap_mcl_event_cb mcl_reconnected,
1930					mcap_mcl_event_cb mcl_disconnected,
1931					mcap_mcl_event_cb mcl_uncached,
1932					gpointer user_data,
1933					GError **gerr)
1934{
1935	struct mcap_instance *ms;
1936
1937	if (sec < BT_IO_SEC_MEDIUM) {
1938		g_set_error(gerr, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
1939				"Security level can't be minor of %d",
1940				BT_IO_SEC_MEDIUM);
1941		return NULL;
1942	}
1943
1944	if (!(mcl_connected && mcl_reconnected &&
1945			mcl_disconnected && mcl_uncached)) {
1946		g_set_error(gerr, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
1947				"The callbacks can't be null");
1948		return NULL;
1949	}
1950
1951	ms = g_new0(struct mcap_instance, 1);
1952
1953	bacpy(&ms->src, src);
1954
1955	ms->sec = sec;
1956	ms->mcl_connected_cb = mcl_connected;
1957	ms->mcl_reconnected_cb = mcl_reconnected;
1958	ms->mcl_disconnected_cb = mcl_disconnected;
1959	ms->mcl_uncached_cb = mcl_uncached;
1960	ms->user_data = user_data;
1961
1962	/* Listen incoming connections in control channel */
1963	ms->ccio = bt_io_listen(BT_IO_L2CAP, NULL, confirm_mcl_event_cb, ms,
1964				NULL, gerr,
1965				BT_IO_OPT_SOURCE_BDADDR, &ms->src,
1966				BT_IO_OPT_PSM, ccpsm,
1967				BT_IO_OPT_MTU, MCAP_CC_MTU,
1968				BT_IO_OPT_SEC_LEVEL, sec,
1969				BT_IO_OPT_INVALID);
1970	if (!ms->ccio) {
1971		error("%s", (*gerr)->message);
1972		g_free(ms);
1973		return NULL;
1974	}
1975
1976	/* Listen incoming connections in data channels */
1977	ms->dcio = bt_io_listen(BT_IO_L2CAP, NULL, confirm_dc_event_cb, ms,
1978				NULL, gerr,
1979				BT_IO_OPT_SOURCE_BDADDR, &ms->src,
1980				BT_IO_OPT_PSM, dcpsm,
1981				BT_IO_OPT_MTU, MCAP_DC_MTU,
1982				BT_IO_OPT_SEC_LEVEL, sec,
1983				BT_IO_OPT_INVALID);
1984	if (!ms->dcio) {
1985		g_io_channel_shutdown(ms->ccio, TRUE, NULL);
1986		g_io_channel_unref(ms->ccio);
1987		ms->ccio = NULL;
1988		error("%s", (*gerr)->message);
1989		g_free(ms);
1990		return NULL;
1991	}
1992
1993	/* Initialize random seed to generate mdlids for this instance */
1994	srand(time(NULL));
1995
1996	return ms;
1997}
1998
1999void mcap_release_instance(struct mcap_instance *mi)
2000{
2001	GSList *l;
2002
2003	if (!mi)
2004		return;
2005
2006	if (mi->ccio) {
2007		g_io_channel_shutdown(mi->ccio, TRUE, NULL);
2008		g_io_channel_unref(mi->ccio);
2009		mi->ccio = NULL;
2010	}
2011
2012	if (mi->dcio) {
2013		g_io_channel_shutdown(mi->dcio, TRUE, NULL);
2014		g_io_channel_unref(mi->dcio);
2015		mi->dcio = NULL;
2016	}
2017
2018	for (l = mi->mcls; l; l = l->next) {
2019		mcap_mcl_shutdown(l->data);
2020		mcap_mcl_unref(l->data);
2021	}
2022	g_slist_free(mi->mcls);
2023	mi->mcls = NULL;
2024
2025	for (l = mi->cached; l; l = l->next)
2026		mcap_mcl_unref(l->data);
2027	g_slist_free(mi->cached);
2028	mi->cached = NULL;
2029
2030	g_free(mi);
2031}
2032
2033uint16_t mcap_get_ctrl_psm(struct mcap_instance *mi, GError **err)
2034{
2035	uint16_t lpsm;
2036
2037	if (!(mi && mi->ccio)) {
2038		g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
2039			"Invalid MCAP instance");
2040		return 0;
2041	}
2042
2043	if (!bt_io_get(mi->ccio, BT_IO_L2CAP, err,
2044			BT_IO_OPT_PSM, &lpsm,
2045			BT_IO_OPT_INVALID))
2046		return 0;
2047
2048	return lpsm;
2049}
2050
2051uint16_t mcap_get_data_psm(struct mcap_instance *mi, GError **err)
2052{
2053	uint16_t lpsm;
2054
2055	if (!(mi && mi->dcio)) {
2056		g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
2057			"Invalid MCAP instance");
2058		return 0;
2059	}
2060
2061	if (!bt_io_get(mi->dcio, BT_IO_L2CAP, err,
2062			BT_IO_OPT_PSM, &lpsm,
2063			BT_IO_OPT_INVALID))
2064		return 0;
2065
2066	return lpsm;
2067}
2068