diff --git a/emulator/bthost.c b/emulator/bthost.c
index a76b02e..5db750a 100644
--- a/emulator/bthost.c
+++ b/emulator/bthost.c
#define acl_handle(h) (h & 0x0fff)
#define acl_flags(h) (h >> 12)
+#define sco_flags_status(f) (f & 0x03)
+
#define iso_flags_pb(f) (f & 0x0003)
#define iso_flags_ts(f) ((f >> 2) & 0x0001)
#define iso_flags_pack(pb, ts) (((pb) & 0x03) | (((ts) & 0x01) << 2))
struct rfcomm_chan_hook *next;
};
+struct sco_hook {
+ bthost_sco_hook_func_t func;
+ void *user_data;
+ bthost_destroy_func_t destroy;
+};
+
struct iso_hook {
- bthost_cid_hook_func_t func;
+ bthost_iso_hook_func_t func;
void *user_data;
bthost_destroy_func_t destroy;
};
struct rcconn *rcconns;
struct cid_hook *cid_hooks;
struct rfcomm_chan_hook *rfcomm_chan_hooks;
+ struct sco_hook *sco_hook;
struct iso_hook *iso_hook;
struct btconn *next;
void *smp_data;
void *cmd_complete_data;
bthost_new_conn_cb new_conn_cb;
void *new_conn_data;
+ bthost_new_conn_cb new_sco_cb;
+ void *new_sco_data;
bthost_accept_conn_cb accept_iso_cb;
bthost_new_conn_cb new_iso_cb;
void *new_iso_data;
free(hook);
}
+ if (conn->sco_hook && conn->sco_hook->destroy)
+ conn->sco_hook->destroy(conn->sco_hook->user_data);
+
if (conn->iso_hook && conn->iso_hook->destroy)
conn->iso_hook->destroy(conn->iso_hook->user_data);
+ free(conn->sco_hook);
free(conn->iso_hook);
free(conn->recv_data);
free(conn);
conn->cid_hooks = hook;
}
+void bthost_add_sco_hook(struct bthost *bthost, uint16_t handle,
+ bthost_sco_hook_func_t func, void *user_data,
+ bthost_destroy_func_t destroy)
+{
+ struct sco_hook *hook;
+ struct btconn *conn;
+
+ conn = bthost_find_conn(bthost, handle);
+ if (!conn || conn->sco_hook)
+ return;
+
+ hook = malloc(sizeof(*hook));
+ if (!hook)
+ return;
+
+ memset(hook, 0, sizeof(*hook));
+
+ hook->func = func;
+ hook->user_data = user_data;
+ hook->destroy = destroy;
+
+ conn->sco_hook = hook;
+}
+
void bthost_add_iso_hook(struct bthost *bthost, uint16_t handle,
bthost_iso_hook_func_t func, void *user_data,
bthost_destroy_func_t destroy)
}
}
+static void init_sco(struct bthost *bthost, uint16_t handle,
+ const uint8_t *bdaddr, uint8_t addr_type)
+{
+ struct btconn *conn;
+
+ bthost_debug(bthost, "SCO handle 0x%4.4x", handle);
+
+ conn = malloc(sizeof(*conn));
+ if (!conn)
+ return;
+
+ memset(conn, 0, sizeof(*conn));
+ conn->handle = handle;
+ memcpy(conn->bdaddr, bdaddr, 6);
+ conn->addr_type = addr_type;
+
+ conn->next = bthost->conns;
+ bthost->conns = conn;
+
+ if (bthost->new_sco_cb)
+ bthost->new_sco_cb(handle, bthost->new_sco_data);
+}
+
static void evt_conn_complete(struct bthost *bthost, const void *data,
uint8_t len)
{
if (ev->status)
return;
- init_conn(bthost, le16_to_cpu(ev->handle), ev->bdaddr, BDADDR_BREDR);
+ if (ev->link_type == 0x00) {
+ init_sco(bthost, le16_to_cpu(ev->handle), ev->bdaddr,
+ BDADDR_BREDR);
+ } else if (ev->link_type == 0x01) {
+ init_conn(bthost, le16_to_cpu(ev->handle), ev->bdaddr,
+ BDADDR_BREDR);
+ }
}
static void evt_disconn_complete(struct bthost *bthost, const void *data,
return;
}
+static void evt_sync_conn_complete(struct bthost *bthost, const void *data,
+ uint8_t len)
+{
+ const struct bt_hci_evt_sync_conn_complete *ev = data;
+
+ if (len < sizeof(*ev))
+ return;
+
+ if (ev->status)
+ return;
+
+ init_sco(bthost, le16_to_cpu(ev->handle), ev->bdaddr, BDADDR_BREDR);
+}
+
static void evt_le_conn_complete(struct bthost *bthost, const void *data,
uint8_t len)
{
evt_disconn_complete(bthost, param, hdr->plen);
break;
+ case BT_HCI_EVT_SYNC_CONN_COMPLETE:
+ evt_sync_conn_complete(bthost, param, hdr->plen);
+ break;
+
case BT_HCI_EVT_NUM_COMPLETED_PACKETS:
evt_num_completed_packets(bthost, param, hdr->plen);
break;
}
}
+static void process_sco(struct bthost *bthost, const void *data, uint16_t len)
+{
+ const struct bt_hci_sco_hdr *sco_hdr = data;
+ uint16_t handle, sco_len;
+ uint8_t status;
+ struct btconn *conn;
+ struct sco_hook *hook;
+
+ sco_len = le16_to_cpu(sco_hdr->dlen);
+ if (len != sizeof(*sco_hdr) + sco_len)
+ return;
+
+ handle = acl_handle(sco_hdr->handle);
+ status = sco_flags_status(acl_flags(sco_hdr->handle));
+
+ conn = bthost_find_conn(bthost, handle);
+ if (!conn) {
+ bthost_debug(bthost, "Unknown handle: 0x%4.4x", handle);
+ return;
+ }
+
+ bthost_debug(bthost, "SCO data: %u bytes", sco_len);
+
+ hook = conn->sco_hook;
+ if (!hook)
+ return;
+
+ hook->func(sco_hdr->data, sco_len, status, hook->user_data);
+}
+
static void process_iso_data(struct bthost *bthost, struct btconn *conn,
const void *data, uint16_t len)
{
case BT_H4_ACL_PKT:
process_acl(bthost, data + 1, len - 1);
break;
+ case BT_H4_SCO_PKT:
+ process_sco(bthost, data + 1, len - 1);
+ break;
case BT_H4_ISO_PKT:
process_iso(bthost, data + 1, len - 1);
break;
bthost->new_conn_data = user_data;
}
+void bthost_set_sco_cb(struct bthost *bthost, bthost_new_conn_cb cb,
+ void *user_data)
+{
+ bthost->new_sco_cb = cb;
+ bthost->new_sco_data = user_data;
+}
+
void bthost_set_iso_cb(struct bthost *bthost, bthost_accept_conn_cb accept,
bthost_new_conn_cb cb, void *user_data)
{
diff --git a/emulator/bthost.h b/emulator/bthost.h
index 2c5b0d5..405d66b 100644
--- a/emulator/bthost.h
+++ b/emulator/bthost.h
void bthost_set_connect_cb(struct bthost *bthost, bthost_new_conn_cb cb,
void *user_data);
+void bthost_set_sco_cb(struct bthost *bthost, bthost_new_conn_cb cb,
+ void *user_data);
+
void bthost_set_iso_cb(struct bthost *bthost, bthost_accept_conn_cb accept,
bthost_new_conn_cb cb, void *user_data);
void bthost_add_cid_hook(struct bthost *bthost, uint16_t handle, uint16_t cid,
bthost_cid_hook_func_t func, void *user_data);
+typedef void (*bthost_sco_hook_func_t)(const void *data, uint16_t len,
+ uint8_t status, void *user_data);
+
+void bthost_add_sco_hook(struct bthost *bthost, uint16_t handle,
+ bthost_sco_hook_func_t func, void *user_data,
+ bthost_destroy_func_t destroy);
+
typedef void (*bthost_iso_hook_func_t)(const void *data, uint16_t len,
void *user_data);
diff --git a/monitor/bt.h b/monitor/bt.h
index 6fb81ab..e708e58 100644
--- a/monitor/bt.h
+++ b/monitor/bt.h
struct bt_hci_sco_hdr {
uint16_t handle;
uint8_t dlen;
+ uint8_t data[];
} __attribute__ ((packed));
struct bt_hci_iso_hdr {