From a7e3e32ea5841a567683d1b9986b5d78235f94a5 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Tue, 9 Mar 2021 17:31:37 +0100 Subject: [PATCH] Bluetooth: host: Refactor out BR/EDR from hci_core to br Refactor out the BR/EDR handling from hci_core.c to its own source file in br.c. BR/EDR consists of inquiry and discovery roles in addition to initialization. SSP is still kept separate. Signed-off-by: Joakim Andersson --- subsys/bluetooth/host/CMakeLists.txt | 1 + subsys/bluetooth/host/br.c | 1090 +++++++++++++++++++++++++ subsys/bluetooth/host/br.h | 12 + subsys/bluetooth/host/hci_core.c | 1122 +------------------------- subsys/bluetooth/host/hci_core.h | 15 + 5 files changed, 1142 insertions(+), 1098 deletions(-) create mode 100644 subsys/bluetooth/host/br.c create mode 100644 subsys/bluetooth/host/br.h diff --git a/subsys/bluetooth/host/CMakeLists.txt b/subsys/bluetooth/host/CMakeLists.txt index 6e3b5a278a5..7063f6a8151 100644 --- a/subsys/bluetooth/host/CMakeLists.txt +++ b/subsys/bluetooth/host/CMakeLists.txt @@ -15,6 +15,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_HOST_CCM aes_ccm.c) zephyr_library_sources_ifdef( CONFIG_BT_BREDR + br.c keys_br.c l2cap_br.c sdp.c diff --git a/subsys/bluetooth/host/br.c b/subsys/bluetooth/host/br.c new file mode 100644 index 00000000000..18c83413626 --- /dev/null +++ b/subsys/bluetooth/host/br.c @@ -0,0 +1,1090 @@ +/* + * Copyright (c) 2017-2021 Nordic Semiconductor ASA + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +#include +#include +#include + +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE) +#define LOG_MODULE_NAME bt_br +#include "common/log.h" + +#include "hci_core.h" +#include "conn_internal.h" +#include "keys.h" + +static bt_br_discovery_cb_t *discovery_cb; +struct bt_br_discovery_result *discovery_results; +static size_t discovery_results_size; +static size_t discovery_results_count; + +static int reject_conn(const bt_addr_t *bdaddr, uint8_t reason) +{ + struct bt_hci_cp_reject_conn_req *cp; + struct net_buf *buf; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_REJECT_CONN_REQ, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + bt_addr_copy(&cp->bdaddr, bdaddr); + cp->reason = reason; + + err = bt_hci_cmd_send_sync(BT_HCI_OP_REJECT_CONN_REQ, buf, NULL); + if (err) { + return err; + } + + return 0; +} + +static int accept_sco_conn(const bt_addr_t *bdaddr, struct bt_conn *sco_conn) +{ + struct bt_hci_cp_accept_sync_conn_req *cp; + struct net_buf *buf; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_ACCEPT_SYNC_CONN_REQ, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + bt_addr_copy(&cp->bdaddr, bdaddr); + cp->pkt_type = sco_conn->sco.pkt_type; + cp->tx_bandwidth = 0x00001f40; + cp->rx_bandwidth = 0x00001f40; + cp->max_latency = 0x0007; + cp->retrans_effort = 0x01; + cp->content_format = BT_VOICE_CVSD_16BIT; + + err = bt_hci_cmd_send_sync(BT_HCI_OP_ACCEPT_SYNC_CONN_REQ, buf, NULL); + if (err) { + return err; + } + + return 0; +} + +static int accept_conn(const bt_addr_t *bdaddr) +{ + struct bt_hci_cp_accept_conn_req *cp; + struct net_buf *buf; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_ACCEPT_CONN_REQ, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + bt_addr_copy(&cp->bdaddr, bdaddr); + cp->role = BT_HCI_ROLE_SLAVE; + + err = bt_hci_cmd_send_sync(BT_HCI_OP_ACCEPT_CONN_REQ, buf, NULL); + if (err) { + return err; + } + + return 0; +} + +static void bt_esco_conn_req(struct bt_hci_evt_conn_request *evt) +{ + struct bt_conn *sco_conn; + + sco_conn = bt_conn_add_sco(&evt->bdaddr, evt->link_type); + if (!sco_conn) { + reject_conn(&evt->bdaddr, BT_HCI_ERR_INSUFFICIENT_RESOURCES); + return; + } + + if (accept_sco_conn(&evt->bdaddr, sco_conn)) { + BT_ERR("Error accepting connection from %s", + bt_addr_str(&evt->bdaddr)); + reject_conn(&evt->bdaddr, BT_HCI_ERR_UNSPECIFIED); + bt_sco_cleanup(sco_conn); + return; + } + + sco_conn->role = BT_HCI_ROLE_SLAVE; + bt_conn_set_state(sco_conn, BT_CONN_CONNECT); + bt_conn_unref(sco_conn); +} + +void bt_hci_conn_req(struct net_buf *buf) +{ + struct bt_hci_evt_conn_request *evt = (void *)buf->data; + struct bt_conn *conn; + + BT_DBG("conn req from %s, type 0x%02x", bt_addr_str(&evt->bdaddr), + evt->link_type); + + if (evt->link_type != BT_HCI_ACL) { + bt_esco_conn_req(evt); + return; + } + + conn = bt_conn_add_br(&evt->bdaddr); + if (!conn) { + reject_conn(&evt->bdaddr, BT_HCI_ERR_INSUFFICIENT_RESOURCES); + return; + } + + accept_conn(&evt->bdaddr); + conn->role = BT_HCI_ROLE_SLAVE; + bt_conn_set_state(conn, BT_CONN_CONNECT); + bt_conn_unref(conn); +} + +static bool br_sufficient_key_size(struct bt_conn *conn) +{ + struct bt_hci_cp_read_encryption_key_size *cp; + struct bt_hci_rp_read_encryption_key_size *rp; + struct net_buf *buf, *rsp; + uint8_t key_size; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE, + sizeof(*cp)); + if (!buf) { + BT_ERR("Failed to allocate command buffer"); + return false; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(conn->handle); + + err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE, + buf, &rsp); + if (err) { + BT_ERR("Failed to read encryption key size (err %d)", err); + return false; + } + + if (rsp->len < sizeof(*rp)) { + BT_ERR("Too small command complete for encryption key size"); + net_buf_unref(rsp); + return false; + } + + rp = (void *)rsp->data; + key_size = rp->key_size; + net_buf_unref(rsp); + + BT_DBG("Encryption key size is %u", key_size); + + if (conn->sec_level == BT_SECURITY_L4) { + return key_size == BT_HCI_ENCRYPTION_KEY_SIZE_MAX; + } + + return key_size >= BT_HCI_ENCRYPTION_KEY_SIZE_MIN; +} + +bool bt_br_update_sec_level(struct bt_conn *conn) +{ + if (!conn->encrypt) { + conn->sec_level = BT_SECURITY_L1; + return true; + } + + if (conn->br.link_key) { + if (conn->br.link_key->flags & BT_LINK_KEY_AUTHENTICATED) { + if (conn->encrypt == 0x02) { + conn->sec_level = BT_SECURITY_L4; + } else { + conn->sec_level = BT_SECURITY_L3; + } + } else { + conn->sec_level = BT_SECURITY_L2; + } + } else { + BT_WARN("No BR/EDR link key found"); + conn->sec_level = BT_SECURITY_L2; + } + + if (!br_sufficient_key_size(conn)) { + BT_ERR("Encryption key size is not sufficient"); + bt_conn_disconnect(conn, BT_HCI_ERR_AUTH_FAIL); + return false; + } + + if (conn->required_sec_level > conn->sec_level) { + BT_ERR("Failed to set required security level"); + bt_conn_disconnect(conn, BT_HCI_ERR_AUTH_FAIL); + return false; + } + + return true; +} + +void bt_hci_synchronous_conn_complete(struct net_buf *buf) +{ + struct bt_hci_evt_sync_conn_complete *evt = (void *)buf->data; + struct bt_conn *sco_conn; + uint16_t handle = sys_le16_to_cpu(evt->handle); + + BT_DBG("status 0x%02x, handle %u, type 0x%02x", evt->status, handle, + evt->link_type); + + sco_conn = bt_conn_lookup_addr_sco(&evt->bdaddr); + if (!sco_conn) { + BT_ERR("Unable to find conn for %s", bt_addr_str(&evt->bdaddr)); + return; + } + + if (evt->status) { + sco_conn->err = evt->status; + bt_conn_set_state(sco_conn, BT_CONN_DISCONNECTED); + bt_conn_unref(sco_conn); + return; + } + + sco_conn->handle = handle; + bt_conn_set_state(sco_conn, BT_CONN_CONNECTED); + bt_conn_unref(sco_conn); +} + +void bt_hci_conn_complete(struct net_buf *buf) +{ + struct bt_hci_evt_conn_complete *evt = (void *)buf->data; + struct bt_conn *conn; + struct bt_hci_cp_read_remote_features *cp; + uint16_t handle = sys_le16_to_cpu(evt->handle); + + BT_DBG("status 0x%02x, handle %u, type 0x%02x", evt->status, handle, + evt->link_type); + + conn = bt_conn_lookup_addr_br(&evt->bdaddr); + if (!conn) { + BT_ERR("Unable to find conn for %s", bt_addr_str(&evt->bdaddr)); + return; + } + + if (evt->status) { + conn->err = evt->status; + bt_conn_set_state(conn, BT_CONN_DISCONNECTED); + bt_conn_unref(conn); + return; + } + + conn->handle = handle; + conn->err = 0U; + conn->encrypt = evt->encr_enabled; + + if (!bt_br_update_sec_level(conn)) { + bt_conn_unref(conn); + return; + } + + bt_conn_set_state(conn, BT_CONN_CONNECTED); + bt_conn_unref(conn); + + buf = bt_hci_cmd_create(BT_HCI_OP_READ_REMOTE_FEATURES, sizeof(*cp)); + if (!buf) { + return; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = evt->handle; + + bt_hci_cmd_send_sync(BT_HCI_OP_READ_REMOTE_FEATURES, buf, NULL); +} + +struct discovery_priv { + uint16_t clock_offset; + uint8_t pscan_rep_mode; + uint8_t resolving; +} __packed; + +static int request_name(const bt_addr_t *addr, uint8_t pscan, uint16_t offset) +{ + struct bt_hci_cp_remote_name_request *cp; + struct net_buf *buf; + + buf = bt_hci_cmd_create(BT_HCI_OP_REMOTE_NAME_REQUEST, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + + bt_addr_copy(&cp->bdaddr, addr); + cp->pscan_rep_mode = pscan; + cp->reserved = 0x00; /* reserver, should be set to 0x00 */ + cp->clock_offset = offset; + + return bt_hci_cmd_send_sync(BT_HCI_OP_REMOTE_NAME_REQUEST, buf, NULL); +} + +#define EIR_SHORT_NAME 0x08 +#define EIR_COMPLETE_NAME 0x09 + +static bool eir_has_name(const uint8_t *eir) +{ + int len = 240; + + while (len) { + if (len < 2) { + break; + }; + + /* Look for early termination */ + if (!eir[0]) { + break; + } + + /* Check if field length is correct */ + if (eir[0] > len - 1) { + break; + } + + switch (eir[1]) { + case EIR_SHORT_NAME: + case EIR_COMPLETE_NAME: + if (eir[0] > 1) { + return true; + } + break; + default: + break; + } + + /* Parse next AD Structure */ + len -= eir[0] + 1; + eir += eir[0] + 1; + } + + return false; +} + +void bt_br_discovery_reset(void) +{ + discovery_cb = NULL; + discovery_results = NULL; + discovery_results_size = 0; + discovery_results_count = 0; +} + +static void report_discovery_results(void) +{ + bool resolving_names = false; + int i; + + for (i = 0; i < discovery_results_count; i++) { + struct discovery_priv *priv; + + priv = (struct discovery_priv *)&discovery_results[i]._priv; + + if (eir_has_name(discovery_results[i].eir)) { + continue; + } + + if (request_name(&discovery_results[i].addr, + priv->pscan_rep_mode, priv->clock_offset)) { + continue; + } + + priv->resolving = 1U; + resolving_names = true; + } + + if (resolving_names) { + return; + } + + atomic_clear_bit(bt_dev.flags, BT_DEV_INQUIRY); + + discovery_cb(discovery_results, discovery_results_count); + bt_br_discovery_reset(); +} + +void bt_hci_inquiry_complete(struct net_buf *buf) +{ + struct bt_hci_evt_inquiry_complete *evt = (void *)buf->data; + + if (evt->status) { + BT_ERR("Failed to complete inquiry"); + } + + report_discovery_results(); +} + +static struct bt_br_discovery_result *get_result_slot(const bt_addr_t *addr, + int8_t rssi) +{ + struct bt_br_discovery_result *result = NULL; + size_t i; + + /* check if already present in results */ + for (i = 0; i < discovery_results_count; i++) { + if (!bt_addr_cmp(addr, &discovery_results[i].addr)) { + return &discovery_results[i]; + } + } + + /* Pick a new slot (if available) */ + if (discovery_results_count < discovery_results_size) { + bt_addr_copy(&discovery_results[discovery_results_count].addr, + addr); + return &discovery_results[discovery_results_count++]; + } + + /* ignore if invalid RSSI */ + if (rssi == 0xff) { + return NULL; + } + + /* + * Pick slot with smallest RSSI that is smaller then passed RSSI + * TODO handle TX if present + */ + for (i = 0; i < discovery_results_size; i++) { + if (discovery_results[i].rssi > rssi) { + continue; + } + + if (!result || result->rssi > discovery_results[i].rssi) { + result = &discovery_results[i]; + } + } + + if (result) { + BT_DBG("Reusing slot (old %s rssi %d dBm)", + bt_addr_str(&result->addr), result->rssi); + + bt_addr_copy(&result->addr, addr); + } + + return result; +} + +void bt_hci_inquiry_result_with_rssi(struct net_buf *buf) +{ + uint8_t num_reports = net_buf_pull_u8(buf); + + if (!atomic_test_bit(bt_dev.flags, BT_DEV_INQUIRY)) { + return; + } + + BT_DBG("number of results: %u", num_reports); + + while (num_reports--) { + struct bt_hci_evt_inquiry_result_with_rssi *evt; + struct bt_br_discovery_result *result; + struct discovery_priv *priv; + + if (buf->len < sizeof(*evt)) { + BT_ERR("Unexpected end to buffer"); + return; + } + + evt = net_buf_pull_mem(buf, sizeof(*evt)); + BT_DBG("%s rssi %d dBm", bt_addr_str(&evt->addr), evt->rssi); + + result = get_result_slot(&evt->addr, evt->rssi); + if (!result) { + return; + } + + priv = (struct discovery_priv *)&result->_priv; + priv->pscan_rep_mode = evt->pscan_rep_mode; + priv->clock_offset = evt->clock_offset; + + memcpy(result->cod, evt->cod, 3); + result->rssi = evt->rssi; + + /* we could reuse slot so make sure EIR is cleared */ + (void)memset(result->eir, 0, sizeof(result->eir)); + } +} + +void bt_hci_extended_inquiry_result(struct net_buf *buf) +{ + struct bt_hci_evt_extended_inquiry_result *evt = (void *)buf->data; + struct bt_br_discovery_result *result; + struct discovery_priv *priv; + + if (!atomic_test_bit(bt_dev.flags, BT_DEV_INQUIRY)) { + return; + } + + BT_DBG("%s rssi %d dBm", bt_addr_str(&evt->addr), evt->rssi); + + result = get_result_slot(&evt->addr, evt->rssi); + if (!result) { + return; + } + + priv = (struct discovery_priv *)&result->_priv; + priv->pscan_rep_mode = evt->pscan_rep_mode; + priv->clock_offset = evt->clock_offset; + + result->rssi = evt->rssi; + memcpy(result->cod, evt->cod, 3); + memcpy(result->eir, evt->eir, sizeof(result->eir)); +} + +void bt_hci_remote_name_request_complete(struct net_buf *buf) +{ + struct bt_hci_evt_remote_name_req_complete *evt = (void *)buf->data; + struct bt_br_discovery_result *result; + struct discovery_priv *priv; + int eir_len = 240; + uint8_t *eir; + int i; + + result = get_result_slot(&evt->bdaddr, 0xff); + if (!result) { + return; + } + + priv = (struct discovery_priv *)&result->_priv; + priv->resolving = 0U; + + if (evt->status) { + goto check_names; + } + + eir = result->eir; + + while (eir_len) { + if (eir_len < 2) { + break; + }; + + /* Look for early termination */ + if (!eir[0]) { + size_t name_len; + + eir_len -= 2; + + /* name is null terminated */ + name_len = strlen((const char *)evt->name); + + if (name_len > eir_len) { + eir[0] = eir_len + 1; + eir[1] = EIR_SHORT_NAME; + } else { + eir[0] = name_len + 1; + eir[1] = EIR_SHORT_NAME; + } + + memcpy(&eir[2], evt->name, eir[0] - 1); + + break; + } + + /* Check if field length is correct */ + if (eir[0] > eir_len - 1) { + break; + } + + /* next EIR Structure */ + eir_len -= eir[0] + 1; + eir += eir[0] + 1; + } + +check_names: + /* if still waiting for names */ + for (i = 0; i < discovery_results_count; i++) { + struct discovery_priv *priv; + + priv = (struct discovery_priv *)&discovery_results[i]._priv; + + if (priv->resolving) { + return; + } + } + + /* all names resolved, report discovery results */ + atomic_clear_bit(bt_dev.flags, BT_DEV_INQUIRY); + + discovery_cb(discovery_results, discovery_results_count); + +} + +void bt_hci_read_remote_features_complete(struct net_buf *buf) +{ + struct bt_hci_evt_remote_features *evt = (void *)buf->data; + uint16_t handle = sys_le16_to_cpu(evt->handle); + struct bt_hci_cp_read_remote_ext_features *cp; + struct bt_conn *conn; + + BT_DBG("status 0x%02x handle %u", evt->status, handle); + + conn = bt_conn_lookup_handle(handle); + if (!conn) { + BT_ERR("Can't find conn for handle %u", handle); + return; + } + + if (evt->status) { + goto done; + } + + memcpy(conn->br.features[0], evt->features, sizeof(evt->features)); + + if (!BT_FEAT_EXT_FEATURES(conn->br.features)) { + goto done; + } + + buf = bt_hci_cmd_create(BT_HCI_OP_READ_REMOTE_EXT_FEATURES, + sizeof(*cp)); + if (!buf) { + goto done; + } + + /* Read remote host features (page 1) */ + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = evt->handle; + cp->page = 0x01; + + bt_hci_cmd_send_sync(BT_HCI_OP_READ_REMOTE_EXT_FEATURES, buf, NULL); + +done: + bt_conn_unref(conn); +} + +void bt_hci_read_remote_ext_features_complete(struct net_buf *buf) +{ + struct bt_hci_evt_remote_ext_features *evt = (void *)buf->data; + uint16_t handle = sys_le16_to_cpu(evt->handle); + struct bt_conn *conn; + + BT_DBG("status 0x%02x handle %u", evt->status, handle); + + conn = bt_conn_lookup_handle(handle); + if (!conn) { + BT_ERR("Can't find conn for handle %u", handle); + return; + } + + if (!evt->status && evt->page == 0x01) { + memcpy(conn->br.features[1], evt->features, + sizeof(conn->br.features[1])); + } + + bt_conn_unref(conn); +} + +void bt_hci_role_change(struct net_buf *buf) +{ + struct bt_hci_evt_role_change *evt = (void *)buf->data; + struct bt_conn *conn; + + BT_DBG("status 0x%02x role %u addr %s", evt->status, evt->role, + bt_addr_str(&evt->bdaddr)); + + if (evt->status) { + return; + } + + conn = bt_conn_lookup_addr_br(&evt->bdaddr); + if (!conn) { + BT_ERR("Can't find conn for %s", bt_addr_str(&evt->bdaddr)); + return; + } + + if (evt->role) { + conn->role = BT_CONN_ROLE_SLAVE; + } else { + conn->role = BT_CONN_ROLE_MASTER; + } + + bt_conn_unref(conn); +} + +static int read_ext_features(void) +{ + int i; + + /* Read Local Supported Extended Features */ + for (i = 1; i < LMP_FEAT_PAGES_COUNT; i++) { + struct bt_hci_cp_read_local_ext_features *cp; + struct bt_hci_rp_read_local_ext_features *rp; + struct net_buf *buf, *rsp; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_READ_LOCAL_EXT_FEATURES, + sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->page = i; + + err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_LOCAL_EXT_FEATURES, + buf, &rsp); + if (err) { + return err; + } + + rp = (void *)rsp->data; + + memcpy(&bt_dev.features[i], rp->ext_features, + sizeof(bt_dev.features[i])); + + if (rp->max_page <= i) { + net_buf_unref(rsp); + break; + } + + net_buf_unref(rsp); + } + + return 0; +} + +void device_supported_pkt_type(void) +{ + /* Device supported features and sco packet types */ + if (BT_FEAT_HV2_PKT(bt_dev.features)) { + bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_HV2); + } + + if (BT_FEAT_HV3_PKT(bt_dev.features)) { + bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_HV3); + } + + if (BT_FEAT_LMP_ESCO_CAPABLE(bt_dev.features)) { + bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_EV3); + } + + if (BT_FEAT_EV4_PKT(bt_dev.features)) { + bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_EV4); + } + + if (BT_FEAT_EV5_PKT(bt_dev.features)) { + bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_EV5); + } + + if (BT_FEAT_2EV3_PKT(bt_dev.features)) { + bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_2EV3); + } + + if (BT_FEAT_3EV3_PKT(bt_dev.features)) { + bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_3EV3); + } + + if (BT_FEAT_3SLOT_PKT(bt_dev.features)) { + bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_2EV5 | + HCI_PKT_TYPE_ESCO_3EV5); + } +} + +static void read_buffer_size_complete(struct net_buf *buf) +{ + struct bt_hci_rp_read_buffer_size *rp = (void *)buf->data; + uint16_t pkts; + + BT_DBG("status 0x%02x", rp->status); + + bt_dev.br.mtu = sys_le16_to_cpu(rp->acl_max_len); + pkts = sys_le16_to_cpu(rp->acl_max_num); + + BT_DBG("ACL BR/EDR buffers: pkts %u mtu %u", pkts, bt_dev.br.mtu); + + k_sem_init(&bt_dev.br.pkts, pkts, pkts); +} + +int bt_br_init(void) +{ + struct net_buf *buf; + struct bt_hci_cp_write_ssp_mode *ssp_cp; + struct bt_hci_cp_write_inquiry_mode *inq_cp; + struct bt_hci_write_local_name *name_cp; + int err; + + /* Read extended local features */ + if (BT_FEAT_EXT_FEATURES(bt_dev.features)) { + err = read_ext_features(); + if (err) { + return err; + } + } + + /* Add local supported packet types to bt_dev */ + device_supported_pkt_type(); + + /* Get BR/EDR buffer size */ + err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_BUFFER_SIZE, NULL, &buf); + if (err) { + return err; + } + + read_buffer_size_complete(buf); + net_buf_unref(buf); + + /* Set SSP mode */ + buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_SSP_MODE, sizeof(*ssp_cp)); + if (!buf) { + return -ENOBUFS; + } + + ssp_cp = net_buf_add(buf, sizeof(*ssp_cp)); + ssp_cp->mode = 0x01; + err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_SSP_MODE, buf, NULL); + if (err) { + return err; + } + + /* Enable Inquiry results with RSSI or extended Inquiry */ + buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_INQUIRY_MODE, sizeof(*inq_cp)); + if (!buf) { + return -ENOBUFS; + } + + inq_cp = net_buf_add(buf, sizeof(*inq_cp)); + inq_cp->mode = 0x02; + err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_INQUIRY_MODE, buf, NULL); + if (err) { + return err; + } + + /* Set local name */ + buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_LOCAL_NAME, sizeof(*name_cp)); + if (!buf) { + return -ENOBUFS; + } + + name_cp = net_buf_add(buf, sizeof(*name_cp)); + strncpy((char *)name_cp->local_name, CONFIG_BT_DEVICE_NAME, + sizeof(name_cp->local_name)); + + err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_LOCAL_NAME, buf, NULL); + if (err) { + return err; + } + + /* Set page timeout*/ + buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_PAGE_TIMEOUT, sizeof(uint16_t)); + if (!buf) { + return -ENOBUFS; + } + + net_buf_add_le16(buf, CONFIG_BT_PAGE_TIMEOUT); + + err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_PAGE_TIMEOUT, buf, NULL); + if (err) { + return err; + } + + /* Enable BR/EDR SC if supported */ + if (BT_FEAT_SC(bt_dev.features)) { + struct bt_hci_cp_write_sc_host_supp *sc_cp; + + buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_SC_HOST_SUPP, + sizeof(*sc_cp)); + if (!buf) { + return -ENOBUFS; + } + + sc_cp = net_buf_add(buf, sizeof(*sc_cp)); + sc_cp->sc_support = 0x01; + + err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_SC_HOST_SUPP, buf, + NULL); + if (err) { + return err; + } + } + + return 0; +} + +static int br_start_inquiry(const struct bt_br_discovery_param *param) +{ + const uint8_t iac[3] = { 0x33, 0x8b, 0x9e }; + struct bt_hci_op_inquiry *cp; + struct net_buf *buf; + + buf = bt_hci_cmd_create(BT_HCI_OP_INQUIRY, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + + cp->length = param->length; + cp->num_rsp = 0xff; /* we limit discovery only by time */ + + memcpy(cp->lap, iac, 3); + if (param->limited) { + cp->lap[0] = 0x00; + } + + return bt_hci_cmd_send_sync(BT_HCI_OP_INQUIRY, buf, NULL); +} + +static bool valid_br_discov_param(const struct bt_br_discovery_param *param, + size_t num_results) +{ + if (!num_results || num_results > 255) { + return false; + } + + if (!param->length || param->length > 0x30) { + return false; + } + + return true; +} + +int bt_br_discovery_start(const struct bt_br_discovery_param *param, + struct bt_br_discovery_result *results, size_t cnt, + bt_br_discovery_cb_t cb) +{ + int err; + + BT_DBG(""); + + if (!valid_br_discov_param(param, cnt)) { + return -EINVAL; + } + + if (atomic_test_bit(bt_dev.flags, BT_DEV_INQUIRY)) { + return -EALREADY; + } + + err = br_start_inquiry(param); + if (err) { + return err; + } + + atomic_set_bit(bt_dev.flags, BT_DEV_INQUIRY); + + (void)memset(results, 0, sizeof(*results) * cnt); + + discovery_cb = cb; + discovery_results = results; + discovery_results_size = cnt; + discovery_results_count = 0; + + return 0; +} + +int bt_br_discovery_stop(void) +{ + int err; + int i; + + BT_DBG(""); + + if (!atomic_test_bit(bt_dev.flags, BT_DEV_INQUIRY)) { + return -EALREADY; + } + + err = bt_hci_cmd_send_sync(BT_HCI_OP_INQUIRY_CANCEL, NULL, NULL); + if (err) { + return err; + } + + for (i = 0; i < discovery_results_count; i++) { + struct discovery_priv *priv; + struct bt_hci_cp_remote_name_cancel *cp; + struct net_buf *buf; + + priv = (struct discovery_priv *)&discovery_results[i]._priv; + + if (!priv->resolving) { + continue; + } + + buf = bt_hci_cmd_create(BT_HCI_OP_REMOTE_NAME_CANCEL, + sizeof(*cp)); + if (!buf) { + continue; + } + + cp = net_buf_add(buf, sizeof(*cp)); + bt_addr_copy(&cp->bdaddr, &discovery_results[i].addr); + + bt_hci_cmd_send_sync(BT_HCI_OP_REMOTE_NAME_CANCEL, buf, NULL); + } + + atomic_clear_bit(bt_dev.flags, BT_DEV_INQUIRY); + + discovery_cb = NULL; + discovery_results = NULL; + discovery_results_size = 0; + discovery_results_count = 0; + + return 0; +} + +static int write_scan_enable(uint8_t scan) +{ + struct net_buf *buf; + int err; + + BT_DBG("type %u", scan); + + buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_SCAN_ENABLE, 1); + if (!buf) { + return -ENOBUFS; + } + + net_buf_add_u8(buf, scan); + err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_SCAN_ENABLE, buf, NULL); + if (err) { + return err; + } + + atomic_set_bit_to(bt_dev.flags, BT_DEV_ISCAN, + (scan & BT_BREDR_SCAN_INQUIRY)); + atomic_set_bit_to(bt_dev.flags, BT_DEV_PSCAN, + (scan & BT_BREDR_SCAN_PAGE)); + + return 0; +} + +int bt_br_set_connectable(bool enable) +{ + if (enable) { + if (atomic_test_bit(bt_dev.flags, BT_DEV_PSCAN)) { + return -EALREADY; + } else { + return write_scan_enable(BT_BREDR_SCAN_PAGE); + } + } else { + if (!atomic_test_bit(bt_dev.flags, BT_DEV_PSCAN)) { + return -EALREADY; + } else { + return write_scan_enable(BT_BREDR_SCAN_DISABLED); + } + } +} + +int bt_br_set_discoverable(bool enable) +{ + if (enable) { + if (atomic_test_bit(bt_dev.flags, BT_DEV_ISCAN)) { + return -EALREADY; + } + + if (!atomic_test_bit(bt_dev.flags, BT_DEV_PSCAN)) { + return -EPERM; + } + + return write_scan_enable(BT_BREDR_SCAN_INQUIRY | + BT_BREDR_SCAN_PAGE); + } else { + if (!atomic_test_bit(bt_dev.flags, BT_DEV_ISCAN)) { + return -EALREADY; + } + + return write_scan_enable(BT_BREDR_SCAN_PAGE); + } +} diff --git a/subsys/bluetooth/host/br.h b/subsys/bluetooth/host/br.h new file mode 100644 index 00000000000..80622aa637d --- /dev/null +++ b/subsys/bluetooth/host/br.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2017-2021 Nordic Semiconductor ASA + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +int bt_br_init(void); + +void bt_br_discovery_reset(void); + +bool bt_br_update_sec_level(struct bt_conn *conn); diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index cd6a7b98d9d..36653a44bcd 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -50,6 +50,10 @@ #include "crypto.h" #include "settings.h" +#if defined(CONFIG_BT_BREDR) +#include "br.h" +#endif + #if IS_ENABLED(CONFIG_BT_DF) #include "direction_internal.h" #endif /* CONFIG_BT_DF */ @@ -94,13 +98,6 @@ static bt_ready_cb_t ready_cb; static bt_hci_vnd_evt_cb_t *hci_vnd_evt_cb; #endif /* CONFIG_BT_HCI_VS_EVT_USER */ -#if defined(CONFIG_BT_BREDR) -static bt_br_discovery_cb_t *discovery_cb; -struct bt_br_discovery_result *discovery_results; -static size_t discovery_results_size; -static size_t discovery_results_count; -#endif /* CONFIG_BT_BREDR */ - struct cmd_data { /** HCI status of the command completion */ uint8_t status; @@ -1648,688 +1645,6 @@ enum bt_security_err bt_security_err_get(uint8_t hci_err) } #endif /* defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR) */ -#if defined(CONFIG_BT_BREDR) -static int reject_conn(const bt_addr_t *bdaddr, uint8_t reason) -{ - struct bt_hci_cp_reject_conn_req *cp; - struct net_buf *buf; - int err; - - buf = bt_hci_cmd_create(BT_HCI_OP_REJECT_CONN_REQ, sizeof(*cp)); - if (!buf) { - return -ENOBUFS; - } - - cp = net_buf_add(buf, sizeof(*cp)); - bt_addr_copy(&cp->bdaddr, bdaddr); - cp->reason = reason; - - err = bt_hci_cmd_send_sync(BT_HCI_OP_REJECT_CONN_REQ, buf, NULL); - if (err) { - return err; - } - - return 0; -} - -static int accept_sco_conn(const bt_addr_t *bdaddr, struct bt_conn *sco_conn) -{ - struct bt_hci_cp_accept_sync_conn_req *cp; - struct net_buf *buf; - int err; - - buf = bt_hci_cmd_create(BT_HCI_OP_ACCEPT_SYNC_CONN_REQ, sizeof(*cp)); - if (!buf) { - return -ENOBUFS; - } - - cp = net_buf_add(buf, sizeof(*cp)); - bt_addr_copy(&cp->bdaddr, bdaddr); - cp->pkt_type = sco_conn->sco.pkt_type; - cp->tx_bandwidth = 0x00001f40; - cp->rx_bandwidth = 0x00001f40; - cp->max_latency = 0x0007; - cp->retrans_effort = 0x01; - cp->content_format = BT_VOICE_CVSD_16BIT; - - err = bt_hci_cmd_send_sync(BT_HCI_OP_ACCEPT_SYNC_CONN_REQ, buf, NULL); - if (err) { - return err; - } - - return 0; -} - -static int accept_conn(const bt_addr_t *bdaddr) -{ - struct bt_hci_cp_accept_conn_req *cp; - struct net_buf *buf; - int err; - - buf = bt_hci_cmd_create(BT_HCI_OP_ACCEPT_CONN_REQ, sizeof(*cp)); - if (!buf) { - return -ENOBUFS; - } - - cp = net_buf_add(buf, sizeof(*cp)); - bt_addr_copy(&cp->bdaddr, bdaddr); - cp->role = BT_HCI_ROLE_SLAVE; - - err = bt_hci_cmd_send_sync(BT_HCI_OP_ACCEPT_CONN_REQ, buf, NULL); - if (err) { - return err; - } - - return 0; -} - -static void bt_esco_conn_req(struct bt_hci_evt_conn_request *evt) -{ - struct bt_conn *sco_conn; - - sco_conn = bt_conn_add_sco(&evt->bdaddr, evt->link_type); - if (!sco_conn) { - reject_conn(&evt->bdaddr, BT_HCI_ERR_INSUFFICIENT_RESOURCES); - return; - } - - if (accept_sco_conn(&evt->bdaddr, sco_conn)) { - BT_ERR("Error accepting connection from %s", - bt_addr_str(&evt->bdaddr)); - reject_conn(&evt->bdaddr, BT_HCI_ERR_UNSPECIFIED); - bt_sco_cleanup(sco_conn); - return; - } - - sco_conn->role = BT_HCI_ROLE_SLAVE; - bt_conn_set_state(sco_conn, BT_CONN_CONNECT); - bt_conn_unref(sco_conn); -} - -static void conn_req(struct net_buf *buf) -{ - struct bt_hci_evt_conn_request *evt = (void *)buf->data; - struct bt_conn *conn; - - BT_DBG("conn req from %s, type 0x%02x", bt_addr_str(&evt->bdaddr), - evt->link_type); - - if (evt->link_type != BT_HCI_ACL) { - bt_esco_conn_req(evt); - return; - } - - conn = bt_conn_add_br(&evt->bdaddr); - if (!conn) { - reject_conn(&evt->bdaddr, BT_HCI_ERR_INSUFFICIENT_RESOURCES); - return; - } - - accept_conn(&evt->bdaddr); - conn->role = BT_HCI_ROLE_SLAVE; - bt_conn_set_state(conn, BT_CONN_CONNECT); - bt_conn_unref(conn); -} - -static bool br_sufficient_key_size(struct bt_conn *conn) -{ - struct bt_hci_cp_read_encryption_key_size *cp; - struct bt_hci_rp_read_encryption_key_size *rp; - struct net_buf *buf, *rsp; - uint8_t key_size; - int err; - - buf = bt_hci_cmd_create(BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE, - sizeof(*cp)); - if (!buf) { - BT_ERR("Failed to allocate command buffer"); - return false; - } - - cp = net_buf_add(buf, sizeof(*cp)); - cp->handle = sys_cpu_to_le16(conn->handle); - - err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE, - buf, &rsp); - if (err) { - BT_ERR("Failed to read encryption key size (err %d)", err); - return false; - } - - if (rsp->len < sizeof(*rp)) { - BT_ERR("Too small command complete for encryption key size"); - net_buf_unref(rsp); - return false; - } - - rp = (void *)rsp->data; - key_size = rp->key_size; - net_buf_unref(rsp); - - BT_DBG("Encryption key size is %u", key_size); - - if (conn->sec_level == BT_SECURITY_L4) { - return key_size == BT_HCI_ENCRYPTION_KEY_SIZE_MAX; - } - - return key_size >= BT_HCI_ENCRYPTION_KEY_SIZE_MIN; -} - -static bool update_sec_level_br(struct bt_conn *conn) -{ - if (!conn->encrypt) { - conn->sec_level = BT_SECURITY_L1; - return true; - } - - if (conn->br.link_key) { - if (conn->br.link_key->flags & BT_LINK_KEY_AUTHENTICATED) { - if (conn->encrypt == 0x02) { - conn->sec_level = BT_SECURITY_L4; - } else { - conn->sec_level = BT_SECURITY_L3; - } - } else { - conn->sec_level = BT_SECURITY_L2; - } - } else { - BT_WARN("No BR/EDR link key found"); - conn->sec_level = BT_SECURITY_L2; - } - - if (!br_sufficient_key_size(conn)) { - BT_ERR("Encryption key size is not sufficient"); - bt_conn_disconnect(conn, BT_HCI_ERR_AUTH_FAIL); - return false; - } - - if (conn->required_sec_level > conn->sec_level) { - BT_ERR("Failed to set required security level"); - bt_conn_disconnect(conn, BT_HCI_ERR_AUTH_FAIL); - return false; - } - - return true; -} - -static void synchronous_conn_complete(struct net_buf *buf) -{ - struct bt_hci_evt_sync_conn_complete *evt = (void *)buf->data; - struct bt_conn *sco_conn; - uint16_t handle = sys_le16_to_cpu(evt->handle); - - BT_DBG("status 0x%02x, handle %u, type 0x%02x", evt->status, handle, - evt->link_type); - - sco_conn = bt_conn_lookup_addr_sco(&evt->bdaddr); - if (!sco_conn) { - BT_ERR("Unable to find conn for %s", bt_addr_str(&evt->bdaddr)); - return; - } - - if (evt->status) { - sco_conn->err = evt->status; - bt_conn_set_state(sco_conn, BT_CONN_DISCONNECTED); - bt_conn_unref(sco_conn); - return; - } - - sco_conn->handle = handle; - bt_conn_set_state(sco_conn, BT_CONN_CONNECTED); - bt_conn_unref(sco_conn); -} - -static void conn_complete(struct net_buf *buf) -{ - struct bt_hci_evt_conn_complete *evt = (void *)buf->data; - struct bt_conn *conn; - struct bt_hci_cp_read_remote_features *cp; - uint16_t handle = sys_le16_to_cpu(evt->handle); - - BT_DBG("status 0x%02x, handle %u, type 0x%02x", evt->status, handle, - evt->link_type); - - conn = bt_conn_lookup_addr_br(&evt->bdaddr); - if (!conn) { - BT_ERR("Unable to find conn for %s", bt_addr_str(&evt->bdaddr)); - return; - } - - if (evt->status) { - conn->err = evt->status; - bt_conn_set_state(conn, BT_CONN_DISCONNECTED); - bt_conn_unref(conn); - return; - } - - conn->handle = handle; - conn->err = 0U; - conn->encrypt = evt->encr_enabled; - - if (!update_sec_level_br(conn)) { - bt_conn_unref(conn); - return; - } - - bt_conn_set_state(conn, BT_CONN_CONNECTED); - bt_conn_unref(conn); - - buf = bt_hci_cmd_create(BT_HCI_OP_READ_REMOTE_FEATURES, sizeof(*cp)); - if (!buf) { - return; - } - - cp = net_buf_add(buf, sizeof(*cp)); - cp->handle = evt->handle; - - bt_hci_cmd_send_sync(BT_HCI_OP_READ_REMOTE_FEATURES, buf, NULL); -} - -struct discovery_priv { - uint16_t clock_offset; - uint8_t pscan_rep_mode; - uint8_t resolving; -} __packed; - -static int request_name(const bt_addr_t *addr, uint8_t pscan, uint16_t offset) -{ - struct bt_hci_cp_remote_name_request *cp; - struct net_buf *buf; - - buf = bt_hci_cmd_create(BT_HCI_OP_REMOTE_NAME_REQUEST, sizeof(*cp)); - if (!buf) { - return -ENOBUFS; - } - - cp = net_buf_add(buf, sizeof(*cp)); - - bt_addr_copy(&cp->bdaddr, addr); - cp->pscan_rep_mode = pscan; - cp->reserved = 0x00; /* reserver, should be set to 0x00 */ - cp->clock_offset = offset; - - return bt_hci_cmd_send_sync(BT_HCI_OP_REMOTE_NAME_REQUEST, buf, NULL); -} - -#define EIR_SHORT_NAME 0x08 -#define EIR_COMPLETE_NAME 0x09 - -static bool eir_has_name(const uint8_t *eir) -{ - int len = 240; - - while (len) { - if (len < 2) { - break; - }; - - /* Look for early termination */ - if (!eir[0]) { - break; - } - - /* Check if field length is correct */ - if (eir[0] > len - 1) { - break; - } - - switch (eir[1]) { - case EIR_SHORT_NAME: - case EIR_COMPLETE_NAME: - if (eir[0] > 1) { - return true; - } - break; - default: - break; - } - - /* Parse next AD Structure */ - len -= eir[0] + 1; - eir += eir[0] + 1; - } - - return false; -} - -static void report_discovery_results(void) -{ - bool resolving_names = false; - int i; - - for (i = 0; i < discovery_results_count; i++) { - struct discovery_priv *priv; - - priv = (struct discovery_priv *)&discovery_results[i]._priv; - - if (eir_has_name(discovery_results[i].eir)) { - continue; - } - - if (request_name(&discovery_results[i].addr, - priv->pscan_rep_mode, priv->clock_offset)) { - continue; - } - - priv->resolving = 1U; - resolving_names = true; - } - - if (resolving_names) { - return; - } - - atomic_clear_bit(bt_dev.flags, BT_DEV_INQUIRY); - - discovery_cb(discovery_results, discovery_results_count); - - discovery_cb = NULL; - discovery_results = NULL; - discovery_results_size = 0; - discovery_results_count = 0; -} - -static void inquiry_complete(struct net_buf *buf) -{ - struct bt_hci_evt_inquiry_complete *evt = (void *)buf->data; - - if (evt->status) { - BT_ERR("Failed to complete inquiry"); - } - - report_discovery_results(); -} - -static struct bt_br_discovery_result *get_result_slot(const bt_addr_t *addr, - int8_t rssi) -{ - struct bt_br_discovery_result *result = NULL; - size_t i; - - /* check if already present in results */ - for (i = 0; i < discovery_results_count; i++) { - if (!bt_addr_cmp(addr, &discovery_results[i].addr)) { - return &discovery_results[i]; - } - } - - /* Pick a new slot (if available) */ - if (discovery_results_count < discovery_results_size) { - bt_addr_copy(&discovery_results[discovery_results_count].addr, - addr); - return &discovery_results[discovery_results_count++]; - } - - /* ignore if invalid RSSI */ - if (rssi == 0xff) { - return NULL; - } - - /* - * Pick slot with smallest RSSI that is smaller then passed RSSI - * TODO handle TX if present - */ - for (i = 0; i < discovery_results_size; i++) { - if (discovery_results[i].rssi > rssi) { - continue; - } - - if (!result || result->rssi > discovery_results[i].rssi) { - result = &discovery_results[i]; - } - } - - if (result) { - BT_DBG("Reusing slot (old %s rssi %d dBm)", - bt_addr_str(&result->addr), result->rssi); - - bt_addr_copy(&result->addr, addr); - } - - return result; -} - -static void inquiry_result_with_rssi(struct net_buf *buf) -{ - uint8_t num_reports = net_buf_pull_u8(buf); - - if (!atomic_test_bit(bt_dev.flags, BT_DEV_INQUIRY)) { - return; - } - - BT_DBG("number of results: %u", num_reports); - - while (num_reports--) { - struct bt_hci_evt_inquiry_result_with_rssi *evt; - struct bt_br_discovery_result *result; - struct discovery_priv *priv; - - if (buf->len < sizeof(*evt)) { - BT_ERR("Unexpected end to buffer"); - return; - } - - evt = net_buf_pull_mem(buf, sizeof(*evt)); - BT_DBG("%s rssi %d dBm", bt_addr_str(&evt->addr), evt->rssi); - - result = get_result_slot(&evt->addr, evt->rssi); - if (!result) { - return; - } - - priv = (struct discovery_priv *)&result->_priv; - priv->pscan_rep_mode = evt->pscan_rep_mode; - priv->clock_offset = evt->clock_offset; - - memcpy(result->cod, evt->cod, 3); - result->rssi = evt->rssi; - - /* we could reuse slot so make sure EIR is cleared */ - (void)memset(result->eir, 0, sizeof(result->eir)); - } -} - -static void extended_inquiry_result(struct net_buf *buf) -{ - struct bt_hci_evt_extended_inquiry_result *evt = (void *)buf->data; - struct bt_br_discovery_result *result; - struct discovery_priv *priv; - - if (!atomic_test_bit(bt_dev.flags, BT_DEV_INQUIRY)) { - return; - } - - BT_DBG("%s rssi %d dBm", bt_addr_str(&evt->addr), evt->rssi); - - result = get_result_slot(&evt->addr, evt->rssi); - if (!result) { - return; - } - - priv = (struct discovery_priv *)&result->_priv; - priv->pscan_rep_mode = evt->pscan_rep_mode; - priv->clock_offset = evt->clock_offset; - - result->rssi = evt->rssi; - memcpy(result->cod, evt->cod, 3); - memcpy(result->eir, evt->eir, sizeof(result->eir)); -} - -static void remote_name_request_complete(struct net_buf *buf) -{ - struct bt_hci_evt_remote_name_req_complete *evt = (void *)buf->data; - struct bt_br_discovery_result *result; - struct discovery_priv *priv; - int eir_len = 240; - uint8_t *eir; - int i; - - result = get_result_slot(&evt->bdaddr, 0xff); - if (!result) { - return; - } - - priv = (struct discovery_priv *)&result->_priv; - priv->resolving = 0U; - - if (evt->status) { - goto check_names; - } - - eir = result->eir; - - while (eir_len) { - if (eir_len < 2) { - break; - }; - - /* Look for early termination */ - if (!eir[0]) { - size_t name_len; - - eir_len -= 2; - - /* name is null terminated */ - name_len = strlen((const char *)evt->name); - - if (name_len > eir_len) { - eir[0] = eir_len + 1; - eir[1] = EIR_SHORT_NAME; - } else { - eir[0] = name_len + 1; - eir[1] = EIR_SHORT_NAME; - } - - memcpy(&eir[2], evt->name, eir[0] - 1); - - break; - } - - /* Check if field length is correct */ - if (eir[0] > eir_len - 1) { - break; - } - - /* next EIR Structure */ - eir_len -= eir[0] + 1; - eir += eir[0] + 1; - } - -check_names: - /* if still waiting for names */ - for (i = 0; i < discovery_results_count; i++) { - struct discovery_priv *priv; - - priv = (struct discovery_priv *)&discovery_results[i]._priv; - - if (priv->resolving) { - return; - } - } - - /* all names resolved, report discovery results */ - atomic_clear_bit(bt_dev.flags, BT_DEV_INQUIRY); - - discovery_cb(discovery_results, discovery_results_count); - - discovery_cb = NULL; - discovery_results = NULL; - discovery_results_size = 0; - discovery_results_count = 0; -} - -static void read_remote_features_complete(struct net_buf *buf) -{ - struct bt_hci_evt_remote_features *evt = (void *)buf->data; - uint16_t handle = sys_le16_to_cpu(evt->handle); - struct bt_hci_cp_read_remote_ext_features *cp; - struct bt_conn *conn; - - BT_DBG("status 0x%02x handle %u", evt->status, handle); - - conn = bt_conn_lookup_handle(handle); - if (!conn) { - BT_ERR("Can't find conn for handle %u", handle); - return; - } - - if (evt->status) { - goto done; - } - - memcpy(conn->br.features[0], evt->features, sizeof(evt->features)); - - if (!BT_FEAT_EXT_FEATURES(conn->br.features)) { - goto done; - } - - buf = bt_hci_cmd_create(BT_HCI_OP_READ_REMOTE_EXT_FEATURES, - sizeof(*cp)); - if (!buf) { - goto done; - } - - /* Read remote host features (page 1) */ - cp = net_buf_add(buf, sizeof(*cp)); - cp->handle = evt->handle; - cp->page = 0x01; - - bt_hci_cmd_send_sync(BT_HCI_OP_READ_REMOTE_EXT_FEATURES, buf, NULL); - -done: - bt_conn_unref(conn); -} - -static void read_remote_ext_features_complete(struct net_buf *buf) -{ - struct bt_hci_evt_remote_ext_features *evt = (void *)buf->data; - uint16_t handle = sys_le16_to_cpu(evt->handle); - struct bt_conn *conn; - - BT_DBG("status 0x%02x handle %u", evt->status, handle); - - conn = bt_conn_lookup_handle(handle); - if (!conn) { - BT_ERR("Can't find conn for handle %u", handle); - return; - } - - if (!evt->status && evt->page == 0x01) { - memcpy(conn->br.features[1], evt->features, - sizeof(conn->br.features[1])); - } - - bt_conn_unref(conn); -} - -static void role_change(struct net_buf *buf) -{ - struct bt_hci_evt_role_change *evt = (void *)buf->data; - struct bt_conn *conn; - - BT_DBG("status 0x%02x role %u addr %s", evt->status, evt->role, - bt_addr_str(&evt->bdaddr)); - - if (evt->status) { - return; - } - - conn = bt_conn_lookup_addr_br(&evt->bdaddr); - if (!conn) { - BT_ERR("Can't find conn for %s", bt_addr_str(&evt->bdaddr)); - return; - } - - if (evt->role) { - conn->role = BT_CONN_ROLE_SLAVE; - } else { - conn->role = BT_CONN_ROLE_MASTER; - } - - bt_conn_unref(conn); -} -#endif /* CONFIG_BT_BREDR */ - #if defined(CONFIG_BT_SMP) static bool update_sec_level(struct bt_conn *conn) { @@ -2395,7 +1710,7 @@ static void hci_encrypt_change(struct net_buf *buf) #endif /* CONFIG_BT_SMP */ #if defined(CONFIG_BT_BREDR) if (conn->type == BT_CONN_TYPE_BR) { - if (!update_sec_level_br(conn)) { + if (!bt_br_update_sec_level(conn)) { bt_conn_unref(conn); return; } @@ -2464,7 +1779,7 @@ static void hci_encrypt_key_refresh_complete(struct net_buf *buf) #endif /* CONFIG_BT_SMP */ #if defined(CONFIG_BT_BREDR) if (conn->type == BT_CONN_TYPE_BR) { - if (!update_sec_level_br(conn)) { + if (!bt_br_update_sec_level(conn)) { bt_conn_unref(conn); return; } @@ -2606,10 +1921,7 @@ static void hci_reset_complete(struct net_buf *buf) } #if defined(CONFIG_BT_BREDR) - discovery_cb = NULL; - discovery_results = NULL; - discovery_results_size = 0; - discovery_results_count = 0; + bt_br_discovery_reset(); #endif /* CONFIG_BT_BREDR */ flags = (atomic_get(bt_dev.flags) & BT_DEV_PERSISTENT_FLAGS); @@ -2840,9 +2152,9 @@ static const struct event_handler normal_events[] = { EVENT_HANDLER(BT_HCI_EVT_LE_META_EVENT, hci_le_meta_event, sizeof(struct bt_hci_evt_le_meta_event)), #if defined(CONFIG_BT_BREDR) - EVENT_HANDLER(BT_HCI_EVT_CONN_REQUEST, conn_req, + EVENT_HANDLER(BT_HCI_EVT_CONN_REQUEST, bt_hci_conn_req, sizeof(struct bt_hci_evt_conn_request)), - EVENT_HANDLER(BT_HCI_EVT_CONN_COMPLETE, conn_complete, + EVENT_HANDLER(BT_HCI_EVT_CONN_COMPLETE, bt_hci_conn_complete, sizeof(struct bt_hci_evt_conn_complete)), EVENT_HANDLER(BT_HCI_EVT_PIN_CODE_REQ, bt_hci_pin_code_req, sizeof(struct bt_hci_evt_pin_code_req)), @@ -2863,28 +2175,28 @@ static const struct event_handler normal_events[] = { sizeof(struct bt_hci_evt_user_passkey_notify)), EVENT_HANDLER(BT_HCI_EVT_USER_PASSKEY_REQ, bt_hci_user_passkey_req, sizeof(struct bt_hci_evt_user_passkey_req)), - EVENT_HANDLER(BT_HCI_EVT_INQUIRY_COMPLETE, inquiry_complete, + EVENT_HANDLER(BT_HCI_EVT_INQUIRY_COMPLETE, bt_hci_inquiry_complete, sizeof(struct bt_hci_evt_inquiry_complete)), EVENT_HANDLER(BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI, - inquiry_result_with_rssi, + bt_hci_inquiry_result_with_rssi, sizeof(struct bt_hci_evt_inquiry_result_with_rssi)), EVENT_HANDLER(BT_HCI_EVT_EXTENDED_INQUIRY_RESULT, - extended_inquiry_result, + bt_hci_extended_inquiry_result, sizeof(struct bt_hci_evt_extended_inquiry_result)), EVENT_HANDLER(BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE, - remote_name_request_complete, + bt_hci_remote_name_request_complete, sizeof(struct bt_hci_evt_remote_name_req_complete)), EVENT_HANDLER(BT_HCI_EVT_AUTH_COMPLETE, bt_hci_auth_complete, sizeof(struct bt_hci_evt_auth_complete)), EVENT_HANDLER(BT_HCI_EVT_REMOTE_FEATURES, - read_remote_features_complete, + bt_hci_read_remote_features_complete, sizeof(struct bt_hci_evt_remote_features)), EVENT_HANDLER(BT_HCI_EVT_REMOTE_EXT_FEATURES, - read_remote_ext_features_complete, + bt_hci_read_remote_ext_features_complete, sizeof(struct bt_hci_evt_remote_ext_features)), - EVENT_HANDLER(BT_HCI_EVT_ROLE_CHANGE, role_change, + EVENT_HANDLER(BT_HCI_EVT_ROLE_CHANGE, bt_hci_role_change, sizeof(struct bt_hci_evt_role_change)), - EVENT_HANDLER(BT_HCI_EVT_SYNC_CONN_COMPLETE, synchronous_conn_complete, + EVENT_HANDLER(BT_HCI_EVT_SYNC_CONN_COMPLETE, bt_hci_synchronous_conn_complete, sizeof(struct bt_hci_evt_sync_conn_complete)), #endif /* CONFIG_BT_BREDR */ #if defined(CONFIG_BT_CONN) @@ -3063,22 +2375,8 @@ static void read_le_features_complete(struct net_buf *buf) memcpy(bt_dev.le.features, rp->features, sizeof(bt_dev.le.features)); } -#if defined(CONFIG_BT_BREDR) -static void read_buffer_size_complete(struct net_buf *buf) -{ - struct bt_hci_rp_read_buffer_size *rp = (void *)buf->data; - uint16_t pkts; - - BT_DBG("status 0x%02x", rp->status); - - bt_dev.br.mtu = sys_le16_to_cpu(rp->acl_max_len); - pkts = sys_le16_to_cpu(rp->acl_max_num); - - BT_DBG("ACL BR/EDR buffers: pkts %u mtu %u", pkts, bt_dev.br.mtu); - - k_sem_init(&bt_dev.br.pkts, pkts, pkts); -} -#elif defined(CONFIG_BT_CONN) +#if defined(CONFIG_BT_CONN) +#if !defined(CONFIG_BT_BREDR) static void read_buffer_size_complete(struct net_buf *buf) { struct bt_hci_rp_read_buffer_size *rp = (void *)buf->data; @@ -3098,9 +2396,8 @@ static void read_buffer_size_complete(struct net_buf *buf) k_sem_init(&bt_dev.le.acl_pkts, pkts, pkts); } -#endif +#endif /* !defined(CONFIG_BT_BREDR) */ -#if defined(CONFIG_BT_CONN) static void le_read_buffer_size_complete(struct net_buf *buf) { struct bt_hci_rp_le_read_buffer_size *rp = (void *)buf->data; @@ -3543,192 +2840,8 @@ static int le_init(void) return le_set_event_mask(); } -#if defined(CONFIG_BT_BREDR) -static int read_ext_features(void) -{ - int i; - - /* Read Local Supported Extended Features */ - for (i = 1; i < LMP_FEAT_PAGES_COUNT; i++) { - struct bt_hci_cp_read_local_ext_features *cp; - struct bt_hci_rp_read_local_ext_features *rp; - struct net_buf *buf, *rsp; - int err; - - buf = bt_hci_cmd_create(BT_HCI_OP_READ_LOCAL_EXT_FEATURES, - sizeof(*cp)); - if (!buf) { - return -ENOBUFS; - } - - cp = net_buf_add(buf, sizeof(*cp)); - cp->page = i; - - err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_LOCAL_EXT_FEATURES, - buf, &rsp); - if (err) { - return err; - } - - rp = (void *)rsp->data; - - memcpy(&bt_dev.features[i], rp->ext_features, - sizeof(bt_dev.features[i])); - - if (rp->max_page <= i) { - net_buf_unref(rsp); - break; - } - - net_buf_unref(rsp); - } - - return 0; -} - -void device_supported_pkt_type(void) -{ - /* Device supported features and sco packet types */ - if (BT_FEAT_HV2_PKT(bt_dev.features)) { - bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_HV2); - } - - if (BT_FEAT_HV3_PKT(bt_dev.features)) { - bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_HV3); - } - - if (BT_FEAT_LMP_ESCO_CAPABLE(bt_dev.features)) { - bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_EV3); - } - - if (BT_FEAT_EV4_PKT(bt_dev.features)) { - bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_EV4); - } - - if (BT_FEAT_EV5_PKT(bt_dev.features)) { - bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_EV5); - } - - if (BT_FEAT_2EV3_PKT(bt_dev.features)) { - bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_2EV3); - } - - if (BT_FEAT_3EV3_PKT(bt_dev.features)) { - bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_3EV3); - } - - if (BT_FEAT_3SLOT_PKT(bt_dev.features)) { - bt_dev.br.esco_pkt_type |= (HCI_PKT_TYPE_ESCO_2EV5 | - HCI_PKT_TYPE_ESCO_3EV5); - } -} - -static int br_init(void) -{ - struct net_buf *buf; - struct bt_hci_cp_write_ssp_mode *ssp_cp; - struct bt_hci_cp_write_inquiry_mode *inq_cp; - struct bt_hci_write_local_name *name_cp; - int err; - - /* Read extended local features */ - if (BT_FEAT_EXT_FEATURES(bt_dev.features)) { - err = read_ext_features(); - if (err) { - return err; - } - } - - /* Add local supported packet types to bt_dev */ - device_supported_pkt_type(); - - /* Get BR/EDR buffer size */ - err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_BUFFER_SIZE, NULL, &buf); - if (err) { - return err; - } - - read_buffer_size_complete(buf); - net_buf_unref(buf); - - /* Set SSP mode */ - buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_SSP_MODE, sizeof(*ssp_cp)); - if (!buf) { - return -ENOBUFS; - } - - ssp_cp = net_buf_add(buf, sizeof(*ssp_cp)); - ssp_cp->mode = 0x01; - err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_SSP_MODE, buf, NULL); - if (err) { - return err; - } - - /* Enable Inquiry results with RSSI or extended Inquiry */ - buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_INQUIRY_MODE, sizeof(*inq_cp)); - if (!buf) { - return -ENOBUFS; - } - - inq_cp = net_buf_add(buf, sizeof(*inq_cp)); - inq_cp->mode = 0x02; - err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_INQUIRY_MODE, buf, NULL); - if (err) { - return err; - } - - /* Set local name */ - buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_LOCAL_NAME, sizeof(*name_cp)); - if (!buf) { - return -ENOBUFS; - } - - name_cp = net_buf_add(buf, sizeof(*name_cp)); - strncpy((char *)name_cp->local_name, CONFIG_BT_DEVICE_NAME, - sizeof(name_cp->local_name)); - - err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_LOCAL_NAME, buf, NULL); - if (err) { - return err; - } - - /* Set page timeout*/ - buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_PAGE_TIMEOUT, sizeof(uint16_t)); - if (!buf) { - return -ENOBUFS; - } - - net_buf_add_le16(buf, CONFIG_BT_PAGE_TIMEOUT); - - err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_PAGE_TIMEOUT, buf, NULL); - if (err) { - return err; - } - - /* Enable BR/EDR SC if supported */ - if (BT_FEAT_SC(bt_dev.features)) { - struct bt_hci_cp_write_sc_host_supp *sc_cp; - - buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_SC_HOST_SUPP, - sizeof(*sc_cp)); - if (!buf) { - return -ENOBUFS; - } - - sc_cp = net_buf_add(buf, sizeof(*sc_cp)); - sc_cp->sc_support = 0x01; - - err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_SC_HOST_SUPP, buf, - NULL); - if (err) { - return err; - } - } - - return 0; -} -#else -static int br_init(void) +#if !defined(CONFIG_BT_BREDR) +static int bt_br_init(void) { #if defined(CONFIG_BT_CONN) struct net_buf *rsp; @@ -3750,7 +2863,7 @@ static int br_init(void) return 0; } -#endif +#endif /* !defined(CONFIG_BT_BREDR) */ static int set_event_mask(void) { @@ -4034,7 +3147,7 @@ static int hci_init(void) } if (BT_FEAT_BREDR(bt_dev.features)) { - err = br_init(); + err = bt_br_init(); if (err) { return err; } @@ -4505,190 +3618,3 @@ int bt_le_set_chan_map(uint8_t chan_map[5]) return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_HOST_CHAN_CLASSIF, buf, NULL); } - -#if defined(CONFIG_BT_BREDR) -static int br_start_inquiry(const struct bt_br_discovery_param *param) -{ - const uint8_t iac[3] = { 0x33, 0x8b, 0x9e }; - struct bt_hci_op_inquiry *cp; - struct net_buf *buf; - - buf = bt_hci_cmd_create(BT_HCI_OP_INQUIRY, sizeof(*cp)); - if (!buf) { - return -ENOBUFS; - } - - cp = net_buf_add(buf, sizeof(*cp)); - - cp->length = param->length; - cp->num_rsp = 0xff; /* we limit discovery only by time */ - - memcpy(cp->lap, iac, 3); - if (param->limited) { - cp->lap[0] = 0x00; - } - - return bt_hci_cmd_send_sync(BT_HCI_OP_INQUIRY, buf, NULL); -} - -static bool valid_br_discov_param(const struct bt_br_discovery_param *param, - size_t num_results) -{ - if (!num_results || num_results > 255) { - return false; - } - - if (!param->length || param->length > 0x30) { - return false; - } - - return true; -} - -int bt_br_discovery_start(const struct bt_br_discovery_param *param, - struct bt_br_discovery_result *results, size_t cnt, - bt_br_discovery_cb_t cb) -{ - int err; - - BT_DBG(""); - - if (!valid_br_discov_param(param, cnt)) { - return -EINVAL; - } - - if (atomic_test_bit(bt_dev.flags, BT_DEV_INQUIRY)) { - return -EALREADY; - } - - err = br_start_inquiry(param); - if (err) { - return err; - } - - atomic_set_bit(bt_dev.flags, BT_DEV_INQUIRY); - - (void)memset(results, 0, sizeof(*results) * cnt); - - discovery_cb = cb; - discovery_results = results; - discovery_results_size = cnt; - discovery_results_count = 0; - - return 0; -} - -int bt_br_discovery_stop(void) -{ - int err; - int i; - - BT_DBG(""); - - if (!atomic_test_bit(bt_dev.flags, BT_DEV_INQUIRY)) { - return -EALREADY; - } - - err = bt_hci_cmd_send_sync(BT_HCI_OP_INQUIRY_CANCEL, NULL, NULL); - if (err) { - return err; - } - - for (i = 0; i < discovery_results_count; i++) { - struct discovery_priv *priv; - struct bt_hci_cp_remote_name_cancel *cp; - struct net_buf *buf; - - priv = (struct discovery_priv *)&discovery_results[i]._priv; - - if (!priv->resolving) { - continue; - } - - buf = bt_hci_cmd_create(BT_HCI_OP_REMOTE_NAME_CANCEL, - sizeof(*cp)); - if (!buf) { - continue; - } - - cp = net_buf_add(buf, sizeof(*cp)); - bt_addr_copy(&cp->bdaddr, &discovery_results[i].addr); - - bt_hci_cmd_send_sync(BT_HCI_OP_REMOTE_NAME_CANCEL, buf, NULL); - } - - atomic_clear_bit(bt_dev.flags, BT_DEV_INQUIRY); - - discovery_cb = NULL; - discovery_results = NULL; - discovery_results_size = 0; - discovery_results_count = 0; - - return 0; -} - -static int write_scan_enable(uint8_t scan) -{ - struct net_buf *buf; - int err; - - BT_DBG("type %u", scan); - - buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_SCAN_ENABLE, 1); - if (!buf) { - return -ENOBUFS; - } - - net_buf_add_u8(buf, scan); - err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_SCAN_ENABLE, buf, NULL); - if (err) { - return err; - } - - atomic_set_bit_to(bt_dev.flags, BT_DEV_ISCAN, - (scan & BT_BREDR_SCAN_INQUIRY)); - atomic_set_bit_to(bt_dev.flags, BT_DEV_PSCAN, - (scan & BT_BREDR_SCAN_PAGE)); - - return 0; -} - -int bt_br_set_connectable(bool enable) -{ - if (enable) { - if (atomic_test_bit(bt_dev.flags, BT_DEV_PSCAN)) { - return -EALREADY; - } else { - return write_scan_enable(BT_BREDR_SCAN_PAGE); - } - } else { - if (!atomic_test_bit(bt_dev.flags, BT_DEV_PSCAN)) { - return -EALREADY; - } else { - return write_scan_enable(BT_BREDR_SCAN_DISABLED); - } - } -} - -int bt_br_set_discoverable(bool enable) -{ - if (enable) { - if (atomic_test_bit(bt_dev.flags, BT_DEV_ISCAN)) { - return -EALREADY; - } - - if (!atomic_test_bit(bt_dev.flags, BT_DEV_PSCAN)) { - return -EPERM; - } - - return write_scan_enable(BT_BREDR_SCAN_INQUIRY | - BT_BREDR_SCAN_PAGE); - } else { - if (!atomic_test_bit(bt_dev.flags, BT_DEV_ISCAN)) { - return -EALREADY; - } - - return write_scan_enable(BT_BREDR_SCAN_PAGE); - } -} -#endif /* CONFIG_BT_BREDR */ diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index 128a654c049..9c847cfaa26 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -395,3 +395,18 @@ void bt_hci_le_past_received(struct net_buf *buf); /* Adv HCI event handlers */ void bt_hci_le_adv_set_terminated(struct net_buf *buf); void bt_hci_le_scan_req_received(struct net_buf *buf); + +/* BR/EDR HCI event handlers */ +void bt_hci_conn_req(struct net_buf *buf); +void bt_hci_conn_complete(struct net_buf *buf); + + +void bt_hci_inquiry_complete(struct net_buf *buf); +void bt_hci_inquiry_result_with_rssi(struct net_buf *buf); +void bt_hci_extended_inquiry_result(struct net_buf *buf); +void bt_hci_remote_name_request_complete(struct net_buf *buf); + +void bt_hci_read_remote_features_complete(struct net_buf *buf); +void bt_hci_read_remote_ext_features_complete(struct net_buf *buf); +void bt_hci_role_change(struct net_buf *buf); +void bt_hci_synchronous_conn_complete(struct net_buf *buf);