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