3
* MCAP for BlueZ - Bluetooth protocol stack for Linux
5
* Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23
#include <netinet/in.h>
30
#include <bluetooth/bluetooth.h>
31
#include <bluetooth/l2cap.h>
39
#include "mcap_internal.h"
41
#define RESPONSE_TIMER 6 /* seconds */
42
#define MAX_CACHED 10 /* 10 devices */
44
#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
46
#define RELEASE_TIMER(__mcl) do { \
48
g_source_remove(__mcl->tid); \
54
struct mcap_mcl *mcl; /* MCL for this operation */
55
mcap_mcl_connect_cb connect_cb; /* Connect callback */
56
GDestroyNotify destroy; /* Destroy callback */
57
gpointer user_data; /* Callback user data */
61
mcap_mdl_operation_cb op;
62
mcap_mdl_operation_conf_cb op_conf;
63
mcap_mdl_notify_cb notify;
66
struct mcap_mdl_op_cb {
67
struct mcap_mdl *mdl; /* MDL for this operation */
68
mcap_cb_type cb; /* Operation callback */
69
GDestroyNotify destroy; /* Destroy callback */
70
gpointer user_data; /* Callback user data */
73
/* MCAP finite state machine functions */
74
static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
75
static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
76
static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
78
static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = {
84
static void mcap_cache_mcl(struct mcap_mcl *mcl);
86
static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
88
DBG("MCAP Unmanaged mdl connection");
91
static void default_mdl_closed_cb(struct mcap_mdl *mdl, gpointer data)
93
DBG("MCAP Unmanaged mdl closed");
96
static void default_mdl_deleted_cb(struct mcap_mdl *mdl, gpointer data)
98
DBG("MCAP Unmanaged mdl deleted");
101
static void default_mdl_aborted_cb(struct mcap_mdl *mdl, gpointer data)
103
DBG("MCAP Unmanaged mdl aborted");
106
static uint8_t default_mdl_conn_req_cb(struct mcap_mcl *mcl,
107
uint8_t mdepid, uint16_t mdlid,
108
uint8_t *conf, gpointer data)
110
DBG("MCAP mdl remote connection aborted");
111
/* Due to this callback isn't managed this request won't be supported */
112
return MCAP_REQUEST_NOT_SUPPORTED;
115
static uint8_t default_mdl_reconn_req_cb(struct mcap_mdl *mdl,
118
DBG("MCAP mdl remote reconnection aborted");
119
/* Due to this callback isn't managed this request won't be supported */
120
return MCAP_REQUEST_NOT_SUPPORTED;
123
static void set_default_cb(struct mcap_mcl *mcl)
126
mcl->cb = g_new0(struct mcap_mdl_cb, 1);
128
mcl->cb->mdl_connected = default_mdl_connected_cb;
129
mcl->cb->mdl_closed = default_mdl_closed_cb;
130
mcl->cb->mdl_deleted = default_mdl_deleted_cb;
131
mcl->cb->mdl_aborted = default_mdl_aborted_cb;
132
mcl->cb->mdl_conn_req = default_mdl_conn_req_cb;
133
mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
136
static char *error2str(uint8_t rc)
141
case MCAP_INVALID_OP_CODE:
142
return "Invalid Op Code";
143
case MCAP_INVALID_PARAM_VALUE:
144
return "Invalid Parameter Value";
145
case MCAP_INVALID_MDEP:
146
return "Invalid MDEP";
149
case MCAP_INVALID_MDL:
150
return "Invalid MDL";
153
case MCAP_INVALID_OPERATION:
154
return "Invalid Operation";
155
case MCAP_RESOURCE_UNAVAILABLE:
156
return "Resource Unavailable";
157
case MCAP_UNSPECIFIED_ERROR:
158
return "Unspecified Error";
159
case MCAP_REQUEST_NOT_SUPPORTED:
160
return "Request Not Supported";
161
case MCAP_CONFIGURATION_REJECTED:
162
return "Configuration Rejected";
164
return "Unknown Response Code";
168
static gboolean mcap_send_std_opcode(struct mcap_mcl *mcl, void *cmd,
169
uint32_t size, GError **err)
171
if (mcl->state == MCL_IDLE) {
172
g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
173
"MCL is not connected");
177
if (mcl->req != MCL_AVAILABLE) {
178
g_set_error(err, MCAP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE,
183
if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) {
184
g_set_error(err, MCAP_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED,
185
"Remote does not support standard opcodes");
189
if (mcl->state == MCL_PENDING) {
190
g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_OPERATION,
191
"Not Std Op. Codes can be sent in PENDING State");
195
if (mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), cmd, size) < 0) {
196
g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
197
"Command can't be sent, write error");
202
mcl->req = MCL_WAITING_RSP;
207
static void update_mcl_state(struct mcap_mcl *mcl)
210
struct mcap_mdl *mdl;
212
if (mcl->state == MCL_PENDING)
215
for (l = mcl->mdls; l; l = l->next) {
218
if (mdl->state == MDL_CONNECTED) {
219
mcl->state = MCL_ACTIVE;
224
mcl->state = MCL_CONNECTED;
227
static void shutdown_mdl(struct mcap_mdl *mdl)
229
mdl->state = MDL_CLOSED;
232
g_source_remove(mdl->wid);
237
g_io_channel_shutdown(mdl->dc, TRUE, NULL);
238
g_io_channel_unref(mdl->dc);
243
static void free_mdl(struct mcap_mdl *mdl)
248
mcap_mcl_unref(mdl->mcl);
252
static gint cmp_mdl_state(gconstpointer a, gconstpointer b)
254
const struct mcap_mdl *mdl = a;
255
const MDLState *st = b;
257
if (mdl->state == *st)
259
else if (mdl->state < *st)
265
static void free_mcap_mdl_op(struct mcap_mdl_op_cb *op)
268
op->destroy(op->user_data);
271
mcap_mdl_unref(op->mdl);
276
static void free_mcl_priv_data(struct mcap_mcl *mcl)
278
free_mcap_mdl_op(mcl->priv_data);
279
mcl->priv_data = NULL;
282
static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
284
struct mcap_mdl_op_cb *con = mcl->priv_data;
285
struct mcap_mdl *mdl;
289
if (!con || !mcl->lcmd)
292
switch (mcl->lcmd[0]) {
293
case MCAP_MD_CREATE_MDL_REQ:
295
l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
297
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
299
update_mcl_state(mcl);
300
con->cb.op_conf(NULL, 0, err, con->user_data);
302
case MCAP_MD_ABORT_MDL_REQ:
304
l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
305
shutdown_mdl(l->data);
306
update_mcl_state(mcl);
307
con->cb.notify(err, con->user_data);
309
case MCAP_MD_DELETE_MDL_REQ:
310
for (l = mcl->mdls; l; l = l->next) {
312
if (mdl->state == MDL_DELETING)
313
mdl->state = (mdl->dc) ? MDL_CONNECTED :
316
update_mcl_state(mcl);
317
con->cb.notify(err, con->user_data);
319
case MCAP_MD_RECONNECT_MDL_REQ:
321
l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
322
shutdown_mdl(l->data);
323
update_mcl_state(mcl);
324
con->cb.op(NULL, err, con->user_data);
328
free_mcl_priv_data(mcl);
333
int mcap_send_data(int sock, const void *buf, uint32_t size)
335
const uint8_t *buf_b = buf;
338
while (sent < size) {
339
int n = write(sock, buf_b + sent, size - sent);
348
static int mcap_send_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
349
uint16_t mdl, uint8_t *data, size_t len)
357
sock = g_io_channel_unix_get_fd(mcl->cc);
359
cmd = g_malloc(sizeof(mcap_rsp) + len);
362
cmd->mdl = htons(mdl);
365
memcpy(cmd->data, data, len);
367
sent = mcap_send_data(sock, cmd, sizeof(mcap_rsp) + len);
373
static struct mcap_mdl *get_mdl(struct mcap_mcl *mcl, uint16_t mdlid)
376
struct mcap_mdl *mdl;
378
for (l = mcl->mdls; l; l = l->next) {
380
if (mdlid == mdl->mdlid)
387
static uint16_t generate_mdlid(struct mcap_mcl *mcl)
389
uint16_t mdlid = mcl->next_mdl;
390
struct mcap_mdl *mdl;
393
mdl = get_mdl(mcl, mdlid);
395
mcl->next_mdl = (mdlid % MCAP_MDLID_FINAL) + 1;
398
mdlid = (mdlid % MCAP_MDLID_FINAL) + 1;
399
} while (mdlid != mcl->next_mdl);
401
/* No more mdlids availables */
405
static mcap_md_req *create_req(uint8_t op, uint16_t mdl_id)
407
mcap_md_req *req_cmd;
409
req_cmd = g_new0(mcap_md_req, 1);
412
req_cmd->mdl = htons(mdl_id);
417
static mcap_md_create_mdl_req *create_mdl_req(uint16_t mdl_id, uint8_t mdep,
420
mcap_md_create_mdl_req *req_mdl;
422
req_mdl = g_new0(mcap_md_create_mdl_req, 1);
424
req_mdl->op = MCAP_MD_CREATE_MDL_REQ;
425
req_mdl->mdl = htons(mdl_id);
426
req_mdl->mdep = mdep;
427
req_mdl->conf = conf;
432
static gint compare_mdl(gconstpointer a, gconstpointer b)
434
const struct mcap_mdl *mdla = a;
435
const struct mcap_mdl *mdlb = b;
437
if (mdla->mdlid == mdlb->mdlid)
439
else if (mdla->mdlid < mdlb->mdlid)
445
static gboolean wait_response_timer(gpointer data)
447
struct mcap_mcl *mcl = data;
453
g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
454
"Timeout waiting response");
456
mcap_notify_error(mcl, gerr);
459
mcl->mi->mcl_disconnected_cb(mcl, mcl->mi->user_data);
465
gboolean mcap_create_mdl(struct mcap_mcl *mcl,
468
mcap_mdl_operation_conf_cb connect_cb,
470
GDestroyNotify destroy,
473
struct mcap_mdl *mdl;
474
struct mcap_mdl_op_cb *con;
475
mcap_md_create_mdl_req *cmd;
478
id = generate_mdlid(mcl);
480
g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
481
"Not more mdlids available");
485
mdl = g_new0(struct mcap_mdl, 1);
486
mdl->mcl = mcap_mcl_ref(mcl);
488
mdl->mdep_id = mdepid;
489
mdl->state = MDL_WAITING;
491
con = g_new0(struct mcap_mdl_op_cb, 1);
492
con->mdl = mcap_mdl_ref(mdl);
493
con->cb.op_conf = connect_cb;
494
con->destroy = destroy;
495
con->user_data = user_data;
497
cmd = create_mdl_req(id, mdepid, conf);
498
if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_create_mdl_req),
500
mcap_mdl_unref(con->mdl);
506
mcl->state = MCL_ACTIVE;
507
mcl->priv_data = con;
509
mcl->mdls = g_slist_insert_sorted(mcl->mdls, mcap_mdl_ref(mdl),
511
mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
516
gboolean mcap_reconnect_mdl(struct mcap_mdl *mdl,
517
mcap_mdl_operation_cb reconnect_cb,
519
GDestroyNotify destroy,
522
struct mcap_mdl_op_cb *con;
523
struct mcap_mcl *mcl = mdl->mcl;
526
if (mdl->state != MDL_CLOSED) {
527
g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
528
"MDL is not closed");
532
cmd = create_req(MCAP_MD_RECONNECT_MDL_REQ, mdl->mdlid);
533
if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
538
mdl->state = MDL_WAITING;
540
con = g_new0(struct mcap_mdl_op_cb, 1);
541
con->mdl = mcap_mdl_ref(mdl);
542
con->cb.op = reconnect_cb;
543
con->destroy = destroy;
544
con->user_data = user_data;
546
mcl->state = MCL_ACTIVE;
547
mcl->priv_data = con;
549
mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
554
static gboolean send_delete_req(struct mcap_mcl *mcl,
555
struct mcap_mdl_op_cb *con,
561
cmd = create_req(MCAP_MD_DELETE_MDL_REQ, mdlid);
562
if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
567
mcl->priv_data = con;
569
mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
574
gboolean mcap_delete_all_mdls(struct mcap_mcl *mcl,
575
mcap_mdl_notify_cb delete_cb,
577
GDestroyNotify destroy,
581
struct mcap_mdl *mdl;
582
struct mcap_mdl_op_cb *con;
584
DBG("MCL in state: %d", mcl->state);
586
g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
587
"There are not MDLs created");
591
for (l = mcl->mdls; l; l = l->next) {
593
if (mdl->state != MDL_WAITING)
594
mdl->state = MDL_DELETING;
597
con = g_new0(struct mcap_mdl_op_cb, 1);
599
con->cb.notify = delete_cb;
600
con->destroy = destroy;
601
con->user_data = user_data;
604
if (!send_delete_req(mcl, con, MCAP_ALL_MDLIDS, err)) {
612
gboolean mcap_delete_mdl(struct mcap_mdl *mdl, mcap_mdl_notify_cb delete_cb,
614
GDestroyNotify destroy,
617
struct mcap_mcl *mcl= mdl->mcl;
618
struct mcap_mdl_op_cb *con;
621
l = g_slist_find(mcl->mdls, mdl);
624
g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL,
625
"%s" , error2str(MCAP_INVALID_MDEP));
629
if (mdl->state == MDL_WAITING) {
630
g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
631
"Mdl is not created");
635
mdl->state = MDL_DELETING;
637
con = g_new0(struct mcap_mdl_op_cb, 1);
638
con->mdl = mcap_mdl_ref(mdl);
639
con->cb.notify = delete_cb;
640
con->destroy = destroy;
641
con->user_data = user_data;
643
if (!send_delete_req(mcl, con, mdl->mdlid, err)) {
644
mcap_mdl_unref(con->mdl);
652
gboolean mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb,
654
GDestroyNotify destroy,
657
struct mcap_mdl_op_cb *con;
658
struct mcap_mcl *mcl = mdl->mcl;
661
if (mdl->state != MDL_WAITING) {
662
g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
663
"Mdl in invalid state");
667
cmd = create_req(MCAP_MD_ABORT_MDL_REQ, mdl->mdlid);
668
if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
673
con = g_new0(struct mcap_mdl_op_cb, 1);
674
con->mdl = mcap_mdl_ref(mdl);
675
con->cb.notify = abort_cb;
676
con->destroy = destroy;
677
con->user_data = user_data;
679
mcl->priv_data = con;
680
mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
685
static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
687
struct mcap_mcl *mcl;
689
for (; list; list = list->next) {
692
if (!bacmp(&mcl->addr, addr))
699
int mcap_mdl_get_fd(struct mcap_mdl *mdl)
701
if (!mdl || mdl->state != MDL_CONNECTED)
704
return g_io_channel_unix_get_fd(mdl->dc);
707
uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl)
710
return MCAP_MDLID_RESERVED;
715
static void close_mcl(struct mcap_mcl *mcl, gboolean cache_requested)
717
gboolean save = ((!(mcl->ctrl & MCAP_CTRL_FREE)) && cache_requested);
722
g_io_channel_shutdown(mcl->cc, TRUE, NULL);
723
g_io_channel_unref(mcl->cc);
728
g_source_remove(mcl->wid);
738
free_mcl_priv_data(mcl);
740
g_slist_foreach(mcl->mdls, (GFunc) shutdown_mdl, NULL);
744
mcl->state = MCL_IDLE;
749
g_slist_foreach(mcl->mdls, (GFunc) mcap_mdl_unref, NULL);
750
g_slist_free(mcl->mdls);
754
static void mcap_mcl_shutdown(struct mcap_mcl *mcl)
756
close_mcl(mcl, TRUE);
759
static void mcap_mcl_release(struct mcap_mcl *mcl)
761
close_mcl(mcl, FALSE);
764
static void mcap_cache_mcl(struct mcap_mcl *mcl)
767
struct mcap_mcl *last;
770
if (mcl->ctrl & MCAP_CTRL_CACHED)
773
mcl->mi->mcls = g_slist_remove(mcl->mi->mcls, mcl);
775
if (mcl->ctrl & MCAP_CTRL_NOCACHE) {
776
mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl);
777
mcap_mcl_release(mcl);
784
len = g_slist_length(mcl->mi->cached);
785
if (len == MAX_CACHED) {
786
/* Remove the latest cached mcl */
787
l = g_slist_last(mcl->mi->cached);
789
mcl->mi->cached = g_slist_remove(mcl->mi->cached, last);
790
last->ctrl &= ~MCAP_CTRL_CACHED;
791
if (last->ctrl & MCAP_CTRL_CONN) {
792
/* We have to release this MCL if */
793
/* connection is not successful */
794
last->ctrl |= MCAP_CTRL_FREE;
796
mcap_mcl_release(last);
797
last->mi->mcl_uncached_cb(last, last->mi->user_data);
799
mcap_mcl_unref(last);
802
mcl->mi->cached = g_slist_prepend(mcl->mi->cached, mcl);
803
mcl->ctrl |= MCAP_CTRL_CACHED;
804
mcap_mcl_shutdown(mcl);
807
static void mcap_uncache_mcl(struct mcap_mcl *mcl)
809
if (!(mcl->ctrl & MCAP_CTRL_CACHED))
812
DBG("Got MCL from cache");
814
mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl);
815
mcl->mi->mcls = g_slist_prepend(mcl->mi->mcls, mcl);
816
mcl->ctrl &= ~MCAP_CTRL_CACHED;
817
mcl->ctrl &= ~MCAP_CTRL_FREE;
820
void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache)
825
if (mcl->ctrl & MCAP_CTRL_FREE) {
826
mcap_mcl_release(mcl);
831
mcl->ctrl |= MCAP_CTRL_NOCACHE;
834
g_io_channel_shutdown(mcl->cc, TRUE, NULL);
835
g_io_channel_unref(mcl->cc);
837
mcl->state = MCL_IDLE;
838
} else if ((mcl->ctrl & MCAP_CTRL_CACHED) &&
839
(mcl->ctrl & MCAP_CTRL_NOCACHE)) {
840
mcl->ctrl &= ~MCAP_CTRL_CACHED;
841
mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl);
842
mcap_mcl_release(mcl);
847
struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl)
851
DBG("mcap_mcl_ref(%p): ref=%d", mcl, mcl->ref);
856
void mcap_mcl_unref(struct mcap_mcl *mcl)
860
DBG("mcap_mcl_unref(%p): ref=%d", mcl, mcl->ref);
865
mcap_mcl_release(mcl);
866
mcap_instance_unref(mcl->mi);
871
static gboolean parse_set_opts(struct mcap_mdl_cb *mdl_cb, GError **err,
872
McapMclCb cb1, va_list args)
875
struct mcap_mdl_cb *c;
877
c = g_new0(struct mcap_mdl_cb, 1);
879
while (cb != MCAP_MDL_CB_INVALID) {
881
case MCAP_MDL_CB_CONNECTED:
882
c->mdl_connected = va_arg(args, mcap_mdl_event_cb);
884
case MCAP_MDL_CB_CLOSED:
885
c->mdl_closed = va_arg(args, mcap_mdl_event_cb);
887
case MCAP_MDL_CB_DELETED:
888
c->mdl_deleted = va_arg(args, mcap_mdl_event_cb);
890
case MCAP_MDL_CB_ABORTED:
891
c->mdl_aborted = va_arg(args, mcap_mdl_event_cb);
893
case MCAP_MDL_CB_REMOTE_CONN_REQ:
894
c->mdl_conn_req = va_arg(args,
895
mcap_remote_mdl_conn_req_cb);
897
case MCAP_MDL_CB_REMOTE_RECONN_REQ:
898
c->mdl_reconn_req = va_arg(args,
899
mcap_remote_mdl_reconn_req_cb);
902
g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
903
"Unknown option %d", cb);
907
cb = va_arg(args, int);
910
/* Set new callbacks */
911
if (c->mdl_connected)
912
mdl_cb->mdl_connected = c->mdl_connected;
914
mdl_cb->mdl_closed = c->mdl_closed;
916
mdl_cb->mdl_deleted = c->mdl_deleted;
918
mdl_cb->mdl_aborted = c->mdl_aborted;
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;
929
gboolean mcap_mcl_set_cb(struct mcap_mcl *mcl, gpointer user_data,
930
GError **gerr, McapMclCb cb1, ...)
936
ret = parse_set_opts(mcl->cb, gerr, cb1, args);
942
mcl->cb->user_data = user_data;
946
void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)
948
bacpy(addr, &mcl->addr);
951
static void mcap_del_mdl(gpointer elem, gpointer user_data)
953
struct mcap_mdl *mdl = elem;
954
gboolean notify = *(gboolean *) user_data;
958
mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data);
963
static gboolean check_cmd_req_length(struct mcap_mcl *mcl, void *cmd,
964
uint32_t rlen, uint32_t explen, uint8_t rspcod)
969
if (rlen != explen) {
970
if (rlen >= sizeof(mcap_md_req)) {
972
mdl_id = ntohs(req->mdl);
974
/* We can't get mdlid */
975
mdl_id = MCAP_MDLID_RESERVED;
977
mcap_send_cmd(mcl, rspcod, MCAP_INVALID_PARAM_VALUE, mdl_id,
984
static void process_md_create_mdl_req(struct mcap_mcl *mcl, void *cmd,
987
mcap_md_create_mdl_req *req;
988
struct mcap_mdl *mdl;
994
if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_create_mdl_req),
995
MCAP_MD_CREATE_MDL_RSP))
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,
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,
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,
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 */
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);
1039
if (rsp != MCAP_SUCCESS) {
1040
mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id,
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),
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 */
1057
mdl->mdep_id = mdep_id;
1058
mdl->state = MDL_WAITING;
1060
mcl->state = MCL_PENDING;
1061
mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id,
1065
static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, void *cmd,
1069
struct mcap_mdl *mdl;
1073
if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
1074
MCAP_MD_RECONNECT_MDL_RSP))
1078
mdl_id = ntohs(req->mdl);
1080
mdl = get_mdl(mcl, mdl_id);
1082
mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_INVALID_MDL,
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,
1093
/* Callback to upper layer */
1094
rsp = mcl->cb->mdl_reconn_req(mdl, mcl->cb->user_data);
1095
if (mcl->state == MCL_IDLE)
1098
if (rsp != MCAP_SUCCESS) {
1099
mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, rsp, mdl_id,
1104
if (mdl->state == MDL_CONNECTED)
1107
mdl->state = MDL_WAITING;
1108
mcl->state = MCL_PENDING;
1109
mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id,
1113
static void process_md_abort_mdl_req(struct mcap_mcl *mcl, void *cmd,
1118
struct mcap_mdl *mdl, *abrt;
1121
if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
1122
MCAP_MD_ABORT_MDL_RSP))
1126
mdl_id = ntohs(req->mdl);
1127
mcl->state = MCL_CONNECTED;
1129
for (l = mcl->mdls; l; l = l->next) {
1131
if (mdl_id == mdl->mdlid && mdl->state == MDL_WAITING) {
1133
if (mcl->state != MCL_CONNECTED)
1137
if (mdl->state == MDL_CONNECTED && mcl->state != MCL_ACTIVE)
1138
mcl->state = MCL_ACTIVE;
1140
if (abrt && mcl->state == MCL_ACTIVE)
1145
mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL,
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,
1156
static void process_md_delete_mdl_req(struct mcap_mcl *mcl, void *cmd,
1160
struct mcap_mdl *mdl, *aux;
1165
if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
1166
MCAP_MD_DELETE_MDL_RSP))
1170
mdlid = ntohs(req->mdl);
1171
if (mdlid == MCAP_ALL_MDLIDS) {
1173
g_slist_foreach(mcl->mdls, mcap_del_mdl, ¬ify);
1174
g_slist_free(mcl->mdls);
1176
mcl->state = MCL_CONNECTED;
1177
/* NULL mdl means ALL_MDLS */
1178
mcl->cb->mdl_deleted(NULL, mcl->cb->user_data);
1182
if (mdlid < MCAP_MDLID_INITIAL || mdlid > MCAP_MDLID_FINAL) {
1183
mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL,
1188
for (l = mcl->mdls, mdl = NULL; l; l = l->next) {
1190
if (aux->mdlid == mdlid) {
1196
if (!mdl || mdl->state == MDL_WAITING) {
1197
mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL,
1202
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
1203
update_mcl_state(mcl);
1205
mcap_del_mdl(mdl, ¬ify);
1208
mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid,
1212
static void invalid_req_state(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1216
error("Invalid cmd received (op code = %d) in state %d", cmd[0],
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);
1225
/* Function used to process commands depending of MCL state */
1226
static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1229
case MCAP_MD_CREATE_MDL_REQ:
1230
process_md_create_mdl_req(mcl, cmd, len);
1232
case MCAP_MD_RECONNECT_MDL_REQ:
1233
process_md_reconnect_mdl_req(mcl, cmd, len);
1235
case MCAP_MD_DELETE_MDL_REQ:
1236
process_md_delete_mdl_req(mcl, cmd, len);
1239
invalid_req_state(mcl, cmd, len);
1243
static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1245
if (cmd[0] == MCAP_MD_ABORT_MDL_REQ)
1246
process_md_abort_mdl_req(mcl, cmd, len);
1248
invalid_req_state(mcl, cmd, len);
1251
static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1254
case MCAP_MD_CREATE_MDL_REQ:
1255
process_md_create_mdl_req(mcl, cmd, len);
1257
case MCAP_MD_RECONNECT_MDL_REQ:
1258
process_md_reconnect_mdl_req(mcl, cmd, len);
1260
case MCAP_MD_DELETE_MDL_REQ:
1261
process_md_delete_mdl_req(mcl, cmd, len);
1264
invalid_req_state(mcl, cmd, len);
1268
/* Function used to process replies */
1269
static gboolean check_err_rsp(struct mcap_mcl *mcl, mcap_rsp *rsp,
1270
uint32_t rlen, uint32_t len, GError **gerr)
1272
mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
1273
gint err = MCAP_ERROR_FAILED;
1274
gboolean close = FALSE;
1277
if (rsp->op == MCAP_ERROR_RSP) {
1278
msg = "MCAP_ERROR_RSP received";
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";
1291
msg = "Protocol error";
1296
if (rsp->mdl != cmdlast->mdl) {
1297
msg = "MDLID received doesn't match with MDLID sent";
1302
if (rsp->rc == MCAP_REQUEST_NOT_SUPPORTED) {
1303
msg = "Remote does not support opcodes";
1304
mcl->ctrl &= ~MCAP_CTRL_STD_OP;
1308
if (rsp->rc == MCAP_UNSPECIFIED_ERROR) {
1309
msg = "Unspecified error";
1314
if (rsp->rc != MCAP_SUCCESS) {
1315
msg = error2str(rsp->rc);
1323
g_set_error(gerr, MCAP_ERROR, err, "%s", msg);
1327
static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl,
1328
mcap_rsp *rsp, uint32_t len)
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;
1337
GError *gerr = NULL;
1339
close = check_err_rsp(mcl, rsp, len, sizeof(mcap_rsp) + 1, &gerr);
1342
mcl->req = MCL_AVAILABLE;
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");
1355
connect_cb(mdl, rsp->data[0], gerr, user_data);
1359
connect_cb(NULL, 0, gerr, user_data);
1360
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
1361
mcap_mdl_unref(mdl);
1363
update_mcl_state(mcl);
1367
static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
1368
mcap_rsp *rsp, uint32_t len)
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;
1377
close = check_err_rsp(mcl, rsp, len, sizeof(mcap_rsp), &gerr);
1381
mcl->req = MCL_AVAILABLE;
1383
reconn_cb(mdl, gerr, user_data);
1389
update_mcl_state(mcl);
1391
if (rsp->rc != MCAP_INVALID_MDL)
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);
1402
static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
1403
mcap_rsp *rsp, uint32_t len)
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;
1412
close = check_err_rsp(mcl, rsp, len, sizeof(mcap_rsp), &gerr);
1416
mcl->req = MCL_AVAILABLE;
1418
abrt_cb(gerr, user_data);
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);
1430
update_mcl_state(mcl);
1435
static void restore_mdl(gpointer elem, gpointer data)
1437
struct mcap_mdl *mdl = elem;
1439
if (mdl->state == MDL_DELETING) {
1441
mdl->state = MDL_CONNECTED;
1443
mdl->state = MDL_CLOSED;
1444
} else if (mdl->state == MDL_CLOSED)
1445
mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data);
1448
static void check_mdl_del_err(struct mcap_mdl *mdl, mcap_rsp *rsp)
1450
if (rsp->rc != MCAP_ERROR_INVALID_MDL) {
1451
restore_mdl(mdl, NULL);
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);
1460
static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, mcap_rsp *rsp,
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;
1471
gboolean notify = FALSE;
1473
close = check_err_rsp(mcl, rsp, len, sizeof(mcap_rsp), &gerr);
1477
mcl->req = MCL_AVAILABLE;
1481
check_mdl_del_err(mdl, rsp);
1483
g_slist_foreach(mcl->mdls, restore_mdl, NULL);
1484
deleted_cb(gerr, user_data);
1489
if (mdlid == MCAP_ALL_MDLIDS) {
1490
g_slist_foreach(mcl->mdls, mcap_del_mdl, ¬ify);
1491
g_slist_free(mcl->mdls);
1493
mcl->state = MCL_CONNECTED;
1495
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
1496
update_mcl_state(mcl);
1497
mcap_del_mdl(mdl, ¬ify);
1500
deleted_cb(gerr, user_data);
1505
static void post_process_rsp(struct mcap_mcl *mcl, struct mcap_mdl_op_cb *op)
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);
1512
/* This is not a queued request. It's safe */
1513
/* delete the mcl private data here. */
1514
free_mcl_priv_data(mcl);
1518
static void proc_response(struct mcap_mcl *mcl, void *buf, uint32_t len)
1520
struct mcap_mdl_op_cb *op = mcl->priv_data;
1521
mcap_rsp *rsp = buf;
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);
1531
case MCAP_MD_RECONNECT_MDL_RSP:
1532
close = process_md_reconnect_mdl_rsp(mcl, rsp, len);
1533
post_process_rsp(mcl, op);
1535
case MCAP_MD_ABORT_MDL_RSP:
1536
close = process_md_abort_mdl_rsp(mcl, rsp, len);
1537
post_process_rsp(mcl, op);
1539
case MCAP_MD_DELETE_MDL_RSP:
1540
close = process_md_delete_mdl_rsp(mcl, rsp, len);
1541
post_process_rsp(mcl, op);
1544
DBG("Unknown cmd response received (op code = %d)", rsp->op);
1550
mcl->mi->mcl_disconnected_cb(mcl, mcl->mi->user_data);
1551
mcap_cache_mcl(mcl);
1555
static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1557
GError *gerr = NULL;
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);
1568
if (cmd[0] >= MCAP_MD_SYNC_CAP_REQ &&
1569
cmd[0] <= MCAP_MD_SYNC_INFO_IND) {
1570
proc_sync_cmd(mcl, cmd, len);
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");
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)
1586
/* Initiator will ignore our last request */
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);
1595
proc_response(mcl, cmd, len);
1596
} else if (cmd[0] & 0x01)
1597
proc_req[mcl->state](mcl, cmd, len);
1600
static gboolean mdl_event_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
1603
struct mcap_mdl *mdl = data;
1606
DBG("Close MDL %d", mdl->mdlid);
1608
notify = (mdl->state == MDL_CONNECTED);
1611
update_mcl_state(mdl->mcl);
1614
/*Callback to upper layer */
1615
mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data);
1621
static void mcap_connect_mdl_cb(GIOChannel *chan, GError *conn_err,
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;
1629
DBG("mdl connect callback");
1632
DBG("ERROR: mdl connect callback");
1633
mdl->state = MDL_CLOSED;
1634
g_io_channel_unref(mdl->dc);
1636
cb(mdl, conn_err, user_data);
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,
1645
(GDestroyNotify) mcap_mdl_unref);
1647
cb(mdl, conn_err, user_data);
1650
gboolean mcap_connect_mdl(struct mcap_mdl *mdl, uint8_t mode,
1652
mcap_mdl_operation_cb connect_cb,
1654
GDestroyNotify destroy,
1657
struct mcap_mdl_op_cb *con;
1659
if (mdl->state != MDL_WAITING) {
1660
g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL,
1661
"%s", error2str(MCAP_INVALID_MDL));
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");
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;
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,
1687
DBG("MDL Connection error");
1688
mdl->state = MDL_CLOSED;
1689
mcap_mdl_unref(con->mdl);
1697
static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
1700
GError *gerr = NULL;
1701
struct mcap_mcl *mcl = data;
1703
uint8_t buf[MCAP_CC_MTU];
1705
if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
1708
sk = g_io_channel_unix_get_fd(chan);
1709
len = read(sk, buf, sizeof(buf));
1713
proc_cmd(mcl, buf, (uint32_t) len);
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,
1722
mcap_notify_error(mcl, gerr);
1725
mcl->mi->mcl_disconnected_cb(mcl, mcl->mi->user_data);
1727
mcap_cache_mcl(mcl);
1731
static void mcap_connect_mcl_cb(GIOChannel *chan, GError *conn_err,
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;
1741
mcl->ctrl &= ~MCAP_CTRL_CONN;
1744
if (mcl->ctrl & MCAP_CTRL_FREE) {
1745
mcap_mcl_release(mcl);
1746
mcl->mi->mcl_uncached_cb(mcl, mcl->mi->user_data);
1748
connect_cb(NULL, conn_err, data);
1752
ba2str(&mcl->addr, dstaddr);
1754
aux = find_mcl(mcl->mi->mcls, &mcl->addr);
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);
1765
mcl->state = MCL_CONNECTED;
1766
mcl->role = MCL_INITIATOR;
1767
mcl->req = MCL_AVAILABLE;
1768
mcl->ctrl |= MCAP_CTRL_STD_OP;
1770
mcap_sync_init(mcl);
1772
if (mcl->ctrl & MCAP_CTRL_CACHED)
1773
mcap_uncache_mcl(mcl);
1775
mcl->ctrl &= ~MCAP_CTRL_FREE;
1776
mcl->mi->mcls = g_slist_prepend(mcl->mi->mcls,
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,
1784
(GDestroyNotify) mcap_mcl_unref);
1785
connect_cb(mcl, gerr, data);
1788
static void set_mdl_properties(GIOChannel *chan, struct mcap_mdl *mdl)
1790
struct mcap_mcl *mcl = mdl->mcl;
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,
1798
(GDestroyNotify) mcap_mdl_unref);
1800
mcl->state = MCL_ACTIVE;
1801
mcl->cb->mdl_connected(mdl, mcl->cb->user_data);
1804
static void mcl_io_destroy(gpointer data)
1806
struct connect_mcl *con = data;
1808
mcap_mcl_unref(con->mcl);
1810
con->destroy(con->user_data);
1814
gboolean mcap_create_mcl(struct mcap_instance *mi,
1815
const bdaddr_t *addr,
1817
mcap_mcl_connect_cb connect_cb,
1819
GDestroyNotify destroy,
1822
struct mcap_mcl *mcl;
1823
struct connect_mcl *con;
1825
mcl = find_mcl(mi->mcls, addr);
1827
g_set_error(err, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS,
1828
"MCL is already connected.");
1832
mcl = find_mcl(mi->cached, addr);
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;
1842
mcl->ctrl |= MCAP_CTRL_CONN;
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;
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,
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);
1865
mcap_mcl_unref(con->mcl);
1873
static void connect_dc_event_cb(GIOChannel *chan, GError *gerr,
1876
struct mcap_instance *mi = user_data;
1877
struct mcap_mcl *mcl;
1878
struct mcap_mdl *mdl;
1886
bt_io_get(chan, BT_IO_L2CAP, &err,
1887
BT_IO_OPT_DEST_BDADDR, &dst,
1890
error("%s", err->message);
1895
mcl = find_mcl(mi->mcls, &dst);
1896
if (!mcl || mcl->state != MCL_PENDING)
1899
for (l = mcl->mdls; l; l = l->next) {
1901
if (mdl->state == MDL_WAITING) {
1902
set_mdl_properties(chan, mdl);
1908
g_io_channel_shutdown(chan, TRUE, NULL);
1911
static void set_mcl_conf(GIOChannel *chan, struct mcap_mcl *mcl)
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;
1921
mcap_sync_init(mcl);
1923
reconn = (mcl->ctrl & MCAP_CTRL_CACHED);
1925
mcap_uncache_mcl(mcl);
1927
mcl->mi->mcls = g_slist_prepend(mcl->mi->mcls,
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,
1934
(GDestroyNotify) mcap_mcl_unref);
1936
/* Callback to report new MCL */
1938
mcl->mi->mcl_reconnected_cb(mcl, mcl->mi->user_data);
1940
mcl->mi->mcl_connected_cb(mcl, mcl->mi->user_data);
1943
static void connect_mcl_event_cb(GIOChannel *chan, GError *gerr,
1946
struct mcap_instance *mi = user_data;
1947
struct mcap_mcl *mcl;
1949
char address[18], srcstr[18];
1955
bt_io_get(chan, BT_IO_L2CAP, &err,
1956
BT_IO_OPT_DEST_BDADDR, &dst,
1957
BT_IO_OPT_DEST, address,
1960
error("%s", err->message);
1965
ba2str(&mi->src, srcstr);
1966
mcl = find_mcl(mi->mcls, &dst);
1968
error("Control channel already created with %s on adapter %s",
1973
mcl = find_mcl(mi->cached, &dst);
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;
1982
set_mcl_conf(chan, mcl);
1986
g_io_channel_shutdown(chan, TRUE, NULL);
1989
struct mcap_instance *mcap_create_instance(bdaddr_t *src,
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,
2001
struct mcap_instance *mi;
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",
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");
2017
mi = g_new0(struct mcap_instance, 1);
2019
bacpy(&mi->src, src);
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;
2030
/* Listen incoming connections in control channel */
2031
mi->ccio = bt_io_listen(BT_IO_L2CAP, connect_mcl_event_cb, NULL, mi,
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,
2040
error("%s", (*gerr)->message);
2045
/* Listen incoming connections in data channels */
2046
mi->dcio = bt_io_listen(BT_IO_L2CAP, connect_dc_event_cb, NULL, mi,
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,
2054
g_io_channel_shutdown(mi->ccio, TRUE, NULL);
2055
g_io_channel_unref(mi->ccio);
2057
error("%s", (*gerr)->message);
2062
/* Initialize random seed to generate mdlids for this instance */
2065
return mcap_instance_ref(mi);
2068
void mcap_release_instance(struct mcap_instance *mi)
2076
g_io_channel_shutdown(mi->ccio, TRUE, NULL);
2077
g_io_channel_unref(mi->ccio);
2082
g_io_channel_shutdown(mi->dcio, TRUE, NULL);
2083
g_io_channel_unref(mi->dcio);
2087
for (l = mi->mcls; l; l = l->next) {
2088
mcap_mcl_release(l->data);
2089
mcap_mcl_unref(l->data);
2092
g_slist_free(mi->mcls);
2095
for (l = mi->cached; l; l = l->next) {
2096
mcap_mcl_release(l->data);
2097
mcap_mcl_unref(l->data);
2100
g_slist_free(mi->cached);
2104
struct mcap_instance *mcap_instance_ref(struct mcap_instance *mi)
2108
DBG("mcap_instance_ref(%p): ref=%d", mi, mi->ref);
2113
void mcap_instance_unref(struct mcap_instance *mi)
2117
DBG("mcap_instance_unref(%p): ref=%d", mi, mi->ref);
2122
mcap_release_instance(mi);
2126
uint16_t mcap_get_ctrl_psm(struct mcap_instance *mi, GError **err)
2130
if (!(mi && mi->ccio)) {
2131
g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
2132
"Invalid MCAP instance");
2136
if (!bt_io_get(mi->ccio, BT_IO_L2CAP, err,
2137
BT_IO_OPT_PSM, &lpsm,
2144
uint16_t mcap_get_data_psm(struct mcap_instance *mi, GError **err)
2148
if (!(mi && mi->dcio)) {
2149
g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
2150
"Invalid MCAP instance");
2154
if (!bt_io_get(mi->dcio, BT_IO_L2CAP, err,
2155
BT_IO_OPT_PSM, &lpsm,
2162
gboolean mcap_set_data_chan_mode(struct mcap_instance *mi, uint8_t mode,
2165
if (!(mi && mi->dcio)) {
2166
g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
2167
"Invalid MCAP instance");
2171
return bt_io_set(mi->dcio, BT_IO_L2CAP, err, BT_IO_OPT_MODE, mode,
2175
struct mcap_mdl *mcap_mdl_ref(struct mcap_mdl *mdl)
2179
DBG("mcap_mdl_ref(%p): ref=%d", mdl, mdl->ref);
2184
void mcap_mdl_unref(struct mcap_mdl *mdl)
2188
DBG("mcap_mdl_unref(%p): ref=%d", mdl, mdl->ref);