~ubuntu-branches/ubuntu/wily/bluez/wily

« back to all changes in this revision

Viewing changes to health/mcap.c

ImportĀ upstreamĀ versionĀ 4.81

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
87
static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
 
88
{
 
89
        DBG("MCAP Unmanaged mdl connection");
 
90
}
 
91
 
 
92
static void default_mdl_closed_cb(struct mcap_mdl *mdl, gpointer data)
 
93
{
 
94
        DBG("MCAP Unmanaged mdl closed");
 
95
}
 
96
 
 
97
static void default_mdl_deleted_cb(struct mcap_mdl *mdl, gpointer data)
 
98
{
 
99
        DBG("MCAP Unmanaged mdl deleted");
 
100
}
 
101
 
 
102
static void default_mdl_aborted_cb(struct mcap_mdl *mdl, gpointer data)
 
103
{
 
104
        DBG("MCAP Unmanaged mdl aborted");
 
105
}
 
106
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
686
static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 
687
{
 
688
        GSList *l;
 
689
        struct mcap_mcl *mcl;
 
690
 
 
691
        for (l = list; l; l = l->next) {
 
692
                mcl = l->data;
 
693
 
 
694
                if (!bacmp(&mcl->addr, addr))
 
695
                        return mcl;
 
696
        }
 
697
 
 
698
        return NULL;
 
699
}
 
700
 
 
701
int mcap_mdl_get_fd(struct mcap_mdl *mdl)
 
702
{
 
703
        if (!mdl || mdl->state != MDL_CONNECTED)
 
704
                return -ENOTCONN;
 
705
 
 
706
        return g_io_channel_unix_get_fd(mdl->dc);
 
707
}
 
708
 
 
709
uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl)
 
710
{
 
711
        if (!mdl)
 
712
                return MCAP_MDLID_RESERVED;
 
713
 
 
714
        return mdl->mdlid;
 
715
}
 
716
 
 
717
static void close_mcl(struct mcap_mcl *mcl, gboolean cache_requested)
 
718
{
 
719
        gboolean save = ((!(mcl->ctrl & MCAP_CTRL_FREE)) && cache_requested);
 
720
 
 
721
        RELEASE_TIMER(mcl);
 
722
 
 
723
        if (mcl->cc) {
 
724
                g_io_channel_shutdown(mcl->cc, TRUE, NULL);
 
725
                g_io_channel_unref(mcl->cc);
 
726
                mcl->cc = NULL;
 
727
        }
 
728
 
 
729
        if (mcl->wid) {
 
730
                g_source_remove(mcl->wid);
 
731
                mcl->wid = 0;
 
732
        }
 
733
 
 
734
        if (mcl->lcmd) {
 
735
                g_free(mcl->lcmd);
 
736
                mcl->lcmd = NULL;
 
737
        }
 
738
 
 
739
        if (mcl->priv_data)
 
740
                free_mcl_priv_data(mcl);
 
741
 
 
742
        g_slist_foreach(mcl->mdls, (GFunc) shutdown_mdl, NULL);
 
743
 
 
744
        mcap_sync_stop(mcl);
 
745
 
 
746
        mcl->state = MCL_IDLE;
 
747
 
 
748
        if (save)
 
749
                return;
 
750
 
 
751
        g_slist_foreach(mcl->mdls, (GFunc) mcap_mdl_unref, NULL);
 
752
        g_slist_free(mcl->mdls);
 
753
        mcl->mdls = NULL;
 
754
}
 
755
 
 
756
static void mcap_mcl_shutdown(struct mcap_mcl *mcl)
 
757
{
 
758
        close_mcl(mcl, TRUE);
 
759
}
 
760
 
 
761
static void mcap_mcl_release(struct mcap_mcl *mcl)
 
762
{
 
763
        close_mcl(mcl, FALSE);
 
764
}
 
765
 
 
766
static void mcap_cache_mcl(struct mcap_mcl *mcl)
 
767
{
 
768
        GSList *l;
 
769
        struct mcap_mcl *last;
 
770
        int len;
 
771
 
 
772
        if (mcl->ctrl & MCAP_CTRL_CACHED)
 
773
                return;
 
774
 
 
775
        mcl->mi->mcls = g_slist_remove(mcl->mi->mcls, mcl);
 
776
 
 
777
        if (mcl->ctrl & MCAP_CTRL_NOCACHE) {
 
778
                mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl);
 
779
                mcap_mcl_release(mcl);
 
780
                mcap_mcl_unref(mcl);
 
781
                return;
 
782
        }
 
783
 
 
784
        DBG("Caching MCL");
 
785
 
 
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);
 
790
                last = l->data;
 
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;
 
797
                } else {
 
798
                        mcap_mcl_release(last);
 
799
                        last->mi->mcl_uncached_cb(last, last->mi->user_data);
 
800
                }
 
801
                mcap_mcl_unref(last);
 
802
        }
 
803
 
 
804
        mcl->mi->cached = g_slist_prepend(mcl->mi->cached, mcl);
 
805
        mcl->ctrl |= MCAP_CTRL_CACHED;
 
806
        mcap_mcl_shutdown(mcl);
 
807
}
 
808
 
 
809
static void mcap_uncache_mcl(struct mcap_mcl *mcl)
 
810
{
 
811
        if (!(mcl->ctrl & MCAP_CTRL_CACHED))
 
812
                return;
 
813
 
 
814
        DBG("Got MCL from cache");
 
815
 
 
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;
 
820
}
 
821
 
 
822
void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache)
 
823
{
 
824
        if (!mcl)
 
825
                return;
 
826
 
 
827
        if (mcl->ctrl & MCAP_CTRL_FREE) {
 
828
                mcap_mcl_release(mcl);
 
829
                return;
 
830
        }
 
831
 
 
832
        if (!cache)
 
833
                mcl->ctrl |= MCAP_CTRL_NOCACHE;
 
834
 
 
835
        if (mcl->cc) {
 
836
                g_io_channel_shutdown(mcl->cc, TRUE, NULL);
 
837
                g_io_channel_unref(mcl->cc);
 
838
                mcl->cc = NULL;
 
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);
 
845
                mcap_mcl_unref(mcl);
 
846
        }
 
847
}
 
848
 
 
849
struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl)
 
850
{
 
851
        mcl->ref++;
 
852
 
 
853
        DBG("mcap_mcl_ref(%p): ref=%d", mcl, mcl->ref);
 
854
 
 
855
        return mcl;
 
856
}
 
857
 
 
858
void mcap_mcl_unref(struct mcap_mcl *mcl)
 
859
{
 
860
        mcl->ref--;
 
861
 
 
862
        DBG("mcap_mcl_unref(%p): ref=%d", mcl, mcl->ref);
 
863
 
 
864
        if (mcl->ref > 0)
 
865
                return;
 
866
 
 
867
        mcap_mcl_release(mcl);
 
868
        mcap_instance_unref(mcl->mi);
 
869
        g_free(mcl->cb);
 
870
        g_free(mcl);
 
871
}
 
872
 
 
873
static gboolean parse_set_opts(struct mcap_mdl_cb *mdl_cb, GError **err,
 
874
                                                McapMclCb cb1, va_list args)
 
875
{
 
876
        McapMclCb cb = cb1;
 
877
        struct mcap_mdl_cb *c;
 
878
 
 
879
        c = g_new0(struct mcap_mdl_cb, 1);
 
880
 
 
881
        while (cb != MCAP_MDL_CB_INVALID) {
 
882
                switch (cb) {
 
883
                case MCAP_MDL_CB_CONNECTED:
 
884
                        c->mdl_connected = va_arg(args, mcap_mdl_event_cb);
 
885
                        break;
 
886
                case MCAP_MDL_CB_CLOSED:
 
887
                        c->mdl_closed = va_arg(args, mcap_mdl_event_cb);
 
888
                        break;
 
889
                case MCAP_MDL_CB_DELETED:
 
890
                        c->mdl_deleted = va_arg(args, mcap_mdl_event_cb);
 
891
                        break;
 
892
                case MCAP_MDL_CB_ABORTED:
 
893
                        c->mdl_aborted = va_arg(args, mcap_mdl_event_cb);
 
894
                        break;
 
895
                case MCAP_MDL_CB_REMOTE_CONN_REQ:
 
896
                        c->mdl_conn_req = va_arg(args,
 
897
                                                mcap_remote_mdl_conn_req_cb);
 
898
                        break;
 
899
                case MCAP_MDL_CB_REMOTE_RECONN_REQ:
 
900
                        c->mdl_reconn_req = va_arg(args,
 
901
                                                mcap_remote_mdl_reconn_req_cb);
 
902
                        break;
 
903
                default:
 
904
                        g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
 
905
                                                "Unknown option %d", cb);
 
906
                        return FALSE;
 
907
                }
 
908
                cb = va_arg(args, int);
 
909
        }
 
910
 
 
911
        /* Set new callbacks */
 
912
        if (c->mdl_connected)
 
913
                mdl_cb->mdl_connected = c->mdl_connected;
 
914
        if (c->mdl_closed)
 
915
                mdl_cb->mdl_closed = c->mdl_closed;
 
916
        if (c->mdl_deleted)
 
917
                mdl_cb->mdl_deleted = c->mdl_deleted;
 
918
        if (c->mdl_aborted)
 
919
                mdl_cb->mdl_aborted = c->mdl_aborted;
 
920
        if (c->mdl_conn_req)
 
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;
 
924
 
 
925
        g_free(c);
 
926
 
 
927
        return TRUE;
 
928
}
 
929
 
 
930
gboolean mcap_mcl_set_cb(struct mcap_mcl *mcl, gpointer user_data,
 
931
                                        GError **gerr, McapMclCb cb1, ...)
 
932
{
 
933
        va_list args;
 
934
        gboolean ret;
 
935
 
 
936
        va_start(args, cb1);
 
937
        ret = parse_set_opts(mcl->cb, gerr, cb1, args);
 
938
        va_end(args);
 
939
 
 
940
        if (!ret)
 
941
                return FALSE;
 
942
 
 
943
        mcl->cb->user_data = user_data;
 
944
        return TRUE;
 
945
}
 
946
 
 
947
void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)
 
948
{
 
949
        bacpy(addr, &mcl->addr);
 
950
}
 
951
 
 
952
static void mcap_del_mdl(gpointer elem, gpointer user_data)
 
953
{
 
954
        struct mcap_mdl *mdl = elem;
 
955
        gboolean notify = *(gboolean *) user_data;
 
956
 
 
957
        shutdown_mdl(mdl);
 
958
        if (notify)
 
959
                mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data);
 
960
 
 
961
        mcap_mdl_unref(mdl);
 
962
}
 
963
 
 
964
static gboolean check_cmd_req_length(struct mcap_mcl *mcl, void *cmd,
 
965
                                uint32_t rlen, uint32_t explen, uint8_t rspcod)
 
966
{
 
967
        mcap_md_req *req;
 
968
        uint16_t mdl_id;
 
969
 
 
970
        if (rlen != explen) {
 
971
                if (rlen >= sizeof(mcap_md_req)) {
 
972
                        req = cmd;
 
973
                        mdl_id = ntohs(req->mdl);
 
974
                } else {
 
975
                        /* We can't get mdlid */
 
976
                        mdl_id = MCAP_MDLID_RESERVED;
 
977
                }
 
978
                mcap_send_cmd(mcl, rspcod, MCAP_INVALID_PARAM_VALUE, mdl_id,
 
979
                                                                NULL, 0);
 
980
                return FALSE;
 
981
        }
 
982
        return TRUE;
 
983
}
 
984
 
 
985
static void process_md_create_mdl_req(struct mcap_mcl *mcl, void *cmd,
 
986
                                                                uint32_t len)
 
987
{
 
988
        mcap_md_create_mdl_req *req;
 
989
        struct mcap_mdl *mdl;
 
990
        uint16_t mdl_id;
 
991
        uint8_t mdep_id;
 
992
        uint8_t cfga, conf;
 
993
        uint8_t rsp;
 
994
 
 
995
        if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_create_mdl_req),
 
996
                                                        MCAP_MD_CREATE_MDL_RSP))
 
997
                return;
 
998
 
 
999
        req = cmd;
 
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,
 
1003
                                                        mdl_id, NULL, 0);
 
1004
                return;
 
1005
        }
 
1006
 
 
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,
 
1010
                                                        mdl_id, NULL, 0);
 
1011
                return;
 
1012
        }
 
1013
 
 
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,
 
1019
                                                        mdl_id, NULL, 0);
 
1020
                return;
 
1021
        }
 
1022
 
 
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 */
 
1029
                return;
 
1030
        }
 
1031
 
 
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);
 
1038
                return;
 
1039
        }
 
1040
        if (rsp != MCAP_SUCCESS) {
 
1041
                mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id,
 
1042
                                                                NULL, 0);
 
1043
                return;
 
1044
        }
 
1045
 
 
1046
        if (!mdl) {
 
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),
 
1051
                                                                compare_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 */
 
1055
                shutdown_mdl(mdl);
 
1056
        }
 
1057
 
 
1058
        mdl->mdep_id = mdep_id;
 
1059
        mdl->state = MDL_WAITING;
 
1060
 
 
1061
        mcl->state = MCL_PENDING;
 
1062
        mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id,
 
1063
                                                                &conf, 1);
 
1064
}
 
1065
 
 
1066
static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, void *cmd,
 
1067
                                                                uint32_t len)
 
1068
{
 
1069
        mcap_md_req *req;
 
1070
        struct mcap_mdl *mdl;
 
1071
        uint16_t mdl_id;
 
1072
        uint8_t rsp;
 
1073
 
 
1074
        if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
 
1075
                                                MCAP_MD_RECONNECT_MDL_RSP))
 
1076
                return;
 
1077
 
 
1078
        req = cmd;
 
1079
        mdl_id = ntohs(req->mdl);
 
1080
 
 
1081
        mdl = get_mdl(mcl, mdl_id);
 
1082
        if (!mdl) {
 
1083
                mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_INVALID_MDL,
 
1084
                                                        mdl_id, NULL, 0);
 
1085
                return;
 
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,
 
1090
                                                        mdl_id, NULL, 0);
 
1091
                return;
 
1092
        }
 
1093
 
 
1094
        /* Callback to upper layer */
 
1095
        rsp = mcl->cb->mdl_reconn_req(mdl, mcl->cb->user_data);
 
1096
        if (mcl->state == MCL_IDLE)
 
1097
                return;
 
1098
 
 
1099
        if (rsp != MCAP_SUCCESS) {
 
1100
                mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, rsp, mdl_id,
 
1101
                                                                NULL, 0);
 
1102
                return;
 
1103
        }
 
1104
 
 
1105
        if (mdl->state == MDL_CONNECTED)
 
1106
                shutdown_mdl(mdl);
 
1107
 
 
1108
        mdl->state = MDL_WAITING;
 
1109
        mcl->state = MCL_PENDING;
 
1110
        mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id,
 
1111
                                                                NULL, 0);
 
1112
}
 
1113
 
 
1114
static void process_md_abort_mdl_req(struct mcap_mcl *mcl, void *cmd,
 
1115
                                                                uint32_t len)
 
1116
{
 
1117
        mcap_md_req *req;
 
1118
        GSList *l;
 
1119
        struct mcap_mdl *mdl, *abrt;
 
1120
        uint16_t mdl_id;
 
1121
 
 
1122
        if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
 
1123
                                                        MCAP_MD_ABORT_MDL_RSP))
 
1124
                return;
 
1125
 
 
1126
        req = cmd;
 
1127
        mdl_id = ntohs(req->mdl);
 
1128
        mcl->state = MCL_CONNECTED;
 
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
 
 
1156
static void process_md_delete_mdl_req(struct mcap_mcl *mcl, void *cmd,
 
1157
                                                                uint32_t len)
 
1158
{
 
1159
        mcap_md_req *req;
 
1160
        struct mcap_mdl *mdl, *aux;
 
1161
        uint16_t mdlid;
 
1162
        gboolean notify;
 
1163
        GSList *l;
 
1164
 
 
1165
        if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
 
1166
                                                        MCAP_MD_DELETE_MDL_RSP))
 
1167
                return;
 
1168
 
 
1169
        req = cmd;
 
1170
        mdlid = ntohs(req->mdl);
 
1171
        if (mdlid == MCAP_ALL_MDLIDS) {
 
1172
                notify = FALSE;
 
1173
                g_slist_foreach(mcl->mdls, mcap_del_mdl, &notify);
 
1174
                g_slist_free(mcl->mdls);
 
1175
                mcl->mdls = NULL;
 
1176
                mcl->state = MCL_CONNECTED;
 
1177
                /* NULL mdl means ALL_MDLS */
 
1178
                mcl->cb->mdl_deleted(NULL, mcl->cb->user_data);
 
1179
                goto resp;
 
1180
        }
 
1181
 
 
1182
        if (mdlid < MCAP_MDLID_INITIAL || mdlid > MCAP_MDLID_FINAL) {
 
1183
                mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL,
 
1184
                                                                mdlid, NULL, 0);
 
1185
                return;
 
1186
        }
 
1187
 
 
1188
        for (l = mcl->mdls, mdl = NULL; l; l = l->next) {
 
1189
                aux = l->data;
 
1190
                if (aux->mdlid == mdlid) {
 
1191
                        mdl = aux;
 
1192
                        break;
 
1193
                }
 
1194
        }
 
1195
 
 
1196
        if (!mdl || mdl->state == MDL_WAITING) {
 
1197
                mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL,
 
1198
                                                                mdlid, NULL, 0);
 
1199
                return;
 
1200
        }
 
1201
 
 
1202
        mcl->mdls = g_slist_remove(mcl->mdls, mdl);
 
1203
        update_mcl_state(mcl);
 
1204
        notify = TRUE;
 
1205
        mcap_del_mdl(mdl, &notify);
 
1206
 
 
1207
resp:
 
1208
        mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid,
 
1209
                                                                NULL, 0);
 
1210
}
 
1211
 
 
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 */
 
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
 
 
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
 
 
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 */
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
1460
static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, mcap_rsp *rsp,
 
1461
                                                                uint32_t len)
 
1462
{
 
1463
        struct mcap_mdl_op_cb *del = mcl->priv_data;
 
1464
        struct mcap_mdl *mdl = del->mdl;
 
1465
        mcap_mdl_notify_cb deleted_cb = del->cb.notify;
 
1466
        gpointer user_data = del->user_data;
 
1467
        mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
 
1468
        uint16_t mdlid = ntohs(cmdlast->mdl);
 
1469
        GError *gerr = NULL;
 
1470
        gboolean close;
 
1471
        gboolean notify = FALSE;
 
1472
 
 
1473
        close = check_err_rsp(mcl, rsp, len, sizeof(mcap_rsp), &gerr);
 
1474
 
 
1475
        g_free(mcl->lcmd);
 
1476
        mcl->lcmd = NULL;
 
1477
        mcl->req = MCL_AVAILABLE;
 
1478
 
 
1479
        if (gerr) {
 
1480
                if (mdl)
 
1481
                        check_mdl_del_err(mdl, rsp);
 
1482
                else
 
1483
                        g_slist_foreach(mcl->mdls, restore_mdl, NULL);
 
1484
                deleted_cb(gerr, user_data);
 
1485
                g_error_free(gerr);
 
1486
                return close;
 
1487
        }
 
1488
 
 
1489
        if (mdlid == MCAP_ALL_MDLIDS) {
 
1490
                g_slist_foreach(mcl->mdls, mcap_del_mdl, &notify);
 
1491
                g_slist_free(mcl->mdls);
 
1492
                mcl->mdls = NULL;
 
1493
                mcl->state = MCL_CONNECTED;
 
1494
        } else {
 
1495
                mcl->mdls = g_slist_remove(mcl->mdls, mdl);
 
1496
                update_mcl_state(mcl);
 
1497
                mcap_del_mdl(mdl, &notify);
 
1498
        }
 
1499
 
 
1500
        deleted_cb(gerr, user_data);
 
1501
 
 
1502
        return close;
 
1503
}
 
1504
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
}