~bluetooth/bluez/vivid-phone-overlay

« back to all changes in this revision

Viewing changes to health/mcap.c

  • Committer: Simon Fels
  • Date: 2015-09-11 09:01:46 UTC
  • Revision ID: morphis@gravedo.de-20150911090146-4c0ln9s7ec3xf0nx
Import package bluez_4.101-0ubuntu25.1~overlay4 from stable phone overlay PPA

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
 *  This program is free software; you can redistribute it and/or modify
 
8
 *  it under the terms of the GNU General Public License as published by
 
9
 *  the Free Software Foundation; either version 2 of the License, or
 
10
 *  (at your option) any later version.
 
11
 *
 
12
 *  This program is distributed in the hope that it will be useful,
 
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 *  GNU General Public License for more details.
 
16
 *
 
17
 *  You should have received a copy of the GNU General Public License
 
18
 *  along with this program; if not, write to the Free Software
 
19
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
20
 *
 
21
 */
 
22
 
 
23
#include <netinet/in.h>
 
24
#include <stdlib.h>
 
25
#include <errno.h>
 
26
#include <unistd.h>
 
27
 
 
28
#include <glib.h>
 
29
 
 
30
#include <bluetooth/bluetooth.h>
 
31
#include <bluetooth/l2cap.h>
 
32
 
 
33
#include <btio.h>
 
34
#include <log.h>
 
35
#include <error.h>
 
36
 
 
37
#include "mcap.h"
 
38
#include "mcap_lib.h"
 
39
#include "mcap_internal.h"
 
40
 
 
41
#define RESPONSE_TIMER  6       /* seconds */
 
42
#define MAX_CACHED      10      /* 10 devices */
 
43
 
 
44
#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
 
45
 
 
46
#define RELEASE_TIMER(__mcl) do {               \
 
47
        if (__mcl->tid) {                       \
 
48
                g_source_remove(__mcl->tid);    \
 
49
                __mcl->tid = 0;                 \
 
50
        }                                       \
 
51
} while(0)
 
52
 
 
53
struct connect_mcl {
 
54
        struct mcap_mcl         *mcl;           /* MCL for this operation */
 
55
        mcap_mcl_connect_cb     connect_cb;     /* Connect callback */
 
56
        GDestroyNotify          destroy;        /* Destroy callback */
 
57
        gpointer                user_data;      /* Callback user data */
 
58
};
 
59
 
 
60
typedef union {
 
61
        mcap_mdl_operation_cb           op;
 
62
        mcap_mdl_operation_conf_cb      op_conf;
 
63
        mcap_mdl_notify_cb              notify;
 
64
} mcap_cb_type;
 
65
 
 
66
struct mcap_mdl_op_cb {
 
67
        struct mcap_mdl         *mdl;           /* MDL for this operation */
 
68
        mcap_cb_type            cb;             /* Operation callback */
 
69
        GDestroyNotify          destroy;        /* Destroy callback */
 
70
        gpointer                user_data;      /* Callback user data */
 
71
};
 
72
 
 
73
/* MCAP finite state machine functions */
 
74
static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
 
75
static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
 
76
static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
 
77
 
 
78
static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = {
 
79
        proc_req_connected,
 
80
        proc_req_pending,
 
81
        proc_req_active
 
82
};
 
83
 
 
84
static void mcap_cache_mcl(struct mcap_mcl *mcl);
 
85
 
 
86
static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
 
87
{
 
88
        DBG("MCAP Unmanaged mdl connection");
 
89
}
 
90
 
 
91
static void default_mdl_closed_cb(struct mcap_mdl *mdl, gpointer data)
 
92
{
 
93
        DBG("MCAP Unmanaged mdl closed");
 
94
}
 
95
 
 
96
static void default_mdl_deleted_cb(struct mcap_mdl *mdl, gpointer data)
 
97
{
 
98
        DBG("MCAP Unmanaged mdl deleted");
 
99
}
 
100
 
 
101
static void default_mdl_aborted_cb(struct mcap_mdl *mdl, gpointer data)
 
102
{
 
103
        DBG("MCAP Unmanaged mdl aborted");
 
104
}
 
105
 
 
106
static uint8_t default_mdl_conn_req_cb(struct mcap_mcl *mcl,
 
107
                                                uint8_t mdepid, uint16_t mdlid,
 
108
                                                uint8_t *conf, gpointer data)
 
109
{
 
110
        DBG("MCAP mdl remote connection aborted");
 
111
        /* Due to this callback isn't managed this request won't be supported */
 
112
        return MCAP_REQUEST_NOT_SUPPORTED;
 
113
}
 
114
 
 
115
static uint8_t default_mdl_reconn_req_cb(struct mcap_mdl *mdl,
 
116
                                                gpointer data)
 
117
{
 
118
        DBG("MCAP mdl remote reconnection aborted");
 
119
        /* Due to this callback isn't managed this request won't be supported */
 
120
        return MCAP_REQUEST_NOT_SUPPORTED;
 
121
}
 
122
 
 
123
static void set_default_cb(struct mcap_mcl *mcl)
 
124
{
 
125
        if (!mcl->cb)
 
126
                mcl->cb = g_new0(struct mcap_mdl_cb, 1);
 
127
 
 
128
        mcl->cb->mdl_connected = default_mdl_connected_cb;
 
129
        mcl->cb->mdl_closed = default_mdl_closed_cb;
 
130
        mcl->cb->mdl_deleted = default_mdl_deleted_cb;
 
131
        mcl->cb->mdl_aborted = default_mdl_aborted_cb;
 
132
        mcl->cb->mdl_conn_req = default_mdl_conn_req_cb;
 
133
        mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
 
134
}
 
135
 
 
136
static char *error2str(uint8_t rc)
 
137
{
 
138
        switch (rc) {
 
139
        case MCAP_SUCCESS:
 
140
                return "Success";
 
141
        case MCAP_INVALID_OP_CODE:
 
142
                return "Invalid Op Code";
 
143
        case MCAP_INVALID_PARAM_VALUE:
 
144
                return "Invalid Parameter Value";
 
145
        case MCAP_INVALID_MDEP:
 
146
                return "Invalid MDEP";
 
147
        case MCAP_MDEP_BUSY:
 
148
                return "MDEP Busy";
 
149
        case MCAP_INVALID_MDL:
 
150
                return "Invalid MDL";
 
151
        case MCAP_MDL_BUSY:
 
152
                return "MDL Busy";
 
153
        case MCAP_INVALID_OPERATION:
 
154
                return "Invalid Operation";
 
155
        case MCAP_RESOURCE_UNAVAILABLE:
 
156
                return "Resource Unavailable";
 
157
        case MCAP_UNSPECIFIED_ERROR:
 
158
                return "Unspecified Error";
 
159
        case MCAP_REQUEST_NOT_SUPPORTED:
 
160
                return "Request Not Supported";
 
161
        case MCAP_CONFIGURATION_REJECTED:
 
162
                return "Configuration Rejected";
 
163
        default:
 
164
                return "Unknown Response Code";
 
165
        }
 
166
}
 
167
 
 
168
static gboolean mcap_send_std_opcode(struct mcap_mcl *mcl, void *cmd,
 
169
                                                uint32_t size, GError **err)
 
170
{
 
171
        if (mcl->state == MCL_IDLE) {
 
172
                g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
 
173
                                                        "MCL is not connected");
 
174
                return FALSE;
 
175
        }
 
176
 
 
177
        if (mcl->req != MCL_AVAILABLE) {
 
178
                g_set_error(err, MCAP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE,
 
179
                                                        "Pending request");
 
180
                return FALSE;
 
181
        }
 
182
 
 
183
        if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) {
 
184
                g_set_error(err, MCAP_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED,
 
185
                                "Remote does not support standard opcodes");
 
186
                return FALSE;
 
187
        }
 
188
 
 
189
        if (mcl->state == MCL_PENDING) {
 
190
                g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_OPERATION,
 
191
                        "Not Std Op. Codes can be sent in PENDING State");
 
192
                return FALSE;
 
193
        }
 
194
 
 
195
        if (mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), cmd, size) < 0) {
 
196
                g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
 
197
                                        "Command can't be sent, write error");
 
198
                return FALSE;
 
199
        }
 
200
 
 
201
        mcl->lcmd = cmd;
 
202
        mcl->req = MCL_WAITING_RSP;
 
203
 
 
204
        return TRUE;
 
205
}
 
206
 
 
207
static void update_mcl_state(struct mcap_mcl *mcl)
 
208
{
 
209
        GSList *l;
 
210
        struct mcap_mdl *mdl;
 
211
 
 
212
        if (mcl->state == MCL_PENDING)
 
213
                return;
 
214
 
 
215
        for (l = mcl->mdls; l; l = l->next) {
 
216
                mdl = l->data;
 
217
 
 
218
                if (mdl->state == MDL_CONNECTED) {
 
219
                        mcl->state = MCL_ACTIVE;
 
220
                        return;
 
221
                }
 
222
        }
 
223
 
 
224
        mcl->state = MCL_CONNECTED;
 
225
}
 
226
 
 
227
static void shutdown_mdl(struct mcap_mdl *mdl)
 
228
{
 
229
        mdl->state = MDL_CLOSED;
 
230
 
 
231
        if (mdl->wid) {
 
232
                g_source_remove(mdl->wid);
 
233
                mdl->wid = 0;
 
234
        }
 
235
 
 
236
        if (mdl->dc) {
 
237
                g_io_channel_shutdown(mdl->dc, TRUE, NULL);
 
238
                g_io_channel_unref(mdl->dc);
 
239
                mdl->dc = NULL;
 
240
        }
 
241
}
 
242
 
 
243
static void free_mdl(struct mcap_mdl *mdl)
 
244
{
 
245
        if (!mdl)
 
246
                return;
 
247
 
 
248
        mcap_mcl_unref(mdl->mcl);
 
249
        g_free(mdl);
 
250
}
 
251
 
 
252
static gint cmp_mdl_state(gconstpointer a, gconstpointer b)
 
253
{
 
254
        const struct mcap_mdl *mdl = a;
 
255
        const MDLState *st = b;
 
256
 
 
257
        if (mdl->state == *st)
 
258
                return 0;
 
259
        else if (mdl->state < *st)
 
260
                return -1;
 
261
        else
 
262
                return 1;
 
263
}
 
264
 
 
265
static void free_mcap_mdl_op(struct mcap_mdl_op_cb *op)
 
266
{
 
267
        if (op->destroy)
 
268
                op->destroy(op->user_data);
 
269
 
 
270
        if (op->mdl)
 
271
                mcap_mdl_unref(op->mdl);
 
272
 
 
273
        g_free(op);
 
274
}
 
275
 
 
276
static void free_mcl_priv_data(struct mcap_mcl *mcl)
 
277
{
 
278
        free_mcap_mdl_op(mcl->priv_data);
 
279
        mcl->priv_data = NULL;
 
280
}
 
281
 
 
282
static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
 
283
{
 
284
        struct mcap_mdl_op_cb *con = mcl->priv_data;
 
285
        struct mcap_mdl *mdl;
 
286
        MDLState st;
 
287
        GSList *l;
 
288
 
 
289
        if (!con || !mcl->lcmd)
 
290
                return;
 
291
 
 
292
        switch (mcl->lcmd[0]) {
 
293
        case MCAP_MD_CREATE_MDL_REQ:
 
294
                st = MDL_WAITING;
 
295
                l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
 
296
                mdl = l->data;
 
297
                mcl->mdls = g_slist_remove(mcl->mdls, mdl);
 
298
                mcap_mdl_unref(mdl);
 
299
                update_mcl_state(mcl);
 
300
                con->cb.op_conf(NULL, 0, err, con->user_data);
 
301
                break;
 
302
        case MCAP_MD_ABORT_MDL_REQ:
 
303
                st = MDL_WAITING;
 
304
                l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
 
305
                shutdown_mdl(l->data);
 
306
                update_mcl_state(mcl);
 
307
                con->cb.notify(err, con->user_data);
 
308
                break;
 
309
        case MCAP_MD_DELETE_MDL_REQ:
 
310
                for (l = mcl->mdls; l; l = l->next) {
 
311
                        mdl = l->data;
 
312
                        if (mdl->state == MDL_DELETING)
 
313
                                mdl->state = (mdl->dc) ? MDL_CONNECTED :
 
314
                                                                MDL_CLOSED;
 
315
                }
 
316
                update_mcl_state(mcl);
 
317
                con->cb.notify(err, con->user_data);
 
318
                break;
 
319
        case MCAP_MD_RECONNECT_MDL_REQ:
 
320
                st = MDL_WAITING;
 
321
                l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
 
322
                shutdown_mdl(l->data);
 
323
                update_mcl_state(mcl);
 
324
                con->cb.op(NULL, err, con->user_data);
 
325
                break;
 
326
        }
 
327
 
 
328
        free_mcl_priv_data(mcl);
 
329
        g_free(mcl->lcmd);
 
330
        mcl->lcmd = NULL;
 
331
}
 
332
 
 
333
int mcap_send_data(int sock, const void *buf, uint32_t size)
 
334
{
 
335
        const uint8_t *buf_b = buf;
 
336
        uint32_t sent = 0;
 
337
 
 
338
        while (sent < size) {
 
339
                int n = write(sock, buf_b + sent, size - sent);
 
340
                if (n < 0)
 
341
                        return -1;
 
342
                sent += n;
 
343
        }
 
344
 
 
345
        return 0;
 
346
}
 
347
 
 
348
static int mcap_send_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
 
349
                                        uint16_t mdl, uint8_t *data, size_t len)
 
350
{
 
351
        mcap_rsp *cmd;
 
352
        int sock, sent;
 
353
 
 
354
        if (mcl->cc == NULL)
 
355
                return -1;
 
356
 
 
357
        sock = g_io_channel_unix_get_fd(mcl->cc);
 
358
 
 
359
        cmd = g_malloc(sizeof(mcap_rsp) + len);
 
360
        cmd->op = oc;
 
361
        cmd->rc = rc;
 
362
        cmd->mdl = htons(mdl);
 
363
 
 
364
        if (data && len > 0)
 
365
                memcpy(cmd->data, data, len);
 
366
 
 
367
        sent = mcap_send_data(sock, cmd, sizeof(mcap_rsp) + len);
 
368
        g_free(cmd);
 
369
 
 
370
        return sent;
 
371
}
 
372
 
 
373
static struct mcap_mdl *get_mdl(struct mcap_mcl *mcl, uint16_t mdlid)
 
374
{
 
375
        GSList *l;
 
376
        struct mcap_mdl *mdl;
 
377
 
 
378
        for (l = mcl->mdls; l; l = l->next) {
 
379
                mdl = l->data;
 
380
                if (mdlid == mdl->mdlid)
 
381
                        return mdl;
 
382
        }
 
383
 
 
384
        return NULL;
 
385
}
 
386
 
 
387
static uint16_t generate_mdlid(struct mcap_mcl *mcl)
 
388
{
 
389
        uint16_t mdlid = mcl->next_mdl;
 
390
        struct mcap_mdl *mdl;
 
391
 
 
392
        do {
 
393
                mdl = get_mdl(mcl, mdlid);
 
394
                if (!mdl) {
 
395
                        mcl->next_mdl = (mdlid % MCAP_MDLID_FINAL) + 1;
 
396
                        return mdlid;
 
397
                } else
 
398
                        mdlid = (mdlid % MCAP_MDLID_FINAL) + 1;
 
399
        } while (mdlid != mcl->next_mdl);
 
400
 
 
401
        /* No more mdlids availables */
 
402
        return 0;
 
403
}
 
404
 
 
405
static mcap_md_req *create_req(uint8_t op, uint16_t mdl_id)
 
406
{
 
407
        mcap_md_req *req_cmd;
 
408
 
 
409
        req_cmd = g_new0(mcap_md_req, 1);
 
410
 
 
411
        req_cmd->op = op;
 
412
        req_cmd->mdl = htons(mdl_id);
 
413
 
 
414
        return req_cmd;
 
415
}
 
416
 
 
417
static mcap_md_create_mdl_req *create_mdl_req(uint16_t mdl_id, uint8_t mdep,
 
418
                                                                uint8_t conf)
 
419
{
 
420
        mcap_md_create_mdl_req *req_mdl;
 
421
 
 
422
        req_mdl = g_new0(mcap_md_create_mdl_req, 1);
 
423
 
 
424
        req_mdl->op = MCAP_MD_CREATE_MDL_REQ;
 
425
        req_mdl->mdl = htons(mdl_id);
 
426
        req_mdl->mdep = mdep;
 
427
        req_mdl->conf = conf;
 
428
 
 
429
        return req_mdl;
 
430
}
 
431
 
 
432
static gint compare_mdl(gconstpointer a, gconstpointer b)
 
433
{
 
434
        const struct mcap_mdl *mdla = a;
 
435
        const struct mcap_mdl *mdlb = b;
 
436
 
 
437
        if (mdla->mdlid == mdlb->mdlid)
 
438
                return 0;
 
439
        else if (mdla->mdlid < mdlb->mdlid)
 
440
                return -1;
 
441
        else
 
442
                return 1;
 
443
}
 
444
 
 
445
static gboolean wait_response_timer(gpointer data)
 
446
{
 
447
        struct mcap_mcl *mcl = data;
 
448
 
 
449
        GError *gerr = NULL;
 
450
 
 
451
        RELEASE_TIMER(mcl);
 
452
 
 
453
        g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
 
454
                                        "Timeout waiting response");
 
455
 
 
456
        mcap_notify_error(mcl, gerr);
 
457
 
 
458
        g_error_free(gerr);
 
459
        mcl->mi->mcl_disconnected_cb(mcl, mcl->mi->user_data);
 
460
        mcap_cache_mcl(mcl);
 
461
 
 
462
        return FALSE;
 
463
}
 
464
 
 
465
gboolean mcap_create_mdl(struct mcap_mcl *mcl,
 
466
                                uint8_t mdepid,
 
467
                                uint8_t conf,
 
468
                                mcap_mdl_operation_conf_cb connect_cb,
 
469
                                gpointer user_data,
 
470
                                GDestroyNotify destroy,
 
471
                                GError **err)
 
472
{
 
473
        struct mcap_mdl *mdl;
 
474
        struct mcap_mdl_op_cb *con;
 
475
        mcap_md_create_mdl_req *cmd;
 
476
        uint16_t id;
 
477
 
 
478
        id = generate_mdlid(mcl);
 
479
        if (!id) {
 
480
                g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
 
481
                                        "Not more mdlids available");
 
482
                return FALSE;
 
483
        }
 
484
 
 
485
        mdl = g_new0(struct mcap_mdl, 1);
 
486
        mdl->mcl = mcap_mcl_ref(mcl);
 
487
        mdl->mdlid = id;
 
488
        mdl->mdep_id = mdepid;
 
489
        mdl->state = MDL_WAITING;
 
490
 
 
491
        con = g_new0(struct mcap_mdl_op_cb, 1);
 
492
        con->mdl = mcap_mdl_ref(mdl);
 
493
        con->cb.op_conf = connect_cb;
 
494
        con->destroy = destroy;
 
495
        con->user_data = user_data;
 
496
 
 
497
        cmd = create_mdl_req(id, mdepid, conf);
 
498
        if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_create_mdl_req),
 
499
                                                                        err)) {
 
500
                mcap_mdl_unref(con->mdl);
 
501
                g_free(con);
 
502
                g_free(cmd);
 
503
                return FALSE;
 
504
        }
 
505
 
 
506
        mcl->state = MCL_ACTIVE;
 
507
        mcl->priv_data = con;
 
508
 
 
509
        mcl->mdls = g_slist_insert_sorted(mcl->mdls, mcap_mdl_ref(mdl),
 
510
                                                                compare_mdl);
 
511
        mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
 
512
                                                                        mcl);
 
513
        return TRUE;
 
514
}
 
515
 
 
516
gboolean mcap_reconnect_mdl(struct mcap_mdl *mdl,
 
517
                                mcap_mdl_operation_cb reconnect_cb,
 
518
                                gpointer user_data,
 
519
                                GDestroyNotify destroy,
 
520
                                GError **err)
 
521
{
 
522
        struct mcap_mdl_op_cb *con;
 
523
        struct mcap_mcl *mcl = mdl->mcl;
 
524
        mcap_md_req *cmd;
 
525
 
 
526
        if (mdl->state != MDL_CLOSED) {
 
527
                g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
 
528
                                        "MDL is not closed");
 
529
                return FALSE;
 
530
        }
 
531
 
 
532
        cmd = create_req(MCAP_MD_RECONNECT_MDL_REQ, mdl->mdlid);
 
533
        if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
 
534
                g_free(cmd);
 
535
                return FALSE;
 
536
        }
 
537
 
 
538
        mdl->state = MDL_WAITING;
 
539
 
 
540
        con = g_new0(struct mcap_mdl_op_cb, 1);
 
541
        con->mdl = mcap_mdl_ref(mdl);
 
542
        con->cb.op = reconnect_cb;
 
543
        con->destroy = destroy;
 
544
        con->user_data = user_data;
 
545
 
 
546
        mcl->state = MCL_ACTIVE;
 
547
        mcl->priv_data = con;
 
548
 
 
549
        mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
 
550
                                                                        mcl);
 
551
        return TRUE;
 
552
}
 
553
 
 
554
static gboolean send_delete_req(struct mcap_mcl *mcl,
 
555
                                                struct mcap_mdl_op_cb *con,
 
556
                                                uint16_t mdlid,
 
557
                                                GError **err)
 
558
{
 
559
        mcap_md_req *cmd;
 
560
 
 
561
        cmd = create_req(MCAP_MD_DELETE_MDL_REQ, mdlid);
 
562
        if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
 
563
                g_free(cmd);
 
564
                return FALSE;
 
565
        }
 
566
 
 
567
        mcl->priv_data = con;
 
568
 
 
569
        mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
 
570
                                                                        mcl);
 
571
        return TRUE;
 
572
}
 
573
 
 
574
gboolean mcap_delete_all_mdls(struct mcap_mcl *mcl,
 
575
                                        mcap_mdl_notify_cb delete_cb,
 
576
                                        gpointer user_data,
 
577
                                        GDestroyNotify destroy,
 
578
                                        GError **err)
 
579
{
 
580
        GSList *l;
 
581
        struct mcap_mdl *mdl;
 
582
        struct mcap_mdl_op_cb *con;
 
583
 
 
584
        DBG("MCL in state: %d", mcl->state);
 
585
        if (!mcl->mdls) {
 
586
                g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
 
587
                                "There are not MDLs created");
 
588
                return FALSE;
 
589
        }
 
590
 
 
591
        for (l = mcl->mdls; l; l = l->next) {
 
592
                mdl = l->data;
 
593
                if (mdl->state != MDL_WAITING)
 
594
                        mdl->state = MDL_DELETING;
 
595
        }
 
596
 
 
597
        con = g_new0(struct mcap_mdl_op_cb, 1);
 
598
        con->mdl = NULL;
 
599
        con->cb.notify = delete_cb;
 
600
        con->destroy = destroy;
 
601
        con->user_data = user_data;
 
602
 
 
603
 
 
604
        if (!send_delete_req(mcl, con, MCAP_ALL_MDLIDS, err)) {
 
605
                g_free(con);
 
606
                return FALSE;
 
607
        }
 
608
 
 
609
        return TRUE;
 
610
}
 
611
 
 
612
gboolean mcap_delete_mdl(struct mcap_mdl *mdl, mcap_mdl_notify_cb delete_cb,
 
613
                                                        gpointer user_data,
 
614
                                                        GDestroyNotify destroy,
 
615
                                                        GError **err)
 
616
{
 
617
        struct mcap_mcl *mcl= mdl->mcl;
 
618
        struct mcap_mdl_op_cb *con;
 
619
        GSList *l;
 
620
 
 
621
        l = g_slist_find(mcl->mdls, mdl);
 
622
 
 
623
        if (!l) {
 
624
                g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL,
 
625
                                        "%s" , error2str(MCAP_INVALID_MDEP));
 
626
                return FALSE;
 
627
        }
 
628
 
 
629
        if (mdl->state == MDL_WAITING) {
 
630
                g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
 
631
                                                        "Mdl is not created");
 
632
                return FALSE;
 
633
        }
 
634
 
 
635
        mdl->state = MDL_DELETING;
 
636
 
 
637
        con = g_new0(struct mcap_mdl_op_cb, 1);
 
638
        con->mdl = mcap_mdl_ref(mdl);
 
639
        con->cb.notify = delete_cb;
 
640
        con->destroy = destroy;
 
641
        con->user_data = user_data;
 
642
 
 
643
        if (!send_delete_req(mcl, con, mdl->mdlid, err)) {
 
644
                mcap_mdl_unref(con->mdl);
 
645
                g_free(con);
 
646
                return FALSE;
 
647
        }
 
648
 
 
649
        return TRUE;
 
650
}
 
651
 
 
652
gboolean mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb,
 
653
                                                        gpointer user_data,
 
654
                                                        GDestroyNotify destroy,
 
655
                                                        GError **err)
 
656
{
 
657
        struct mcap_mdl_op_cb *con;
 
658
        struct mcap_mcl *mcl = mdl->mcl;
 
659
        mcap_md_req *cmd;
 
660
 
 
661
        if (mdl->state != MDL_WAITING) {
 
662
                g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
 
663
                                                        "Mdl in invalid state");
 
664
                return FALSE;
 
665
        }
 
666
 
 
667
        cmd = create_req(MCAP_MD_ABORT_MDL_REQ, mdl->mdlid);
 
668
        if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
 
669
                g_free(cmd);
 
670
                return FALSE;
 
671
        }
 
672
 
 
673
        con = g_new0(struct mcap_mdl_op_cb, 1);
 
674
        con->mdl = mcap_mdl_ref(mdl);
 
675
        con->cb.notify = abort_cb;
 
676
        con->destroy = destroy;
 
677
        con->user_data = user_data;
 
678
 
 
679
        mcl->priv_data = con;
 
680
        mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
 
681
                                                                        mcl);
 
682
        return TRUE;
 
683
}
 
684
 
 
685
static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 
686
{
 
687
        struct mcap_mcl *mcl;
 
688
 
 
689
        for (; list; list = list->next) {
 
690
                mcl = list->data;
 
691
 
 
692
                if (!bacmp(&mcl->addr, addr))
 
693
                        return mcl;
 
694
        }
 
695
 
 
696
        return NULL;
 
697
}
 
698
 
 
699
int mcap_mdl_get_fd(struct mcap_mdl *mdl)
 
700
{
 
701
        if (!mdl || mdl->state != MDL_CONNECTED)
 
702
                return -ENOTCONN;
 
703
 
 
704
        return g_io_channel_unix_get_fd(mdl->dc);
 
705
}
 
706
 
 
707
uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl)
 
708
{
 
709
        if (!mdl)
 
710
                return MCAP_MDLID_RESERVED;
 
711
 
 
712
        return mdl->mdlid;
 
713
}
 
714
 
 
715
static void close_mcl(struct mcap_mcl *mcl, gboolean cache_requested)
 
716
{
 
717
        gboolean save = ((!(mcl->ctrl & MCAP_CTRL_FREE)) && cache_requested);
 
718
 
 
719
        RELEASE_TIMER(mcl);
 
720
 
 
721
        if (mcl->cc) {
 
722
                g_io_channel_shutdown(mcl->cc, TRUE, NULL);
 
723
                g_io_channel_unref(mcl->cc);
 
724
                mcl->cc = NULL;
 
725
        }
 
726
 
 
727
        if (mcl->wid) {
 
728
                g_source_remove(mcl->wid);
 
729
                mcl->wid = 0;
 
730
        }
 
731
 
 
732
        if (mcl->lcmd) {
 
733
                g_free(mcl->lcmd);
 
734
                mcl->lcmd = NULL;
 
735
        }
 
736
 
 
737
        if (mcl->priv_data)
 
738
                free_mcl_priv_data(mcl);
 
739
 
 
740
        g_slist_foreach(mcl->mdls, (GFunc) shutdown_mdl, NULL);
 
741
 
 
742
        mcap_sync_stop(mcl);
 
743
 
 
744
        mcl->state = MCL_IDLE;
 
745
 
 
746
        if (save)
 
747
                return;
 
748
 
 
749
        g_slist_foreach(mcl->mdls, (GFunc) mcap_mdl_unref, NULL);
 
750
        g_slist_free(mcl->mdls);
 
751
        mcl->mdls = NULL;
 
752
}
 
753
 
 
754
static void mcap_mcl_shutdown(struct mcap_mcl *mcl)
 
755
{
 
756
        close_mcl(mcl, TRUE);
 
757
}
 
758
 
 
759
static void mcap_mcl_release(struct mcap_mcl *mcl)
 
760
{
 
761
        close_mcl(mcl, FALSE);
 
762
}
 
763
 
 
764
static void mcap_cache_mcl(struct mcap_mcl *mcl)
 
765
{
 
766
        GSList *l;
 
767
        struct mcap_mcl *last;
 
768
        int len;
 
769
 
 
770
        if (mcl->ctrl & MCAP_CTRL_CACHED)
 
771
                return;
 
772
 
 
773
        mcl->mi->mcls = g_slist_remove(mcl->mi->mcls, mcl);
 
774
 
 
775
        if (mcl->ctrl & MCAP_CTRL_NOCACHE) {
 
776
                mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl);
 
777
                mcap_mcl_release(mcl);
 
778
                mcap_mcl_unref(mcl);
 
779
                return;
 
780
        }
 
781
 
 
782
        DBG("Caching MCL");
 
783
 
 
784
        len = g_slist_length(mcl->mi->cached);
 
785
        if (len == MAX_CACHED) {
 
786
                /* Remove the latest cached mcl */
 
787
                l = g_slist_last(mcl->mi->cached);
 
788
                last = l->data;
 
789
                mcl->mi->cached = g_slist_remove(mcl->mi->cached, last);
 
790
                last->ctrl &= ~MCAP_CTRL_CACHED;
 
791
                if (last->ctrl & MCAP_CTRL_CONN) {
 
792
                        /* We have to release this MCL if */
 
793
                        /* connection is not successful    */
 
794
                        last->ctrl |= MCAP_CTRL_FREE;
 
795
                } else {
 
796
                        mcap_mcl_release(last);
 
797
                        last->mi->mcl_uncached_cb(last, last->mi->user_data);
 
798
                }
 
799
                mcap_mcl_unref(last);
 
800
        }
 
801
 
 
802
        mcl->mi->cached = g_slist_prepend(mcl->mi->cached, mcl);
 
803
        mcl->ctrl |= MCAP_CTRL_CACHED;
 
804
        mcap_mcl_shutdown(mcl);
 
805
}
 
806
 
 
807
static void mcap_uncache_mcl(struct mcap_mcl *mcl)
 
808
{
 
809
        if (!(mcl->ctrl & MCAP_CTRL_CACHED))
 
810
                return;
 
811
 
 
812
        DBG("Got MCL from cache");
 
813
 
 
814
        mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl);
 
815
        mcl->mi->mcls = g_slist_prepend(mcl->mi->mcls, mcl);
 
816
        mcl->ctrl &= ~MCAP_CTRL_CACHED;
 
817
        mcl->ctrl &= ~MCAP_CTRL_FREE;
 
818
}
 
819
 
 
820
void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache)
 
821
{
 
822
        if (!mcl)
 
823
                return;
 
824
 
 
825
        if (mcl->ctrl & MCAP_CTRL_FREE) {
 
826
                mcap_mcl_release(mcl);
 
827
                return;
 
828
        }
 
829
 
 
830
        if (!cache)
 
831
                mcl->ctrl |= MCAP_CTRL_NOCACHE;
 
832
 
 
833
        if (mcl->cc) {
 
834
                g_io_channel_shutdown(mcl->cc, TRUE, NULL);
 
835
                g_io_channel_unref(mcl->cc);
 
836
                mcl->cc = NULL;
 
837
                mcl->state = MCL_IDLE;
 
838
        } else if ((mcl->ctrl & MCAP_CTRL_CACHED) &&
 
839
                                        (mcl->ctrl & MCAP_CTRL_NOCACHE)) {
 
840
                mcl->ctrl &= ~MCAP_CTRL_CACHED;
 
841
                mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl);
 
842
                mcap_mcl_release(mcl);
 
843
                mcap_mcl_unref(mcl);
 
844
        }
 
845
}
 
846
 
 
847
struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl)
 
848
{
 
849
        mcl->ref++;
 
850
 
 
851
        DBG("mcap_mcl_ref(%p): ref=%d", mcl, mcl->ref);
 
852
 
 
853
        return mcl;
 
854
}
 
855
 
 
856
void mcap_mcl_unref(struct mcap_mcl *mcl)
 
857
{
 
858
        mcl->ref--;
 
859
 
 
860
        DBG("mcap_mcl_unref(%p): ref=%d", mcl, mcl->ref);
 
861
 
 
862
        if (mcl->ref > 0)
 
863
                return;
 
864
 
 
865
        mcap_mcl_release(mcl);
 
866
        mcap_instance_unref(mcl->mi);
 
867
        g_free(mcl->cb);
 
868
        g_free(mcl);
 
869
}
 
870
 
 
871
static gboolean parse_set_opts(struct mcap_mdl_cb *mdl_cb, GError **err,
 
872
                                                McapMclCb cb1, va_list args)
 
873
{
 
874
        McapMclCb cb = cb1;
 
875
        struct mcap_mdl_cb *c;
 
876
 
 
877
        c = g_new0(struct mcap_mdl_cb, 1);
 
878
 
 
879
        while (cb != MCAP_MDL_CB_INVALID) {
 
880
                switch (cb) {
 
881
                case MCAP_MDL_CB_CONNECTED:
 
882
                        c->mdl_connected = va_arg(args, mcap_mdl_event_cb);
 
883
                        break;
 
884
                case MCAP_MDL_CB_CLOSED:
 
885
                        c->mdl_closed = va_arg(args, mcap_mdl_event_cb);
 
886
                        break;
 
887
                case MCAP_MDL_CB_DELETED:
 
888
                        c->mdl_deleted = va_arg(args, mcap_mdl_event_cb);
 
889
                        break;
 
890
                case MCAP_MDL_CB_ABORTED:
 
891
                        c->mdl_aborted = va_arg(args, mcap_mdl_event_cb);
 
892
                        break;
 
893
                case MCAP_MDL_CB_REMOTE_CONN_REQ:
 
894
                        c->mdl_conn_req = va_arg(args,
 
895
                                                mcap_remote_mdl_conn_req_cb);
 
896
                        break;
 
897
                case MCAP_MDL_CB_REMOTE_RECONN_REQ:
 
898
                        c->mdl_reconn_req = va_arg(args,
 
899
                                                mcap_remote_mdl_reconn_req_cb);
 
900
                        break;
 
901
                default:
 
902
                        g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
 
903
                                                "Unknown option %d", cb);
 
904
                        g_free(c);
 
905
                        return FALSE;
 
906
                }
 
907
                cb = va_arg(args, int);
 
908
        }
 
909
 
 
910
        /* Set new callbacks */
 
911
        if (c->mdl_connected)
 
912
                mdl_cb->mdl_connected = c->mdl_connected;
 
913
        if (c->mdl_closed)
 
914
                mdl_cb->mdl_closed = c->mdl_closed;
 
915
        if (c->mdl_deleted)
 
916
                mdl_cb->mdl_deleted = c->mdl_deleted;
 
917
        if (c->mdl_aborted)
 
918
                mdl_cb->mdl_aborted = c->mdl_aborted;
 
919
        if (c->mdl_conn_req)
 
920
                mdl_cb->mdl_conn_req = c->mdl_conn_req;
 
921
        if (c->mdl_reconn_req)
 
922
                mdl_cb->mdl_reconn_req = c->mdl_reconn_req;
 
923
 
 
924
        g_free(c);
 
925
 
 
926
        return TRUE;
 
927
}
 
928
 
 
929
gboolean mcap_mcl_set_cb(struct mcap_mcl *mcl, gpointer user_data,
 
930
                                        GError **gerr, McapMclCb cb1, ...)
 
931
{
 
932
        va_list args;
 
933
        gboolean ret;
 
934
 
 
935
        va_start(args, cb1);
 
936
        ret = parse_set_opts(mcl->cb, gerr, cb1, args);
 
937
        va_end(args);
 
938
 
 
939
        if (!ret)
 
940
                return FALSE;
 
941
 
 
942
        mcl->cb->user_data = user_data;
 
943
        return TRUE;
 
944
}
 
945
 
 
946
void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)
 
947
{
 
948
        bacpy(addr, &mcl->addr);
 
949
}
 
950
 
 
951
static void mcap_del_mdl(gpointer elem, gpointer user_data)
 
952
{
 
953
        struct mcap_mdl *mdl = elem;
 
954
        gboolean notify = *(gboolean *) user_data;
 
955
 
 
956
        shutdown_mdl(mdl);
 
957
        if (notify)
 
958
                mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data);
 
959
 
 
960
        mcap_mdl_unref(mdl);
 
961
}
 
962
 
 
963
static gboolean check_cmd_req_length(struct mcap_mcl *mcl, void *cmd,
 
964
                                uint32_t rlen, uint32_t explen, uint8_t rspcod)
 
965
{
 
966
        mcap_md_req *req;
 
967
        uint16_t mdl_id;
 
968
 
 
969
        if (rlen != explen) {
 
970
                if (rlen >= sizeof(mcap_md_req)) {
 
971
                        req = cmd;
 
972
                        mdl_id = ntohs(req->mdl);
 
973
                } else {
 
974
                        /* We can't get mdlid */
 
975
                        mdl_id = MCAP_MDLID_RESERVED;
 
976
                }
 
977
                mcap_send_cmd(mcl, rspcod, MCAP_INVALID_PARAM_VALUE, mdl_id,
 
978
                                                                NULL, 0);
 
979
                return FALSE;
 
980
        }
 
981
        return TRUE;
 
982
}
 
983
 
 
984
static void process_md_create_mdl_req(struct mcap_mcl *mcl, void *cmd,
 
985
                                                                uint32_t len)
 
986
{
 
987
        mcap_md_create_mdl_req *req;
 
988
        struct mcap_mdl *mdl;
 
989
        uint16_t mdl_id;
 
990
        uint8_t mdep_id;
 
991
        uint8_t cfga, conf;
 
992
        uint8_t rsp;
 
993
 
 
994
        if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_create_mdl_req),
 
995
                                                        MCAP_MD_CREATE_MDL_RSP))
 
996
                return;
 
997
 
 
998
        req = cmd;
 
999
        mdl_id = ntohs(req->mdl);
 
1000
        if (mdl_id < MCAP_MDLID_INITIAL || mdl_id > MCAP_MDLID_FINAL) {
 
1001
                mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL,
 
1002
                                                        mdl_id, NULL, 0);
 
1003
                return;
 
1004
        }
 
1005
 
 
1006
        mdep_id = req->mdep;
 
1007
        if (mdep_id > MCAP_MDEPID_FINAL) {
 
1008
                mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDEP,
 
1009
                                                        mdl_id, NULL, 0);
 
1010
                return;
 
1011
        }
 
1012
 
 
1013
        mdl = get_mdl(mcl, mdl_id);
 
1014
        if (mdl && (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING )) {
 
1015
                /* Creation request arrives for a MDL that is being managed
 
1016
                * at current moment */
 
1017
                mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY,
 
1018
                                                        mdl_id, NULL, 0);
 
1019
                return;
 
1020
        }
 
1021
 
 
1022
        cfga = conf = req->conf;
 
1023
        /* Callback to upper layer */
 
1024
        rsp = mcl->cb->mdl_conn_req(mcl, mdep_id, mdl_id, &conf,
 
1025
                                                        mcl->cb->user_data);
 
1026
        if (mcl->state == MCL_IDLE) {
 
1027
                /* MCL has been closed int the callback */
 
1028
                return;
 
1029
        }
 
1030
 
 
1031
        if (cfga != 0 && cfga != conf) {
 
1032
                /* Remote device set default configuration but upper profile */
 
1033
                /* has changed it. Protocol Error: force closing the MCL by */
 
1034
                /* remote device using UNSPECIFIED_ERROR response */
 
1035
                mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP,
 
1036
                                MCAP_UNSPECIFIED_ERROR, mdl_id, NULL, 0);
 
1037
                return;
 
1038
        }
 
1039
        if (rsp != MCAP_SUCCESS) {
 
1040
                mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id,
 
1041
                                                                NULL, 0);
 
1042
                return;
 
1043
        }
 
1044
 
 
1045
        if (!mdl) {
 
1046
                mdl = g_new0(struct mcap_mdl, 1);
 
1047
                mdl->mcl = mcap_mcl_ref(mcl);
 
1048
                mdl->mdlid = mdl_id;
 
1049
                mcl->mdls = g_slist_insert_sorted(mcl->mdls, mcap_mdl_ref(mdl),
 
1050
                                                                compare_mdl);
 
1051
        } else if (mdl->state == MDL_CONNECTED) {
 
1052
                /* MCAP specification says that we should close the MCL if
 
1053
                 * it is open when we receive a MD_CREATE_MDL_REQ */
 
1054
                shutdown_mdl(mdl);
 
1055
        }
 
1056
 
 
1057
        mdl->mdep_id = mdep_id;
 
1058
        mdl->state = MDL_WAITING;
 
1059
 
 
1060
        mcl->state = MCL_PENDING;
 
1061
        mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id,
 
1062
                                                                &conf, 1);
 
1063
}
 
1064
 
 
1065
static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, void *cmd,
 
1066
                                                                uint32_t len)
 
1067
{
 
1068
        mcap_md_req *req;
 
1069
        struct mcap_mdl *mdl;
 
1070
        uint16_t mdl_id;
 
1071
        uint8_t rsp;
 
1072
 
 
1073
        if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
 
1074
                                                MCAP_MD_RECONNECT_MDL_RSP))
 
1075
                return;
 
1076
 
 
1077
        req = cmd;
 
1078
        mdl_id = ntohs(req->mdl);
 
1079
 
 
1080
        mdl = get_mdl(mcl, mdl_id);
 
1081
        if (!mdl) {
 
1082
                mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_INVALID_MDL,
 
1083
                                                        mdl_id, NULL, 0);
 
1084
                return;
 
1085
        } else if (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING ) {
 
1086
                /* Creation request arrives for a MDL that is being managed
 
1087
                * at current moment */
 
1088
                mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_MDL_BUSY,
 
1089
                                                        mdl_id, NULL, 0);
 
1090
                return;
 
1091
        }
 
1092
 
 
1093
        /* Callback to upper layer */
 
1094
        rsp = mcl->cb->mdl_reconn_req(mdl, mcl->cb->user_data);
 
1095
        if (mcl->state == MCL_IDLE)
 
1096
                return;
 
1097
 
 
1098
        if (rsp != MCAP_SUCCESS) {
 
1099
                mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, rsp, mdl_id,
 
1100
                                                                NULL, 0);
 
1101
                return;
 
1102
        }
 
1103
 
 
1104
        if (mdl->state == MDL_CONNECTED)
 
1105
                shutdown_mdl(mdl);
 
1106
 
 
1107
        mdl->state = MDL_WAITING;
 
1108
        mcl->state = MCL_PENDING;
 
1109
        mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id,
 
1110
                                                                NULL, 0);
 
1111
}
 
1112
 
 
1113
static void process_md_abort_mdl_req(struct mcap_mcl *mcl, void *cmd,
 
1114
                                                                uint32_t len)
 
1115
{
 
1116
        mcap_md_req *req;
 
1117
        GSList *l;
 
1118
        struct mcap_mdl *mdl, *abrt;
 
1119
        uint16_t mdl_id;
 
1120
 
 
1121
        if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
 
1122
                                                        MCAP_MD_ABORT_MDL_RSP))
 
1123
                return;
 
1124
 
 
1125
        req = cmd;
 
1126
        mdl_id = ntohs(req->mdl);
 
1127
        mcl->state = MCL_CONNECTED;
 
1128
        abrt = NULL;
 
1129
        for (l = mcl->mdls; l; l = l->next) {
 
1130
                mdl = l->data;
 
1131
                if (mdl_id == mdl->mdlid && mdl->state == MDL_WAITING) {
 
1132
                        abrt = mdl;
 
1133
                        if (mcl->state != MCL_CONNECTED)
 
1134
                                break;
 
1135
                        continue;
 
1136
                }
 
1137
                if (mdl->state == MDL_CONNECTED && mcl->state != MCL_ACTIVE)
 
1138
                        mcl->state = MCL_ACTIVE;
 
1139
 
 
1140
                if (abrt && mcl->state == MCL_ACTIVE)
 
1141
                        break;
 
1142
        }
 
1143
 
 
1144
        if (!abrt) {
 
1145
                mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL,
 
1146
                                                        mdl_id, NULL, 0);
 
1147
                return;
 
1148
        }
 
1149
 
 
1150
        mcl->cb->mdl_aborted(abrt, mcl->cb->user_data);
 
1151
        abrt->state = MDL_CLOSED;
 
1152
        mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_SUCCESS, mdl_id,
 
1153
                                                                NULL, 0);
 
1154
}
 
1155
 
 
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
}