/* hci_core.c - HCI core Bluetooth handling */
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <atomic.h>
#include <misc/util.h>
#include <misc/slist.h>
#include <misc/byteorder.h>
#include <misc/stack.h>
#include <misc/__assert.h>
#include <soc.h>
#include <settings/settings.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_vs.h>
#include <bluetooth/hci_driver.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE)
#define LOG_MODULE_NAME bt_hci_core
#include "common/log.h"
#include "common/rpa.h"
#include "keys.h"
#include "monitor.h"
#include "hci_core.h"
#include "hci_ecc.h"
#include "ecc.h"
#include "conn_internal.h"
#include "l2cap_internal.h"
#include "gatt_internal.h"
#include "smp.h"
#include "crypto.h"
#include "settings.h"
/* Peripheral timeout to initialize Connection Parameter Update procedure */
#define CONN_UPDATE_TIMEOUT K_SECONDS(5)
#define RPA_TIMEOUT K_SECONDS(CONFIG_BT_RPA_TIMEOUT)
#define HCI_CMD_TIMEOUT K_SECONDS(10)
/* Stacks for the threads */
#if !defined(CONFIG_BT_RECV_IS_RX_THREAD)
static struct k_thread rx_thread_data;
static K_THREAD_STACK_DEFINE(rx_thread_stack, CONFIG_BT_RX_STACK_SIZE);
#endif
static struct k_thread tx_thread_data;
static K_THREAD_STACK_DEFINE(tx_thread_stack, CONFIG_BT_HCI_TX_STACK_SIZE);
static void init_work(struct k_work *work);
struct bt_dev bt_dev = {
.init = Z_WORK_INITIALIZER(init_work),
/* Give cmd_sem allowing to send first HCI_Reset cmd, the only
* exception is if the controller requests to wait for an
* initial Command Complete for NOP.
*/
#if !defined(CONFIG_BT_WAIT_NOP)
.ncmd_sem = Z_SEM_INITIALIZER(bt_dev.ncmd_sem, 1, 1),
#else
.ncmd_sem = Z_SEM_INITIALIZER(bt_dev.ncmd_sem, 0, 1),
#endif
.cmd_tx_queue = Z_FIFO_INITIALIZER(bt_dev.cmd_tx_queue),
#if !defined(CONFIG_BT_RECV_IS_RX_THREAD)
.rx_queue = Z_FIFO_INITIALIZER(bt_dev.rx_queue),
#endif
};
static bt_ready_cb_t ready_cb;
static bt_le_scan_cb_t *scan_dev_found_cb;
#if defined(CONFIG_BT_ECC)
static u8_t pub_key[64];
static struct bt_pub_key_cb *pub_key_cb;
static bt_dh_key_cb_t dh_key_cb;
#endif /* CONFIG_BT_ECC */
#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 */
u8_t status;
/** The command OpCode that the buffer contains */
u16_t opcode;
/** Used by bt_hci_cmd_send_sync. */
struct k_sem *sync;
};
struct acl_data {
/** BT_BUF_ACL_IN */
u8_t type;
/* Index into the bt_conn storage array */
u8_t id;
/** ACL connection handle */
u16_t handle;
};
static struct cmd_data cmd_data[CONFIG_BT_HCI_CMD_COUNT];
#define cmd(buf) (&cmd_data[net_buf_id(buf)])
#define acl(buf) ((struct acl_data *)net_buf_user_data(buf))
/* HCI command buffers. Derive the needed size from BT_BUF_RX_SIZE since
* the same buffer is also used for the response.
*/
#define CMD_BUF_SIZE BT_BUF_RX_SIZE
NET_BUF_POOL_DEFINE(hci_cmd_pool, CONFIG_BT_HCI_CMD_COUNT,
CMD_BUF_SIZE, BT_BUF_USER_DATA_MIN, NULL);
NET_BUF_POOL_DEFINE(hci_rx_pool, CONFIG_BT_RX_BUF_COUNT,
BT_BUF_RX_SIZE, BT_BUF_USER_DATA_MIN, NULL);
#if defined(CONFIG_BT_CONN)
/* Dedicated pool for HCI_Number_of_Completed_Packets. This event is always
* consumed synchronously by bt_recv_prio() so a single buffer is enough.
* Having a dedicated pool for it ensures that exhaustion of the RX pool
* cannot block the delivery of this priority event.
*/
NET_BUF_POOL_DEFINE(num_complete_pool, 1, BT_BUF_RX_SIZE,
BT_BUF_USER_DATA_MIN, NULL);
#endif /* CONFIG_BT_CONN */
#if defined(CONFIG_BT_DISCARDABLE_BUF_COUNT)
NET_BUF_POOL_DEFINE(discardable_pool, CONFIG_BT_DISCARDABLE_BUF_COUNT,
BT_BUF_RX_SIZE, BT_BUF_USER_DATA_MIN, NULL);
#endif /* CONFIG_BT_DISCARDABLE_BUF_COUNT */
struct event_handler {
u8_t event;
u8_t min_len;
void (*handler)(struct net_buf *buf);
};
#define EVENT_HANDLER(_evt, _handler, _min_len) \
{ \
.event = _evt, \
.handler = _handler, \
.min_len = _min_len, \
}
static inline void handle_event(u8_t event, struct net_buf *buf,
const struct event_handler *handlers,
size_t num_handlers)
{
size_t i;
for (i = 0; i < num_handlers; i++) {
const struct event_handler *handler = &handlers[i];
if (handler->event != event) {
continue;
}
if (buf->len < handler->min_len) {
BT_ERR("Too small (%u bytes) event 0x%02x",
buf->len, event);
return;
}
handler->handler(buf);
return;
}
BT_WARN("Unhandled event 0x%02x len %u: %s", event,
buf->len, bt_hex(buf->data, buf->len));
}
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
static void report_completed_packet(struct net_buf *buf)
{
struct bt_hci_cp_host_num_completed_packets *cp;
u16_t handle = acl(buf)->handle;
struct bt_hci_handle_count *hc;
struct bt_conn *conn;
net_buf_destroy(buf);
/* Do nothing if controller to host flow control is not supported */
if (!BT_CMD_TEST(bt_dev.supported_commands, 10, 5)) {
return;
}
conn = bt_conn_lookup_id(acl(buf)->id);
if (!conn) {
BT_WARN("Unable to look up conn with id 0x%02x", acl(buf)->id);
return;
}
if (conn->state != BT_CONN_CONNECTED &&
conn->state != BT_CONN_DISCONNECT) {
BT_WARN("Not reporting packet for non-connected conn");
bt_conn_unref(conn);
return;
}
bt_conn_unref(conn);
BT_DBG("Reporting completed packet for handle %u", handle);
buf = bt_hci_cmd_create(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS,
sizeof(*cp) + sizeof(*hc));
if (!buf) {
BT_ERR("Unable to allocate new HCI command");
return;
}
cp = net_buf_add(buf, sizeof(*cp));
cp->num_handles = sys_cpu_to_le16(1);
hc = net_buf_add(buf, sizeof(*hc));
hc->handle = sys_cpu_to_le16(handle);
hc->count = sys_cpu_to_le16(1);
bt_hci_cmd_send(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS, buf);
}
#define ACL_IN_SIZE BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_RX_MTU)
NET_BUF_POOL_DEFINE(acl_in_pool, CONFIG_BT_ACL_RX_COUNT, ACL_IN_SIZE,
BT_BUF_USER_DATA_MIN, report_completed_packet);
#endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */
struct net_buf *bt_hci_cmd_create(u16_t opcode, u8_t param_len)
{
struct bt_hci_cmd_hdr *hdr;
struct net_buf *buf;
BT_DBG("opcode 0x%04x param_len %u", opcode, param_len);
buf = net_buf_alloc(&hci_cmd_pool, K_FOREVER);
__ASSERT_NO_MSG(buf);
BT_DBG("buf %p", buf);
net_buf_reserve(buf, CONFIG_BT_HCI_RESERVE);
bt_buf_set_type(buf, BT_BUF_CMD);
cmd(buf)->opcode = opcode;
cmd(buf)->sync = NULL;
hdr = net_buf_add(buf, sizeof(*hdr));
hdr->opcode = sys_cpu_to_le16(opcode);
hdr->param_len = param_len;
return buf;
}
int bt_hci_cmd_send(u16_t opcode, struct net_buf *buf)
{
if (!buf) {
buf = bt_hci_cmd_create(opcode, 0);
if (!buf) {
return -ENOBUFS;
}
}
BT_DBG("opcode 0x%04x len %u", opcode, buf->len);
/* Host Number of Completed Packets can ignore the ncmd value
* and does not generate any cmd complete/status events.
*/
if (opcode == BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS) {
int err;
err = bt_send(buf);
if (err) {
BT_ERR("Unable to send to driver (err %d)", err);
net_buf_unref(buf);
}
return err;
}
net_buf_put(&bt_dev.cmd_tx_queue, buf);
return 0;
}
int bt_hci_cmd_send_sync(u16_t opcode, struct net_buf *buf,
struct net_buf **rsp)
{
struct k_sem sync_sem;
int err;
if (!buf) {
buf = bt_hci_cmd_create(opcode, 0);
if (!buf) {
return -ENOBUFS;
}
}
BT_DBG("buf %p opcode 0x%04x len %u", buf, opcode, buf->len);
k_sem_init(&sync_sem, 0, 1);
cmd(buf)->sync = &sync_sem;
/* Make sure the buffer stays around until the command completes */
net_buf_ref(buf);
net_buf_put(&bt_dev.cmd_tx_queue, buf);
err = k_sem_take(&sync_sem, HCI_CMD_TIMEOUT);
__ASSERT(err == 0, "k_sem_take failed with err %d", err);
BT_DBG("opcode 0x%04x status 0x%02x", opcode, cmd(buf)->status);
if (cmd(buf)->status) {
switch (cmd(buf)->status) {
case BT_HCI_ERR_CONN_LIMIT_EXCEEDED:
err = -ECONNREFUSED;
break;
default:
err = -EIO;
break;
}
net_buf_unref(buf);
} else {
err = 0;
if (rsp) {
*rsp = buf;
} else {
net_buf_unref(buf);
}
}
return err;
}
#if defined(CONFIG_BT_OBSERVER) || defined(CONFIG_BT_CONN)
const bt_addr_le_t *bt_lookup_id_addr(u8_t id, const bt_addr_le_t *addr)
{
if (IS_ENABLED(CONFIG_BT_SMP)) {
struct bt_keys *keys;
keys = bt_keys_find_irk(id, addr);
if (keys) {
BT_DBG("Identity %s matched RPA %s",
bt_addr_le_str(&keys->addr),
bt_addr_le_str(addr));
return &keys->addr;
}
}
return addr;
}
#endif /* CONFIG_BT_OBSERVER || CONFIG_BT_CONN */
static int set_advertise_enable(bool enable)
{
struct net_buf *buf;
int err;
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADV_ENABLE, 1);
if (!buf) {
return -ENOBUFS;
}
if (enable) {
net_buf_add_u8(buf, BT_HCI_LE_ADV_ENABLE);
} else {
net_buf_add_u8(buf, BT_HCI_LE_ADV_DISABLE);
}
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_ADV_ENABLE, buf, NULL);
if (err) {
return err;
}
atomic_set_bit_to(bt_dev.flags, BT_DEV_ADVERTISING, enable);
return 0;
}
static int set_random_address(const bt_addr_t *addr)
{
struct net_buf *buf;
int err;
BT_DBG("%s", bt_addr_str(addr));
/* Do nothing if we already have the right address */
if (!bt_addr_cmp(addr, &bt_dev.random_addr.a)) {
return 0;
}
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_RANDOM_ADDRESS, sizeof(*addr));
if (!buf) {
return -ENOBUFS;
}
net_buf_add_mem(buf, addr, sizeof(*addr));
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_RANDOM_ADDRESS, buf, NULL);
if (err) {
return err;
}
bt_addr_copy(&bt_dev.random_addr.a, addr);
bt_dev.random_addr.type = BT_ADDR_LE_RANDOM;
return 0;
}
#if defined(CONFIG_BT_PRIVACY)
/* this function sets new RPA only if current one is no longer valid */
static int le_set_private_addr(u8_t id)
{
bt_addr_t rpa;
int err;
/* check if RPA is valid */
if (atomic_test_bit(bt_dev.flags, BT_DEV_RPA_VALID)) {
return 0;
}
err = bt_rpa_create(bt_dev.irk[id], &rpa);
if (!err) {
err = set_random_address(&rpa);
if (!err) {
atomic_set_bit(bt_dev.flags, BT_DEV_RPA_VALID);
}
}
/* restart timer even if failed to set new RPA */
k_delayed_work_submit(&bt_dev.rpa_update, RPA_TIMEOUT);
return err;
}
static void rpa_timeout(struct k_work *work)
{
int err_adv = 0, err_scan = 0;
BT_DBG("");
/* Invalidate RPA */
atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID);
/*
* we need to update rpa only if advertising is ongoing, with
* BT_DEV_KEEP_ADVERTISING flag is handled in disconnected event
*/
if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) {
/* make sure new address is used */
set_advertise_enable(false);
err_adv = le_set_private_addr(bt_dev.adv_id);
set_advertise_enable(true);
}
if (atomic_test_bit(bt_dev.flags, BT_DEV_ACTIVE_SCAN)) {
/* TODO do we need to toggle scan? */
err_scan = le_set_private_addr(BT_ID_DEFAULT);
}
/* If both advertising and scanning is active, le_set_private_addr
* will fail. In this case, set back RPA_VALID so that if either of
* advertising or scanning was restarted by application then
* le_set_private_addr in the public API call path will not retry
* set_random_address. This is needed so as to be able to stop and
* restart either of the role by the application after rpa_timeout.
*/
if (err_adv || err_scan) {
atomic_set_bit(bt_dev.flags, BT_DEV_RPA_VALID);
}
}
#else
static int le_set_private_addr(u8_t id)
{
bt_addr_t nrpa;
int err;
err = bt_rand(nrpa.val, sizeof(nrpa.val));
if (err) {
return err;
}
nrpa.val[5] &= 0x3f;
return set_random_address(&nrpa);
}
#endif
#if defined(CONFIG_BT_OBSERVER)
static int set_le_scan_enable(u8_t enable)
{
struct bt_hci_cp_le_set_scan_enable *cp;
struct net_buf *buf;
int err;
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_SCAN_ENABLE, sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}
cp = net_buf_add(buf, sizeof(*cp));
if (enable == BT_HCI_LE_SCAN_ENABLE) {
cp->filter_dup = atomic_test_bit(bt_dev.flags,
BT_DEV_SCAN_FILTER_DUP);
} else {
cp->filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_DISABLE;
}
cp->enable = enable;
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_SCAN_ENABLE, buf, NULL);
if (err) {
return err;
}
atomic_set_bit_to(bt_dev.flags, BT_DEV_SCANNING,
enable == BT_HCI_LE_SCAN_ENABLE);
return 0;
}
#endif /* CONFIG_BT_OBSERVER */
#if defined(CONFIG_BT_CONN)
static void hci_acl(struct net_buf *buf)
{
struct bt_hci_acl_hdr *hdr;
u16_t handle, len;
struct bt_conn *conn;
u8_t flags;
BT_DBG("buf %p", buf);
BT_ASSERT(buf->len >= sizeof(*hdr));
hdr = net_buf_pull_mem(buf, sizeof(*hdr));
len = sys_le16_to_cpu(hdr->len);
handle = sys_le16_to_cpu(hdr->handle);
flags = bt_acl_flags(handle);
acl(buf)->handle = bt_acl_handle(handle);
acl(buf)->id = BT_CONN_ID_INVALID;
BT_DBG("handle %u len %u flags %u", acl(buf)->handle, len, flags);
if (buf->len != len) {
BT_ERR("ACL data length mismatch (%u != %u)", buf->len, len);
net_buf_unref(buf);
return;
}
conn = bt_conn_lookup_handle(acl(buf)->handle);
if (!conn) {
BT_ERR("Unable to find conn for handle %u", acl(buf)->handle);
net_buf_unref(buf);
return;
}
acl(buf)->id = bt_conn_index(conn);
bt_conn_recv(conn, buf, flags);
bt_conn_unref(conn);
}
static void hci_num_completed_packets(struct net_buf *buf)
{
struct bt_hci_evt_num_completed_packets *evt = (void *)buf->data;
int i;
BT_DBG("num_handles %u", evt->num_handles);
for (i = 0; i < evt->num_handles; i++) {
u16_t handle, count;
struct bt_conn *conn;
unsigned int key;
handle = sys_le16_to_cpu(evt->h[i].handle);
count = sys_le16_to_cpu(evt->h[i].count);
BT_DBG("handle %u count %u", handle, count);
key = irq_lock();
conn = bt_conn_lookup_handle(handle);
if (!conn) {
BT_ERR("No connection for handle %u", handle);
irq_unlock(key);
continue;
}
irq_unlock(key);
while (count--) {
sys_snode_t *node;
key = irq_lock();
node = sys_slist_get(&conn->tx_pending);
irq_unlock(key);
if (!node) {
BT_ERR("packets count mismatch");
break;
}
k_fifo_put(&conn->tx_notify, node);
k_sem_give(bt_conn_get_pkts(conn));
}
bt_conn_unref(conn);
}
}
#if defined(CONFIG_BT_CENTRAL)
static int hci_le_create_conn(const struct bt_conn *conn)
{
struct net_buf *buf;
struct bt_hci_cp_le_create_conn *cp;
u8_t own_addr_type;
const bt_addr_le_t *peer_addr;
int err;
if (IS_ENABLED(CONFIG_BT_PRIVACY)) {
err = le_set_private_addr(conn->id);
if (err) {
return err;
}
if (BT_FEAT_LE_PRIVACY(bt_dev.le.features)) {
own_addr_type = BT_HCI_OWN_ADDR_RPA_OR_RANDOM;
} else {
own_addr_type = BT_ADDR_LE_RANDOM;
}
} else {
/* If Static Random address is used as Identity address we
* need to restore it before creating connection. Otherwise
* NRPA used for active scan could be used for connection.
*/
const bt_addr_le_t *own_addr = &bt_dev.id_addr[conn->id];
if (own_addr->type == BT_ADDR_LE_RANDOM) {
set_random_address(&own_addr->a);
}
own_addr_type = own_addr->type;
}
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CREATE_CONN, sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}
cp = net_buf_add(buf, sizeof(*cp));
(void)memset(cp, 0, sizeof(*cp));
/* Interval == window for continuous scanning */
cp->scan_interval = sys_cpu_to_le16(BT_GAP_SCAN_FAST_INTERVAL);
cp->scan_window = cp->scan_interval;
peer_addr = &conn->le.dst;
#if defined(CONFIG_BT_SMP)
if (!bt_dev.le.rl_size || bt_dev.le.rl_entries > bt_dev.le.rl_size) {
/* Host resolving is used, use the RPA directly. */
peer_addr = &conn->le.resp_addr;
}
#endif
bt_addr_le_copy(&cp->peer_addr, peer_addr);
cp->own_addr_type = own_addr_type;
cp->conn_interval_min = sys_cpu_to_le16(conn->le.interval_min);
cp->conn_interval_max = sys_cpu_to_le16(conn->le.interval_max);
cp->conn_latency = sys_cpu_to_le16(conn->le.latency);
cp->supervision_timeout = sys_cpu_to_le16(conn->le.timeout);
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_CONN, buf, NULL);
}
#endif /* CONFIG_BT_CENTRAL */
static void hci_stack_dump(const struct k_thread *thread, void *user_data)
{
#if defined(CONFIG_THREAD_STACK_INFO)
stack_analyze((char *)user_data, (char *)thread->stack_info.start,
thread->stack_info.size);
#endif
}
static void hci_disconn_complete(struct net_buf *buf)
{
struct bt_hci_evt_disconn_complete *evt = (void *)buf->data;
u16_t handle = sys_le16_to_cpu(evt->handle);
struct bt_conn *conn;
BT_DBG("status %u handle %u reason %u", evt->status, handle,
evt->reason);
if (evt->status) {
return;
}
conn = bt_conn_lookup_handle(handle);
if (!conn) {
BT_ERR("Unable to look up conn with handle %u", handle);
goto advertise;
}
conn->err = evt->reason;
/* Check stacks usage (no-ops if not enabled) */
k_thread_foreach(hci_stack_dump, "HCI");
#if !defined(CONFIG_BT_RECV_IS_RX_THREAD)
STACK_ANALYZE("rx stack", rx_thread_stack);
#endif
STACK_ANALYZE("tx stack", tx_thread_stack);
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
conn->handle = 0U;
if (conn->type != BT_CONN_TYPE_LE) {
#if defined(CONFIG_BT_BREDR)
if (conn->type == BT_CONN_TYPE_SCO) {
bt_sco_cleanup(conn);
return;
}
/*
* If only for one connection session bond was set, clear keys
* database row for this connection.
*/
if (conn->type == BT_CONN_TYPE_BR &&
atomic_test_and_clear_bit(conn->flags, BT_CONN_BR_NOBOND)) {
bt_keys_link_key_clear(conn->br.link_key);
}
#endif
bt_conn_unref(conn);
return;
}
#if defined(CONFIG_BT_CENTRAL)
if (atomic_test_bit(conn->flags, BT_CONN_AUTO_CONNECT)) {
bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN);
bt_le_scan_update(false);
}
#endif /* CONFIG_BT_CENTRAL */
bt_conn_unref(conn);
advertise:
if (atomic_test_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING) &&
!atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) {
if (IS_ENABLED(CONFIG_BT_PRIVACY)) {
le_set_private_addr(bt_dev.adv_id);
}
set_advertise_enable(true);
}
}
static int hci_le_read_remote_features(struct bt_conn *conn)
{
struct bt_hci_cp_le_read_remote_features *cp;
struct net_buf *buf;
buf = bt_hci_cmd_create(BT_HCI_OP_LE_READ_REMOTE_FEATURES,
sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}
cp = net_buf_add(buf, sizeof(*cp));
cp->handle = sys_cpu_to_le16(conn->handle);
bt_hci_cmd_send(BT_HCI_OP_LE_READ_REMOTE_FEATURES, buf);
return 0;
}
/* LE Data Length Change Event is optional so this function just ignore
* error and stack will continue to use default values.
*/
static void hci_le_set_data_len(struct bt_conn *conn)
{
struct bt_hci_rp_le_read_max_data_len *rp;
struct bt_hci_cp_le_set_data_len *cp;
struct net_buf *buf, *rsp;
u16_t tx_octets, tx_time;
int err;
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_MAX_DATA_LEN, NULL, &rsp);
if (err) {
BT_ERR("Failed to read DLE max data len");
return;
}
rp = (void *)rsp->data;
tx_octets = sys_le16_to_cpu(rp->max_tx_octets);
tx_time = sys_le16_to_cpu(rp->max_tx_time);
net_buf_unref(rsp);
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_DATA_LEN, sizeof(*cp));
if (!buf) {
BT_ERR("Failed to create LE Set Data Length Command");
return;
}
cp = net_buf_add(buf, sizeof(*cp));
cp->handle = sys_cpu_to_le16(conn->handle);
cp->tx_octets = sys_cpu_to_le16(tx_octets);
cp->tx_time = sys_cpu_to_le16(tx_time);
err = bt_hci_cmd_send(BT_HCI_OP_LE_SET_DATA_LEN, buf);
if (err) {
BT_ERR("Failed to send LE Set Data Length Command");
}
}
static int hci_le_set_phy(struct bt_conn *conn)
{
struct bt_hci_cp_le_set_phy *cp;
struct net_buf *buf;
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_PHY, sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}
cp = net_buf_add(buf, sizeof(*cp));
cp->handle = sys_cpu_to_le16(conn->handle);
cp->all_phys = 0U;
cp->tx_phys = BT_HCI_LE_PHY_PREFER_2M;
cp->rx_phys = BT_HCI_LE_PHY_PREFER_2M;
cp->phy_opts = BT_HCI_LE_PHY_CODED_ANY;
bt_hci_cmd_send(BT_HCI_OP_LE_SET_PHY, buf);
return 0;
}
static void slave_update_conn_param(struct bt_conn *conn)
{
if (!IS_ENABLED(CONFIG_BT_PERIPHERAL)) {
return;
}
/* don't start timer again on PHY update etc */
if (atomic_test_bit(conn->flags, BT_CONN_SLAVE_PARAM_UPDATE)) {
return;
}
/*
* Core 4.2 Vol 3, Part C, 9.3.12.2
* The Peripheral device should not perform a Connection Parameter
* Update procedure within 5 s after establishing a connection.
*/
k_delayed_work_submit(&conn->le.update_work, CONN_UPDATE_TIMEOUT);
}
#if defined(CONFIG_BT_SMP)
static void update_pending_id(struct bt_keys *keys, void *data)
{
if (keys->flags & BT_KEYS_ID_PENDING_ADD) {
keys->flags &= ~BT_KEYS_ID_PENDING_ADD;
bt_id_add(keys);
return;
}
if (keys->flags & BT_KEYS_ID_PENDING_DEL) {
keys->flags &= ~BT_KEYS_ID_PENDING_DEL;
bt_id_del(keys);
return;
}
}
#endif
static struct bt_conn *find_pending_connect(bt_addr_le_t *peer_addr)
{
struct bt_conn *conn;
/*
* Make lookup to check if there's a connection object in
* CONNECT or DIR_ADV state associated with passed peer LE address.
*/
conn = bt_conn_lookup_state_le(peer_addr, BT_CONN_CONNECT);
if (conn) {
return conn;
}
return bt_conn_lookup_state_le(peer_addr, BT_CONN_CONNECT_DIR_ADV);
}
static void enh_conn_complete(struct bt_hci_evt_le_enh_conn_complete *evt)
{
u16_t handle = sys_le16_to_cpu(evt->handle);
bt_addr_le_t peer_addr, id_addr;
struct bt_conn *conn;
int err;
BT_DBG("status %u handle %u role %u %s", evt->status, handle,
evt->role, bt_addr_le_str(&evt->peer_addr));
#if defined(CONFIG_BT_SMP)
if (atomic_test_and_clear_bit(bt_dev.flags, BT_DEV_ID_PENDING)) {
bt_keys_foreach(BT_KEYS_IRK, update_pending_id, NULL);
}
#endif
if (evt->status) {
/*
* If there was an error we are only interested in pending
* connection. There is no need to check ID address as
* only one connection can be in that state.
*
* Depending on error code address might not be valid anyway.
*/
conn = find_pending_connect(NULL);
if (!conn) {
return;
}
conn->err = evt->status;
if (IS_ENABLED(CONFIG_BT_PERIPHERAL)) {
/*
* Handle advertising timeout after high duty directed
* advertising.
*/
if (conn->err == BT_HCI_ERR_ADV_TIMEOUT) {
atomic_clear_bit(bt_dev.flags,
BT_DEV_ADVERTISING);
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
goto done;
}
}
if (IS_ENABLED(CONFIG_BT_CENTRAL)) {
/*
* Handle cancellation of outgoing connection attempt.
*/
if (conn->err == BT_HCI_ERR_UNKNOWN_CONN_ID) {
/* We notify before checking autoconnect flag
* as application may choose to change it from
* callback.
*/
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
/* Check if device is marked for autoconnect. */
if (atomic_test_bit(conn->flags,
BT_CONN_AUTO_CONNECT)) {
bt_conn_set_state(conn,
BT_CONN_CONNECT_SCAN);
}
goto done;
}
}
BT_WARN("Unexpected status 0x%02x", evt->status);
bt_conn_unref(conn);
return;
}
bt_addr_le_copy(&id_addr, &evt->peer_addr);
/* Translate "enhanced" identity address type to normal one */
if (id_addr.type == BT_ADDR_LE_PUBLIC_ID ||
id_addr.type == BT_ADDR_LE_RANDOM_ID) {
id_addr.type -= BT_ADDR_LE_PUBLIC_ID;
bt_addr_copy(&peer_addr.a, &evt->peer_rpa);
peer_addr.type = BT_ADDR_LE_RANDOM;
} else {
bt_addr_le_copy(&peer_addr, &evt->peer_addr);
}
conn = find_pending_connect(&id_addr);
if (evt->role == BT_CONN_ROLE_SLAVE) {
/*
* clear advertising even if we are not able to add connection
* object to keep host in sync with controller state
*/
atomic_clear_bit(bt_dev.flags, BT_DEV_ADVERTISING);
/* only for slave we may need to add new connection */
if (!conn) {
conn = bt_conn_add_le(&id_addr);
}
}
if (!conn) {
BT_ERR("Unable to add new conn for handle %u", handle);
return;
}
conn->handle = handle;
bt_addr_le_copy(&conn->le.dst, &id_addr);
conn->le.interval = sys_le16_to_cpu(evt->interval);
conn->le.latency = sys_le16_to_cpu(evt->latency);
conn->le.timeout = sys_le16_to_cpu(evt->supv_timeout);
conn->role = evt->role;
conn->err = 0U;
/*
* Use connection address (instead of identity address) as initiator
* or responder address. Only slave needs to be updated. For master all
* was set during outgoing connection creation.
*/
if (conn->role == BT_HCI_ROLE_SLAVE) {
conn->id = bt_dev.adv_id;
bt_addr_le_copy(&conn->le.init_addr, &peer_addr);
if (IS_ENABLED(CONFIG_BT_PRIVACY)) {
bt_addr_copy(&conn->le.resp_addr.a, &evt->local_rpa);
conn->le.resp_addr.type = BT_ADDR_LE_RANDOM;
} else {
bt_addr_le_copy(&conn->le.resp_addr,
&bt_dev.id_addr[conn->id]);
}
/* if the controller supports, lets advertise for another
* slave connection.
* check for connectable advertising state is sufficient as
* this is how this le connection complete for slave occurred.
*/
if (atomic_test_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING) &&
BT_LE_STATES_SLAVE_CONN_ADV(bt_dev.le.states)) {
if (IS_ENABLED(CONFIG_BT_PRIVACY)) {
le_set_private_addr(bt_dev.adv_id);
}
set_advertise_enable(true);
}
}
if (conn->role == BT_HCI_ROLE_MASTER) {
bt_addr_le_copy(&conn->le.resp_addr, &peer_addr);
if (IS_ENABLED(CONFIG_BT_PRIVACY)) {
bt_addr_copy(&conn->le.init_addr.a, &evt->local_rpa);
conn->le.init_addr.type = BT_ADDR_LE_RANDOM;
} else {
bt_addr_le_copy(&conn->le.init_addr,
&bt_dev.id_addr[conn->id]);
}
}
bt_conn_set_state(conn, BT_CONN_CONNECTED);
/*
* it is possible that connection was disconnected directly from
* connected callback so we must check state before doing connection
* parameters update
*/
if (conn->state != BT_CONN_CONNECTED) {
goto done;
}
if ((evt->role == BT_HCI_ROLE_MASTER) ||
BT_FEAT_LE_SLAVE_FEATURE_XCHG(bt_dev.le.features)) {
err = hci_le_read_remote_features(conn);
if (!err) {
goto done;
}
}
if (IS_ENABLED(CONFIG_BT_AUTO_PHY_UPDATE) &&
BT_FEAT_LE_PHY_2M(bt_dev.le.features)) {
err = hci_le_set_phy(conn);
if (!err) {
atomic_set_bit(conn->flags, BT_CONN_AUTO_PHY_UPDATE);
goto done;
}
}
if (IS_ENABLED(CONFIG_BT_DATA_LEN_UPDATE) &&
BT_FEAT_LE_DLE(bt_dev.le.features)) {
hci_le_set_data_len(conn);
}
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) &&
conn->role == BT_CONN_ROLE_SLAVE) {
slave_update_conn_param(conn);
}
done:
bt_conn_unref(conn);
if (IS_ENABLED(CONFIG_BT_CENTRAL)) {
bt_le_scan_update(false);
}
}
static void le_enh_conn_complete(struct net_buf *buf)
{
enh_conn_complete((void *)buf->data);
}
static void le_legacy_conn_complete(struct net_buf *buf)
{
struct bt_hci_evt_le_conn_complete *evt = (void *)buf->data;
struct bt_hci_evt_le_enh_conn_complete enh;
const bt_addr_le_t *id_addr;
BT_DBG("status %u role %u %s", evt->status, evt->role,
bt_addr_le_str(&evt->peer_addr));
enh.status = evt->status;
enh.handle = evt->handle;
enh.role = evt->role;
enh.interval = evt->interval;
enh.latency = evt->latency;
enh.supv_timeout = evt->supv_timeout;
enh.clock_accuracy = evt->clock_accuracy;
bt_addr_le_copy(&enh.peer_addr, &evt->peer_addr);
if (IS_ENABLED(CONFIG_BT_PRIVACY)) {
bt_addr_copy(&enh.local_rpa, &bt_dev.random_addr.a);
} else {
bt_addr_copy(&enh.local_rpa, BT_ADDR_ANY);
}
if (evt->role == BT_HCI_ROLE_SLAVE) {
id_addr = bt_lookup_id_addr(bt_dev.adv_id, &enh.peer_addr);
} else {
id_addr = bt_lookup_id_addr(BT_ID_DEFAULT, &enh.peer_addr);
}
if (id_addr != &enh.peer_addr) {
bt_addr_copy(&enh.peer_rpa, &enh.peer_addr.a);
bt_addr_le_copy(&enh.peer_addr, id_addr);
enh.peer_addr.type += BT_ADDR_LE_PUBLIC_ID;
} else {
bt_addr_copy(&enh.peer_rpa, BT_ADDR_ANY);
}
enh_conn_complete(&enh);
}
static void le_remote_feat_complete(struct net_buf *buf)
{
struct bt_hci_evt_le_remote_feat_complete *evt = (void *)buf->data;
u16_t handle = sys_le16_to_cpu(evt->handle);
struct bt_conn *conn;
conn = bt_conn_lookup_handle(handle);
if (!conn) {
BT_ERR("Unable to lookup conn for handle %u", handle);
return;
}
if (!evt->status) {
memcpy(conn->le.features, evt->features,
sizeof(conn->le.features));
}
if (IS_ENABLED(CONFIG_BT_AUTO_PHY_UPDATE) &&
BT_FEAT_LE_PHY_2M(bt_dev.le.features) &&
BT_FEAT_LE_PHY_2M(conn->le.features)) {
int err;
err = hci_le_set_phy(conn);
if (!err) {
atomic_set_bit(conn->flags, BT_CONN_AUTO_PHY_UPDATE);
goto done;
}
}
if (IS_ENABLED(CONFIG_BT_DATA_LEN_UPDATE) &&
BT_FEAT_LE_DLE(bt_dev.le.features) &&
BT_FEAT_LE_DLE(conn->le.features)) {
hci_le_set_data_len(conn);
}
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) &&
conn->role == BT_CONN_ROLE_SLAVE) {
slave_update_conn_param(conn);
}
done:
bt_conn_unref(conn);
}
#if defined(CONFIG_BT_DATA_LEN_UPDATE)
static void le_data_len_change(struct net_buf *buf)
{
struct bt_hci_evt_le_data_len_change *evt = (void *)buf->data;
u16_t max_tx_octets = sys_le16_to_cpu(evt->max_tx_octets);
u16_t max_rx_octets = sys_le16_to_cpu(evt->max_rx_octets);
u16_t max_tx_time = sys_le16_to_cpu(evt->max_tx_time);
u16_t max_rx_time = sys_le16_to_cpu(evt->max_rx_time);
u16_t handle = sys_le16_to_cpu(evt->handle);
struct bt_conn *conn;
conn = bt_conn_lookup_handle(handle);
if (!conn) {
BT_ERR("Unable to lookup conn for handle %u", handle);
return;
}
BT_DBG("max. tx: %u (%uus), max. rx: %u (%uus)", max_tx_octets,
max_tx_time, max_rx_octets, max_rx_time);
/* TODO use those */
bt_conn_unref(conn);
}
#endif /* CONFIG_BT_DATA_LEN_UPDATE */
#if defined(CONFIG_BT_PHY_UPDATE)
static void le_phy_update_complete(struct net_buf *buf)
{
struct bt_hci_evt_le_phy_update_complete *evt = (void *)buf->data;
u16_t handle = sys_le16_to_cpu(evt->handle);
struct bt_conn *conn;
conn = bt_conn_lookup_handle(handle);
if (!conn) {
BT_ERR("Unable to lookup conn for handle %u", handle);
return;
}
BT_DBG("PHY updated: status: 0x%x, tx: %u, rx: %u",
evt->status, evt->tx_phy, evt->rx_phy);
if (!IS_ENABLED(CONFIG_BT_AUTO_PHY_UPDATE) ||
!atomic_test_and_clear_bit(conn->flags, BT_CONN_AUTO_PHY_UPDATE)) {
goto done;
}
if (IS_ENABLED(CONFIG_BT_DATA_LEN_UPDATE) &&
BT_FEAT_LE_DLE(bt_dev.le.features) &&
BT_FEAT_LE_DLE(conn->le.features)) {
hci_le_set_data_len(conn);
}
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) &&
conn->role == BT_CONN_ROLE_SLAVE) {
slave_update_conn_param(conn);
}
done:
bt_conn_unref(conn);
}
#endif /* CONFIG_BT_PHY_UPDATE */
bool bt_le_conn_params_valid(const struct bt_le_conn_param *param)
{
/* All limits according to BT Core spec 5.0 [Vol 2, Part E, 7.8.12] */
if (param->interval_min > param->interval_max ||
param->interval_min < 6 || param->interval_max > 3200) {
return false;
}
if (param->latency > 499) {
return false;
}
if (param->timeout < 10 || param->timeout > 3200 ||
((param->timeout * 4U) <=
((1 + param->latency) * param->interval_max))) {
return false;
}
return true;
}
static void le_conn_param_neg_reply(u16_t handle, u8_t reason)
{
struct bt_hci_cp_le_conn_param_req_neg_reply *cp;
struct net_buf *buf;
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY,
sizeof(*cp));
if (!buf) {
BT_ERR("Unable to allocate buffer");
return;
}
cp = net_buf_add(buf, sizeof(*cp));
cp->handle = sys_cpu_to_le16(handle);
cp->reason = sys_cpu_to_le16(reason);
bt_hci_cmd_send(BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY, buf);
}
static int le_conn_param_req_reply(u16_t handle,
const struct bt_le_conn_param *param)
{
struct bt_hci_cp_le_conn_param_req_reply *cp;
struct net_buf *buf;
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY, sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}
cp = net_buf_add(buf, sizeof(*cp));
(void)memset(cp, 0, sizeof(*cp));
cp->handle = sys_cpu_to_le16(handle);
cp->interval_min = sys_cpu_to_le16(param->interval_min);
cp->interval_max = sys_cpu_to_le16(param->interval_max);
cp->latency = sys_cpu_to_le16(param->latency);
cp->timeout = sys_cpu_to_le16(param->timeout);
return bt_hci_cmd_send(BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY, buf);
}
static void le_conn_param_req(struct net_buf *buf)
{
struct bt_hci_evt_le_conn_param_req *evt = (void *)buf->data;
struct bt_le_conn_param param;
struct bt_conn *conn;
u16_t handle;
handle = sys_le16_to_cpu(evt->handle);
param.interval_min = sys_le16_to_cpu(evt->interval_min);
param.interval_max = sys_le16_to_cpu(evt->interval_max);
param.latency = sys_le16_to_cpu(evt->latency);
param.timeout = sys_le16_to_cpu(evt->timeout);
conn = bt_conn_lookup_handle(handle);
if (!conn) {
BT_ERR("Unable to lookup conn for handle %u", handle);
le_conn_param_neg_reply(handle, BT_HCI_ERR_UNKNOWN_CONN_ID);
return;
}
if (!le_param_req(conn, ¶m)) {
le_conn_param_neg_reply(handle, BT_HCI_ERR_INVALID_LL_PARAM);
} else {
le_conn_param_req_reply(handle, ¶m);
}
bt_conn_unref(conn);
}
static void le_conn_update_complete(struct net_buf *buf)
{
struct bt_hci_evt_le_conn_update_complete *evt = (void *)buf->data;
struct bt_conn *conn;
u16_t handle;
handle = sys_le16_to_cpu(evt->handle);
BT_DBG("status %u, handle %u", evt->status, handle);
conn = bt_conn_lookup_handle(handle);
if (!conn) {
BT_ERR("Unable to lookup conn for handle %u", handle);
return;
}
if (!evt->status) {
conn->le.interval = sys_le16_to_cpu(evt->interval);
conn->le.latency = sys_le16_to_cpu(evt->latency);
conn->le.timeout = sys_le16_to_cpu(evt->supv_timeout);
notify_le_param_updated(conn);
} else if (evt->status == BT_HCI_ERR_UNSUPP_REMOTE_FEATURE &&
conn->role == BT_HCI_ROLE_SLAVE &&
!atomic_test_and_set_bit(conn->flags,
BT_CONN_SLAVE_PARAM_L2CAP)) {
/* CPR not supported, let's try L2CAP CPUP instead */
struct bt_le_conn_param param;
param.interval_min = conn->le.interval_min;
param.interval_max = conn->le.interval_max;
param.latency = conn->le.pending_latency;
param.timeout = conn->le.pending_timeout;
bt_l2cap_update_conn_param(conn, ¶m);
}
bt_conn_unref(conn);
}
#if defined(CONFIG_BT_CENTRAL)
static void check_pending_conn(const bt_addr_le_t *id_addr,
const bt_addr_le_t *addr, u8_t evtype)
{
struct bt_conn *conn;
/* No connections are allowed during explicit scanning */
if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
return;
}
/* Return if event is not connectable */
if (evtype != BT_LE_ADV_IND && evtype != BT_LE_ADV_DIRECT_IND) {
return;
}
conn = bt_conn_lookup_state_le(id_addr, BT_CONN_CONNECT_SCAN);
if (!conn) {
return;
}
if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING) &&
set_le_scan_enable(BT_HCI_LE_SCAN_DISABLE)) {
goto failed;
}
bt_addr_le_copy(&conn->le.resp_addr, addr);
if (hci_le_create_conn(conn)) {
goto failed;
}
bt_conn_set_state(conn, BT_CONN_CONNECT);
bt_conn_unref(conn);
return;
failed:
conn->err = BT_HCI_ERR_UNSPECIFIED;
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
bt_conn_unref(conn);
bt_le_scan_update(false);
}
#endif /* CONFIG_BT_CENTRAL */
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
static int set_flow_control(void)
{
struct bt_hci_cp_host_buffer_size *hbs;
struct net_buf *buf;
int err;
/* Check if host flow control is actually supported */
if (!BT_CMD_TEST(bt_dev.supported_commands, 10, 5)) {
BT_WARN("Controller to host flow control not supported");
return 0;
}
buf = bt_hci_cmd_create(BT_HCI_OP_HOST_BUFFER_SIZE,
sizeof(*hbs));
if (!buf) {
return -ENOBUFS;
}
hbs = net_buf_add(buf, sizeof(*hbs));
(void)memset(hbs, 0, sizeof(*hbs));
hbs->acl_mtu = sys_cpu_to_le16(CONFIG_BT_L2CAP_RX_MTU +
sizeof(struct bt_l2cap_hdr));
hbs->acl_pkts = sys_cpu_to_le16(CONFIG_BT_ACL_RX_COUNT);
err = bt_hci_cmd_send_sync(BT_HCI_OP_HOST_BUFFER_SIZE, buf, NULL);
if (err) {
return err;
}
buf = bt_hci_cmd_create(BT_HCI_OP_SET_CTL_TO_HOST_FLOW, 1);
if (!buf) {
return -ENOBUFS;
}
net_buf_add_u8(buf, BT_HCI_CTL_TO_HOST_FLOW_ENABLE);
return bt_hci_cmd_send_sync(BT_HCI_OP_SET_CTL_TO_HOST_FLOW, buf, NULL);
}
#endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */
static int bt_clear_all_pairings(u8_t id)
{
bt_conn_disconnect_all(id);
if (IS_ENABLED(CONFIG_BT_SMP)) {
bt_keys_clear_all(id);
}
if (IS_ENABLED(CONFIG_BT_BREDR)) {
bt_keys_link_key_clear_addr(NULL);
}
return 0;
}
int bt_unpair(u8_t id, const bt_addr_le_t *addr)
{
struct bt_keys *keys = NULL;
struct bt_conn *conn;
if (id >= CONFIG_BT_ID_MAX) {
return -EINVAL;
}
if (!addr || !bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) {
return bt_clear_all_pairings(id);
}
conn = bt_conn_lookup_addr_le(id, addr);
if (conn) {
/* Clear the conn->le.keys pointer since we'll invalidate it,
* and don't want any subsequent code (like disconnected
* callbacks) accessing it.
*/
if (conn->type == BT_CONN_TYPE_LE) {
keys = conn->le.keys;
conn->le.keys = NULL;
}
bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
bt_conn_unref(conn);
}
if (IS_ENABLED(CONFIG_BT_BREDR)) {
/* LE Public may indicate BR/EDR as well */
if (addr->type == BT_ADDR_LE_PUBLIC) {
bt_keys_link_key_clear_addr(&addr->a);
}
}
if (IS_ENABLED(CONFIG_BT_SMP)) {
if (!keys) {
keys = bt_keys_find_addr(id, addr);
}
if (keys) {
bt_keys_clear(keys);
}
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_gatt_clear(id, addr);
}
return 0;
}
#endif /* CONFIG_BT_CONN */
#if defined(CONFIG_BT_BREDR)
static void reset_pairing(struct bt_conn *conn)
{
atomic_clear_bit(conn->flags, BT_CONN_BR_PAIRING);
atomic_clear_bit(conn->flags, BT_CONN_BR_PAIRING_INITIATOR);
atomic_clear_bit(conn->flags, BT_CONN_BR_LEGACY_SECURE);
/* Reset required security level to current operational */
conn->required_sec_level = conn->sec_level;
}
static int reject_conn(const bt_addr_t *bdaddr, u8_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 void update_sec_level_br(struct bt_conn *conn)
{
if (!conn->encrypt) {
conn->sec_level = BT_SECURITY_LOW;
return;
}
if (conn->br.link_key) {
if (conn->br.link_key->flags & BT_LINK_KEY_AUTHENTICATED) {
if (conn->encrypt == 0x02) {
conn->sec_level = BT_SECURITY_FIPS;
} else {
conn->sec_level = BT_SECURITY_HIGH;
}
} else {
conn->sec_level = BT_SECURITY_MEDIUM;
}
} else {
BT_WARN("No BR/EDR link key found");
conn->sec_level = BT_SECURITY_MEDIUM;
}
if (conn->required_sec_level > conn->sec_level) {
BT_ERR("Failed to set required security level");
bt_conn_disconnect(conn, BT_HCI_ERR_AUTHENTICATION_FAIL);
}
}
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;
u16_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;
u16_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;
update_sec_level_br(conn);
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);
}
static void pin_code_req(struct net_buf *buf)
{
struct bt_hci_evt_pin_code_req *evt = (void *)buf->data;
struct bt_conn *conn;
BT_DBG("");
conn = bt_conn_lookup_addr_br(&evt->bdaddr);
if (!conn) {
BT_ERR("Can't find conn for %s", bt_addr_str(&evt->bdaddr));
return;
}
bt_conn_pin_code_req(conn);
bt_conn_unref(conn);
}
static void link_key_notify(struct net_buf *buf)
{
struct bt_hci_evt_link_key_notify *evt = (void *)buf->data;
struct bt_conn *conn;
conn = bt_conn_lookup_addr_br(&evt->bdaddr);
if (!conn) {
BT_ERR("Can't find conn for %s", bt_addr_str(&evt->bdaddr));
return;
}
BT_DBG("%s, link type 0x%02x", bt_addr_str(&evt->bdaddr), evt->key_type);
if (!conn->br.link_key) {
conn->br.link_key = bt_keys_get_link_key(&evt->bdaddr);
}
if (!conn->br.link_key) {
BT_ERR("Can't update keys for %s", bt_addr_str(&evt->bdaddr));
bt_conn_unref(conn);
return;
}
/* clear any old Link Key flags */
conn->br.link_key->flags = 0U;
switch (evt->key_type) {
case BT_LK_COMBINATION:
/*
* Setting Combination Link Key as AUTHENTICATED means it was
* successfully generated by 16 digits wide PIN code.
*/
if (atomic_test_and_clear_bit(conn->flags,
BT_CONN_BR_LEGACY_SECURE)) {
conn->br.link_key->flags |= BT_LINK_KEY_AUTHENTICATED;
}
memcpy(conn->br.link_key->val, evt->link_key, 16);
break;
case BT_LK_AUTH_COMBINATION_P192:
conn->br.link_key->flags |= BT_LINK_KEY_AUTHENTICATED;
/* fall through */
case BT_LK_UNAUTH_COMBINATION_P192:
/* Mark no-bond so that link-key is removed on disconnection */
if (bt_conn_ssp_get_auth(conn) < BT_HCI_DEDICATED_BONDING) {
atomic_set_bit(conn->flags, BT_CONN_BR_NOBOND);
}
memcpy(conn->br.link_key->val, evt->link_key, 16);
break;
case BT_LK_AUTH_COMBINATION_P256:
conn->br.link_key->flags |= BT_LINK_KEY_AUTHENTICATED;
/* fall through */
case BT_LK_UNAUTH_COMBINATION_P256:
conn->br.link_key->flags |= BT_LINK_KEY_SC;
/* Mark no-bond so that link-key is removed on disconnection */
if (bt_conn_ssp_get_auth(conn) < BT_HCI_DEDICATED_BONDING) {
atomic_set_bit(conn->flags, BT_CONN_BR_NOBOND);
}
memcpy(conn->br.link_key->val, evt->link_key, 16);
break;
default:
BT_WARN("Unsupported Link Key type %u", evt->key_type);
(void)memset(conn->br.link_key->val, 0,
sizeof(conn->br.link_key->val));
break;
}
bt_conn_unref(conn);
}
static void link_key_neg_reply(const bt_addr_t *bdaddr)
{
struct bt_hci_cp_link_key_neg_reply *cp;
struct net_buf *buf;
BT_DBG("");
buf = bt_hci_cmd_create(BT_HCI_OP_LINK_KEY_NEG_REPLY, sizeof(*cp));
if (!buf) {
BT_ERR("Out of command buffers");
return;
}
cp = net_buf_add(buf, sizeof(*cp));
bt_addr_copy(&cp->bdaddr, bdaddr);
bt_hci_cmd_send_sync(BT_HCI_OP_LINK_KEY_NEG_REPLY, buf, NULL);
}
static void link_key_reply(const bt_addr_t *bdaddr, const u8_t *lk)
{
struct bt_hci_cp_link_key_reply *cp;
struct net_buf *buf;
BT_DBG("");
buf = bt_hci_cmd_create(BT_HCI_OP_LINK_KEY_REPLY, sizeof(*cp));
if (!buf) {
BT_ERR("Out of command buffers");
return;
}
cp = net_buf_add(buf, sizeof(*cp));
bt_addr_copy(&cp->bdaddr, bdaddr);
memcpy(cp->link_key, lk, 16);
bt_hci_cmd_send_sync(BT_HCI_OP_LINK_KEY_REPLY, buf, NULL);
}
static void link_key_req(struct net_buf *buf)
{
struct bt_hci_evt_link_key_req *evt = (void *)buf->data;
struct bt_conn *conn;
BT_DBG("%s", bt_addr_str(&evt->bdaddr));
conn = bt_conn_lookup_addr_br(&evt->bdaddr);
if (!conn) {
BT_ERR("Can't find conn for %s", bt_addr_str(&evt->bdaddr));
link_key_neg_reply(&evt->bdaddr);
return;
}
if (!