• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
54 struct 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 
61 typedef 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 
67 struct 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 */
75 static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
76 static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
77 static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
78 
79 static 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 
85 static void mcap_cache_mcl(struct mcap_mcl *mcl);
86 
default_mdl_connected_cb(struct mcap_mdl * mdl,gpointer data)87 static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
88 {
89 	DBG("MCAP Unmanaged mdl connection");
90 }
91 
default_mdl_closed_cb(struct mcap_mdl * mdl,gpointer data)92 static void default_mdl_closed_cb(struct mcap_mdl *mdl, gpointer data)
93 {
94 	DBG("MCAP Unmanaged mdl closed");
95 }
96 
default_mdl_deleted_cb(struct mcap_mdl * mdl,gpointer data)97 static void default_mdl_deleted_cb(struct mcap_mdl *mdl, gpointer data)
98 {
99 	DBG("MCAP Unmanaged mdl deleted");
100 }
101 
default_mdl_aborted_cb(struct mcap_mdl * mdl,gpointer data)102 static void default_mdl_aborted_cb(struct mcap_mdl *mdl, gpointer data)
103 {
104 	DBG("MCAP Unmanaged mdl aborted");
105 }
106 
default_mdl_conn_req_cb(struct mcap_mcl * mcl,uint8_t mdepid,uint16_t mdlid,uint8_t * conf,gpointer data)107 static 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 
default_mdl_reconn_req_cb(struct mcap_mdl * mdl,gpointer data)116 static 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 
set_default_cb(struct mcap_mcl * mcl)124 static 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 
error2str(uint8_t rc)137 static 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 
mcap_send_std_opcode(struct mcap_mcl * mcl,void * cmd,uint32_t size,GError ** err)169 static 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 
update_mcl_state(struct mcap_mcl * mcl)208 static 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 
shutdown_mdl(struct mcap_mdl * mdl)228 static 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 
free_mdl(struct mcap_mdl * mdl)244 static 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 
cmp_mdl_state(gconstpointer a,gconstpointer b)253 static 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 
free_mcap_mdl_op(struct mcap_mdl_op_cb * op)266 static 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 
free_mcl_priv_data(struct mcap_mcl * mcl)277 static 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 
mcap_notify_error(struct mcap_mcl * mcl,GError * err)283 static 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 
mcap_send_data(int sock,const void * buf,uint32_t size)334 int 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 
mcap_send_cmd(struct mcap_mcl * mcl,uint8_t oc,uint8_t rc,uint16_t mdl,uint8_t * data,size_t len)349 static 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 
get_mdl(struct mcap_mcl * mcl,uint16_t mdlid)374 static 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 
generate_mdlid(struct mcap_mcl * mcl)388 static 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 
create_req(uint8_t op,uint16_t mdl_id)406 static 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 
create_mdl_req(uint16_t mdl_id,uint8_t mdep,uint8_t conf)418 static 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 
compare_mdl(gconstpointer a,gconstpointer b)433 static 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 
wait_response_timer(gpointer data)446 static 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 
mcap_create_mdl(struct mcap_mcl * mcl,uint8_t mdepid,uint8_t conf,mcap_mdl_operation_conf_cb connect_cb,gpointer user_data,GDestroyNotify destroy,GError ** err)466 gboolean 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 
mcap_reconnect_mdl(struct mcap_mdl * mdl,mcap_mdl_operation_cb reconnect_cb,gpointer user_data,GDestroyNotify destroy,GError ** err)517 gboolean 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 
send_delete_req(struct mcap_mcl * mcl,struct mcap_mdl_op_cb * con,uint16_t mdlid,GError ** err)555 static 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 
mcap_delete_all_mdls(struct mcap_mcl * mcl,mcap_mdl_notify_cb delete_cb,gpointer user_data,GDestroyNotify destroy,GError ** err)575 gboolean 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 
mcap_delete_mdl(struct mcap_mdl * mdl,mcap_mdl_notify_cb delete_cb,gpointer user_data,GDestroyNotify destroy,GError ** err)613 gboolean 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 
mcap_mdl_abort(struct mcap_mdl * mdl,mcap_mdl_notify_cb abort_cb,gpointer user_data,GDestroyNotify destroy,GError ** err)653 gboolean 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 
find_mcl(GSList * list,const bdaddr_t * addr)686 static 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 
mcap_mdl_get_fd(struct mcap_mdl * mdl)700 int 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 
mcap_mdl_get_mdlid(struct mcap_mdl * mdl)708 uint16_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 
close_mcl(struct mcap_mcl * mcl,gboolean cache_requested)716 static 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 
mcap_mcl_shutdown(struct mcap_mcl * mcl)755 static void mcap_mcl_shutdown(struct mcap_mcl *mcl)
756 {
757 	close_mcl(mcl, TRUE);
758 }
759 
mcap_mcl_release(struct mcap_mcl * mcl)760 static void mcap_mcl_release(struct mcap_mcl *mcl)
761 {
762 	close_mcl(mcl, FALSE);
763 }
764 
mcap_cache_mcl(struct mcap_mcl * mcl)765 static 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 
mcap_uncache_mcl(struct mcap_mcl * mcl)808 static 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 
mcap_close_mcl(struct mcap_mcl * mcl,gboolean cache)821 void 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 
mcap_mcl_ref(struct mcap_mcl * mcl)848 struct 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 
mcap_mcl_unref(struct mcap_mcl * mcl)857 void 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 
parse_set_opts(struct mcap_mdl_cb * mdl_cb,GError ** err,McapMclCb cb1,va_list args)872 static 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 
mcap_mcl_set_cb(struct mcap_mcl * mcl,gpointer user_data,GError ** gerr,McapMclCb cb1,...)929 gboolean 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 
mcap_mcl_get_addr(struct mcap_mcl * mcl,bdaddr_t * addr)946 void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)
947 {
948 	bacpy(addr, &mcl->addr);
949 }
950 
mcap_del_mdl(gpointer elem,gpointer user_data)951 static 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 
check_cmd_req_length(struct mcap_mcl * mcl,void * cmd,uint32_t rlen,uint32_t explen,uint8_t rspcod)963 static 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 
process_md_create_mdl_req(struct mcap_mcl * mcl,void * cmd,uint32_t len)984 static 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 
process_md_reconnect_mdl_req(struct mcap_mcl * mcl,void * cmd,uint32_t len)1065 static 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 
process_md_abort_mdl_req(struct mcap_mcl * mcl,void * cmd,uint32_t len)1113 static 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 
process_md_delete_mdl_req(struct mcap_mcl * mcl,void * cmd,uint32_t len)1156 static 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 
1207 resp:
1208 	mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid,
1209 								NULL, 0);
1210 }
1211 
invalid_req_state(struct mcap_mcl * mcl,uint8_t * cmd,uint32_t len)1212 static 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 */
proc_req_connected(struct mcap_mcl * mcl,uint8_t * cmd,uint32_t len)1226 static 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 
proc_req_pending(struct mcap_mcl * mcl,uint8_t * cmd,uint32_t len)1243 static 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 
proc_req_active(struct mcap_mcl * mcl,uint8_t * cmd,uint32_t len)1251 static 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 */
check_err_rsp(struct mcap_mcl * mcl,mcap_rsp * rsp,uint32_t rlen,uint32_t len,GError ** gerr)1269 static 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 
1322 fail:
1323 	g_set_error(gerr, MCAP_ERROR, err, "%s", msg);
1324 	return close;
1325 }
1326 
process_md_create_mdl_rsp(struct mcap_mcl * mcl,mcap_rsp * rsp,uint32_t len)1327 static 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 
1358 fail:
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 
process_md_reconnect_mdl_rsp(struct mcap_mcl * mcl,mcap_rsp * rsp,uint32_t len)1367 static 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 
process_md_abort_mdl_rsp(struct mcap_mcl * mcl,mcap_rsp * rsp,uint32_t len)1402 static 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 
restore_mdl(gpointer elem,gpointer data)1435 static 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 
check_mdl_del_err(struct mcap_mdl * mdl,mcap_rsp * rsp)1448 static 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 
process_md_delete_mdl_rsp(struct mcap_mcl * mcl,mcap_rsp * rsp,uint32_t len)1460 static 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 
post_process_rsp(struct mcap_mcl * mcl,struct mcap_mdl_op_cb * op)1505 static 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 
proc_response(struct mcap_mcl * mcl,void * buf,uint32_t len)1518 static 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 
proc_cmd(struct mcap_mcl * mcl,uint8_t * cmd,uint32_t len)1555 static 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 
mdl_event_cb(GIOChannel * chan,GIOCondition cond,gpointer data)1600 static 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 
mcap_connect_mdl_cb(GIOChannel * chan,GError * conn_err,gpointer data)1621 static 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 
mcap_connect_mdl(struct mcap_mdl * mdl,uint8_t mode,uint16_t dcpsm,mcap_mdl_operation_cb connect_cb,gpointer user_data,GDestroyNotify destroy,GError ** err)1650 gboolean 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 
mcl_control_cb(GIOChannel * chan,GIOCondition cond,gpointer data)1697 static 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 
1716 fail:
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 
mcap_connect_mcl_cb(GIOChannel * chan,GError * conn_err,gpointer user_data)1731 static 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 
set_mdl_properties(GIOChannel * chan,struct mcap_mdl * mdl)1788 static 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 
mcl_io_destroy(gpointer data)1804 static 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 
mcap_create_mcl(struct mcap_instance * mi,const bdaddr_t * addr,uint16_t ccpsm,mcap_mcl_connect_cb connect_cb,gpointer user_data,GDestroyNotify destroy,GError ** err)1814 gboolean 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 
connect_dc_event_cb(GIOChannel * chan,GError * gerr,gpointer user_data)1873 static 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 
1907 drop:
1908 	g_io_channel_shutdown(chan, TRUE, NULL);
1909 }
1910 
set_mcl_conf(GIOChannel * chan,struct mcap_mcl * mcl)1911 static 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 
connect_mcl_event_cb(GIOChannel * chan,GError * gerr,gpointer user_data)1943 static 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;
1985 drop:
1986 	g_io_channel_shutdown(chan, TRUE, NULL);
1987 }
1988 
mcap_create_instance(bdaddr_t * src,BtIOSecLevel sec,uint16_t ccpsm,uint16_t dcpsm,mcap_mcl_event_cb mcl_connected,mcap_mcl_event_cb mcl_reconnected,mcap_mcl_event_cb mcl_disconnected,mcap_mcl_event_cb mcl_uncached,mcap_info_ind_event_cb mcl_sync_info_ind,gpointer user_data,GError ** gerr)1989 struct 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 
mcap_release_instance(struct mcap_instance * mi)2068 void 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 
mcap_instance_ref(struct mcap_instance * mi)2104 struct 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 
mcap_instance_unref(struct mcap_instance * mi)2113 void 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 
mcap_get_ctrl_psm(struct mcap_instance * mi,GError ** err)2126 uint16_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 
mcap_get_data_psm(struct mcap_instance * mi,GError ** err)2144 uint16_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 
mcap_set_data_chan_mode(struct mcap_instance * mi,uint8_t mode,GError ** err)2162 gboolean 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 
mcap_mdl_ref(struct mcap_mdl * mdl)2175 struct 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 
mcap_mdl_unref(struct mcap_mdl * mdl)2184 void 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