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, ¬ify);
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, ¬ify);
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, ¬ify);
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, ¬ify);
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