3
* MCAP for BlueZ - Bluetooth protocol stack for Linux
5
* Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
8
* Santiago Carot-Nemesio <sancane at gmail.com>
9
* Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
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.
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.
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
30
#include <netinet/in.h>
36
#include <bluetooth/bluetooth.h>
37
#include <bluetooth/l2cap.h>
40
#include "mcap_internal.h"
42
#define RESPONSE_TIMER 6 /* seconds */
43
#define MAX_CACHED 10 /* 10 devices */
45
#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
47
#define RELEASE_TIMER(__mcl) do { \
49
g_source_remove(__mcl->tid); \
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 */
62
mcap_mdl_operation_cb op;
63
mcap_mdl_operation_conf_cb op_conf;
64
mcap_mdl_notify_cb notify;
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 */
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);
79
static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = {
85
static void mcap_cache_mcl(struct mcap_mcl *mcl);
87
static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
89
DBG("MCAP Unmanaged mdl connection");
92
static void default_mdl_closed_cb(struct mcap_mdl *mdl, gpointer data)
94
DBG("MCAP Unmanaged mdl closed");
97
static void default_mdl_deleted_cb(struct mcap_mdl *mdl, gpointer data)
99
DBG("MCAP Unmanaged mdl deleted");
102
static void default_mdl_aborted_cb(struct mcap_mdl *mdl, gpointer data)
104
DBG("MCAP Unmanaged mdl aborted");
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)
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;
116
static uint8_t default_mdl_reconn_req_cb(struct mcap_mdl *mdl,
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;
124
static void set_default_cb(struct mcap_mcl *mcl)
127
mcl->cb = g_new0(struct mcap_mdl_cb, 1);
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;
137
static char *error2str(uint8_t rc)
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";
150
case MCAP_INVALID_MDL:
151
return "Invalid MDL";
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";
165
return "Unknown Response Code";
169
static gboolean mcap_send_std_opcode(struct mcap_mcl *mcl, void *cmd,
170
uint32_t size, GError **err)
172
if (mcl->state == MCL_IDLE) {
173
g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
174
"MCL is not connected");
178
if (mcl->req != MCL_AVAILABLE) {
179
g_set_error(err, MCAP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE,
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");
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");
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");
203
mcl->req = MCL_WAITING_RSP;
208
static void update_mcl_state(struct mcap_mcl *mcl)
211
struct mcap_mdl *mdl;
213
if (mcl->state == MCL_PENDING)
216
for (l = mcl->mdls; l; l = l->next) {
219
if (mdl->state == MDL_CONNECTED) {
220
mcl->state = MCL_ACTIVE;
225
mcl->state = MCL_CONNECTED;
228
static void shutdown_mdl(struct mcap_mdl *mdl)
230
mdl->state = MDL_CLOSED;
233
g_source_remove(mdl->wid);
238
g_io_channel_shutdown(mdl->dc, TRUE, NULL);
239
g_io_channel_unref(mdl->dc);
244
static void free_mdl(struct mcap_mdl *mdl)
249
mcap_mcl_unref(mdl->mcl);
253
static gint cmp_mdl_state(gconstpointer a, gconstpointer b)
255
const struct mcap_mdl *mdl = a;
256
const MDLState *st = b;
258
if (mdl->state == *st)
260
else if (mdl->state < *st)
266
static void free_mcap_mdl_op(struct mcap_mdl_op_cb *op)
269
op->destroy(op->user_data);
272
mcap_mdl_unref(op->mdl);
277
static void free_mcl_priv_data(struct mcap_mcl *mcl)
279
free_mcap_mdl_op(mcl->priv_data);
280
mcl->priv_data = NULL;
283
static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
285
struct mcap_mdl_op_cb *con = mcl->priv_data;
286
struct mcap_mdl *mdl;
290
if (!con || !mcl->lcmd)
293
switch (mcl->lcmd[0]) {
294
case MCAP_MD_CREATE_MDL_REQ:
296
l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
298
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
300
update_mcl_state(mcl);
301
con->cb.op_conf(NULL, 0, err, con->user_data);
303
case MCAP_MD_ABORT_MDL_REQ:
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);
310
case MCAP_MD_DELETE_MDL_REQ:
311
for (l = mcl->mdls; l; l = l->next) {
313
if (mdl->state == MDL_DELETING)
314
mdl->state = (mdl->dc) ? MDL_CONNECTED :
317
update_mcl_state(mcl);
318
con->cb.notify(err, con->user_data);
320
case MCAP_MD_RECONNECT_MDL_REQ:
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);
329
free_mcl_priv_data(mcl);
334
int mcap_send_data(int sock, const void *buf, uint32_t size)
336
const uint8_t *buf_b = buf;
339
while (sent < size) {
340
int n = write(sock, buf_b + sent, size - sent);
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)
358
sock = g_io_channel_unix_get_fd(mcl->cc);
360
cmd = g_malloc(sizeof(mcap_rsp) + len);
363
cmd->mdl = htons(mdl);
366
memcpy(cmd->data, data, len);
368
sent = mcap_send_data(sock, cmd, sizeof(mcap_rsp) + len);
374
static struct mcap_mdl *get_mdl(struct mcap_mcl *mcl, uint16_t mdlid)
377
struct mcap_mdl *mdl;
379
for (l = mcl->mdls; l; l = l->next) {
381
if (mdlid == mdl->mdlid)
388
static uint16_t generate_mdlid(struct mcap_mcl *mcl)
390
uint16_t mdlid = mcl->next_mdl;
391
struct mcap_mdl *mdl;
394
mdl = get_mdl(mcl, mdlid);
396
mcl->next_mdl = (mdlid % MCAP_MDLID_FINAL) + 1;
399
mdlid = (mdlid % MCAP_MDLID_FINAL) + 1;
400
} while (mdlid != mcl->next_mdl);
402
/* No more mdlids availables */
406
static mcap_md_req *create_req(uint8_t op, uint16_t mdl_id)
408
mcap_md_req *req_cmd;
410
req_cmd = g_new0(mcap_md_req, 1);
413
req_cmd->mdl = htons(mdl_id);
418
static mcap_md_create_mdl_req *create_mdl_req(uint16_t mdl_id, uint8_t mdep,
421
mcap_md_create_mdl_req *req_mdl;
423
req_mdl = g_new0(mcap_md_create_mdl_req, 1);
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;
433
static gint compare_mdl(gconstpointer a, gconstpointer b)
435
const struct mcap_mdl *mdla = a;
436
const struct mcap_mdl *mdlb = b;
438
if (mdla->mdlid == mdlb->mdlid)
440
else if (mdla->mdlid < mdlb->mdlid)
446
static gboolean wait_response_timer(gpointer data)
448
struct mcap_mcl *mcl = data;
454
g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
455
"Timeout waiting response");
457
mcap_notify_error(mcl, gerr);
460
mcl->mi->mcl_disconnected_cb(mcl, mcl->mi->user_data);
466
gboolean mcap_create_mdl(struct mcap_mcl *mcl,
469
mcap_mdl_operation_conf_cb connect_cb,
471
GDestroyNotify destroy,
474
struct mcap_mdl *mdl;
475
struct mcap_mdl_op_cb *con;
476
mcap_md_create_mdl_req *cmd;
479
id = generate_mdlid(mcl);
481
g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
482
"Not more mdlids available");
486
mdl = g_new0(struct mcap_mdl, 1);
487
mdl->mcl = mcap_mcl_ref(mcl);
489
mdl->mdep_id = mdepid;
490
mdl->state = MDL_WAITING;
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;
498
cmd = create_mdl_req(id, mdepid, conf);
499
if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_create_mdl_req),
501
mcap_mdl_unref(con->mdl);
507
mcl->state = MCL_ACTIVE;
508
mcl->priv_data = con;
510
mcl->mdls = g_slist_insert_sorted(mcl->mdls, mcap_mdl_ref(mdl),
512
mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
517
gboolean mcap_reconnect_mdl(struct mcap_mdl *mdl,
518
mcap_mdl_operation_cb reconnect_cb,
520
GDestroyNotify destroy,
523
struct mcap_mdl_op_cb *con;
524
struct mcap_mcl *mcl = mdl->mcl;
527
if (mdl->state != MDL_CLOSED) {
528
g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
529
"MDL is not closed");
533
cmd = create_req(MCAP_MD_RECONNECT_MDL_REQ, mdl->mdlid);
534
if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
539
mdl->state = MDL_WAITING;
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;
547
mcl->state = MCL_ACTIVE;
548
mcl->priv_data = con;
550
mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
555
static gboolean send_delete_req(struct mcap_mcl *mcl,
556
struct mcap_mdl_op_cb *con,
562
cmd = create_req(MCAP_MD_DELETE_MDL_REQ, mdlid);
563
if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
568
mcl->priv_data = con;
570
mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
575
gboolean mcap_delete_all_mdls(struct mcap_mcl *mcl,
576
mcap_mdl_notify_cb delete_cb,
578
GDestroyNotify destroy,
582
struct mcap_mdl *mdl;
583
struct mcap_mdl_op_cb *con;
585
DBG("MCL in state: %d", mcl->state);
587
g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
588
"There are not MDLs created");
592
for (l = mcl->mdls; l; l = l->next) {
594
if (mdl->state != MDL_WAITING)
595
mdl->state = MDL_DELETING;
598
con = g_new0(struct mcap_mdl_op_cb, 1);
600
con->cb.notify = delete_cb;
601
con->destroy = destroy;
602
con->user_data = user_data;
605
if (!send_delete_req(mcl, con, MCAP_ALL_MDLIDS, err)) {
613
gboolean mcap_delete_mdl(struct mcap_mdl *mdl, mcap_mdl_notify_cb delete_cb,
615
GDestroyNotify destroy,
618
struct mcap_mcl *mcl= mdl->mcl;
619
struct mcap_mdl_op_cb *con;
622
l = g_slist_find(mcl->mdls, mdl);
625
g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL,
626
"%s" , error2str(MCAP_INVALID_MDEP));
630
if (mdl->state == MDL_WAITING) {
631
g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
632
"Mdl is not created");
636
mdl->state = MDL_DELETING;
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;
644
if (!send_delete_req(mcl, con, mdl->mdlid, err)) {
645
mcap_mdl_unref(con->mdl);
653
gboolean mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb,
655
GDestroyNotify destroy,
658
struct mcap_mdl_op_cb *con;
659
struct mcap_mcl *mcl = mdl->mcl;
662
if (mdl->state != MDL_WAITING) {
663
g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
664
"Mdl in invalid state");
668
cmd = create_req(MCAP_MD_ABORT_MDL_REQ, mdl->mdlid);
669
if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
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;
680
mcl->priv_data = con;
681
mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
686
static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
689
struct mcap_mcl *mcl;
691
for (l = list; l; l = l->next) {
694
if (!bacmp(&mcl->addr, addr))
701
int mcap_mdl_get_fd(struct mcap_mdl *mdl)
703
if (!mdl || mdl->state != MDL_CONNECTED)
706
return g_io_channel_unix_get_fd(mdl->dc);
709
uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl)
712
return MCAP_MDLID_RESERVED;
717
static void close_mcl(struct mcap_mcl *mcl, gboolean cache_requested)
719
gboolean save = ((!(mcl->ctrl & MCAP_CTRL_FREE)) && cache_requested);
724
g_io_channel_shutdown(mcl->cc, TRUE, NULL);
725
g_io_channel_unref(mcl->cc);
730
g_source_remove(mcl->wid);
740
free_mcl_priv_data(mcl);
742
g_slist_foreach(mcl->mdls, (GFunc) shutdown_mdl, NULL);
746
mcl->state = MCL_IDLE;
751
g_slist_foreach(mcl->mdls, (GFunc) mcap_mdl_unref, NULL);
752
g_slist_free(mcl->mdls);
756
static void mcap_mcl_shutdown(struct mcap_mcl *mcl)
758
close_mcl(mcl, TRUE);
761
static void mcap_mcl_release(struct mcap_mcl *mcl)
763
close_mcl(mcl, FALSE);
766
static void mcap_cache_mcl(struct mcap_mcl *mcl)
769
struct mcap_mcl *last;
772
if (mcl->ctrl & MCAP_CTRL_CACHED)
775
mcl->mi->mcls = g_slist_remove(mcl->mi->mcls, mcl);
777
if (mcl->ctrl & MCAP_CTRL_NOCACHE) {
778
mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl);
779
mcap_mcl_release(mcl);
786
len = g_slist_length(mcl->mi->cached);
787
if (len == MAX_CACHED) {
788
/* Remove the latest cached mcl */
789
l = g_slist_last(mcl->mi->cached);
791
mcl->mi->cached = g_slist_remove(mcl->mi->cached, last);
792
last->ctrl &= ~MCAP_CTRL_CACHED;
793
if (last->ctrl & MCAP_CTRL_CONN) {
794
/* We have to release this MCL if */
795
/* connection is not succesful */
796
last->ctrl |= MCAP_CTRL_FREE;
798
mcap_mcl_release(last);
799
last->mi->mcl_uncached_cb(last, last->mi->user_data);
801
mcap_mcl_unref(last);
804
mcl->mi->cached = g_slist_prepend(mcl->mi->cached, mcl);
805
mcl->ctrl |= MCAP_CTRL_CACHED;
806
mcap_mcl_shutdown(mcl);
809
static void mcap_uncache_mcl(struct mcap_mcl *mcl)
811
if (!(mcl->ctrl & MCAP_CTRL_CACHED))
814
DBG("Got MCL from cache");
816
mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl);
817
mcl->mi->mcls = g_slist_prepend(mcl->mi->mcls, mcl);
818
mcl->ctrl &= ~MCAP_CTRL_CACHED;
819
mcl->ctrl &= ~MCAP_CTRL_FREE;
822
void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache)
827
if (mcl->ctrl & MCAP_CTRL_FREE) {
828
mcap_mcl_release(mcl);
833
mcl->ctrl |= MCAP_CTRL_NOCACHE;
836
g_io_channel_shutdown(mcl->cc, TRUE, NULL);
837
g_io_channel_unref(mcl->cc);
839
mcl->state = MCL_IDLE;
840
} else if ((mcl->ctrl & MCAP_CTRL_CACHED) &&
841
(mcl->ctrl & MCAP_CTRL_NOCACHE)) {
842
mcl->ctrl &= ~MCAP_CTRL_CACHED;
843
mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl);
844
mcap_mcl_release(mcl);
849
struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl)
853
DBG("mcap_mcl_ref(%p): ref=%d", mcl, mcl->ref);
858
void mcap_mcl_unref(struct mcap_mcl *mcl)
862
DBG("mcap_mcl_unref(%p): ref=%d", mcl, mcl->ref);
867
mcap_mcl_release(mcl);
868
mcap_instance_unref(mcl->mi);
873
static gboolean parse_set_opts(struct mcap_mdl_cb *mdl_cb, GError **err,
874
McapMclCb cb1, va_list args)
877
struct mcap_mdl_cb *c;
879
c = g_new0(struct mcap_mdl_cb, 1);
881
while (cb != MCAP_MDL_CB_INVALID) {
883
case MCAP_MDL_CB_CONNECTED:
884
c->mdl_connected = va_arg(args, mcap_mdl_event_cb);
886
case MCAP_MDL_CB_CLOSED:
887
c->mdl_closed = va_arg(args, mcap_mdl_event_cb);
889
case MCAP_MDL_CB_DELETED:
890
c->mdl_deleted = va_arg(args, mcap_mdl_event_cb);
892
case MCAP_MDL_CB_ABORTED:
893
c->mdl_aborted = va_arg(args, mcap_mdl_event_cb);
895
case MCAP_MDL_CB_REMOTE_CONN_REQ:
896
c->mdl_conn_req = va_arg(args,
897
mcap_remote_mdl_conn_req_cb);
899
case MCAP_MDL_CB_REMOTE_RECONN_REQ:
900
c->mdl_reconn_req = va_arg(args,
901
mcap_remote_mdl_reconn_req_cb);
904
g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
905
"Unknown option %d", cb);
908
cb = va_arg(args, int);
911
/* Set new callbacks */
912
if (c->mdl_connected)
913
mdl_cb->mdl_connected = c->mdl_connected;
915
mdl_cb->mdl_closed = c->mdl_closed;
917
mdl_cb->mdl_deleted = c->mdl_deleted;
919
mdl_cb->mdl_aborted = c->mdl_aborted;
921
mdl_cb->mdl_conn_req = c->mdl_conn_req;
922
if (c->mdl_reconn_req)
923
mdl_cb->mdl_reconn_req = c->mdl_reconn_req;
930
gboolean mcap_mcl_set_cb(struct mcap_mcl *mcl, gpointer user_data,
931
GError **gerr, McapMclCb cb1, ...)
937
ret = parse_set_opts(mcl->cb, gerr, cb1, args);
943
mcl->cb->user_data = user_data;
947
void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)
949
bacpy(addr, &mcl->addr);
952
static void mcap_del_mdl(gpointer elem, gpointer user_data)
954
struct mcap_mdl *mdl = elem;
955
gboolean notify = *(gboolean *) user_data;
959
mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data);
964
static gboolean check_cmd_req_length(struct mcap_mcl *mcl, void *cmd,
965
uint32_t rlen, uint32_t explen, uint8_t rspcod)
970
if (rlen != explen) {
971
if (rlen >= sizeof(mcap_md_req)) {
973
mdl_id = ntohs(req->mdl);
975
/* We can't get mdlid */
976
mdl_id = MCAP_MDLID_RESERVED;
978
mcap_send_cmd(mcl, rspcod, MCAP_INVALID_PARAM_VALUE, mdl_id,
985
static void process_md_create_mdl_req(struct mcap_mcl *mcl, void *cmd,
988
mcap_md_create_mdl_req *req;
989
struct mcap_mdl *mdl;
995
if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_create_mdl_req),
996
MCAP_MD_CREATE_MDL_RSP))
1000
mdl_id = ntohs(req->mdl);
1001
if (mdl_id < MCAP_MDLID_INITIAL || mdl_id > MCAP_MDLID_FINAL) {
1002
mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL,
1007
mdep_id = req->mdep;
1008
if (mdep_id > MCAP_MDEPID_FINAL) {
1009
mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDEP,
1014
mdl = get_mdl(mcl, mdl_id);
1015
if (mdl && (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING )) {
1016
/* Creation request arrives for a MDL that is being managed
1017
* at current moment */
1018
mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY,
1023
cfga = conf = req->conf;
1024
/* Callback to upper layer */
1025
rsp = mcl->cb->mdl_conn_req(mcl, mdep_id, mdl_id, &conf,
1026
mcl->cb->user_data);
1027
if (mcl->state == MCL_IDLE) {
1028
/* MCL has been closed int the callback */
1032
if (cfga != 0 && cfga != conf) {
1033
/* Remote device set default configuration but upper profile */
1034
/* has changed it. Protocol Error: force closing the MCL by */
1035
/* remote device using UNSPECIFIED_ERROR response */
1036
mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP,
1037
MCAP_UNSPECIFIED_ERROR, mdl_id, NULL, 0);
1040
if (rsp != MCAP_SUCCESS) {
1041
mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id,
1047
mdl = g_new0(struct mcap_mdl, 1);
1048
mdl->mcl = mcap_mcl_ref(mcl);
1049
mdl->mdlid = mdl_id;
1050
mcl->mdls = g_slist_insert_sorted(mcl->mdls, mcap_mdl_ref(mdl),
1052
} else if (mdl->state == MDL_CONNECTED) {
1053
/* MCAP specification says that we should close the MCL if
1054
* it is open when we receive a MD_CREATE_MDL_REQ */
1058
mdl->mdep_id = mdep_id;
1059
mdl->state = MDL_WAITING;
1061
mcl->state = MCL_PENDING;
1062
mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id,
1066
static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, void *cmd,
1070
struct mcap_mdl *mdl;
1074
if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
1075
MCAP_MD_RECONNECT_MDL_RSP))
1079
mdl_id = ntohs(req->mdl);
1081
mdl = get_mdl(mcl, mdl_id);
1083
mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_INVALID_MDL,
1086
} else if (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING ) {
1087
/* Creation request arrives for a MDL that is being managed
1088
* at current moment */
1089
mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_MDL_BUSY,
1094
/* Callback to upper layer */
1095
rsp = mcl->cb->mdl_reconn_req(mdl, mcl->cb->user_data);
1096
if (mcl->state == MCL_IDLE)
1099
if (rsp != MCAP_SUCCESS) {
1100
mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, rsp, mdl_id,
1105
if (mdl->state == MDL_CONNECTED)
1108
mdl->state = MDL_WAITING;
1109
mcl->state = MCL_PENDING;
1110
mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id,
1114
static void process_md_abort_mdl_req(struct mcap_mcl *mcl, void *cmd,
1119
struct mcap_mdl *mdl, *abrt;
1122
if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
1123
MCAP_MD_ABORT_MDL_RSP))
1127
mdl_id = ntohs(req->mdl);
1128
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);