1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * BlueZ - Bluetooth protocol stack for Linux
6 * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
7 * Copyright (C) 2010 Signove
8 * Copyright (C) 2014 Intel Corporation. All rights reserved.
16 #include <netinet/in.h>
20 #include <sys/random.h>
24 #include "lib/bluetooth.h"
25 #include "bluetooth/l2cap.h"
26 #include "btio/btio.h"
28 #include "src/shared/timeout.h"
32 #define MCAP_BTCLOCK_HALF (MCAP_BTCLOCK_FIELD / 2)
33 #define CLK CLOCK_MONOTONIC
35 #define MCAP_CSP_ERROR g_quark_from_static_string("mcap-csp-error-quark")
36 #define MAX_RETRIES 10
37 #define SAMPLE_COUNT 20
39 #define RESPONSE_TIMER 6 /* seconds */
40 #define MAX_CACHED 10 /* 10 devices */
42 #define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
44 #define RELEASE_TIMER(__mcl) do { \
46 timeout_remove(__mcl->tid); \
52 uint64_t base_tmstamp; /* CSP base timestamp */
53 struct timespec base_time; /* CSP base time when timestamp set */
54 guint local_caps; /* CSP-Cent.: have got remote caps */
55 guint remote_caps; /* CSP-Perip: remote central got caps */
56 guint rem_req_acc; /* CSP-Perip: accuracy req by central */
57 guint ind_expected; /* CSP-Cent.: indication expected */
58 uint8_t csp_req; /* CSP-Cent.: Request control flag */
59 guint ind_timer; /* CSP-Perip: indication timer */
60 guint set_timer; /* CSP-Perip: delayed set timer */
61 void *set_data; /* CSP-Perip: delayed set data */
62 void *csp_priv_data; /* CSP-Cent.: In-flight request data */
65 struct mcap_sync_cap_cbdata {
70 struct mcap_sync_set_cbdata {
76 int ts_acc; /* timestamp accuracy */
77 int ts_res; /* timestamp resolution */
78 int latency; /* Read BT clock latency */
79 int preempt_thresh; /* Preemption threshold for latency */
80 int syncleadtime_ms; /* SyncLeadTime in ms */
83 struct sync_set_data {
85 uint32_t sched_btclock;
92 struct mcap_mcl *mcl; /* MCL for this operation */
93 mcap_mcl_connect_cb connect_cb; /* Connect callback */
94 GDestroyNotify destroy; /* Destroy callback */
95 gpointer user_data; /* Callback user data */
99 mcap_mdl_operation_cb op;
100 mcap_mdl_operation_conf_cb op_conf;
101 mcap_mdl_notify_cb notify;
104 struct mcap_mdl_op_cb {
105 struct mcap_mdl *mdl; /* MDL for this operation */
106 mcap_cb_type cb; /* Operation callback */
107 GDestroyNotify destroy; /* Destroy callback */
108 gpointer user_data; /* Callback user data */
111 /* MCAP finite state machine functions */
112 static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
113 static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
114 static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
116 static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = {
122 static gboolean csp_caps_initialized = FALSE;
123 struct csp_caps _caps;
125 static void mcap_cache_mcl(struct mcap_mcl *mcl);
127 static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
129 DBG("MCAP Unmanaged mdl connection");
132 static void default_mdl_closed_cb(struct mcap_mdl *mdl, gpointer data)
134 DBG("MCAP Unmanaged mdl closed");
137 static void default_mdl_deleted_cb(struct mcap_mdl *mdl, gpointer data)
139 DBG("MCAP Unmanaged mdl deleted");
142 static void default_mdl_aborted_cb(struct mcap_mdl *mdl, gpointer data)
144 DBG("MCAP Unmanaged mdl aborted");
147 static uint8_t default_mdl_conn_req_cb(struct mcap_mcl *mcl,
148 uint8_t mdepid, uint16_t mdlid,
149 uint8_t *conf, gpointer data)
151 DBG("MCAP mdl remote connection aborted");
152 /* Due to this callback isn't managed this request won't be supported */
153 return MCAP_REQUEST_NOT_SUPPORTED;
156 static uint8_t default_mdl_reconn_req_cb(struct mcap_mdl *mdl,
159 DBG("MCAP mdl remote reconnection aborted");
160 /* Due to this callback isn't managed this request won't be supported */
161 return MCAP_REQUEST_NOT_SUPPORTED;
164 static void set_default_cb(struct mcap_mcl *mcl)
167 mcl->cb = g_new0(struct mcap_mdl_cb, 1);
169 mcl->cb->mdl_connected = default_mdl_connected_cb;
170 mcl->cb->mdl_closed = default_mdl_closed_cb;
171 mcl->cb->mdl_deleted = default_mdl_deleted_cb;
172 mcl->cb->mdl_aborted = default_mdl_aborted_cb;
173 mcl->cb->mdl_conn_req = default_mdl_conn_req_cb;
174 mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
177 static char *error2str(uint8_t rc)
182 case MCAP_INVALID_OP_CODE:
183 return "Invalid Op Code";
184 case MCAP_INVALID_PARAM_VALUE:
185 return "Invalid Parameter Value";
186 case MCAP_INVALID_MDEP:
187 return "Invalid MDEP";
190 case MCAP_INVALID_MDL:
191 return "Invalid MDL";
194 case MCAP_INVALID_OPERATION:
195 return "Invalid Operation";
196 case MCAP_RESOURCE_UNAVAILABLE:
197 return "Resource Unavailable";
198 case MCAP_UNSPECIFIED_ERROR:
199 return "Unspecified Error";
200 case MCAP_REQUEST_NOT_SUPPORTED:
201 return "Request Not Supported";
202 case MCAP_CONFIGURATION_REJECTED:
203 return "Configuration Rejected";
205 return "Unknown Response Code";
209 static gboolean mcap_send_std_opcode(struct mcap_mcl *mcl, void *cmd,
210 uint32_t size, GError **err)
212 if (mcl->state == MCL_IDLE) {
213 g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
214 "MCL is not connected");
218 if (mcl->req != MCL_AVAILABLE) {
219 g_set_error(err, MCAP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE,
224 if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) {
225 g_set_error(err, MCAP_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED,
226 "Remote does not support standard opcodes");
230 if (mcl->state == MCL_PENDING) {
231 g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_OPERATION,
232 "Not Std Op. Codes can be sent in PENDING State");
236 if (mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), cmd, size) < 0) {
237 g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
238 "Command can't be sent, write error");
243 mcl->req = MCL_WAITING_RSP;
248 static void update_mcl_state(struct mcap_mcl *mcl)
251 struct mcap_mdl *mdl;
253 if (mcl->state == MCL_PENDING)
256 for (l = mcl->mdls; l; l = l->next) {
259 if (mdl->state == MDL_CONNECTED) {
260 mcl->state = MCL_ACTIVE;
265 mcl->state = MCL_CONNECTED;
268 static void shutdown_mdl(struct mcap_mdl *mdl)
270 mdl->state = MDL_CLOSED;
273 g_source_remove(mdl->wid);
278 g_io_channel_shutdown(mdl->dc, TRUE, NULL);
279 g_io_channel_unref(mdl->dc);
284 static void free_mdl(struct mcap_mdl *mdl)
289 mcap_mcl_unref(mdl->mcl);
293 static int cmp_mdl_state(gconstpointer a, gconstpointer b)
295 const struct mcap_mdl *mdl = a;
296 const MDLState *st = b;
298 if (mdl->state == *st)
300 else if (mdl->state < *st)
306 static void free_mcap_mdl_op(struct mcap_mdl_op_cb *op)
309 op->destroy(op->user_data);
312 mcap_mdl_unref(op->mdl);
317 static void free_mcl_priv_data(struct mcap_mcl *mcl)
319 free_mcap_mdl_op(mcl->priv_data);
320 mcl->priv_data = NULL;
323 static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
325 struct mcap_mdl_op_cb *con = mcl->priv_data;
326 struct mcap_mdl *mdl;
330 if (!con || !mcl->lcmd)
333 switch (mcl->lcmd[0]) {
334 case MCAP_MD_CREATE_MDL_REQ:
336 l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
338 mcl->mdls = g_slist_remove(mcl->mdls, mdl);
340 update_mcl_state(mcl);
341 con->cb.op_conf(NULL, 0, err, con->user_data);
343 case MCAP_MD_ABORT_MDL_REQ:
345 l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
346 shutdown_mdl(l->data);
347 update_mcl_state(mcl);
348 con->cb.notify(err, con->user_data);
350 case MCAP_MD_DELETE_MDL_REQ:
351 for (l = mcl->mdls; l; l = l->next) {
353 if (mdl->state == MDL_DELETING)
354 mdl->state = (mdl->dc) ? MDL_CONNECTED :
357 update_mcl_state(mcl);
358 con->cb.notify(err, con->user_data);
360 case MCAP_MD_RECONNECT_MDL_REQ:
362 l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
363 shutdown_mdl(l->data);
364 update_mcl_state(mcl);
365 con->cb.op(NULL, err, con->user_data);
369 free_mcl_priv_data(mcl);
374 int mcap_send_data(int sock, const void *buf, uint32_t size)
376 const uint8_t *buf_b = buf;
379 while (sent < size) {
380 int n = write(sock, buf_b + sent, size - sent);
389 static int mcap_send_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
390 uint16_t mdl, uint8_t *data, size_t len)
398 sock = g_io_channel_unix_get_fd(mcl->cc);
400 cmd = g_malloc(sizeof(mcap_rsp) + len);
403 cmd->mdl = htons(mdl);
406 memcpy(cmd->data, data, len);
408 sent = mcap_send_data(sock, cmd, sizeof(mcap_rsp) + len);
414 static struct mcap_mdl *get_mdl(struct mcap_mcl *mcl, uint16_t mdlid)
417 struct mcap_mdl *mdl;
419 for (l = mcl->mdls; l; l = l->next) {
421 if (mdlid == mdl->mdlid)
428 static uint16_t generate_mdlid(struct mcap_mcl *mcl)
430 uint16_t mdlid = mcl->next_mdl;
431 struct mcap_mdl *mdl;
434 mdl = get_mdl(mcl, mdlid);
436 mcl->next_mdl = (mdlid % MCAP_MDLID_FINAL) + 1;
439 mdlid = (mdlid % MCAP_MDLID_FINAL) + 1;
440 } while (mdlid != mcl->next_mdl);
442 /* No more mdlids availables */
446 static mcap_md_req *create_req(uint8_t op, uint16_t mdl_id)
448 mcap_md_req *req_cmd;
450 req_cmd = g_new0(mcap_md_req, 1);
453 req_cmd->mdl = htons(mdl_id);
458 static mcap_md_create_mdl_req *create_mdl_req(uint16_t mdl_id, uint8_t mdep,
461 mcap_md_create_mdl_req *req_mdl;
463 req_mdl = g_new0(mcap_md_create_mdl_req, 1);
465 req_mdl->op = MCAP_MD_CREATE_MDL_REQ;
466 req_mdl->mdl = htons(mdl_id);
467 req_mdl->mdep = mdep;
468 req_mdl->conf = conf;
473 static int compare_mdl(gconstpointer a, gconstpointer b)
475 const struct mcap_mdl *mdla = a;
476 const struct mcap_mdl *mdlb = b;
478 if (mdla->mdlid == mdlb->mdlid)
480 else if (mdla->mdlid < mdlb->mdlid)
486 static bool wait_response_timer(gpointer data)
488 struct mcap_mcl *mcl = data;
494 g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
495 "Timeout waiting response");
497 mcap_notify_error(mcl, gerr);
500 mcl->mi->mcl_disconnected_cb(mcl, mcl->mi->user_data);
506 gboolean mcap_create_mdl(struct mcap_mcl *mcl,
509 mcap_mdl_operation_conf_cb connect_cb,
511 GDestroyNotify destroy,
514 struct mcap_mdl *mdl;
515 struct mcap_mdl_op_cb *con;
516 mcap_md_create_mdl_req *cmd;
519 id = generate_mdlid(mcl);
521 g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
522 "Not more mdlids available");
526 mdl = g_new0(struct mcap_mdl, 1);
527 mdl->mcl = mcap_mcl_ref(mcl);
529 mdl->mdep_id = mdepid;
530 mdl->state = MDL_WAITING;
532 con = g_new0(struct mcap_mdl_op_cb, 1);
533 con->mdl = mcap_mdl_ref(mdl);
534 con->cb.op_conf = connect_cb;
535 con->destroy = destroy;
536 con->user_data = user_data;
538 cmd = create_mdl_req(id, mdepid, conf);
539 if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_create_mdl_req),
541 mcap_mdl_unref(con->mdl);
547 mcl->state = MCL_ACTIVE;
548 mcl->priv_data = con;
550 mcl->mdls = g_slist_insert_sorted(mcl->mdls, mcap_mdl_ref(mdl),
552 mcl->tid = timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
557 gboolean mcap_reconnect_mdl(struct mcap_mdl *mdl,
558 mcap_mdl_operation_cb reconnect_cb,
560 GDestroyNotify destroy,
563 struct mcap_mdl_op_cb *con;
564 struct mcap_mcl *mcl = mdl->mcl;
567 if (mdl->state != MDL_CLOSED) {
568 g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
569 "MDL is not closed");
573 cmd = create_req(MCAP_MD_RECONNECT_MDL_REQ, mdl->mdlid);
574 if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
579 mdl->state = MDL_WAITING;
581 con = g_new0(struct mcap_mdl_op_cb, 1);
582 con->mdl = mcap_mdl_ref(mdl);
583 con->cb.op = reconnect_cb;
584 con->destroy = destroy;
585 con->user_data = user_data;
587 mcl->state = MCL_ACTIVE;
588 mcl->priv_data = con;
590 mcl->tid = timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
595 static gboolean send_delete_req(struct mcap_mcl *mcl,
596 struct mcap_mdl_op_cb *con,
602 cmd = create_req(MCAP_MD_DELETE_MDL_REQ, mdlid);
603 if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
608 mcl->priv_data = con;
610 mcl->tid = timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
615 gboolean mcap_delete_all_mdls(struct mcap_mcl *mcl,
616 mcap_mdl_notify_cb delete_cb,
618 GDestroyNotify destroy,
622 struct mcap_mdl *mdl;
623 struct mcap_mdl_op_cb *con;
625 DBG("MCL in state: %d", mcl->state);
627 g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
628 "There are not MDLs created");
632 for (l = mcl->mdls; l; l = l->next) {
634 if (mdl->state != MDL_WAITING)
635 mdl->state = MDL_DELETING;
638 con = g_new0(struct mcap_mdl_op_cb, 1);
640 con->cb.notify = delete_cb;
641 con->destroy = destroy;
642 con->user_data = user_data;
645 if (!send_delete_req(mcl, con, MCAP_ALL_MDLIDS, err)) {
653 gboolean mcap_delete_mdl(struct mcap_mdl *mdl, mcap_mdl_notify_cb delete_cb,
655 GDestroyNotify destroy,
658 struct mcap_mcl *mcl= mdl->mcl;
659 struct mcap_mdl_op_cb *con;
662 l = g_slist_find(mcl->mdls, mdl);
665 g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL,
666 "%s" , error2str(MCAP_INVALID_MDEP));
670 if (mdl->state == MDL_WAITING) {
671 g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
672 "Mdl is not created");
676 mdl->state = MDL_DELETING;
678 con = g_new0(struct mcap_mdl_op_cb, 1);
679 con->mdl = mcap_mdl_ref(mdl);
680 con->cb.notify = delete_cb;
681 con->destroy = destroy;
682 con->user_data = user_data;
684 if (!send_delete_req(mcl, con, mdl->mdlid, err)) {
685 mcap_mdl_unref(con->mdl);
693 gboolean mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb,
695 GDestroyNotify destroy,
698 struct mcap_mdl_op_cb *con;
699 struct mcap_mcl *mcl = mdl->mcl;
702 if (mdl->state != MDL_WAITING) {
703 g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
704 "Mdl in invalid state");
708 cmd = create_req(MCAP_MD_ABORT_MDL_REQ, mdl->mdlid);
709 if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) {
714 con = g_new0(struct mcap_mdl_op_cb, 1);
715 con->mdl = mcap_mdl_ref(mdl);
716 con->cb.notify = abort_cb;
717 con->destroy = destroy;
718 con->user_data = user_data;
720 mcl->priv_data = con;
721 mcl->tid = timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
726 static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
728 struct mcap_mcl *mcl;
730 for (; list; list = list->next) {
733 if (!bacmp(&mcl->addr, addr))
740 int mcap_mdl_get_fd(struct mcap_mdl *mdl)
742 if (!mdl || mdl->state != MDL_CONNECTED)
745 return g_io_channel_unix_get_fd(mdl->dc);
748 uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl)
751 return MCAP_MDLID_RESERVED;
756 static void shutdown_mdl_cb(void *data, void *user_data)
761 static void mdl_unref_cb(void *data, void *user_data)
763 mcap_mdl_unref(data);
766 static void close_mcl(struct mcap_mcl *mcl, gboolean cache_requested)
768 gboolean save = ((!(mcl->ctrl & MCAP_CTRL_FREE)) && cache_requested);
773 g_io_channel_shutdown(mcl->cc, TRUE, NULL);
774 g_io_channel_unref(mcl->cc);
779 g_source_remove(mcl->wid);
789 free_mcl_priv_data(mcl);
791 g_slist_foreach(mcl->mdls, shutdown_mdl_cb, NULL);
795 mcl->state = MCL_IDLE;
800 g_slist_foreach(mcl->mdls, mdl_unref_cb, NULL);
801 g_slist_free(mcl->mdls);
805 static void mcap_mcl_shutdown(struct mcap_mcl *mcl)
807 close_mcl(mcl, TRUE);
810 static void mcap_mcl_release(struct mcap_mcl *mcl)
812 close_mcl(mcl, FALSE);
815 static void mcap_cache_mcl(struct mcap_mcl *mcl)
818 struct mcap_mcl *last;
821 if (mcl->ctrl & MCAP_CTRL_CACHED)
824 mcl->mi->mcls = g_slist_remove(mcl->mi->mcls, mcl);
826 if (mcl->ctrl & MCAP_CTRL_NOCACHE) {
827 mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl);
828 mcap_mcl_release(mcl);
835 len = g_slist_length(mcl->mi->cached);
836 if (len == MAX_CACHED) {
837 /* Remove the latest cached mcl */
838 l = g_slist_last(mcl->mi->cached);
840 mcl->mi->cached = g_slist_remove(mcl->mi->cached, last);
841 last->ctrl &= ~MCAP_CTRL_CACHED;
842 if (last->ctrl & MCAP_CTRL_CONN) {
844 * We have to release this MCL if connection is not
847 last->ctrl |= MCAP_CTRL_FREE;
849 mcap_mcl_release(last);
850 last->mi->mcl_uncached_cb(last, last->mi->user_data);
852 mcap_mcl_unref(last);
855 mcl->mi->cached = g_slist_prepend(mcl->mi->cached, mcl);
856 mcl->ctrl |= MCAP_CTRL_CACHED;
857 mcap_mcl_shutdown(mcl);
860 static void mcap_uncache_mcl(struct mcap_mcl *mcl)
862 if (!(mcl->ctrl & MCAP_CTRL_CACHED))
865 DBG("Got MCL from cache");
867 mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl);
868 mcl->mi->mcls = g_slist_prepend(mcl->mi->mcls, mcl);
869 mcl->ctrl &= ~MCAP_CTRL_CACHED;
870 mcl->ctrl &= ~MCAP_CTRL_FREE;
873 void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache)
878 if (mcl->ctrl & MCAP_CTRL_FREE) {
879 mcap_mcl_release(mcl);
884 mcl->ctrl |= MCAP_CTRL_NOCACHE;
887 g_io_channel_shutdown(mcl->cc, TRUE, NULL);
888 g_io_channel_unref(mcl->cc);
890 mcl->state = MCL_IDLE;
891 } else if ((mcl->ctrl & MCAP_CTRL_CACHED) &&
892 (mcl->ctrl & MCAP_CTRL_NOCACHE)) {
893 mcl->ctrl &= ~MCAP_CTRL_CACHED;
894 mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl);
895 mcap_mcl_release(mcl);
900 struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl)
904 DBG("mcap_mcl_ref(%p): ref=%d", mcl, mcl->ref);
909 void mcap_mcl_unref(struct mcap_mcl *mcl)
913 DBG("mcap_mcl_unref(%p): ref=%d", mcl, mcl->ref);
918 mcap_mcl_release(mcl);
919 mcap_instance_unref(mcl->mi);
924 static gboolean parse_set_opts(struct mcap_mdl_cb *mdl_cb, GError **err,
925 McapMclCb cb1, va_list args)
928 struct mcap_mdl_cb *c;
930 c = g_new0(struct mcap_mdl_cb, 1);
932 while (cb != MCAP_MDL_CB_INVALID) {
934 case MCAP_MDL_CB_CONNECTED:
935 c->mdl_connected = va_arg(args, mcap_mdl_event_cb);
937 case MCAP_MDL_CB_CLOSED:
938 c->mdl_closed = va_arg(args, mcap_mdl_event_cb);
940 case MCAP_MDL_CB_DELETED:
941 c->mdl_deleted = va_arg(args, mcap_mdl_event_cb);
943 case MCAP_MDL_CB_ABORTED:
944 c->mdl_aborted = va_arg(args, mcap_mdl_event_cb);
946 case MCAP_MDL_CB_REMOTE_CONN_REQ:
947 c->mdl_conn_req = va_arg(args,
948 mcap_remote_mdl_conn_req_cb);
950 case MCAP_MDL_CB_REMOTE_RECONN_REQ:
951 c->mdl_reconn_req = va_arg(args,
952 mcap_remote_mdl_reconn_req_cb);
954 case MCAP_MDL_CB_INVALID:
956 g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
957 "Unknown option %d", cb);
961 cb = va_arg(args, int);
964 /* Set new callbacks */
965 if (c->mdl_connected)
966 mdl_cb->mdl_connected = c->mdl_connected;
968 mdl_cb->mdl_closed = c->mdl_closed;
970 mdl_cb->mdl_deleted = c->mdl_deleted;
972 mdl_cb->mdl_aborted = c->mdl_aborted;
974 mdl_cb->mdl_conn_req = c->mdl_conn_req;
975 if (c->mdl_reconn_req)
976 mdl_cb->mdl_reconn_req = c->mdl_reconn_req;
983 gboolean mcap_mcl_set_cb(struct mcap_mcl *mcl, gpointer user_data,
984 GError **gerr, McapMclCb cb1, ...)
990 ret = parse_set_opts(mcl->cb, gerr, cb1, args);
996 mcl->cb->user_data = user_data;
1000 void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr)
1002 bacpy(addr, &mcl->addr);
1005 static void mcap_del_mdl(gpointer elem, gpointer user_data)
1007 struct mcap_mdl *mdl = elem;
1008 gboolean notify = *(gboolean *) user_data;
1011 mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data);
1014 mcap_mdl_unref(mdl);
1017 static gboolean check_cmd_req_length(struct mcap_mcl *mcl, void *cmd,
1018 uint32_t rlen, uint32_t explen, uint8_t rspcod)
1023 if (rlen != explen) {
1024 if (rlen >= sizeof(mcap_md_req)) {
1026 mdl_id = ntohs(req->mdl);
1028 /* We can't get mdlid */
1029 mdl_id = MCAP_MDLID_RESERVED;
1031 mcap_send_cmd(mcl, rspcod, MCAP_INVALID_PARAM_VALUE, mdl_id,
1038 static void process_md_create_mdl_req(struct mcap_mcl *mcl, void *cmd,
1041 mcap_md_create_mdl_req *req;
1042 struct mcap_mdl *mdl;
1048 if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_create_mdl_req),
1049 MCAP_MD_CREATE_MDL_RSP))
1053 mdl_id = ntohs(req->mdl);
1054 if (mdl_id < MCAP_MDLID_INITIAL || mdl_id > MCAP_MDLID_FINAL) {
1055 mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL,
1060 mdep_id = req->mdep;
1061 if (mdep_id > MCAP_MDEPID_FINAL) {
1062 mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDEP,
1067 mdl = get_mdl(mcl, mdl_id);
1068 if (mdl && (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING )) {
1070 * Creation request arrives for a MDL that is being managed
1073 mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY,
1078 cfga = conf = req->conf;
1079 /* Callback to upper layer */
1080 rsp = mcl->cb->mdl_conn_req(mcl, mdep_id, mdl_id, &conf,
1081 mcl->cb->user_data);
1082 if (mcl->state == MCL_IDLE) {
1083 /* MCL has been closed int the callback */
1087 if (cfga != 0 && cfga != conf) {
1089 * Remote device set default configuration but upper profile
1090 * has changed it. Protocol Error: force closing the MCL by
1091 * remote device using UNSPECIFIED_ERROR response
1093 mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP,
1094 MCAP_UNSPECIFIED_ERROR, mdl_id, NULL, 0);
1097 if (rsp != MCAP_SUCCESS) {
1098 mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id,
1104 mdl = g_new0(struct mcap_mdl, 1);
1105 mdl->mcl = mcap_mcl_ref(mcl);
1106 mdl->mdlid = mdl_id;
1107 mcl->mdls = g_slist_insert_sorted(mcl->mdls, mcap_mdl_ref(mdl),
1109 } else if (mdl->state == MDL_CONNECTED) {
1111 * MCAP specification says that we should close the MCL if
1112 * it is open when we receive a MD_CREATE_MDL_REQ
1117 mdl->mdep_id = mdep_id;
1118 mdl->state = MDL_WAITING;
1120 mcl->state = MCL_PENDING;
1121 mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id,
1125 static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, void *cmd,
1129 struct mcap_mdl *mdl;
1133 if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
1134 MCAP_MD_RECONNECT_MDL_RSP))
1138 mdl_id = ntohs(req->mdl);
1140 mdl = get_mdl(mcl, mdl_id);
1142 mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_INVALID_MDL,
1145 } else if (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING ) {
1147 * Creation request arrives for a MDL that is being managed
1150 mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_MDL_BUSY,
1155 /* Callback to upper layer */
1156 rsp = mcl->cb->mdl_reconn_req(mdl, mcl->cb->user_data);
1157 if (mcl->state == MCL_IDLE)
1160 if (rsp != MCAP_SUCCESS) {
1161 mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, rsp, mdl_id,
1166 if (mdl->state == MDL_CONNECTED)
1169 mdl->state = MDL_WAITING;
1170 mcl->state = MCL_PENDING;
1171 mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id,
1175 static void process_md_abort_mdl_req(struct mcap_mcl *mcl, void *cmd,
1180 struct mcap_mdl *mdl, *abrt;
1183 if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
1184 MCAP_MD_ABORT_MDL_RSP))
1188 mdl_id = ntohs(req->mdl);
1189 mcl->state = MCL_CONNECTED;
1191 for (l = mcl->mdls; l; l = l->next) {
1193 if (mdl_id == mdl->mdlid && mdl->state == MDL_WAITING) {
1195 if (mcl->state != MCL_CONNECTED)
1199 if (mdl->state == MDL_CONNECTED && mcl->state != MCL_ACTIVE)
1200 mcl->state = MCL_ACTIVE;
1202 if (abrt && mcl->state == MCL_ACTIVE)
1207 mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL,
1212 mcl->cb->mdl_aborted(abrt, mcl->cb->user_data);
1213 abrt->state = MDL_CLOSED;
1214 mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_SUCCESS, mdl_id,
1218 static void process_md_delete_mdl_req(struct mcap_mcl *mcl, void *cmd,
1222 struct mcap_mdl *mdl, *aux;
1227 if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req),
1228 MCAP_MD_DELETE_MDL_RSP))
1232 mdlid = ntohs(req->mdl);
1233 if (mdlid == MCAP_ALL_MDLIDS) {
1235 g_slist_foreach(mcl->mdls, mcap_del_mdl, ¬ify);
1236 g_slist_free(mcl->mdls);
1238 mcl->state = MCL_CONNECTED;
1242 if (mdlid < MCAP_MDLID_INITIAL || mdlid > MCAP_MDLID_FINAL) {
1243 mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL,
1248 for (l = mcl->mdls, mdl = NULL; l; l = l->next) {
1250 if (aux->mdlid == mdlid) {
1256 if (!mdl || mdl->state == MDL_WAITING) {
1257 mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL,
1262 mcl->mdls = g_slist_remove(mcl->mdls, mdl);
1263 update_mcl_state(mcl);
1265 mcap_del_mdl(mdl, ¬ify);
1268 mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid,
1272 static void invalid_req_state(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1276 error("Invalid cmd received (op code = %d) in state %d", cmd[0],
1279 * Get previously mdlid sent to generate an appropriate
1280 * response if it is possible
1282 mdlr = len < sizeof(mcap_md_req) ? MCAP_MDLID_RESERVED :
1283 ntohs(((mcap_md_req *) cmd)->mdl);
1284 mcap_send_cmd(mcl, cmd[0]+1, MCAP_INVALID_OPERATION, mdlr, NULL, 0);
1287 /* Function used to process commands depending of MCL state */
1288 static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1291 case MCAP_MD_CREATE_MDL_REQ:
1292 process_md_create_mdl_req(mcl, cmd, len);
1294 case MCAP_MD_RECONNECT_MDL_REQ:
1295 process_md_reconnect_mdl_req(mcl, cmd, len);
1297 case MCAP_MD_DELETE_MDL_REQ:
1298 process_md_delete_mdl_req(mcl, cmd, len);
1301 invalid_req_state(mcl, cmd, len);
1305 static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1307 if (cmd[0] == MCAP_MD_ABORT_MDL_REQ)
1308 process_md_abort_mdl_req(mcl, cmd, len);
1310 invalid_req_state(mcl, cmd, len);
1313 static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1316 case MCAP_MD_CREATE_MDL_REQ:
1317 process_md_create_mdl_req(mcl, cmd, len);
1319 case MCAP_MD_RECONNECT_MDL_REQ:
1320 process_md_reconnect_mdl_req(mcl, cmd, len);
1322 case MCAP_MD_DELETE_MDL_REQ:
1323 process_md_delete_mdl_req(mcl, cmd, len);
1326 invalid_req_state(mcl, cmd, len);
1330 /* Function used to process replies */
1331 static gboolean check_err_rsp(struct mcap_mcl *mcl, mcap_rsp *rsp,
1332 uint32_t rlen, uint32_t len, GError **gerr)
1334 mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
1335 int err = MCAP_ERROR_FAILED;
1336 gboolean close = FALSE;
1339 if (rsp->op == MCAP_ERROR_RSP) {
1340 msg = "MCAP_ERROR_RSP received";
1345 /* Check if the response matches with the last request */
1346 if (rlen < sizeof(mcap_rsp) || (mcl->lcmd[0] + 1) != rsp->op) {
1347 msg = "Protocol error";
1353 msg = "Protocol error";
1358 if (rsp->mdl != cmdlast->mdl) {
1359 msg = "MDLID received doesn't match with MDLID sent";
1364 if (rsp->rc == MCAP_REQUEST_NOT_SUPPORTED) {
1365 msg = "Remote does not support opcodes";
1366 mcl->ctrl &= ~MCAP_CTRL_STD_OP;
1370 if (rsp->rc == MCAP_UNSPECIFIED_ERROR) {
1371 msg = "Unspecified error";
1376 if (rsp->rc != MCAP_SUCCESS) {
1377 msg = error2str(rsp->rc);
1385 g_set_error(gerr, MCAP_ERROR, err, "%s", msg);
1389 static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl,
1390 mcap_rsp *rsp, uint32_t len)
1392 mcap_md_create_mdl_req *cmdlast = (mcap_md_create_mdl_req *) mcl->lcmd;
1393 struct mcap_mdl_op_cb *conn = mcl->priv_data;
1394 mcap_mdl_operation_conf_cb connect_cb = conn->cb.op_conf;
1395 gpointer user_data = conn->user_data;
1396 struct mcap_mdl *mdl = conn->mdl;
1397 uint8_t conf = cmdlast->conf;
1399 GError *gerr = NULL;
1401 close = check_err_rsp(mcl, rsp, len, sizeof(mcap_rsp) + 1, &gerr);
1404 mcl->req = MCL_AVAILABLE;
1409 /* Check if preferences changed */
1410 if (conf != 0x00 && rsp->data[0] != conf) {
1411 g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
1412 "Configuration changed");
1417 connect_cb(mdl, rsp->data[0], gerr, user_data);
1421 connect_cb(NULL, 0, gerr, user_data);
1422 mcl->mdls = g_slist_remove(mcl->mdls, mdl);
1423 mcap_mdl_unref(mdl);
1425 update_mcl_state(mcl);
1429 static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
1430 mcap_rsp *rsp, uint32_t len)
1432 struct mcap_mdl_op_cb *reconn = mcl->priv_data;
1433 mcap_mdl_operation_cb reconn_cb = reconn->cb.op;
1434 gpointer user_data = reconn->user_data;
1435 struct mcap_mdl *mdl = reconn->mdl;
1436 GError *gerr = NULL;
1439 close = check_err_rsp(mcl, rsp, len, sizeof(mcap_rsp), &gerr);
1443 mcl->req = MCL_AVAILABLE;
1445 reconn_cb(mdl, gerr, user_data);
1451 update_mcl_state(mcl);
1453 if (rsp->rc != MCAP_INVALID_MDL)
1456 /* Remove cached mdlid */
1457 mcl->mdls = g_slist_remove(mcl->mdls, mdl);
1458 mcl->cb->mdl_deleted(mdl, mcl->cb->user_data);
1459 mcap_mdl_unref(mdl);
1464 static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
1465 mcap_rsp *rsp, uint32_t len)
1467 struct mcap_mdl_op_cb *abrt = mcl->priv_data;
1468 mcap_mdl_notify_cb abrt_cb = abrt->cb.notify;
1469 gpointer user_data = abrt->user_data;
1470 struct mcap_mdl *mdl = abrt->mdl;
1471 GError *gerr = NULL;
1474 close = check_err_rsp(mcl, rsp, len, sizeof(mcap_rsp), &gerr);
1478 mcl->req = MCL_AVAILABLE;
1480 abrt_cb(gerr, user_data);
1483 if (len >= sizeof(mcap_rsp) && rsp->rc == MCAP_INVALID_MDL) {
1484 mcl->mdls = g_slist_remove(mcl->mdls, mdl);
1485 mcl->cb->mdl_deleted(mdl, mcl->cb->user_data);
1486 mcap_mdl_unref(mdl);
1492 update_mcl_state(mcl);
1497 static void restore_mdl(gpointer elem, gpointer data)
1499 struct mcap_mdl *mdl = elem;
1501 if (mdl->state == MDL_DELETING) {
1503 mdl->state = MDL_CONNECTED;
1505 mdl->state = MDL_CLOSED;
1506 } else if (mdl->state == MDL_CLOSED)
1507 mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data);
1510 static void check_mdl_del_err(struct mcap_mdl *mdl, mcap_rsp *rsp)
1512 if (rsp->rc != MCAP_ERROR_INVALID_MDL) {
1513 restore_mdl(mdl, NULL);
1517 /* MDL does not exist in remote side, we can delete it */
1518 mdl->mcl->mdls = g_slist_remove(mdl->mcl->mdls, mdl);
1519 mcap_mdl_unref(mdl);
1522 static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, mcap_rsp *rsp,
1525 struct mcap_mdl_op_cb *del = mcl->priv_data;
1526 struct mcap_mdl *mdl = del->mdl;
1527 mcap_mdl_notify_cb deleted_cb = del->cb.notify;
1528 gpointer user_data = del->user_data;
1529 mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
1530 uint16_t mdlid = ntohs(cmdlast->mdl);
1531 GError *gerr = NULL;
1533 gboolean notify = FALSE;
1535 close = check_err_rsp(mcl, rsp, len, sizeof(mcap_rsp), &gerr);
1539 mcl->req = MCL_AVAILABLE;
1543 check_mdl_del_err(mdl, rsp);
1545 g_slist_foreach(mcl->mdls, restore_mdl, NULL);
1546 deleted_cb(gerr, user_data);
1551 if (mdlid == MCAP_ALL_MDLIDS) {
1552 g_slist_foreach(mcl->mdls, mcap_del_mdl, ¬ify);
1553 g_slist_free(mcl->mdls);
1555 mcl->state = MCL_CONNECTED;
1557 mcl->mdls = g_slist_remove(mcl->mdls, mdl);
1558 update_mcl_state(mcl);
1559 mcap_del_mdl(mdl, ¬ify);
1562 deleted_cb(gerr, user_data);
1567 static void post_process_rsp(struct mcap_mcl *mcl, struct mcap_mdl_op_cb *op)
1569 if (mcl->priv_data != op) {
1571 * Queued MCAP request in some callback.
1572 * We should not delete the mcl private data
1574 free_mcap_mdl_op(op);
1577 * This is not a queued request. It's safe
1578 * delete the mcl private data here.
1580 free_mcl_priv_data(mcl);
1584 static void proc_response(struct mcap_mcl *mcl, void *buf, uint32_t len)
1586 struct mcap_mdl_op_cb *op = mcl->priv_data;
1587 mcap_rsp *rsp = buf;
1592 switch (mcl->lcmd[0] + 1) {
1593 case MCAP_MD_CREATE_MDL_RSP:
1594 close = process_md_create_mdl_rsp(mcl, rsp, len);
1595 post_process_rsp(mcl, op);
1597 case MCAP_MD_RECONNECT_MDL_RSP:
1598 close = process_md_reconnect_mdl_rsp(mcl, rsp, len);
1599 post_process_rsp(mcl, op);
1601 case MCAP_MD_ABORT_MDL_RSP:
1602 close = process_md_abort_mdl_rsp(mcl, rsp, len);
1603 post_process_rsp(mcl, op);
1605 case MCAP_MD_DELETE_MDL_RSP:
1606 close = process_md_delete_mdl_rsp(mcl, rsp, len);
1607 post_process_rsp(mcl, op);
1610 DBG("Unknown cmd response received (op code = %d)", rsp->op);
1616 mcl->mi->mcl_disconnected_cb(mcl, mcl->mi->user_data);
1617 mcap_cache_mcl(mcl);
1621 static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
1623 GError *gerr = NULL;
1625 if (cmd[0] > MCAP_MD_SYNC_INFO_IND ||
1626 (cmd[0] > MCAP_MD_DELETE_MDL_RSP &&
1627 cmd[0] < MCAP_MD_SYNC_CAP_REQ)) {
1628 error("Unknown cmd received (op code = %d)", cmd[0]);
1629 mcap_send_cmd(mcl, MCAP_ERROR_RSP, MCAP_INVALID_OP_CODE,
1630 MCAP_MDLID_RESERVED, NULL, 0);
1634 if (cmd[0] >= MCAP_MD_SYNC_CAP_REQ &&
1635 cmd[0] <= MCAP_MD_SYNC_INFO_IND) {
1636 proc_sync_cmd(mcl, cmd, len);
1640 if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) {
1641 /* In case the remote device doesn't work correctly */
1642 error("Remote device does not support opcodes, cmd ignored");
1646 if (mcl->req == MCL_WAITING_RSP) {
1647 if (cmd[0] & 0x01) {
1648 /* Request arrived when a response is expected */
1649 if (mcl->role == MCL_INITIATOR)
1652 /* Initiator will ignore our last request */
1654 mcl->req = MCL_AVAILABLE;
1655 g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_REQ_IGNORED,
1656 "Initiator sent a request with more priority");
1657 mcap_notify_error(mcl, gerr);
1658 proc_req[mcl->state](mcl, cmd, len);
1661 proc_response(mcl, cmd, len);
1662 } else if (cmd[0] & 0x01)
1663 proc_req[mcl->state](mcl, cmd, len);
1666 static gboolean mdl_event_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
1669 struct mcap_mdl *mdl = data;
1672 DBG("Close MDL %d", mdl->mdlid);
1674 notify = (mdl->state == MDL_CONNECTED);
1677 update_mcl_state(mdl->mcl);
1680 /*Callback to upper layer */
1681 mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data);
1687 static void mcap_connect_mdl_cb(GIOChannel *chan, GError *conn_err,
1690 struct mcap_mdl_op_cb *con = data;
1691 struct mcap_mdl *mdl = con->mdl;
1692 mcap_mdl_operation_cb cb = con->cb.op;
1693 gpointer user_data = con->user_data;
1695 DBG("mdl connect callback");
1698 DBG("ERROR: mdl connect callback");
1699 mdl->state = MDL_CLOSED;
1700 g_io_channel_unref(mdl->dc);
1702 cb(mdl, conn_err, user_data);
1706 mdl->state = MDL_CONNECTED;
1707 mdl->wid = g_io_add_watch_full(mdl->dc, G_PRIORITY_DEFAULT,
1708 G_IO_ERR | G_IO_HUP | G_IO_NVAL,
1709 (GIOFunc) mdl_event_cb,
1711 (GDestroyNotify) mcap_mdl_unref);
1713 cb(mdl, conn_err, user_data);
1716 gboolean mcap_connect_mdl(struct mcap_mdl *mdl, uint8_t mode,
1718 mcap_mdl_operation_cb connect_cb,
1720 GDestroyNotify destroy,
1723 struct mcap_mdl_op_cb *con;
1725 if (mdl->state != MDL_WAITING) {
1726 g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL,
1727 "%s", error2str(MCAP_INVALID_MDL));
1731 if ((mode != BT_IO_MODE_ERTM) && (mode != BT_IO_MODE_STREAMING)) {
1732 g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
1733 "Invalid MDL configuration");
1737 con = g_new0(struct mcap_mdl_op_cb, 1);
1738 con->mdl = mcap_mdl_ref(mdl);
1739 con->cb.op = connect_cb;
1740 con->destroy = destroy;
1741 con->user_data = user_data;
1743 mdl->dc = bt_io_connect(mcap_connect_mdl_cb, con,
1744 (GDestroyNotify) free_mcap_mdl_op, err,
1745 BT_IO_OPT_SOURCE_BDADDR, &mdl->mcl->mi->src,
1746 BT_IO_OPT_DEST_BDADDR, &mdl->mcl->addr,
1747 BT_IO_OPT_PSM, dcpsm,
1748 BT_IO_OPT_MTU, MCAP_DC_MTU,
1749 BT_IO_OPT_SEC_LEVEL, mdl->mcl->mi->sec,
1750 BT_IO_OPT_MODE, mode,
1753 DBG("MDL Connection error");
1754 mdl->state = MDL_CLOSED;
1755 mcap_mdl_unref(con->mdl);
1763 static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
1766 GError *gerr = NULL;
1767 struct mcap_mcl *mcl = data;
1769 uint8_t buf[MCAP_CC_MTU];
1771 if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
1774 sk = g_io_channel_unix_get_fd(chan);
1775 len = read(sk, buf, sizeof(buf));
1779 proc_cmd(mcl, buf, (uint32_t) len);
1783 if (mcl->state != MCL_IDLE) {
1784 if (mcl->req == MCL_WAITING_RSP) {
1785 /* notify error in pending callback */
1786 g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_MCL_CLOSED,
1788 mcap_notify_error(mcl, gerr);
1791 mcl->mi->mcl_disconnected_cb(mcl, mcl->mi->user_data);
1793 mcap_cache_mcl(mcl);
1797 static void mcap_connect_mcl_cb(GIOChannel *chan, GError *conn_err,
1801 struct connect_mcl *con = user_data;
1802 struct mcap_mcl *aux, *mcl = con->mcl;
1803 mcap_mcl_connect_cb connect_cb = con->connect_cb;
1804 gpointer data = con->user_data;
1805 GError *gerr = NULL;
1807 mcl->ctrl &= ~MCAP_CTRL_CONN;
1810 if (mcl->ctrl & MCAP_CTRL_FREE) {
1811 mcap_mcl_release(mcl);
1812 mcl->mi->mcl_uncached_cb(mcl, mcl->mi->user_data);
1814 connect_cb(NULL, conn_err, data);
1818 ba2str(&mcl->addr, dstaddr);
1820 aux = find_mcl(mcl->mi->mcls, &mcl->addr);
1822 /* Double MCL connection case */
1823 error("MCL error: Device %s is already connected", dstaddr);
1824 g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS,
1825 "MCL %s is already connected", dstaddr);
1826 connect_cb(NULL, gerr, data);
1831 mcl->state = MCL_CONNECTED;
1832 mcl->role = MCL_INITIATOR;
1833 mcl->req = MCL_AVAILABLE;
1834 mcl->ctrl |= MCAP_CTRL_STD_OP;
1836 mcap_sync_init(mcl);
1838 if (mcl->ctrl & MCAP_CTRL_CACHED)
1839 mcap_uncache_mcl(mcl);
1841 mcl->ctrl &= ~MCAP_CTRL_FREE;
1842 mcl->mi->mcls = g_slist_prepend(mcl->mi->mcls,
1846 mcl->wid = g_io_add_watch_full(mcl->cc, G_PRIORITY_DEFAULT,
1847 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
1848 (GIOFunc) mcl_control_cb,
1850 (GDestroyNotify) mcap_mcl_unref);
1851 connect_cb(mcl, gerr, data);
1854 static void set_mdl_properties(GIOChannel *chan, struct mcap_mdl *mdl)
1856 struct mcap_mcl *mcl = mdl->mcl;
1858 mdl->state = MDL_CONNECTED;
1859 mdl->dc = g_io_channel_ref(chan);
1860 mdl->wid = g_io_add_watch_full(mdl->dc, G_PRIORITY_DEFAULT,
1861 G_IO_ERR | G_IO_HUP | G_IO_NVAL,
1862 (GIOFunc) mdl_event_cb,
1864 (GDestroyNotify) mcap_mdl_unref);
1866 mcl->state = MCL_ACTIVE;
1867 mcl->cb->mdl_connected(mdl, mcl->cb->user_data);
1870 static void mcl_io_destroy(gpointer data)
1872 struct connect_mcl *con = data;
1874 mcap_mcl_unref(con->mcl);
1876 con->destroy(con->user_data);
1880 gboolean mcap_create_mcl(struct mcap_instance *mi,
1881 const bdaddr_t *addr,
1883 mcap_mcl_connect_cb connect_cb,
1885 GDestroyNotify destroy,
1888 struct mcap_mcl *mcl;
1889 struct connect_mcl *con;
1892 mcl = find_mcl(mi->mcls, addr);
1894 g_set_error(err, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS,
1895 "MCL is already connected.");
1899 mcl = find_mcl(mi->cached, addr);
1901 mcl = g_new0(struct mcap_mcl, 1);
1902 mcl->mi = mcap_instance_ref(mi);
1903 mcl->state = MCL_IDLE;
1904 bacpy(&mcl->addr, addr);
1905 set_default_cb(mcl);
1906 if (getrandom(&val, sizeof(val), 0) < 0) {
1907 mcap_instance_unref(mcl->mi);
1911 mcl->next_mdl = (val % MCAP_MDLID_FINAL) + 1;
1914 mcl->ctrl |= MCAP_CTRL_CONN;
1916 con = g_new0(struct connect_mcl, 1);
1917 con->mcl = mcap_mcl_ref(mcl);
1918 con->connect_cb = connect_cb;
1919 con->destroy = destroy;
1920 con->user_data = user_data;
1922 mcl->cc = bt_io_connect(mcap_connect_mcl_cb, con,
1923 mcl_io_destroy, err,
1924 BT_IO_OPT_SOURCE_BDADDR, &mi->src,
1925 BT_IO_OPT_DEST_BDADDR, addr,
1926 BT_IO_OPT_PSM, ccpsm,
1927 BT_IO_OPT_MTU, MCAP_CC_MTU,
1928 BT_IO_OPT_SEC_LEVEL, mi->sec,
1929 BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
1932 mcl->ctrl &= ~MCAP_CTRL_CONN;
1933 if (mcl->ctrl & MCAP_CTRL_FREE) {
1934 mcap_mcl_release(mcl);
1935 mcl->mi->mcl_uncached_cb(mcl, mcl->mi->user_data);
1937 mcap_mcl_unref(con->mcl);
1945 static void connect_dc_event_cb(GIOChannel *chan, GError *gerr,
1948 struct mcap_instance *mi = user_data;
1949 struct mcap_mcl *mcl;
1950 struct mcap_mdl *mdl;
1958 bt_io_get(chan, &err, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_INVALID);
1960 error("%s", err->message);
1965 mcl = find_mcl(mi->mcls, &dst);
1966 if (!mcl || mcl->state != MCL_PENDING)
1969 for (l = mcl->mdls; l; l = l->next) {
1971 if (mdl->state == MDL_WAITING) {
1972 set_mdl_properties(chan, mdl);
1978 g_io_channel_shutdown(chan, TRUE, NULL);
1981 static void set_mcl_conf(GIOChannel *chan, struct mcap_mcl *mcl)
1985 mcl->state = MCL_CONNECTED;
1986 mcl->role = MCL_ACCEPTOR;
1987 mcl->req = MCL_AVAILABLE;
1988 mcl->cc = g_io_channel_ref(chan);
1989 mcl->ctrl |= MCAP_CTRL_STD_OP;
1991 mcap_sync_init(mcl);
1993 reconn = (mcl->ctrl & MCAP_CTRL_CACHED);
1995 mcap_uncache_mcl(mcl);
1997 mcl->mi->mcls = g_slist_prepend(mcl->mi->mcls,
2000 mcl->wid = g_io_add_watch_full(mcl->cc, G_PRIORITY_DEFAULT,
2001 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
2002 (GIOFunc) mcl_control_cb,
2004 (GDestroyNotify) mcap_mcl_unref);
2006 /* Callback to report new MCL */
2008 mcl->mi->mcl_reconnected_cb(mcl, mcl->mi->user_data);
2010 mcl->mi->mcl_connected_cb(mcl, mcl->mi->user_data);
2013 static void connect_mcl_event_cb(GIOChannel *chan, GError *gerr,
2016 struct mcap_instance *mi = user_data;
2017 struct mcap_mcl *mcl;
2019 char address[18], srcstr[18];
2026 bt_io_get(chan, &err,
2027 BT_IO_OPT_DEST_BDADDR, &dst,
2028 BT_IO_OPT_DEST, address,
2031 error("%s", err->message);
2036 ba2str(&mi->src, srcstr);
2037 mcl = find_mcl(mi->mcls, &dst);
2039 error("Control channel already created with %s on adapter %s",
2044 mcl = find_mcl(mi->cached, &dst);
2046 mcl = g_new0(struct mcap_mcl, 1);
2047 mcl->mi = mcap_instance_ref(mi);
2048 bacpy(&mcl->addr, &dst);
2049 set_default_cb(mcl);
2050 if (getrandom(&val, sizeof(val), 0) < 0) {
2051 mcap_instance_unref(mcl->mi);
2055 mcl->next_mdl = (val % MCAP_MDLID_FINAL) + 1;
2058 set_mcl_conf(chan, mcl);
2062 g_io_channel_shutdown(chan, TRUE, NULL);
2065 struct mcap_instance *mcap_create_instance(const bdaddr_t *src,
2069 mcap_mcl_event_cb mcl_connected,
2070 mcap_mcl_event_cb mcl_reconnected,
2071 mcap_mcl_event_cb mcl_disconnected,
2072 mcap_mcl_event_cb mcl_uncached,
2073 mcap_info_ind_event_cb mcl_sync_info_ind,
2077 struct mcap_instance *mi;
2079 if (sec < BT_IO_SEC_MEDIUM) {
2080 g_set_error(gerr, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
2081 "Security level can't be minor of %d",
2086 if (!(mcl_connected && mcl_reconnected &&
2087 mcl_disconnected && mcl_uncached)) {
2088 g_set_error(gerr, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
2089 "The callbacks can't be null");
2093 mi = g_new0(struct mcap_instance, 1);
2095 bacpy(&mi->src, src);
2098 mi->mcl_connected_cb = mcl_connected;
2099 mi->mcl_reconnected_cb = mcl_reconnected;
2100 mi->mcl_disconnected_cb = mcl_disconnected;
2101 mi->mcl_uncached_cb = mcl_uncached;
2102 mi->mcl_sync_infoind_cb = mcl_sync_info_ind;
2103 mi->user_data = user_data;
2104 mi->csp_enabled = FALSE;
2106 /* Listen incoming connections in control channel */
2107 mi->ccio = bt_io_listen(connect_mcl_event_cb, NULL, mi,
2109 BT_IO_OPT_SOURCE_BDADDR, &mi->src,
2110 BT_IO_OPT_PSM, ccpsm,
2111 BT_IO_OPT_MTU, MCAP_CC_MTU,
2112 BT_IO_OPT_SEC_LEVEL, sec,
2113 BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
2116 error("%s", (*gerr)->message);
2121 /* Listen incoming connections in data channels */
2122 mi->dcio = bt_io_listen(connect_dc_event_cb, NULL, mi,
2124 BT_IO_OPT_SOURCE_BDADDR, &mi->src,
2125 BT_IO_OPT_PSM, dcpsm,
2126 BT_IO_OPT_MTU, MCAP_DC_MTU,
2127 BT_IO_OPT_SEC_LEVEL, sec,
2130 g_io_channel_shutdown(mi->ccio, TRUE, NULL);
2131 g_io_channel_unref(mi->ccio);
2133 error("%s", (*gerr)->message);
2138 /* Initialize random seed to generate mdlids for this instance */
2141 return mcap_instance_ref(mi);
2144 void mcap_release_instance(struct mcap_instance *mi)
2152 g_io_channel_shutdown(mi->ccio, TRUE, NULL);
2153 g_io_channel_unref(mi->ccio);
2158 g_io_channel_shutdown(mi->dcio, TRUE, NULL);
2159 g_io_channel_unref(mi->dcio);
2163 for (l = mi->mcls; l; l = l->next) {
2164 mcap_mcl_release(l->data);
2165 mcap_mcl_unref(l->data);
2168 g_slist_free(mi->mcls);
2171 for (l = mi->cached; l; l = l->next) {
2172 mcap_mcl_release(l->data);
2173 mcap_mcl_unref(l->data);
2176 g_slist_free(mi->cached);
2180 struct mcap_instance *mcap_instance_ref(struct mcap_instance *mi)
2184 DBG("mcap_instance_ref(%p): ref=%d", mi, mi->ref);
2189 void mcap_instance_unref(struct mcap_instance *mi)
2193 DBG("mcap_instance_unref(%p): ref=%d", mi, mi->ref);
2198 mcap_release_instance(mi);
2202 uint16_t mcap_get_ctrl_psm(struct mcap_instance *mi, GError **err)
2206 if (!(mi && mi->ccio)) {
2207 g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
2208 "Invalid MCAP instance");
2212 if (!bt_io_get(mi->ccio, err, BT_IO_OPT_PSM, &lpsm, BT_IO_OPT_INVALID))
2218 uint16_t mcap_get_data_psm(struct mcap_instance *mi, GError **err)
2222 if (!(mi && mi->dcio)) {
2223 g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
2224 "Invalid MCAP instance");
2228 if (!bt_io_get(mi->dcio, err, BT_IO_OPT_PSM, &lpsm, BT_IO_OPT_INVALID))
2234 gboolean mcap_set_data_chan_mode(struct mcap_instance *mi, uint8_t mode,
2237 if (!(mi && mi->dcio)) {
2238 g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
2239 "Invalid MCAP instance");
2243 return bt_io_set(mi->dcio, err, BT_IO_OPT_MODE, mode,
2247 struct mcap_mdl *mcap_mdl_ref(struct mcap_mdl *mdl)
2251 DBG("mcap_mdl_ref(%p): ref=%d", mdl, mdl->ref);
2256 void mcap_mdl_unref(struct mcap_mdl *mdl)
2260 DBG("mcap_mdl_unref(%p): ref=%d", mdl, mdl->ref);
2269 static int send_sync_cmd(struct mcap_mcl *mcl, const void *buf, uint32_t size)
2273 if (mcl->cc == NULL)
2276 sock = g_io_channel_unix_get_fd(mcl->cc);
2277 return mcap_send_data(sock, buf, size);
2280 static int send_unsupported_cap_req(struct mcap_mcl *mcl)
2282 mcap_md_sync_cap_rsp *cmd;
2285 cmd = g_new0(mcap_md_sync_cap_rsp, 1);
2286 cmd->op = MCAP_MD_SYNC_CAP_RSP;
2287 cmd->rc = MCAP_REQUEST_NOT_SUPPORTED;
2289 sent = send_sync_cmd(mcl, cmd, sizeof(*cmd));
2295 static int send_unsupported_set_req(struct mcap_mcl *mcl)
2297 mcap_md_sync_set_rsp *cmd;
2300 cmd = g_new0(mcap_md_sync_set_rsp, 1);
2301 cmd->op = MCAP_MD_SYNC_SET_RSP;
2302 cmd->rc = MCAP_REQUEST_NOT_SUPPORTED;
2304 sent = send_sync_cmd(mcl, cmd, sizeof(*cmd));
2310 static void reset_tmstamp(struct mcap_csp *csp, struct timespec *base_time,
2311 uint64_t new_tmstamp)
2313 csp->base_tmstamp = new_tmstamp;
2315 csp->base_time = *base_time;
2317 clock_gettime(CLK, &csp->base_time);
2320 void mcap_sync_init(struct mcap_mcl *mcl)
2322 if (!mcl->mi->csp_enabled) {
2327 mcl->csp = g_new0(struct mcap_csp, 1);
2329 mcl->csp->rem_req_acc = 10000; /* safe divisor */
2330 mcl->csp->set_data = NULL;
2331 mcl->csp->csp_priv_data = NULL;
2333 reset_tmstamp(mcl->csp, NULL, 0);
2336 void mcap_sync_stop(struct mcap_mcl *mcl)
2341 if (mcl->csp->ind_timer)
2342 g_source_remove(mcl->csp->ind_timer);
2344 if (mcl->csp->set_timer)
2345 g_source_remove(mcl->csp->set_timer);
2347 if (mcl->csp->set_data)
2348 g_free(mcl->csp->set_data);
2350 if (mcl->csp->csp_priv_data)
2351 g_free(mcl->csp->csp_priv_data);
2353 mcl->csp->ind_timer = 0;
2354 mcl->csp->set_timer = 0;
2355 mcl->csp->set_data = NULL;
2356 mcl->csp->csp_priv_data = NULL;
2362 static uint64_t time_us(struct timespec *tv)
2364 return tv->tv_sec * 1000000ll + tv->tv_nsec / 1000ll;
2367 static int64_t bt2us(int bt)
2372 static int bt2ms(int bt)
2374 return bt * 312.5 / 1000;
2377 static int btoffset(uint32_t btclk1, uint32_t btclk2)
2379 int offset = btclk2 - btclk1;
2381 if (offset <= -MCAP_BTCLOCK_HALF)
2382 offset += MCAP_BTCLOCK_FIELD;
2383 else if (offset > MCAP_BTCLOCK_HALF)
2384 offset -= MCAP_BTCLOCK_FIELD;
2389 static int btdiff(uint32_t btclk1, uint32_t btclk2)
2391 return btoffset(btclk1, btclk2);
2394 static gboolean valid_btclock(uint32_t btclk)
2396 return btclk <= MCAP_BTCLOCK_MAX;
2399 /* This call may fail; either deal with retry or use read_btclock_retry */
2400 static gboolean read_btclock(struct mcap_mcl *mcl, uint32_t *btclock,
2401 uint16_t *btaccuracy)
2404 * FIXME: btd_adapter_read_clock(...) always return FALSE, current
2405 * code doesn't support CSP (Clock Synchronization Protocol). To avoid
2406 * build dependancy on struct 'btd_adapter', removing this code.
2412 static gboolean read_btclock_retry(struct mcap_mcl *mcl, uint32_t *btclock,
2413 uint16_t *btaccuracy)
2417 while (--retries >= 0) {
2418 if (read_btclock(mcl, btclock, btaccuracy))
2420 DBG("CSP: retrying to read bt clock...");
2426 static gboolean get_btrole(struct mcap_mcl *mcl)
2431 if (mcl->cc == NULL)
2434 sock = g_io_channel_unix_get_fd(mcl->cc);
2435 len = sizeof(flags);
2437 if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, &len))
2438 DBG("CSP: could not read role");
2440 return flags & L2CAP_LM_MASTER;
2443 uint64_t mcap_get_timestamp(struct mcap_mcl *mcl,
2444 struct timespec *given_time)
2446 struct timespec now;
2450 return MCAP_TMSTAMP_DONTSET;
2455 if (clock_gettime(CLK, &now) < 0)
2456 return MCAP_TMSTAMP_DONTSET;
2458 tmstamp = time_us(&now) - time_us(&mcl->csp->base_time)
2459 + mcl->csp->base_tmstamp;
2464 uint32_t mcap_get_btclock(struct mcap_mcl *mcl)
2470 return MCAP_BTCLOCK_IMMEDIATE;
2472 if (!read_btclock_retry(mcl, &btclock, &accuracy))
2473 btclock = 0xffffffff;
2478 static gboolean initialize_caps(struct mcap_mcl *mcl)
2480 struct timespec t1, t2;
2481 int latencies[SAMPLE_COUNT];
2482 int latency, avg, dev;
2484 uint16_t btaccuracy;
2488 clock_getres(CLK, &t1);
2490 _caps.ts_res = time_us(&t1);
2491 if (_caps.ts_res < 1)
2494 _caps.ts_acc = 20; /* ppm, estimated */
2496 /* A little exercise before measuing latency */
2497 clock_gettime(CLK, &t1);
2498 read_btclock_retry(mcl, &btclock, &btaccuracy);
2500 /* Read clock a number of times and measure latency */
2503 retries = MAX_RETRIES;
2504 while (i < SAMPLE_COUNT && retries > 0) {
2505 clock_gettime(CLK, &t1);
2506 if (!read_btclock(mcl, &btclock, &btaccuracy)) {
2510 clock_gettime(CLK, &t2);
2512 latency = time_us(&t2) - time_us(&t1);
2513 latencies[i] = latency;
2521 /* Calculate average and deviation */
2522 avg /= SAMPLE_COUNT;
2524 for (i = 0; i < SAMPLE_COUNT; ++i)
2525 dev += abs(latencies[i] - avg);
2526 dev /= SAMPLE_COUNT;
2528 /* Calculate corrected average, without 'freak' latencies */
2530 for (i = 0; i < SAMPLE_COUNT; ++i) {
2531 if (latencies[i] > (avg + dev * 6))
2534 latency += latencies[i];
2536 latency /= SAMPLE_COUNT;
2538 _caps.latency = latency;
2539 _caps.preempt_thresh = latency * 4;
2540 _caps.syncleadtime_ms = latency * 50 / 1000;
2542 csp_caps_initialized = TRUE;
2546 static struct csp_caps *caps(struct mcap_mcl *mcl)
2548 if (!csp_caps_initialized)
2549 if (!initialize_caps(mcl)) {
2550 /* Temporary failure in reading BT clock */
2557 static int send_sync_cap_rsp(struct mcap_mcl *mcl, uint8_t rspcode,
2558 uint8_t btclockres, uint16_t synclead,
2559 uint16_t tmstampres, uint16_t tmstampacc)
2561 mcap_md_sync_cap_rsp *rsp;
2564 rsp = g_new0(mcap_md_sync_cap_rsp, 1);
2566 rsp->op = MCAP_MD_SYNC_CAP_RSP;
2569 rsp->btclock = btclockres;
2570 rsp->sltime = htons(synclead);
2571 rsp->timestnr = htons(tmstampres);
2572 rsp->timestna = htons(tmstampacc);
2574 sent = send_sync_cmd(mcl, rsp, sizeof(*rsp));
2580 static void proc_sync_cap_req(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
2582 mcap_md_sync_cap_req *req;
2583 uint16_t required_accuracy;
2584 uint16_t our_accuracy;
2588 if (len != sizeof(mcap_md_sync_cap_req)) {
2589 send_sync_cap_rsp(mcl, MCAP_INVALID_PARAM_VALUE,
2595 send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE,
2600 req = (mcap_md_sync_cap_req *) cmd;
2601 required_accuracy = ntohs(req->timest);
2602 our_accuracy = caps(mcl)->ts_acc;
2605 if (required_accuracy < our_accuracy || required_accuracy < 1) {
2606 send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE,
2611 if (!read_btclock_retry(mcl, &btclock, &btres)) {
2612 send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE,
2617 mcl->csp->remote_caps = 1;
2618 mcl->csp->rem_req_acc = required_accuracy;
2620 send_sync_cap_rsp(mcl, MCAP_SUCCESS, btres,
2621 caps(mcl)->syncleadtime_ms,
2622 caps(mcl)->ts_res, our_accuracy);
2625 static int send_sync_set_rsp(struct mcap_mcl *mcl, uint8_t rspcode,
2626 uint32_t btclock, uint64_t timestamp,
2627 uint16_t tmstampres)
2629 mcap_md_sync_set_rsp *rsp;
2632 rsp = g_new0(mcap_md_sync_set_rsp, 1);
2634 rsp->op = MCAP_MD_SYNC_SET_RSP;
2636 rsp->btclock = htonl(btclock);
2637 rsp->timestst = hton64(timestamp);
2638 rsp->timestsa = htons(tmstampres);
2640 sent = send_sync_cmd(mcl, rsp, sizeof(*rsp));
2646 static gboolean get_all_clocks(struct mcap_mcl *mcl, uint32_t *btclock,
2647 struct timespec *base_time,
2648 uint64_t *timestamp)
2658 latency = caps(mcl)->preempt_thresh + 1;
2660 while (latency > caps(mcl)->preempt_thresh && --retry >= 0) {
2662 if (clock_gettime(CLK, &t0) < 0)
2665 if (!read_btclock(mcl, btclock, &btres))
2668 if (clock_gettime(CLK, base_time) < 0)
2672 * Tries to detect preemption between clock_gettime
2673 * and read_btclock by measuring transaction time
2675 latency = time_us(base_time) - time_us(&t0);
2681 *timestamp = mcap_get_timestamp(mcl, base_time);
2686 static gboolean sync_send_indication(gpointer user_data)
2688 struct mcap_mcl *mcl;
2689 mcap_md_sync_info_ind *cmd;
2692 struct timespec base_time;
2704 if (!get_all_clocks(mcl, &btclock, &base_time, &tmstamp))
2707 cmd = g_new0(mcap_md_sync_info_ind, 1);
2709 cmd->op = MCAP_MD_SYNC_INFO_IND;
2710 cmd->btclock = htonl(btclock);
2711 cmd->timestst = hton64(tmstamp);
2712 cmd->timestsa = htons(caps(mcl)->latency);
2714 sent = send_sync_cmd(mcl, cmd, sizeof(*cmd));
2720 static gboolean proc_sync_set_req_phase2(gpointer user_data)
2722 struct mcap_mcl *mcl;
2723 struct sync_set_data *data;
2725 uint32_t sched_btclock;
2726 uint64_t new_tmstamp;
2731 struct timespec base_time;
2732 uint16_t tmstampacc;
2741 if (!mcl->csp->set_data)
2745 data = mcl->csp->set_data;
2746 update = data->update;
2747 sched_btclock = data->sched_btclock;
2748 new_tmstamp = data->timestamp;
2749 ind_freq = data->ind_freq;
2753 send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0);
2757 if (!get_all_clocks(mcl, &btclock, &base_time, &tmstamp)) {
2758 send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0);
2762 if (get_btrole(mcl) != role) {
2763 send_sync_set_rsp(mcl, MCAP_INVALID_OPERATION, 0, 0, 0);
2767 reset = (new_tmstamp != MCAP_TMSTAMP_DONTSET);
2770 if (sched_btclock != MCAP_BTCLOCK_IMMEDIATE) {
2771 delay = bt2us(btdiff(sched_btclock, btclock));
2772 if (delay >= 0 || ((new_tmstamp - delay) > 0)) {
2773 new_tmstamp += delay;
2774 DBG("CSP: reset w/ delay %dus, compensated",
2777 DBG("CSP: reset w/ delay %dus, uncompensated",
2781 reset_tmstamp(mcl->csp, &base_time, new_tmstamp);
2782 tmstamp = new_tmstamp;
2785 tmstampacc = caps(mcl)->latency + caps(mcl)->ts_acc;
2787 if (mcl->csp->ind_timer) {
2788 g_source_remove(mcl->csp->ind_timer);
2789 mcl->csp->ind_timer = 0;
2793 int when = ind_freq + caps(mcl)->syncleadtime_ms;
2794 mcl->csp->ind_timer = g_timeout_add(when,
2795 sync_send_indication,
2799 send_sync_set_rsp(mcl, MCAP_SUCCESS, btclock, tmstamp, tmstampacc);
2801 /* First indication after set is immediate */
2803 sync_send_indication(mcl);
2808 static void proc_sync_set_req(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
2810 mcap_md_sync_set_req *req;
2811 uint32_t sched_btclock, cur_btclock;
2815 struct sync_set_data *set_data;
2816 int phase2_delay, ind_freq, when;
2818 if (len != sizeof(mcap_md_sync_set_req)) {
2819 send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0);
2823 req = (mcap_md_sync_set_req *) cmd;
2824 sched_btclock = ntohl(req->btclock);
2825 update = req->timestui;
2826 timestamp = ntoh64(req->timestst);
2829 if (sched_btclock != MCAP_BTCLOCK_IMMEDIATE &&
2830 !valid_btclock(sched_btclock)) {
2831 send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0);
2836 send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0);
2840 if (!mcl->csp->remote_caps) {
2841 /* Remote side did not ask our capabilities yet */
2842 send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0);
2847 send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0);
2851 if (!read_btclock_retry(mcl, &cur_btclock, &btres)) {
2852 send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0);
2856 if (sched_btclock == MCAP_BTCLOCK_IMMEDIATE)
2859 phase2_delay = btdiff(cur_btclock, sched_btclock);
2861 if (phase2_delay < 0) {
2862 /* can not reset in the past tense */
2863 send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE,
2868 /* Convert to miliseconds */
2869 phase2_delay = bt2ms(phase2_delay);
2871 if (phase2_delay > 61*1000) {
2872 /* More than 60 seconds in the future */
2873 send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE,
2876 } else if (phase2_delay < caps(mcl)->latency / 1000) {
2877 /* Too fast for us to do in time */
2878 send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE,
2886 * Indication frequency: required accuracy divided by ours
2887 * Converted to milisseconds
2889 ind_freq = (1000 * mcl->csp->rem_req_acc) / caps(mcl)->ts_acc;
2891 if (ind_freq < MAX(caps(mcl)->latency * 2 / 1000, 100)) {
2892 /* Too frequent, we can't handle */
2893 send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE,
2898 DBG("CSP: indication every %dms", ind_freq);
2902 if (mcl->csp->ind_timer) {
2903 /* Old indications are no longer sent */
2904 g_source_remove(mcl->csp->ind_timer);
2905 mcl->csp->ind_timer = 0;
2908 if (!mcl->csp->set_data)
2909 mcl->csp->set_data = g_new0(struct sync_set_data, 1);
2911 set_data = (struct sync_set_data *) mcl->csp->set_data;
2913 set_data->update = update;
2914 set_data->sched_btclock = sched_btclock;
2915 set_data->timestamp = timestamp;
2916 set_data->ind_freq = ind_freq;
2917 set_data->role = get_btrole(mcl);
2920 * TODO is there some way to schedule a call based directly on
2921 * a BT clock value, instead of this estimation that uses
2925 if (phase2_delay > 0) {
2926 when = phase2_delay + caps(mcl)->syncleadtime_ms;
2927 mcl->csp->set_timer = g_timeout_add(when,
2928 proc_sync_set_req_phase2,
2931 proc_sync_set_req_phase2(mcl);
2933 /* First indication is immediate */
2935 sync_send_indication(mcl);
2938 static void proc_sync_cap_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
2940 mcap_md_sync_cap_rsp *rsp;
2944 uint16_t tmstampres;
2945 uint16_t tmstampacc;
2946 struct mcap_sync_cap_cbdata *cbdata;
2947 mcap_sync_cap_cb cb;
2950 if (mcl->csp->csp_req != MCAP_MD_SYNC_CAP_REQ) {
2951 DBG("CSP: got unexpected cap respose");
2955 if (!mcl->csp->csp_priv_data) {
2956 DBG("CSP: no priv data for cap respose");
2960 cbdata = mcl->csp->csp_priv_data;
2962 user_data = cbdata->user_data;
2965 mcl->csp->csp_priv_data = NULL;
2966 mcl->csp->csp_req = 0;
2968 if (len != sizeof(mcap_md_sync_cap_rsp)) {
2969 DBG("CSP: got corrupted cap respose");
2973 rsp = (mcap_md_sync_cap_rsp *) cmd;
2975 btclockres = rsp->btclock;
2976 synclead = ntohs(rsp->sltime);
2977 tmstampres = ntohs(rsp->timestnr);
2978 tmstampacc = ntohs(rsp->timestna);
2981 mcl->csp->local_caps = TRUE;
2983 cb(mcl, mcap_err, btclockres, synclead, tmstampres, tmstampacc, NULL,
2987 static void proc_sync_set_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
2989 mcap_md_sync_set_rsp *rsp;
2994 struct mcap_sync_set_cbdata *cbdata;
2995 mcap_sync_set_cb cb;
2998 if (mcl->csp->csp_req != MCAP_MD_SYNC_SET_REQ) {
2999 DBG("CSP: got unexpected set respose");
3003 if (!mcl->csp->csp_priv_data) {
3004 DBG("CSP: no priv data for set respose");
3008 cbdata = mcl->csp->csp_priv_data;
3010 user_data = cbdata->user_data;
3013 mcl->csp->csp_priv_data = NULL;
3014 mcl->csp->csp_req = 0;
3016 if (len != sizeof(mcap_md_sync_set_rsp)) {
3017 DBG("CSP: got corrupted set respose");
3021 rsp = (mcap_md_sync_set_rsp *) cmd;
3023 btclock = ntohl(rsp->btclock);
3024 timestamp = ntoh64(rsp->timestst);
3025 accuracy = ntohs(rsp->timestsa);
3027 if (!mcap_err && !valid_btclock(btclock))
3028 mcap_err = MCAP_ERROR_INVALID_ARGS;
3030 cb(mcl, mcap_err, btclock, timestamp, accuracy, NULL, user_data);
3033 static void proc_sync_info_ind(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
3035 mcap_md_sync_info_ind *req;
3036 struct sync_info_ind_data data;
3039 if (!mcl->csp->ind_expected) {
3040 DBG("CSP: received unexpected info indication");
3044 if (len != sizeof(mcap_md_sync_info_ind))
3047 req = (mcap_md_sync_info_ind *) cmd;
3049 btclock = ntohl(req->btclock);
3051 if (!valid_btclock(btclock))
3054 data.btclock = btclock;
3055 data.timestamp = ntoh64(req->timestst);
3056 data.accuracy = ntohs(req->timestsa);
3058 if (mcl->mi->mcl_sync_infoind_cb)
3059 mcl->mi->mcl_sync_infoind_cb(mcl, &data);
3062 void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
3064 if (!mcl->mi->csp_enabled || !mcl->csp) {
3066 case MCAP_MD_SYNC_CAP_REQ:
3067 send_unsupported_cap_req(mcl);
3069 case MCAP_MD_SYNC_SET_REQ:
3070 send_unsupported_set_req(mcl);
3077 case MCAP_MD_SYNC_CAP_REQ:
3078 proc_sync_cap_req(mcl, cmd, len);
3080 case MCAP_MD_SYNC_CAP_RSP:
3081 proc_sync_cap_rsp(mcl, cmd, len);
3083 case MCAP_MD_SYNC_SET_REQ:
3084 proc_sync_set_req(mcl, cmd, len);
3086 case MCAP_MD_SYNC_SET_RSP:
3087 proc_sync_set_rsp(mcl, cmd, len);
3089 case MCAP_MD_SYNC_INFO_IND:
3090 proc_sync_info_ind(mcl, cmd, len);
3095 void mcap_sync_cap_req(struct mcap_mcl *mcl, uint16_t reqacc,
3096 mcap_sync_cap_cb cb, gpointer user_data,
3099 struct mcap_sync_cap_cbdata *cbdata;
3100 mcap_md_sync_cap_req *cmd;
3102 if (!mcl->mi->csp_enabled || !mcl->csp) {
3105 MCAP_ERROR_RESOURCE_UNAVAILABLE,
3106 "CSP not enabled for the instance");
3110 if (mcl->csp->csp_req) {
3113 MCAP_ERROR_RESOURCE_UNAVAILABLE,
3114 "Pending CSP request");
3118 mcl->csp->csp_req = MCAP_MD_SYNC_CAP_REQ;
3119 cmd = g_new0(mcap_md_sync_cap_req, 1);
3121 cmd->op = MCAP_MD_SYNC_CAP_REQ;
3122 cmd->timest = htons(reqacc);
3124 cbdata = g_new0(struct mcap_sync_cap_cbdata, 1);
3126 cbdata->user_data = user_data;
3127 mcl->csp->csp_priv_data = cbdata;
3129 send_sync_cmd(mcl, cmd, sizeof(*cmd));
3134 void mcap_sync_set_req(struct mcap_mcl *mcl, uint8_t update, uint32_t btclock,
3135 uint64_t timestamp, mcap_sync_set_cb cb,
3136 gpointer user_data, GError **err)
3138 mcap_md_sync_set_req *cmd;
3139 struct mcap_sync_set_cbdata *cbdata;
3141 if (!mcl->mi->csp_enabled || !mcl->csp) {
3144 MCAP_ERROR_RESOURCE_UNAVAILABLE,
3145 "CSP not enabled for the instance");
3149 if (!mcl->csp->local_caps) {
3152 MCAP_ERROR_RESOURCE_UNAVAILABLE,
3153 "Did not get CSP caps from peripheral yet");
3157 if (mcl->csp->csp_req) {
3160 MCAP_ERROR_RESOURCE_UNAVAILABLE,
3161 "Pending CSP request");
3165 mcl->csp->csp_req = MCAP_MD_SYNC_SET_REQ;
3166 cmd = g_new0(mcap_md_sync_set_req, 1);
3168 cmd->op = MCAP_MD_SYNC_SET_REQ;
3169 cmd->timestui = update;
3170 cmd->btclock = htonl(btclock);
3171 cmd->timestst = hton64(timestamp);
3173 mcl->csp->ind_expected = update;
3175 cbdata = g_new0(struct mcap_sync_set_cbdata, 1);
3177 cbdata->user_data = user_data;
3178 mcl->csp->csp_priv_data = cbdata;
3180 send_sync_cmd(mcl, cmd, sizeof(*cmd));
3185 void mcap_enable_csp(struct mcap_instance *mi)
3187 mi->csp_enabled = TRUE;
3190 void mcap_disable_csp(struct mcap_instance *mi)
3192 mi->csp_enabled = FALSE;