summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--emulator/btdev.c930
-rw-r--r--lib/hci.h1
2 files changed, 610 insertions, 321 deletions
diff --git a/emulator/btdev.c b/emulator/btdev.c
index a26d73865..ae382d9b9 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -29,6 +29,7 @@
#include "src/shared/timeout.h"
#include "src/shared/crypto.h"
#include "src/shared/ecc.h"
+#include "src/shared/queue.h"
#include "monitor/bt.h"
#include "btdev.h"
@@ -36,7 +37,7 @@
#define has_le(btdev) (!!((btdev)->features[4] & 0x40))
#define ACL_HANDLE 42
-#define ISO_HANDLE 44
+#define ISO_HANDLE 257
#define SCO_HANDLE 257
struct hook {
@@ -48,10 +49,17 @@ struct hook {
#define MAX_HOOK_ENTRIES 16
+struct btdev_conn {
+ uint16_t handle;
+ uint8_t type;
+ struct btdev *dev;
+ struct btdev_conn *link;
+};
+
struct btdev {
enum btdev_type type;
- struct btdev *conn;
+ struct queue *conns;
bool auth_init;
uint8_t link_key[16];
@@ -520,36 +528,70 @@ static void send_event(struct btdev *btdev, uint8_t event,
send_packet(btdev, iov, len > 0 ? 3 : 2);
}
+static bool match_handle(const void *data, const void *match_data)
+{
+ const struct btdev_conn *conn = data;
+ uint16_t handle = PTR_TO_UINT(match_data);
+
+ return conn->handle == handle;
+}
+
+static void conn_unlink(struct btdev_conn *conn1, struct btdev_conn *conn2)
+{
+ conn1->link = NULL;
+ conn2->link = NULL;
+}
+
+static void conn_remove(struct btdev_conn *conn)
+{
+ if (conn->link) {
+ struct btdev_conn *link = conn->link;
+
+ conn_unlink(conn, conn->link);
+ conn_remove(link);
+ }
+
+ queue_remove(conn->dev->conns, conn);
+
+ free(conn);
+}
+
+static void disconnect_complete(struct btdev *dev, uint16_t handle,
+ uint8_t status, uint8_t reason)
+{
+ struct bt_hci_evt_disconnect_complete rsp;
+
+ memset(&rsp, 0, sizeof(rsp));
+
+ rsp.status = status;
+ rsp.handle = cpu_to_le16(handle);
+ rsp.reason = reason;
+
+ send_event(dev, BT_HCI_EVT_DISCONNECT_COMPLETE, &rsp, sizeof(rsp));
+}
+
static int cmd_disconnect_complete(struct btdev *dev, const void *data,
uint8_t len)
{
const struct bt_hci_cmd_disconnect *cmd = data;
struct bt_hci_evt_disconnect_complete rsp;
- struct btdev *remote = dev->conn;
+ struct btdev_conn *conn;
memset(&rsp, 0, sizeof(rsp));
- if (!remote) {
- rsp.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
- rsp.handle = cpu_to_le16(cmd->handle);
- rsp.reason = 0x00;
-
- send_event(dev, BT_HCI_EVT_DISCONNECT_COMPLETE, &rsp,
- sizeof(rsp));
+ conn = queue_remove_if(dev->conns, match_handle,
+ UINT_TO_PTR(cpu_to_le16(cmd->handle)));
+ if (!conn) {
+ disconnect_complete(dev, 0x0000, BT_HCI_ERR_UNKNOWN_CONN_ID,
+ 0x00);
return 0;
}
- rsp.status = BT_HCI_ERR_SUCCESS;
- rsp.handle = cpu_to_le16(cmd->handle);
- rsp.reason = cmd->reason;
+ disconnect_complete(dev, conn->handle, BT_HCI_ERR_SUCCESS, cmd->reason);
+ disconnect_complete(conn->link->dev, conn->link->handle,
+ BT_HCI_ERR_SUCCESS, cmd->reason);
- if (rsp.handle == ACL_HANDLE) {
- dev->conn = NULL;
- remote->conn = NULL;
- }
-
- send_event(dev, BT_HCI_EVT_DISCONNECT_COMPLETE, &rsp, sizeof(rsp));
- send_event(remote, BT_HCI_EVT_DISCONNECT_COMPLETE, &rsp, sizeof(rsp));
+ conn_remove(conn);
return 0;
}
@@ -566,15 +608,18 @@ static int cmd_remote_version_complete(struct btdev *dev, const void *data,
{
const struct bt_hci_cmd_read_remote_version *cmd = data;
struct bt_hci_evt_remote_version_complete ev;
+ struct btdev_conn *conn;
memset(&ev, 0, sizeof(ev));
- if (dev->conn) {
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(cpu_to_le16(cmd->handle)));
+ if (conn) {
ev.status = BT_HCI_ERR_SUCCESS;
ev.handle = cpu_to_le16(cmd->handle);
- ev.lmp_ver = dev->conn->version;
- ev.manufacturer = cpu_to_le16(dev->conn->manufacturer);
- ev.lmp_subver = cpu_to_le16(dev->conn->revision);
+ ev.lmp_ver = conn->link->dev->version;
+ ev.manufacturer = cpu_to_le16(conn->link->dev->manufacturer);
+ ev.lmp_subver = cpu_to_le16(conn->link->dev->revision);
} else {
ev.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
ev.handle = cpu_to_le16(cmd->handle);
@@ -860,27 +905,105 @@ static int cmd_create_conn(struct btdev *dev, const void *data, uint8_t len)
return 0;
}
+static struct btdev_conn *conn_new(struct btdev *dev, uint16_t handle,
+ uint8_t type)
+{
+ struct btdev_conn *conn;
+
+ while ((conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(handle))))
+ handle++;
+
+ conn = new0(struct btdev_conn, 1);
+ conn->handle = handle;
+ conn->type = type;
+ conn->dev = dev;
+
+ if (!queue_push_tail(dev->conns, conn)) {
+ free(conn);
+ return NULL;
+ }
+
+ return conn;
+}
+
+static struct btdev_conn *conn_link(struct btdev *dev, struct btdev *remote,
+ uint16_t handle, uint8_t type)
+{
+ struct btdev_conn *conn1, *conn2;
+
+ conn1 = conn_new(dev, handle, type);
+ if (!conn1)
+ return NULL;
+
+ conn2 = conn_new(remote, handle, type);
+ if (!conn2) {
+ free(conn1);
+ return NULL;
+ }
+
+ conn1->link = conn2;
+ conn2->link = conn1;
+
+ util_debug(dev->debug_callback, dev->debug_data,
+ "conn1 %p handle 0x%04x conn2 %p handle 0x%04x",
+ conn1, conn1->handle, conn2, conn2->handle);
+
+ return conn1;
+}
+
+static struct btdev_conn *conn_add(struct btdev *dev,
+ const uint8_t *bdaddr, uint8_t bdaddr_type,
+ uint16_t handle, uint8_t type)
+{
+ struct btdev *remote;
+
+ remote = find_btdev_by_bdaddr_type(bdaddr, bdaddr_type);
+ if (!remote)
+ return NULL;
+
+ return conn_link(dev, remote, handle, type);
+}
+
+static struct btdev_conn *conn_add_acl(struct btdev *dev,
+ const uint8_t *bdaddr, uint8_t bdaddr_type)
+{
+ return conn_add(dev, bdaddr, bdaddr_type, ACL_HANDLE, HCI_ACLDATA_PKT);
+}
+
+static struct btdev_conn *conn_add_sco(struct btdev_conn *acl)
+{
+ return conn_link(acl->dev, acl->link->dev, SCO_HANDLE, HCI_SCODATA_PKT);
+}
+
+static struct btdev_conn *conn_add_iso(struct btdev_conn *acl, uint16_t handle)
+{
+ return conn_link(acl->dev, acl->link->dev, handle, HCI_ISODATA_PKT);
+}
+
static void conn_complete(struct btdev *btdev,
const uint8_t *bdaddr, uint8_t status)
{
struct bt_hci_evt_conn_complete cc;
if (!status) {
- struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
+ struct btdev_conn *conn;
- btdev->conn = remote;
- remote->conn = btdev;
+ conn = conn_add_acl(btdev, bdaddr, BDADDR_BREDR);
+ if (!conn)
+ return;
cc.status = status;
memcpy(cc.bdaddr, btdev->bdaddr, 6);
cc.encr_mode = 0x00;
- cc.handle = cpu_to_le16(ACL_HANDLE);
+ cc.handle = cpu_to_le16(conn->link->handle);
cc.link_type = 0x01;
- send_event(remote, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
+ send_event(conn->link->dev, BT_HCI_EVT_CONN_COMPLETE, &cc,
+ sizeof(cc));
- cc.handle = cpu_to_le16(ACL_HANDLE);
+ cc.handle = cpu_to_le16(conn->handle);
cc.link_type = 0x01;
} else {
cc.handle = cpu_to_le16(0x0000);
@@ -917,17 +1040,32 @@ static int cmd_create_conn_complete(struct btdev *dev, const void *data,
static int cmd_add_sco_conn(struct btdev *dev, const void *data, uint8_t len)
{
+ const struct bt_hci_cmd_add_sco_conn *cmd = data;
struct bt_hci_evt_conn_complete cc;
+ struct btdev_conn *conn;
- if (!dev->conn)
- return 0;
+ memset(&cc, 0, sizeof(cc));
+
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(cpu_to_le16(cmd->handle)));
+ if (!conn) {
+ cc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ goto done;
+ }
+
+ conn = conn_add_sco(conn);
+ if (!conn) {
+ cc.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
+ goto done;
+ }
cc.status = BT_HCI_ERR_SUCCESS;
- memcpy(cc.bdaddr, dev->conn->bdaddr, 6);
- cc.handle = cpu_to_le16(SCO_HANDLE);
+ memcpy(cc.bdaddr, conn->link->dev->bdaddr, 6);
+ cc.handle = cpu_to_le16(conn->handle);
cc.link_type = 0x00;
cc.encr_mode = 0x00;
+done:
send_event(dev, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
return 0;
@@ -1004,35 +1142,57 @@ static int cmd_link_key_reply(struct btdev *dev, const void *data, uint8_t len)
return 0;
}
+static bool match_bdaddr(const void *data, const void *match_data)
+{
+ const struct btdev_conn *conn = data;
+ const uint8_t *bdaddr = match_data;
+
+ return !memcmp(conn->link->dev->bdaddr, bdaddr, 6);
+}
+
+static void auth_complete(struct btdev_conn *conn, uint8_t status)
+{
+ struct bt_hci_evt_auth_complete ev;
+
+ memset(&ev, 0, sizeof(ev));
+
+ ev.handle = conn ? cpu_to_le16(conn->handle) : 0x0000;
+ ev.status = status;
+
+ send_event(conn->dev, BT_HCI_EVT_AUTH_COMPLETE, &ev, sizeof(ev));
+}
+
static int cmd_link_key_reply_complete(struct btdev *dev, const void *data,
uint8_t len)
{
const struct bt_hci_cmd_link_key_request_reply *cmd = data;
- struct btdev *remote = dev->conn;
- struct bt_hci_evt_auth_complete ev;
-
- memcpy(dev->link_key, cmd->link_key, 16);
+ struct btdev_conn *conn;
+ uint8_t status;
- if (!remote) {
- remote = find_btdev_by_bdaddr(cmd->bdaddr);
- if (!remote)
- return 0;
+ conn = queue_find(dev->conns, match_bdaddr, cmd->bdaddr);
+ if (!conn) {
+ status = BT_HCI_ERR_INVALID_PARAMETERS;
+ goto done;
}
- if (!memcmp(remote->link_key, LINK_KEY_NONE, 16)) {
- send_event(remote, BT_HCI_EVT_LINK_KEY_REQUEST, dev->bdaddr, 6);
+ memcpy(dev->link_key, cmd->link_key, 16);
+
+ if (!memcmp(conn->link->dev->link_key, LINK_KEY_NONE, 16)) {
+ send_event(conn->link->dev, BT_HCI_EVT_LINK_KEY_REQUEST,
+ dev->bdaddr, 6);
return 0;
}
- ev.handle = cpu_to_le16(ACL_HANDLE);
-
- if (!memcmp(dev->link_key, remote->link_key, 16))
- ev.status = BT_HCI_ERR_SUCCESS;
+ if (!memcmp(dev->link_key, conn->link->dev->link_key, 16))
+ status = BT_HCI_ERR_SUCCESS;
else
- ev.status = BT_HCI_ERR_AUTH_FAILURE;
+ status = BT_HCI_ERR_AUTH_FAILURE;
+
+done:
+ auth_complete(conn, status);
- send_event(dev, BT_HCI_EVT_AUTH_COMPLETE, &ev, sizeof(ev));
- send_event(remote, BT_HCI_EVT_AUTH_COMPLETE, &ev, sizeof(ev));
+ if (conn)
+ auth_complete(conn->link, status);
return 0;
}
@@ -1063,13 +1223,11 @@ static int cmd_link_key_neg_reply_complete(struct btdev *dev, const void *data,
uint8_t len)
{
const struct bt_hci_cmd_link_key_request_neg_reply *cmd = data;
- struct btdev *remote = dev->conn;
+ struct btdev *remote;
- if (!remote) {
- remote = find_btdev_by_bdaddr(cmd->bdaddr);
- if (!remote)
- return 0;
- }
+ remote = find_btdev_by_bdaddr(cmd->bdaddr);
+ if (!remote)
+ return 0;
if (use_ssp(dev, remote)) {
struct bt_hci_evt_io_capability_request io_req;
@@ -1100,21 +1258,23 @@ static int cmd_pin_code_reply(struct btdev *dev, const void *data, uint8_t len)
return 0;
}
-static uint8_t get_link_key_type(struct btdev *btdev)
+static uint8_t get_link_key_type(struct btdev *btdev, const uint8_t *bdaddr)
{
- struct btdev *remote = btdev->conn;
+ struct btdev_conn *conn;
uint8_t auth, unauth;
- if (!remote)
+ conn = queue_find(btdev->conns, match_bdaddr, bdaddr);
+ if (!conn)
return 0x00;
if (!btdev->simple_pairing_mode)
return 0x00;
- if (btdev->ssp_debug_mode || remote->ssp_debug_mode)
+ if (btdev->ssp_debug_mode || conn->link->dev->ssp_debug_mode)
return 0x03;
- if (btdev->secure_conn_support && remote->secure_conn_support) {
+ if (btdev->secure_conn_support &&
+ conn->link->dev->secure_conn_support) {
unauth = 0x07;
auth = 0x08;
} else {
@@ -1122,18 +1282,18 @@ static uint8_t get_link_key_type(struct btdev *btdev)
auth = 0x05;
}
- if (btdev->io_cap == 0x03 || remote->io_cap == 0x03)
+ if (btdev->io_cap == 0x03 || conn->link->dev->io_cap == 0x03)
return unauth;
- if (!(btdev->auth_req & 0x01) && !(remote->auth_req & 0x01))
+ if (!(btdev->auth_req & 0x01) && !(conn->link->dev->auth_req & 0x01))
return unauth;
/* DisplayOnly only produces authenticated with KeyboardOnly */
- if (btdev->io_cap == 0x00 && remote->io_cap != 0x02)
+ if (btdev->io_cap == 0x00 && conn->link->dev->io_cap != 0x02)
return unauth;
/* DisplayOnly only produces authenticated with KeyboardOnly */
- if (remote->io_cap == 0x00 && btdev->io_cap != 0x02)
+ if (conn->link->dev->io_cap == 0x00 && btdev->io_cap != 0x02)
return unauth;
return auth;
@@ -1148,7 +1308,7 @@ static void link_key_notify(struct btdev *btdev, const uint8_t *bdaddr,
memcpy(ev.bdaddr, bdaddr, 6);
memcpy(ev.link_key, key, 16);
- ev.key_type = get_link_key_type(btdev);
+ ev.key_type = get_link_key_type(btdev, bdaddr);
send_event(btdev, BT_HCI_EVT_LINK_KEY_NOTIFY, &ev, sizeof(ev));
}
@@ -1157,14 +1317,17 @@ static int cmd_pin_code_reply_complete(struct btdev *dev, const void *data,
uint8_t len)
{
const struct bt_hci_cmd_pin_code_request_reply *cmd = data;
- struct bt_hci_evt_auth_complete ev;
- struct btdev *remote = dev->conn;
+ struct btdev *remote;
+ struct btdev_conn *conn;
+ uint8_t status;
- if (!remote) {
+ conn = queue_find(dev->conns, match_bdaddr, cmd->bdaddr);
+ if (!conn) {
remote = find_btdev_by_bdaddr(cmd->bdaddr);
if (!remote)
return 0;
- }
+ } else
+ remote = conn->link->dev;
memcpy(dev->pin, cmd->pin_code, cmd->pin_len);
dev->pin_len = cmd->pin_len;
@@ -1173,8 +1336,8 @@ static int cmd_pin_code_reply_complete(struct btdev *dev, const void *data,
struct bt_hci_evt_pin_code_request pin_req;
memcpy(pin_req.bdaddr, dev->bdaddr, 6);
- send_event(remote, BT_HCI_EVT_PIN_CODE_REQUEST, &pin_req,
- sizeof(pin_req));
+ send_event(remote, BT_HCI_EVT_PIN_CODE_REQUEST,
+ &pin_req, sizeof(pin_req));
return 0;
}
@@ -1182,17 +1345,15 @@ static int cmd_pin_code_reply_complete(struct btdev *dev, const void *data,
!memcmp(dev->pin, remote->pin, dev->pin_len)) {
link_key_notify(dev, remote->bdaddr, LINK_KEY_DUMMY);
link_key_notify(remote, dev->bdaddr, LINK_KEY_DUMMY);
- ev.status = BT_HCI_ERR_SUCCESS;
+ status = BT_HCI_ERR_SUCCESS;
} else {
- ev.status = BT_HCI_ERR_AUTH_FAILURE;
+ status = BT_HCI_ERR_AUTH_FAILURE;
}
- if (remote->conn) {
- ev.handle = cpu_to_le16(ACL_HANDLE);
- send_event(remote, BT_HCI_EVT_AUTH_COMPLETE, &ev, sizeof(ev));
- } else {
- conn_complete(remote, dev->bdaddr, ev.status);
- }
+ if (conn)
+ auth_complete(conn->link, status);
+ else
+ conn_complete(remote, dev->bdaddr, status);
dev->pin_len = 0;
remote->pin_len = 0;
@@ -1218,27 +1379,25 @@ static int cmd_pin_code_neg_reply_complete(struct btdev *dev, const void *data,
uint8_t len)
{
const struct bt_hci_cmd_pin_code_request_neg_reply *cmd = data;
- struct bt_hci_evt_auth_complete ev;
- struct btdev *remote = dev->conn;
+ struct btdev *remote;
+ struct btdev_conn *conn;
+ uint8_t status;
- if (!remote) {
- remote = find_btdev_by_bdaddr(cmd->bdaddr);
- if (!remote)
- return 0;
- }
+ remote = find_btdev_by_bdaddr(cmd->bdaddr);
+ if (!remote)
+ return 0;
- ev.status = BT_HCI_ERR_PIN_OR_KEY_MISSING;
- ev.handle = cpu_to_le16(ACL_HANDLE);
+ status = BT_HCI_ERR_PIN_OR_KEY_MISSING;
- if (dev->conn)
- send_event(dev, BT_HCI_EVT_AUTH_COMPLETE, &ev, sizeof(ev));
+ conn = queue_find(dev->conns, match_bdaddr, cmd->bdaddr);
+ if (conn)
+ auth_complete(conn, status);
else
conn_complete(dev, cmd->bdaddr, BT_HCI_ERR_PIN_OR_KEY_MISSING);
- if (remote->conn) {
+ if (conn) {
if (remote->pin_len)
- send_event(remote, BT_HCI_EVT_AUTH_COMPLETE, &ev,
- sizeof(ev));
+ auth_complete(conn->link, status);
} else {
conn_complete(remote, dev->bdaddr,
BT_HCI_ERR_PIN_OR_KEY_MISSING);
@@ -1258,9 +1417,11 @@ static int cmd_auth_requested_complete(struct btdev *dev, const void *data,
uint8_t len)
{
const struct bt_hci_cmd_auth_requested *cmd = data;
- struct btdev *remote = dev->conn;
+ struct btdev_conn *conn;
- if (!remote) {
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (!conn) {
struct bt_hci_evt_auth_complete ev;
ev.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
@@ -1273,7 +1434,8 @@ static int cmd_auth_requested_complete(struct btdev *dev, const void *data,
dev->auth_init = true;
- send_event(dev, BT_HCI_EVT_LINK_KEY_REQUEST, remote->bdaddr, 6);
+ send_event(dev, BT_HCI_EVT_LINK_KEY_REQUEST, conn->link->dev->bdaddr,
+ sizeof(conn->link->dev->bdaddr));
return 0;
}
@@ -1286,35 +1448,45 @@ static int cmd_set_conn_encrypt(struct btdev *dev, const void *data,
return 0;
}
-static void encrypt_change(struct btdev *btdev, uint8_t mode, uint8_t status)
+static void encrypt_change(struct btdev_conn *conn, uint8_t mode,
+ uint8_t status)
{
struct bt_hci_evt_encrypt_change ev;
+ if (!conn)
+ return;
+
+ memset(&ev, 0, sizeof(ev));
+
ev.status = status;
- ev.handle = cpu_to_le16(ACL_HANDLE);
+ ev.handle = cpu_to_le16(conn->handle);
ev.encr_mode = mode;
- send_event(btdev, BT_HCI_EVT_ENCRYPT_CHANGE, &ev, sizeof(ev));
+ send_event(conn->dev, BT_HCI_EVT_ENCRYPT_CHANGE, &ev, sizeof(ev));
}
static int cmd_set_conn_encrypt_complete(struct btdev *dev, const void *data,
uint8_t len)
{
const struct bt_hci_cmd_set_conn_encrypt *cmd = data;
+ struct btdev_conn *conn;
uint8_t mode;
- if (!dev->conn)
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (!conn)
return 0;
if (!cmd->encr_mode)
mode = 0x00;
- else if (dev->secure_conn_support && dev->conn->secure_conn_support)
+ else if (dev->secure_conn_support &&
+ conn->link->dev->secure_conn_support)
mode = 0x02;
else
mode = 0x01;
- encrypt_change(dev, mode, BT_HCI_ERR_SUCCESS);
- encrypt_change(dev->conn, mode, BT_HCI_ERR_SUCCESS);
+ encrypt_change(conn, mode, BT_HCI_ERR_SUCCESS);
+ encrypt_change(conn->link, mode, BT_HCI_ERR_SUCCESS);
return 0;
}
@@ -1396,11 +1568,14 @@ static int cmd_read_remote_features_complete(struct btdev *dev,
{
const struct bt_hci_cmd_read_remote_features *cmd = data;
struct bt_hci_evt_remote_features_complete rfc;
+ struct btdev_conn *conn;
- if (dev->conn) {
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (conn) {
rfc.status = BT_HCI_ERR_SUCCESS;
rfc.handle = cpu_to_le16(cmd->handle);
- memcpy(rfc.features, dev->conn->features, 8);
+ memcpy(rfc.features, conn->link->dev->features, 8);
} else {
rfc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
rfc.handle = cpu_to_le16(cmd->handle);
@@ -1439,10 +1614,13 @@ static int cmd_read_remote_ext_features_compl(struct btdev *dev,
{
const struct bt_hci_cmd_read_remote_ext_features *cmd = data;
struct bt_hci_evt_remote_ext_features_complete ev;
+ struct btdev_conn *conn;
memset(&ev, 0, sizeof(ev));
- if (dev->conn && cmd->page < 0x02) {
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (conn && cmd->page < 0x02) {
ev.handle = cpu_to_le16(cmd->handle);
ev.page = cmd->page;
ev.max_page = 0x01;
@@ -1450,11 +1628,11 @@ static int cmd_read_remote_ext_features_compl(struct btdev *dev,
switch (cmd->page) {
case 0x00:
ev.status = BT_HCI_ERR_SUCCESS;
- memcpy(ev.features, dev->conn->features, 8);
+ memcpy(ev.features, conn->link->dev->features, 8);
break;
case 0x01:
ev.status = BT_HCI_ERR_SUCCESS;
- btdev_get_host_features(dev->conn, ev.features);
+ btdev_get_host_features(conn->link->dev, ev.features);
break;
default:
ev.status = BT_HCI_ERR_INVALID_PARAMETERS;
@@ -1488,10 +1666,13 @@ static int cmd_read_clock_offset_complete(struct btdev *dev, const void *data,
{
const struct bt_hci_cmd_read_clock_offset *cmd = data;
struct bt_hci_evt_clock_offset_complete ev;
+ struct btdev_conn *conn;
memset(&ev, 0, sizeof(ev));
- if (dev->conn) {
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (conn) {
ev.status = BT_HCI_ERR_SUCCESS;
ev.handle = cpu_to_le16(cmd->handle);
ev.clock_offset = 0;
@@ -2143,19 +2324,37 @@ static void set_common_commands_bredr20(struct btdev *btdev)
static int cmd_setup_sync_conn(struct btdev *dev, const void *data, uint8_t len)
{
+ cmd_status(dev, BT_HCI_ERR_SUCCESS, BT_HCI_EVT_SYNC_CONN_COMPLETE);
+
+ return 0;
+}
+
+static int cmd_setup_sync_conn_complete(struct btdev *dev, const void *data,
+ uint8_t len)
+{
const struct bt_hci_cmd_setup_sync_conn *cmd = data;
struct bt_hci_evt_sync_conn_complete cc;
- uint8_t status = BT_HCI_ERR_SUCCESS;
+ struct btdev_conn *conn;
- cmd_status(dev, status, BT_HCI_EVT_SYNC_CONN_COMPLETE);
+ memset(&cc, 0, sizeof(cc));
- if (!dev->conn)
- return 0;
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (!conn) {
+ cc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ goto done;
+ }
- cc.status = status;
- memcpy(cc.bdaddr, dev->conn->bdaddr, 6);
+ conn = conn_add_sco(conn);
+ if (!conn) {
+ cc.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
+ goto done;
+ }
- cc.handle = cpu_to_le16(status == BT_HCI_ERR_SUCCESS ? SCO_HANDLE : 0);
+ cc.status = BT_HCI_ERR_SUCCESS;
+ memcpy(cc.bdaddr, conn->link->dev->bdaddr, 6);
+
+ cc.handle = cpu_to_le16(conn->handle);
cc.link_type = 0x02;
cc.tx_interval = 0x000c;
cc.retrans_window = 0x06;
@@ -2163,6 +2362,7 @@ static int cmd_setup_sync_conn(struct btdev *dev, const void *data, uint8_t len)
cc.tx_pkt_len = 60;
cc.air_mode = (cmd->voice_setting == 0x0060) ? 0x02 : 0x03;
+done:
send_event(dev, BT_HCI_EVT_SYNC_CONN_COMPLETE, &cc, sizeof(cc));
return 0;
@@ -2255,13 +2455,14 @@ static int cmd_write_inquiry_tx_power(struct btdev *dev, const void *data,
static int cmd_io_cap_reply(struct btdev *dev, const void *data, uint8_t len)
{
- struct btdev *remote = dev->conn;
const struct bt_hci_cmd_io_capability_request_reply *cmd = data;
struct bt_hci_evt_io_capability_response ev;
struct bt_hci_rsp_io_capability_request_reply rsp;
+ struct btdev_conn *conn;
uint8_t status;
- if (!remote) {
+ conn = queue_find(dev->conns, match_bdaddr, cmd->bdaddr);
+ if (!conn) {
status = BT_HCI_ERR_UNKNOWN_CONN_ID;
goto done;
}
@@ -2276,22 +2477,23 @@ static int cmd_io_cap_reply(struct btdev *dev, const void *data, uint8_t len)
ev.oob_data = cmd->oob_data;
ev.authentication = cmd->authentication;
- send_event(remote, BT_HCI_EVT_IO_CAPABILITY_RESPONSE, &ev, sizeof(ev));
+ send_event(conn->link->dev, BT_HCI_EVT_IO_CAPABILITY_RESPONSE, &ev,
+ sizeof(ev));
- if (remote->io_cap) {
+ if (conn->link->dev->io_cap) {
struct bt_hci_evt_user_confirm_request cfm;
memcpy(cfm.bdaddr, dev->bdaddr, 6);
cfm.passkey = 0;
- send_event(remote, BT_HCI_EVT_USER_CONFIRM_REQUEST,
+ send_event(conn->link->dev, BT_HCI_EVT_USER_CONFIRM_REQUEST,
&cfm, sizeof(cfm));
memcpy(cfm.bdaddr, cmd->bdaddr, 6);
send_event(dev, BT_HCI_EVT_USER_CONFIRM_REQUEST,
&cfm, sizeof(cfm));
} else {
- send_event(remote, BT_HCI_EVT_IO_CAPABILITY_REQUEST,
+ send_event(conn->link->dev, BT_HCI_EVT_IO_CAPABILITY_REQUEST,
dev->bdaddr, 6);
}
@@ -2308,51 +2510,49 @@ static void ssp_complete(struct btdev *btdev, const uint8_t *bdaddr,
uint8_t status, bool wait)
{
struct bt_hci_evt_simple_pairing_complete iev, aev;
- struct bt_hci_evt_auth_complete auth;
- struct btdev *remote = btdev->conn;
- struct btdev *init, *accp;
+ struct btdev_conn *conn;
+ struct btdev_conn *init, *accp;
- if (!remote)
+ conn = queue_find(btdev->conns, match_bdaddr, bdaddr);
+ if (!conn)
return;
btdev->ssp_status = status;
btdev->ssp_auth_complete = true;
- if (!remote->ssp_auth_complete && wait)
+ if (!conn->link->dev->ssp_auth_complete && wait)
return;
if (status == BT_HCI_ERR_SUCCESS &&
- remote->ssp_status != BT_HCI_ERR_SUCCESS)
- status = remote->ssp_status;
+ conn->link->dev->ssp_status != BT_HCI_ERR_SUCCESS)
+ status = conn->link->dev->ssp_status;
iev.status = status;
aev.status = status;
if (btdev->auth_init) {
- init = btdev;
- accp = remote;
+ init = conn;
+ accp = conn->link;
memcpy(iev.bdaddr, bdaddr, 6);
memcpy(aev.bdaddr, btdev->bdaddr, 6);
} else {
- init = remote;
- accp = btdev;
+ init = conn->link;
+ accp = conn;
memcpy(iev.bdaddr, btdev->bdaddr, 6);
memcpy(aev.bdaddr, bdaddr, 6);
}
- send_event(init, BT_HCI_EVT_SIMPLE_PAIRING_COMPLETE, &iev,
- sizeof(iev));
- send_event(accp, BT_HCI_EVT_SIMPLE_PAIRING_COMPLETE, &aev,
- sizeof(aev));
+ send_event(init->dev, BT_HCI_EVT_SIMPLE_PAIRING_COMPLETE, &iev,
+ sizeof(iev));
+ send_event(accp->dev, BT_HCI_EVT_SIMPLE_PAIRING_COMPLETE, &aev,
+ sizeof(aev));
if (status == BT_HCI_ERR_SUCCESS) {
- link_key_notify(init, iev.bdaddr, LINK_KEY_DUMMY);
- link_key_notify(accp, aev.bdaddr, LINK_KEY_DUMMY);
+ link_key_notify(init->dev, iev.bdaddr, LINK_KEY_DUMMY);
+ link_key_notify(accp->dev, aev.bdaddr, LINK_KEY_DUMMY);
}
- auth.status = status;
- auth.handle = cpu_to_le16(ACL_HANDLE);
- send_event(init, BT_HCI_EVT_AUTH_COMPLETE, &auth, sizeof(auth));
+ auth_complete(init, status);
}
static int cmd_user_confirm_reply(struct btdev *dev, const void *data,
@@ -2419,10 +2619,15 @@ static int cmd_read_encrypt_key_size(struct btdev *dev, const void *data,
{
const struct bt_hci_cmd_read_encrypt_key_size *cmd = data;
struct bt_hci_rsp_read_encrypt_key_size rsp;
+ struct btdev_conn *conn;
+
+ memset(&rsp, 0, sizeof(rsp));
rsp.handle = cmd->handle;
- if (dev->conn) {
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (conn) {
rsp.status = BT_HCI_ERR_SUCCESS;
rsp.key_size = 16;
} else {
@@ -2485,7 +2690,8 @@ static int cmd_get_mws_transport_config(struct btdev *dev, const void *data,
}
#define CMD_BREDR \
- CMD(BT_HCI_CMD_SETUP_SYNC_CONN, cmd_setup_sync_conn, NULL), \
+ CMD(BT_HCI_CMD_SETUP_SYNC_CONN, cmd_setup_sync_conn, \
+ cmd_setup_sync_conn_complete), \
CMD(BT_HCI_CMD_READ_EXT_INQUIRY_RESPONSE, cmd_read_ext_inquiry, NULL), \
CMD(BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE, cmd_write_ext_inquiry, \
NULL), \
@@ -2986,50 +3192,67 @@ static bool adv_connectable(struct btdev *btdev)
return btdev->le_adv_type != 0x03;
}
+static void le_meta_event(struct btdev *btdev, uint8_t event,
+ void *data, uint8_t len)
+{
+ void *pkt_data;
+
+ util_debug(btdev->debug_callback, btdev->debug_data,
+ "meta event 0x%02x", event);
+
+ pkt_data = alloca(1 + len);
+ if (!pkt_data)
+ return;
+
+ ((uint8_t *) pkt_data)[0] = event;
+
+ if (len > 0)
+ memcpy(pkt_data + 1, data, len);
+
+ send_event(btdev, BT_HCI_EVT_LE_META_EVENT, pkt_data, 1 + len);
+}
+
static void le_conn_complete(struct btdev *btdev,
const struct bt_hci_cmd_le_create_conn *lecc,
uint8_t status)
{
- char buf[1 + sizeof(struct bt_hci_evt_le_conn_complete)];
- struct bt_hci_evt_le_conn_complete *cc = (void *) &buf[1];
+ struct bt_hci_evt_le_conn_complete cc;
- memset(buf, 0, sizeof(buf));
-
- buf[0] = BT_HCI_EVT_LE_CONN_COMPLETE;
+ memset(&cc, 0, sizeof(cc));
if (!status) {
- struct btdev *remote;
+ struct btdev_conn *conn;
- remote = find_btdev_by_bdaddr_type(lecc->peer_addr,
- lecc->peer_addr_type);
+ conn = conn_add_acl(btdev, lecc->peer_addr,
+ lecc->peer_addr_type);
+ if (!conn)
+ return;
- btdev->conn = remote;
btdev->le_adv_enable = 0;
- remote->conn = btdev;
- remote->le_adv_enable = 0;
+ conn->link->dev->le_adv_enable = 0;
- cc->status = status;
- cc->peer_addr_type = btdev->le_scan_own_addr_type;
- if (cc->peer_addr_type == 0x01)
- memcpy(cc->peer_addr, btdev->random_addr, 6);
+ cc.status = status;
+ cc.peer_addr_type = btdev->le_scan_own_addr_type;
+ if (cc.peer_addr_type == 0x01)
+ memcpy(cc.peer_addr, btdev->random_addr, 6);
else
- memcpy(cc->peer_addr, btdev->bdaddr, 6);
-
- cc->role = 0x01;
- cc->handle = cpu_to_le16(ACL_HANDLE);
- cc->interval = lecc->max_interval;
- cc->latency = lecc->latency;
- cc->supv_timeout = lecc->supv_timeout;
-
- send_event(remote, BT_HCI_EVT_LE_META_EVENT, buf, sizeof(buf));
+ memcpy(cc.peer_addr, btdev->bdaddr, 6);
+
+ cc.role = 0x01;
+ cc.handle = cpu_to_le16(conn->handle);
+ cc.interval = lecc->max_interval;
+ cc.latency = lecc->latency;
+ cc.supv_timeout = lecc->supv_timeout;
+ le_meta_event(conn->link->dev, BT_HCI_EVT_LE_CONN_COMPLETE,
+ &cc, sizeof(cc));
}
- cc->status = status;
- cc->peer_addr_type = lecc->peer_addr_type;
- memcpy(cc->peer_addr, lecc->peer_addr, 6);
- cc->role = 0x00;
+ cc.status = status;
+ cc.peer_addr_type = lecc->peer_addr_type;
+ memcpy(cc.peer_addr, lecc->peer_addr, 6);
+ cc.role = 0x00;
- send_event(btdev, BT_HCI_EVT_LE_META_EVENT, buf, sizeof(buf));
+ le_meta_event(btdev, BT_HCI_EVT_LE_CONN_COMPLETE, &cc, sizeof(cc));
}
static int cmd_le_create_conn(struct btdev *dev, const void *data, uint8_t len)
@@ -3092,27 +3315,29 @@ static void le_conn_update(struct btdev *btdev, uint16_t handle,
uint16_t latency, uint16_t supv_timeout,
uint16_t min_length, uint16_t max_length)
{
- struct btdev *remote = btdev->conn;
- struct __packed {
- uint8_t subevent;
- struct bt_hci_evt_le_conn_update_complete ev;
- } ev;
+ struct bt_hci_evt_le_conn_update_complete ev;
+ struct btdev_conn *conn;
+
+ memset(&ev, 0, sizeof(ev));
- ev.subevent = BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE;
- ev.ev.handle = cpu_to_le16(handle);
- ev.ev.interval = cpu_to_le16(min_interval);
- ev.ev.latency = cpu_to_le16(latency);
- ev.ev.supv_timeout = cpu_to_le16(supv_timeout);
+ ev.handle = cpu_to_le16(handle);
+ ev.interval = cpu_to_le16(min_interval);
+ ev.latency = cpu_to_le16(latency);
+ ev.supv_timeout = cpu_to_le16(supv_timeout);
- if (remote)
- ev.ev.status = BT_HCI_ERR_SUCCESS;
+ conn = queue_find(btdev->conns, match_handle, UINT_TO_PTR(handle));
+ if (conn)
+ ev.status = BT_HCI_ERR_SUCCESS;
else
- ev.ev.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ ev.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
- send_event(btdev, BT_HCI_EVT_LE_META_EVENT, &ev, sizeof(ev));
+ le_meta_event(btdev, BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE, &ev,
+ sizeof(ev));
- if (remote)
- send_event(remote, BT_HCI_EVT_LE_META_EVENT, &ev, sizeof(ev));
+ if (conn)
+ le_meta_event(conn->link->dev,
+ BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE,
+ &ev, sizeof(ev));
}
static void le_conn_param_req(struct btdev *btdev, uint16_t handle,
@@ -3120,23 +3345,23 @@ static void le_conn_param_req(struct btdev *btdev, uint16_t handle,
uint16_t latency, uint16_t supv_timeout,
uint16_t min_length, uint16_t max_length)
{
- struct btdev *remote = btdev->conn;
- struct __packed {
- uint8_t subevent;
- struct bt_hci_evt_le_conn_param_request ev;
- } ev;
+ struct bt_hci_evt_le_conn_param_request ev;
+ struct btdev_conn *conn;
- if (!remote)
+ conn = queue_find(btdev->conns, match_handle, UINT_TO_PTR(handle));
+ if (!conn)
return;
- ev.subevent = BT_HCI_EVT_LE_CONN_PARAM_REQUEST;
- ev.ev.handle = cpu_to_le16(handle);
- ev.ev.min_interval = cpu_to_le16(min_interval);
- ev.ev.max_interval = cpu_to_le16(max_interval);
- ev.ev.latency = cpu_to_le16(latency);
- ev.ev.supv_timeout = cpu_to_le16(supv_timeout);
+ memset(&ev, 0, sizeof(ev));
+
+ ev.handle = cpu_to_le16(handle);
+ ev.min_interval = cpu_to_le16(min_interval);
+ ev.max_interval = cpu_to_le16(max_interval);
+ ev.latency = cpu_to_le16(latency);
+ ev.supv_timeout = cpu_to_le16(supv_timeout);
- send_event(remote, BT_HCI_EVT_LE_META_EVENT, &ev, sizeof(ev));
+ le_meta_event(conn->link->dev, BT_HCI_EVT_LE_CONN_PARAM_REQUEST, &ev,
+ sizeof(ev));
}
static int cmd_conn_update_complete(struct btdev *dev, const void *data,
@@ -3164,44 +3389,28 @@ static int cmd_conn_update_complete(struct btdev *dev, const void *data,
return 0;
}
-static void le_meta_event(struct btdev *btdev, uint8_t event,
- void *data, uint8_t len)
-{
- void *pkt_data;
-
- util_debug(btdev->debug_callback, btdev->debug_data,
- "meta event 0x%02x", event);
-
- pkt_data = alloca(1 + len);
- if (!pkt_data)
- return;
-
- ((uint8_t *) pkt_data)[0] = event;
-
- if (len > 0)
- memcpy(pkt_data + 1, data, len);
-
- send_event(btdev, BT_HCI_EVT_LE_META_EVENT, pkt_data, 1 + len);
-}
-
static int cmd_le_read_remote_features(struct btdev *dev, const void *data,
uint8_t len)
{
+ const struct bt_hci_cmd_read_remote_features *cmd = data;
struct bt_hci_evt_le_remote_features_complete ev;
- struct btdev *remote = dev->conn;
+ struct btdev_conn *conn;
+ uint8_t status = BT_HCI_ERR_SUCCESS;
- if (!remote) {
- cmd_status(dev, BT_HCI_ERR_UNKNOWN_CONN_ID,
- BT_HCI_CMD_LE_READ_REMOTE_FEATURES);
- return 0;
- }
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (!conn)
+ status = BT_HCI_ERR_UNKNOWN_CONN_ID;
- cmd_status(dev, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_LE_READ_REMOTE_FEATURES);
+ cmd_status(dev, status, BT_HCI_CMD_LE_READ_REMOTE_FEATURES);
+
+ if (status)
+ return 0;
memset(&ev, 0, sizeof(ev));
ev.status = BT_HCI_ERR_SUCCESS;
- ev.handle = cpu_to_le16(ACL_HANDLE);
- memcpy(ev.features, remote->le_features, 8);
+ ev.handle = cpu_to_le16(conn->handle);
+ memcpy(ev.features, conn->link->dev->le_features, 8);
le_meta_event(dev, BT_HCI_EVT_LE_REMOTE_FEATURES_COMPLETE, &ev,
sizeof(ev));
@@ -3246,27 +3455,27 @@ static int cmd_rand(struct btdev *dev, const void *data, uint8_t len)
static int cmd_start_encrypt(struct btdev *dev, const void *data, uint8_t len)
{
const struct bt_hci_cmd_le_start_encrypt *cmd = data;
- char buf[1 + sizeof(struct bt_hci_evt_le_long_term_key_request)];
- struct bt_hci_evt_le_long_term_key_request *ev = (void *) &buf[1];
- struct btdev *remote = dev->conn;
+ struct bt_hci_evt_le_long_term_key_request ev;
+ struct btdev_conn *conn;
- if (!remote) {
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (!conn) {
cmd_status(dev, BT_HCI_ERR_UNKNOWN_CONN_ID,
- BT_HCI_CMD_LE_START_ENCRYPT);
+ BT_HCI_CMD_LE_START_ENCRYPT);
return 0;
}
- memcpy(dev->le_ltk, cmd->ltk, 16);
-
cmd_status(dev, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_LE_START_ENCRYPT);
- memset(buf, 0, sizeof(buf));
- buf[0] = BT_HCI_EVT_LE_LONG_TERM_KEY_REQUEST;
- ev->handle = cpu_to_le16(ACL_HANDLE);
- ev->ediv = cmd->ediv;
- ev->rand = cmd->rand;
+ memcpy(dev->le_ltk, cmd->ltk, 16);
+
+ ev.handle = cpu_to_le16(conn->handle);
+ ev.ediv = cmd->ediv;
+ ev.rand = cmd->rand;
- send_event(remote, BT_HCI_EVT_LE_META_EVENT, buf, sizeof(buf));
+ le_meta_event(conn->link->dev, BT_HCI_EVT_LE_LONG_TERM_KEY_REQUEST, &ev,
+ sizeof(ev));
return 0;
}
@@ -3274,11 +3483,13 @@ static int cmd_start_encrypt(struct btdev *dev, const void *data, uint8_t len)
static int cmd_ltk_reply(struct btdev *dev, const void *data, uint8_t len)
{
const struct bt_hci_cmd_le_ltk_req_reply *cmd = data;
- struct bt_hci_evt_encrypt_change ev;
struct bt_hci_rsp_le_ltk_req_reply rp;
- struct btdev *remote = dev->conn;
+ struct btdev_conn *conn;
+ uint8_t mode, status;
- if (!remote) {
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (!conn) {
rp.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
cmd_complete(dev, BT_HCI_CMD_LE_LTK_REQ_REPLY, &rp, sizeof(rp));
return 0;
@@ -3287,36 +3498,34 @@ static int cmd_ltk_reply(struct btdev *dev, const void *data, uint8_t len)
memcpy(dev->le_ltk, cmd->ltk, 16);
memset(&rp, 0, sizeof(rp));
- rp.handle = cpu_to_le16(ACL_HANDLE);
+ rp.handle = cpu_to_le16(conn->handle);
rp.status = BT_HCI_ERR_SUCCESS;
cmd_complete(dev, BT_HCI_CMD_LE_LTK_REQ_REPLY, &rp, sizeof(rp));
- memset(&ev, 0, sizeof(ev));
-
- if (memcmp(dev->le_ltk, remote->le_ltk, 16)) {
- ev.status = BT_HCI_ERR_AUTH_FAILURE;
- ev.encr_mode = 0x00;
+ if (memcmp(dev->le_ltk, conn->link->dev->le_ltk, 16)) {
+ status = BT_HCI_ERR_AUTH_FAILURE;
+ mode = 0x00;
} else {
- ev.status = BT_HCI_ERR_SUCCESS;
- ev.encr_mode = 0x01;
+ status = BT_HCI_ERR_SUCCESS;
+ mode = 0x01;
}
- ev.handle = cpu_to_le16(ACL_HANDLE);
-
- send_event(dev, BT_HCI_EVT_ENCRYPT_CHANGE, &ev, sizeof(ev));
- send_event(remote, BT_HCI_EVT_ENCRYPT_CHANGE, &ev, sizeof(ev));
+ encrypt_change(conn, mode, status);
+ encrypt_change(conn->link, mode, status);
return 0;
}
static int cmd_ltk_neg_reply(struct btdev *dev, const void *data, uint8_t len)
{
+ const struct bt_hci_cmd_le_ltk_req_neg_reply *cmd = data;
struct bt_hci_rsp_le_ltk_req_neg_reply rp;
- struct bt_hci_evt_encrypt_change ev;
- struct btdev *remote = dev->conn;
+ struct btdev_conn *conn;
- if (!remote) {
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (!conn) {
rp.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
cmd_complete(dev, BT_HCI_CMD_LE_LTK_REQ_NEG_REPLY, &rp,
sizeof(rp));
@@ -3324,15 +3533,11 @@ static int cmd_ltk_neg_reply(struct btdev *dev, const void *data, uint8_t len)
}
memset(&rp, 0, sizeof(rp));
- rp.handle = cpu_to_le16(ACL_HANDLE);
+ rp.handle = cpu_to_le16(conn->handle);
rp.status = BT_HCI_ERR_SUCCESS;
cmd_complete(dev, BT_HCI_CMD_LE_LTK_REQ_NEG_REPLY, &rp, sizeof(rp));
- memset(&ev, 0, sizeof(ev));
- ev.status = BT_HCI_ERR_PIN_OR_KEY_MISSING;
- ev.handle = cpu_to_le16(ACL_HANDLE);
-
- send_event(remote, BT_HCI_EVT_ENCRYPT_CHANGE, &ev, sizeof(ev));
+ encrypt_change(conn->link, 0x00, BT_HCI_ERR_PIN_OR_KEY_MISSING);
return 0;
}
@@ -3413,10 +3618,12 @@ static int cmd_conn_param_neg_reply_complete(struct btdev *dev,
const void *data, uint8_t len)
{
const struct bt_hci_cmd_le_conn_param_req_neg_reply *cmd = data;
- struct btdev *remote = dev->conn;
+ struct btdev_conn *conn;
struct bt_hci_evt_le_conn_update_complete ev;
- if (!remote)
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (!conn)
return 0;
memset(&ev, 0, sizeof(ev));
@@ -3424,7 +3631,7 @@ static int cmd_conn_param_neg_reply_complete(struct btdev *dev,
ev.handle = cpu_to_le16(cmd->handle);
ev.status = cpu_to_le16(cmd->reason);
- le_meta_event(remote, BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE, &ev,
+ le_meta_event(conn->link->dev, BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE, &ev,
sizeof(ev));
return 0;
@@ -3861,15 +4068,14 @@ static void le_ext_conn_complete(struct btdev *btdev,
memset(&ev, 0, sizeof(ev));
if (!status) {
- struct btdev *remote;
+ struct btdev_conn *conn;
- remote = find_btdev_by_bdaddr_type(cmd->peer_addr,
- cmd->peer_addr_type);
+ conn = conn_add_acl(btdev, cmd->peer_addr, cmd->peer_addr_type);
+ if (!conn)
+ return;
- btdev->conn = remote;
btdev->le_adv_enable = 0;
- remote->conn = btdev;
- remote->le_adv_enable = 0;
+ conn->link->dev->le_adv_enable = 0;
ev.status = status;
ev.peer_addr_type = btdev->le_scan_own_addr_type;
@@ -3879,13 +4085,14 @@ static void le_ext_conn_complete(struct btdev *btdev,
memcpy(ev.peer_addr, btdev->bdaddr, 6);
ev.role = 0x01;
- ev.handle = cpu_to_le16(ACL_HANDLE);
+ ev.handle = cpu_to_le16(conn->handle);
ev.interval = lecc->max_interval;
ev.latency = lecc->latency;
ev.supv_timeout = lecc->supv_timeout;
- le_meta_event(remote, BT_HCI_EVT_LE_ENHANCED_CONN_COMPLETE, &ev,
- sizeof(ev));
+ le_meta_event(conn->link->dev,
+ BT_HCI_EVT_LE_ENHANCED_CONN_COMPLETE, &ev,
+ sizeof(ev));
}
ev.status = status;
@@ -4066,17 +4273,30 @@ static int cmd_set_cig_params(struct btdev *dev, const void *data,
const struct bt_hci_cmd_le_set_cig_params *cmd = data;
struct lescp {
struct bt_hci_rsp_le_set_cig_params params;
- uint16_t handle;
+ uint16_t handle[3];
} __attribute__ ((packed)) rsp;
+ int i = 0;
memset(&rsp, 0, sizeof(rsp));
memcpy(&dev->le_cig, data, len);
+
+ if (cmd->num_cis > ARRAY_SIZE(rsp.handle)) {
+ rsp.params.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
+ goto done;
+ }
+
rsp.params.status = BT_HCI_ERR_SUCCESS;
rsp.params.cig_id = cmd->cig_id;
- rsp.params.num_handles = 1;
- rsp.handle = cpu_to_le16(ISO_HANDLE);
- cmd_complete(dev, BT_HCI_CMD_LE_SET_CIG_PARAMS, &rsp, sizeof(rsp));
+
+ for (i = 0; i < cmd->num_cis; i++) {
+ rsp.params.num_handles++;
+ rsp.handle[i] = cpu_to_le16(ISO_HANDLE + i);
+ }
+
+done:
+ cmd_complete(dev, BT_HCI_CMD_LE_SET_CIG_PARAMS, &rsp,
+ sizeof(rsp.params) + (i * sizeof(uint16_t)));
return 0;
}
@@ -4095,7 +4315,8 @@ static int cmd_create_cis(struct btdev *dev, const void *data, uint8_t len)
return 0;
}
-static void le_cis_estabilished(struct btdev *dev, uint8_t status)
+static void le_cis_estabilished(struct btdev *dev, struct btdev_conn *conn,
+ uint8_t status)
{
struct bt_hci_evt_le_cis_established evt;
@@ -4103,11 +4324,8 @@ static void le_cis_estabilished(struct btdev *dev, uint8_t status)
evt.status = status;
- if (dev->conn)
- dev = dev->conn;
-
if (!evt.status) {
- evt.conn_handle = cpu_to_le16(ISO_HANDLE);
+ evt.conn_handle = cpu_to_le16(conn->handle);
/* TODO: Figure out if these values makes sense */
memcpy(evt.cig_sync_delay, dev->le_cig.params.m_interval,
sizeof(dev->le_cig.params.m_interval));
@@ -4131,27 +4349,49 @@ static void le_cis_estabilished(struct btdev *dev, uint8_t status)
le_meta_event(dev, BT_HCI_EVT_LE_CIS_ESTABLISHED, &evt, sizeof(evt));
- if (dev->conn)
- le_meta_event(dev->conn, BT_HCI_EVT_LE_CIS_ESTABLISHED, &evt,
- sizeof(evt));
+ if (conn)
+ le_meta_event(conn->link->dev, BT_HCI_EVT_LE_CIS_ESTABLISHED,
+ &evt, sizeof(evt));
}
static int cmd_create_cis_complete(struct btdev *dev, const void *data,
uint8_t len)
{
- struct btdev *remote = dev->conn;
+ const struct bt_hci_cmd_le_create_cis *cmd = data;
+ int i;
- if (remote) {
+ for (i = 0; i < cmd->num_cis; i++) {
+ const struct bt_hci_cis *cis = &cmd->cis[i];
+ struct btdev_conn *acl;
+ struct btdev_conn *iso;
struct bt_hci_evt_le_cis_req evt;
- evt.acl_handle = cpu_to_le16(ACL_HANDLE);
- evt.cis_handle = cpu_to_le16(ISO_HANDLE);
+ acl = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(cpu_to_le16(cis->acl_handle)));
+ if (!acl) {
+ le_cis_estabilished(dev, NULL,
+ BT_HCI_ERR_UNKNOWN_CONN_ID);
+ break;
+ }
+
+ iso = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(cpu_to_le16(cis->cis_handle)));
+ if (!iso) {
+ iso = conn_add_iso(acl, cpu_to_le16(cis->cis_handle));
+ if (!iso) {
+ le_cis_estabilished(dev, NULL,
+ BT_HCI_ERR_UNKNOWN_CONN_ID);
+ break;
+ }
+ }
+
+ evt.acl_handle = cpu_to_le16(acl->handle);
+ evt.cis_handle = cpu_to_le16(iso->handle);
evt.cig_id = 0x00;
evt.cis_id = 0x00;
- le_meta_event(remote, BT_HCI_EVT_LE_CIS_REQ, &evt, sizeof(evt));
- } else {
- le_cis_estabilished(dev, BT_HCI_ERR_UNKNOWN_CONN_ID);
+ le_meta_event(iso->dev, BT_HCI_EVT_LE_CIS_REQ, &evt,
+ sizeof(evt));
}
return 0;
@@ -4173,8 +4413,19 @@ static int cmd_remove_cig(struct btdev *dev, const void *data, uint8_t len)
static int cmd_accept_cis(struct btdev *dev, const void *data, uint8_t len)
{
+ const struct bt_hci_cmd_le_accept_cis *cmd = data;
+ struct btdev_conn *conn;
+
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(cpu_to_le16(cmd->handle)));
+ if (!conn) {
+ cmd_status(dev, BT_HCI_ERR_UNKNOWN_CONN_ID,
+ BT_HCI_CMD_LE_ACCEPT_CIS);
+ return 0;
+ }
+
cmd_status(dev, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_LE_ACCEPT_CIS);
- le_cis_estabilished(dev, BT_HCI_ERR_SUCCESS);
+ le_cis_estabilished(dev, conn, BT_HCI_ERR_SUCCESS);
return 0;
}
@@ -4182,9 +4433,18 @@ static int cmd_accept_cis(struct btdev *dev, const void *data, uint8_t len)
static int cmd_reject_cis(struct btdev *dev, const void *data, uint8_t len)
{
const struct bt_hci_cmd_le_reject_cis *cmd = data;
+ struct btdev_conn *conn;
- cmd_status(dev, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_LE_ACCEPT_CIS);
- le_cis_estabilished(dev, cmd->reason);
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(cpu_to_le16(cmd->handle)));
+ if (!conn) {
+ cmd_status(dev, BT_HCI_ERR_UNKNOWN_CONN_ID,
+ BT_HCI_CMD_LE_REJECT_CIS);
+ return 0;
+ }
+
+ cmd_status(dev, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_LE_REJECT_CIS);
+ le_cis_estabilished(dev, conn, cmd->reason);
return 0;
}
@@ -4229,10 +4489,13 @@ static int cmd_setup_iso_path(struct btdev *dev, const void *data, uint8_t len)
{
const struct bt_hci_cmd_le_setup_iso_path *cmd = data;
struct bt_hci_rsp_le_setup_iso_path rsp;
+ struct btdev_conn *conn;
memset(&rsp, 0, sizeof(rsp));
- if (le16_to_cpu(cmd->handle) != ISO_HANDLE) {
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(cpu_to_le16(cmd->handle)));
+ if (!conn) {
rsp.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
goto done;
}
@@ -4246,11 +4509,11 @@ static int cmd_setup_iso_path(struct btdev *dev, const void *data, uint8_t len)
switch (cmd->direction) {
case 0x00:
dev->le_iso_path[0] = cmd->path;
- rsp.handle = cpu_to_le16(ISO_HANDLE);
+ rsp.handle = cpu_to_le16(conn->handle);
break;
case 0x01:
dev->le_iso_path[1] = cmd->path;
- rsp.handle = cpu_to_le16(ISO_HANDLE);
+ rsp.handle = cpu_to_le16(conn->handle);
break;
default:
rsp.status = BT_HCI_ERR_INVALID_PARAMETERS;
@@ -4266,9 +4529,14 @@ static int cmd_remove_iso_path(struct btdev *dev, const void *data, uint8_t len)
{
const struct bt_hci_cmd_le_remove_iso_path *cmd = data;
uint8_t status = BT_HCI_ERR_SUCCESS;
+ struct btdev_conn *conn;
- if (!dev->conn || le16_to_cpu(cmd->handle) != ISO_HANDLE)
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(cpu_to_le16(cmd->handle)));
+ if (!conn) {
status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ goto done;
+ }
switch (cmd->direction) {
case 0x00:
@@ -4281,6 +4549,7 @@ static int cmd_remove_iso_path(struct btdev *dev, const void *data, uint8_t len)
status = BT_HCI_ERR_INVALID_PARAMETERS;
}
+done:
cmd_complete(dev, BT_HCI_CMD_LE_REMOVE_ISO_PATH, &status,
sizeof(status));
@@ -4797,6 +5066,8 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id)
get_bdaddr(id, index, btdev->bdaddr);
+ btdev->conns = queue_new();
+
return btdev;
}
@@ -4878,7 +5149,10 @@ void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler,
static void num_completed_packets(struct btdev *btdev, uint16_t handle)
{
- if (btdev->conn) {
+ struct btdev_conn *conn;
+
+ conn = queue_find(btdev->conns, match_handle, UINT_TO_PTR(handle));
+ if (conn) {
struct bt_hci_evt_num_completed_packets ncp;
ncp.num_handles = 1;
@@ -5019,10 +5293,11 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
}
}
-static void send_acl(struct btdev *conn, const void *data, uint16_t len)
+static void send_acl(struct btdev *dev, const void *data, uint16_t len)
{
struct bt_hci_acl_hdr hdr;
struct iovec iov[3];
+ struct btdev_conn *conn;
/* Packet type */
iov[0].iov_base = (void *) data;
@@ -5032,8 +5307,16 @@ static void send_acl(struct btdev *conn, const void *data, uint16_t len)
* From controller to host this should be converted to ACL_START.
*/
memcpy(&hdr, data + 1, sizeof(hdr));
+
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(acl_handle(hdr.handle)));
+ if (!conn)
+ return;
+
+ num_completed_packets(dev, conn->handle);
+
if (acl_flags(hdr.handle) == ACL_START_NO_FLUSH)
- hdr.handle = acl_handle_pack(acl_handle(hdr.handle), ACL_START);
+ hdr.handle = acl_handle_pack(conn->handle, ACL_START);
iov[1].iov_base = &hdr;
iov[1].iov_len = sizeof(hdr);
@@ -5041,17 +5324,26 @@ static void send_acl(struct btdev *conn, const void *data, uint16_t len)
iov[2].iov_base = (void *) (data + 1 + sizeof(hdr));
iov[2].iov_len = len - 1 - sizeof(hdr);
- send_packet(conn, iov, 3);
+ send_packet(conn->link->dev, iov, 3);
}
-static void send_iso(struct btdev *conn, const void *data, uint16_t len)
+static void send_iso(struct btdev *dev, const void *data, uint16_t len)
{
+ struct bt_hci_acl_hdr *hdr;
struct iovec iov;
+ struct btdev_conn *conn;
- iov.iov_base = (void *) (data);
+ iov.iov_base = hdr = (void *) (data);
iov.iov_len = len;
- send_packet(conn, &iov, 1);
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(acl_handle(hdr->handle)));
+ if (!conn)
+ return;
+
+ num_completed_packets(dev, conn->handle);
+
+ send_packet(conn->link->dev, &iov, 1);
}
void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len)
@@ -5074,14 +5366,10 @@ void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len)
process_cmd(btdev, data + 1, len - 1);
break;
case BT_H4_ACL_PKT:
- if (btdev->conn)
- send_acl(btdev->conn, data, len);
- num_completed_packets(btdev, ACL_HANDLE);
+ send_acl(btdev, data, len);
break;
case BT_H4_ISO_PKT:
- num_completed_packets(btdev, ISO_HANDLE);
- if (btdev->conn)
- send_iso(btdev->conn, data, len);
+ send_iso(btdev, data, len);
break;
default:
util_debug(btdev->debug_callback, btdev->debug_data,
diff --git a/lib/hci.h b/lib/hci.h
index 0ca20421a..3382b87bf 100644
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -107,6 +107,7 @@ enum {
#define HCI_ACLDATA_PKT 0x02
#define HCI_SCODATA_PKT 0x03
#define HCI_EVENT_PKT 0x04
+#define HCI_ISODATA_PKT 0x05
#define HCI_VENDOR_PKT 0xff
/* HCI Packet types */