2015-04-28 10:39:50 +03:00
|
|
|
/* conn.c - Bluetooth connection handling */
|
|
|
|
|
|
|
|
/*
|
2016-06-10 12:10:18 +03:00
|
|
|
* Copyright (c) 2015-2016 Intel Corporation
|
2015-04-28 10:39:50 +03:00
|
|
|
*
|
2017-01-18 17:01:01 -08:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2015-04-28 10:39:50 +03:00
|
|
|
*/
|
|
|
|
|
includes: prefer <zephyr/kernel.h> over <zephyr/zephyr.h>
As of today <zephyr/zephyr.h> is 100% equivalent to <zephyr/kernel.h>.
This patch proposes to then include <zephyr/kernel.h> instead of
<zephyr/zephyr.h> since it is more clear that you are including the
Kernel APIs and (probably) nothing else. <zephyr/zephyr.h> sounds like a
catch-all header that may be confusing. Most applications need to
include a bunch of other things to compile, e.g. driver headers or
subsystem headers like BT, logging, etc.
The idea of a catch-all header in Zephyr is probably not feasible
anyway. Reason is that Zephyr is not a library, like it could be for
example `libpython`. Zephyr provides many utilities nowadays: a kernel,
drivers, subsystems, etc and things will likely grow. A catch-all header
would be massive, difficult to keep up-to-date. It is also likely that
an application will only build a small subset. Note that subsystem-level
headers may use a catch-all approach to make things easier, though.
NOTE: This patch is **NOT** removing the header, just removing its usage
in-tree. I'd advocate for its deprecation (add a #warning on it), but I
understand many people will have concerns.
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
2022-08-25 09:58:46 +02:00
|
|
|
#include <zephyr/kernel.h>
|
2015-04-28 10:39:50 +03:00
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
2015-05-25 09:13:33 +03:00
|
|
|
#include <stdbool.h>
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/sys/atomic.h>
|
|
|
|
#include <zephyr/sys/byteorder.h>
|
|
|
|
#include <zephyr/sys/check.h>
|
2023-05-15 15:50:28 +02:00
|
|
|
#include <zephyr/sys/iterable_sections.h>
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/sys/util.h>
|
2023-01-10 21:56:09 +01:00
|
|
|
#include <zephyr/sys/util_macro.h>
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/sys/slist.h>
|
|
|
|
#include <zephyr/debug/stack.h>
|
|
|
|
#include <zephyr/sys/__assert.h>
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/bluetooth/hci.h>
|
|
|
|
#include <zephyr/bluetooth/bluetooth.h>
|
|
|
|
#include <zephyr/bluetooth/direction.h>
|
|
|
|
#include <zephyr/bluetooth/conn.h>
|
|
|
|
#include <zephyr/drivers/bluetooth/hci_driver.h>
|
|
|
|
#include <zephyr/bluetooth/att.h>
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2022-10-24 13:25:02 +02:00
|
|
|
#include "common/assert.h"
|
2023-09-14 10:22:43 +02:00
|
|
|
#include "common/bt_str.h"
|
2017-05-10 16:27:16 +02:00
|
|
|
|
2023-07-18 10:39:44 +02:00
|
|
|
#include "buf_view.h"
|
2023-01-11 17:40:02 +01:00
|
|
|
#include "addr_internal.h"
|
2015-04-28 10:39:50 +03:00
|
|
|
#include "hci_core.h"
|
2021-03-08 14:24:34 +01:00
|
|
|
#include "id.h"
|
2021-03-08 14:30:34 +01:00
|
|
|
#include "adv.h"
|
2024-06-03 12:49:05 +02:00
|
|
|
#include "scan.h"
|
2015-06-15 11:05:35 +03:00
|
|
|
#include "conn_internal.h"
|
2015-10-05 13:53:03 +03:00
|
|
|
#include "l2cap_internal.h"
|
2015-06-25 11:08:57 +02:00
|
|
|
#include "keys.h"
|
|
|
|
#include "smp.h"
|
2024-03-01 15:29:10 +08:00
|
|
|
#include "classic/ssp.h"
|
2016-02-17 11:18:10 +02:00
|
|
|
#include "att_internal.h"
|
2021-01-20 14:11:01 +01:00
|
|
|
#include "iso_internal.h"
|
2021-11-24 14:12:07 +01:00
|
|
|
#include "direction_internal.h"
|
2024-02-27 15:27:59 +08:00
|
|
|
#include "classic/sco_internal.h"
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
#define LOG_LEVEL CONFIG_BT_CONN_LOG_LEVEL
|
|
|
|
#include <zephyr/logging/log.h>
|
|
|
|
LOG_MODULE_REGISTER(bt_conn);
|
|
|
|
|
2021-06-24 15:36:28 +02:00
|
|
|
K_FIFO_DEFINE(free_tx);
|
|
|
|
|
2022-05-31 13:42:22 +02:00
|
|
|
static void tx_free(struct bt_conn_tx *tx);
|
|
|
|
|
|
|
|
static void conn_tx_destroy(struct bt_conn *conn, struct bt_conn_tx *tx)
|
|
|
|
{
|
|
|
|
__ASSERT_NO_MSG(tx);
|
|
|
|
|
|
|
|
bt_conn_tx_cb_t cb = tx->cb;
|
|
|
|
void *user_data = tx->user_data;
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
LOG_DBG("conn %p tx %p cb %p ud %p", conn, tx, cb, user_data);
|
|
|
|
|
2022-05-31 13:42:22 +02:00
|
|
|
/* Free up TX metadata before calling callback in case the callback
|
|
|
|
* tries to allocate metadata
|
|
|
|
*/
|
|
|
|
tx_free(tx);
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
if (cb) {
|
|
|
|
cb(conn, user_data, -ESHUTDOWN);
|
|
|
|
}
|
2022-05-31 13:42:22 +02:00
|
|
|
}
|
|
|
|
|
2021-11-18 14:26:32 +01:00
|
|
|
#if defined(CONFIG_BT_CONN_TX)
|
2021-11-18 14:13:15 +01:00
|
|
|
static void tx_complete_work(struct k_work *work);
|
2021-11-18 14:26:32 +01:00
|
|
|
#endif /* CONFIG_BT_CONN_TX */
|
2021-11-18 14:13:15 +01:00
|
|
|
|
2024-01-29 16:31:50 -05:00
|
|
|
static void notify_recycled_conn_slot(void);
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
void bt_tx_irq_raise(void);
|
|
|
|
|
2021-06-24 15:36:28 +02:00
|
|
|
/* Group Connected BT_CONN only in this */
|
|
|
|
#if defined(CONFIG_BT_CONN)
|
|
|
|
/* Peripheral timeout to initialize Connection Parameter Update procedure */
|
|
|
|
#define CONN_UPDATE_TIMEOUT K_MSEC(CONFIG_BT_CONN_PARAM_UPDATE_TIMEOUT)
|
2019-11-26 20:54:58 +02:00
|
|
|
|
2021-06-24 15:36:28 +02:00
|
|
|
static void deferred_work(struct k_work *work);
|
|
|
|
static void notify_connected(struct bt_conn *conn);
|
|
|
|
|
|
|
|
static struct bt_conn acl_conns[CONFIG_BT_MAX_CONN];
|
2017-08-09 09:21:11 +03:00
|
|
|
NET_BUF_POOL_DEFINE(acl_tx_pool, CONFIG_BT_L2CAP_TX_BUF_COUNT,
|
|
|
|
BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU),
|
2023-02-17 08:55:41 +01:00
|
|
|
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
|
2015-11-05 15:46:25 +02:00
|
|
|
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_CLASSIC)
|
2016-01-14 22:12:28 +02:00
|
|
|
const struct bt_conn_auth_cb *bt_auth;
|
2022-03-08 14:33:56 +01:00
|
|
|
sys_slist_t bt_auth_info_cbs = SYS_SLIST_STATIC_INIT(&bt_auth_info_cbs);
|
2024-03-01 18:45:44 +08:00
|
|
|
#endif /* CONFIG_BT_SMP || CONFIG_BT_CLASSIC */
|
2016-01-14 17:32:53 +02:00
|
|
|
|
2024-06-10 14:30:04 +02:00
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
static sys_slist_t conn_cbs = SYS_SLIST_STATIC_INIT(&conn_cbs);
|
2017-03-17 08:02:57 +02:00
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
static struct bt_conn_tx conn_tx[CONFIG_BT_CONN_TX_MAX];
|
2017-03-17 08:02:57 +02:00
|
|
|
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
2021-06-22 15:30:10 +02:00
|
|
|
static int bt_hci_connect_br_cancel(struct bt_conn *conn);
|
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
static struct bt_conn sco_conns[CONFIG_BT_MAX_SCO_CONN];
|
2024-03-01 18:45:44 +08:00
|
|
|
#endif /* CONFIG_BT_CLASSIC */
|
2021-06-22 15:32:51 +02:00
|
|
|
#endif /* CONFIG_BT_CONN */
|
|
|
|
|
2023-07-18 10:39:44 +02:00
|
|
|
#if defined(CONFIG_BT_CONN_TX)
|
|
|
|
void frag_destroy(struct net_buf *buf);
|
|
|
|
|
|
|
|
/* Storage for fragments (views) into the upper layers' PDUs. */
|
|
|
|
/* TODO: remove user-data requirements */
|
|
|
|
NET_BUF_POOL_FIXED_DEFINE(fragments, CONFIG_BT_CONN_FRAG_COUNT, 0,
|
|
|
|
CONFIG_BT_CONN_TX_USER_DATA_SIZE, frag_destroy);
|
|
|
|
|
|
|
|
struct frag_md {
|
|
|
|
struct bt_buf_view_meta view_meta;
|
|
|
|
};
|
|
|
|
struct frag_md frag_md_pool[CONFIG_BT_CONN_FRAG_COUNT];
|
|
|
|
|
|
|
|
struct frag_md *get_frag_md(struct net_buf *fragment)
|
|
|
|
{
|
|
|
|
return &frag_md_pool[net_buf_id(fragment)];
|
|
|
|
}
|
|
|
|
|
|
|
|
void frag_destroy(struct net_buf *frag)
|
|
|
|
{
|
|
|
|
/* allow next view to be allocated (and unlock the parent buf) */
|
|
|
|
bt_buf_destroy_view(frag, &get_frag_md(frag)->view_meta);
|
2023-07-21 10:22:32 +02:00
|
|
|
|
|
|
|
LOG_DBG("");
|
|
|
|
|
|
|
|
/* Kick the TX processor to send the rest of the frags. */
|
|
|
|
bt_tx_irq_raise();
|
2023-07-18 10:39:44 +02:00
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
static struct net_buf *get_data_frag(struct net_buf *outside, size_t winsize)
|
2023-07-18 10:39:44 +02:00
|
|
|
{
|
|
|
|
struct net_buf *window;
|
|
|
|
|
|
|
|
__ASSERT_NO_MSG(!bt_buf_has_view(outside));
|
|
|
|
|
|
|
|
/* Keeping a ref is the caller's responsibility */
|
|
|
|
window = net_buf_alloc_len(&fragments, 0, K_NO_WAIT);
|
|
|
|
if (!window) {
|
|
|
|
return window;
|
|
|
|
}
|
|
|
|
|
2024-05-21 17:13:31 +02:00
|
|
|
window = bt_buf_make_view(window, outside,
|
2023-07-18 10:39:44 +02:00
|
|
|
winsize, &get_frag_md(window)->view_meta);
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
LOG_DBG("get-acl-frag: outside %p window %p size %d", outside, window, winsize);
|
2023-07-18 10:39:44 +02:00
|
|
|
|
|
|
|
return window;
|
|
|
|
}
|
2023-07-21 10:22:32 +02:00
|
|
|
#else /* !CONFIG_BT_CONN_TX */
|
|
|
|
static struct net_buf *get_data_frag(struct net_buf *outside, size_t winsize)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(outside);
|
|
|
|
ARG_UNUSED(winsize);
|
|
|
|
|
|
|
|
/* This will never get called. It's only to allow compilation to take
|
|
|
|
* place and the later linker stage to remove this implementation.
|
|
|
|
*/
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2023-07-18 10:39:44 +02:00
|
|
|
#endif /* CONFIG_BT_CONN_TX */
|
|
|
|
|
2021-09-16 17:43:49 +02:00
|
|
|
#if defined(CONFIG_BT_ISO)
|
2023-03-24 09:21:36 +01:00
|
|
|
extern struct bt_conn iso_conns[CONFIG_BT_ISO_MAX_CHAN];
|
|
|
|
|
2021-09-16 17:43:49 +02:00
|
|
|
/* Callback TX buffers for ISO */
|
|
|
|
static struct bt_conn_tx iso_tx[CONFIG_BT_ISO_TX_BUF_COUNT];
|
|
|
|
|
|
|
|
int bt_conn_iso_init(void)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(iso_tx); i++) {
|
|
|
|
k_fifo_put(&free_tx, &iso_tx[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_ISO */
|
|
|
|
|
2017-03-19 13:35:09 +02:00
|
|
|
struct k_sem *bt_conn_get_pkts(struct bt_conn *conn)
|
|
|
|
{
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
2020-05-11 15:13:59 -07:00
|
|
|
if (conn->type == BT_CONN_TYPE_BR || !bt_dev.le.acl_mtu) {
|
2017-03-19 13:35:09 +02:00
|
|
|
return &bt_dev.br.pkts;
|
|
|
|
}
|
2024-03-01 18:45:44 +08:00
|
|
|
#endif /* CONFIG_BT_CLASSIC */
|
2022-12-18 16:00:44 +05:30
|
|
|
|
2020-05-11 15:13:59 -07:00
|
|
|
#if defined(CONFIG_BT_ISO)
|
2022-06-03 16:40:58 +05:30
|
|
|
/* Use ISO pkts semaphore if LE Read Buffer Size command returned
|
|
|
|
* dedicated ISO buffers.
|
|
|
|
*/
|
|
|
|
if (conn->type == BT_CONN_TYPE_ISO) {
|
2022-10-12 10:55:56 -07:00
|
|
|
if (bt_dev.le.iso_mtu && bt_dev.le.iso_limit != 0) {
|
2020-05-11 15:13:59 -07:00
|
|
|
return &bt_dev.le.iso_pkts;
|
|
|
|
}
|
2022-06-03 16:40:58 +05:30
|
|
|
|
|
|
|
return NULL;
|
2020-05-11 15:13:59 -07:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_ISO */
|
2022-12-18 16:00:44 +05:30
|
|
|
|
2021-06-24 15:21:39 +02:00
|
|
|
#if defined(CONFIG_BT_CONN)
|
2022-12-18 16:00:44 +05:30
|
|
|
if (bt_dev.le.acl_mtu) {
|
|
|
|
return &bt_dev.le.acl_pkts;
|
|
|
|
}
|
2021-06-24 15:21:39 +02:00
|
|
|
#endif /* CONFIG_BT_CONN */
|
2022-12-18 16:00:44 +05:30
|
|
|
|
|
|
|
return NULL;
|
2017-03-19 13:35:09 +02:00
|
|
|
}
|
|
|
|
|
2017-01-17 11:01:47 +02:00
|
|
|
static inline const char *state2str(bt_conn_state_t state)
|
2015-06-19 23:03:18 +02:00
|
|
|
{
|
|
|
|
switch (state) {
|
|
|
|
case BT_CONN_DISCONNECTED:
|
|
|
|
return "disconnected";
|
2020-06-03 14:48:04 +02:00
|
|
|
case BT_CONN_DISCONNECT_COMPLETE:
|
|
|
|
return "disconnect-complete";
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_INITIATING:
|
|
|
|
return "initiating";
|
|
|
|
case BT_CONN_SCAN_BEFORE_INITIATING:
|
|
|
|
return "scan-before-initiating";
|
|
|
|
case BT_CONN_INITIATING_FILTER_LIST:
|
|
|
|
return "initiating-filter-list";
|
|
|
|
case BT_CONN_ADV_CONNECTABLE:
|
|
|
|
return "adv-connectable";
|
|
|
|
case BT_CONN_ADV_DIR_CONNECTABLE:
|
|
|
|
return "adv-dir-connectable";
|
2015-06-19 23:03:18 +02:00
|
|
|
case BT_CONN_CONNECTED:
|
|
|
|
return "connected";
|
2022-02-22 15:16:34 +01:00
|
|
|
case BT_CONN_DISCONNECTING:
|
|
|
|
return "disconnecting";
|
2015-06-19 23:03:18 +02:00
|
|
|
default:
|
|
|
|
return "(unknown)";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-28 14:11:57 +02:00
|
|
|
static void tx_free(struct bt_conn_tx *tx)
|
|
|
|
{
|
2023-07-14 16:29:13 +02:00
|
|
|
LOG_DBG("%p", tx);
|
2019-11-28 14:11:57 +02:00
|
|
|
tx->cb = NULL;
|
|
|
|
tx->user_data = NULL;
|
|
|
|
k_fifo_put(&free_tx, tx);
|
|
|
|
}
|
|
|
|
|
2024-02-01 08:26:21 +01:00
|
|
|
#if defined(CONFIG_BT_CONN_TX)
|
2019-11-28 14:11:57 +02:00
|
|
|
static void tx_notify(struct bt_conn *conn)
|
|
|
|
{
|
2024-03-12 11:46:48 +01:00
|
|
|
__ASSERT_NO_MSG(k_current_get() ==
|
|
|
|
k_work_queue_thread_get(&k_sys_work_q));
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("conn %p", conn);
|
2019-11-28 14:11:57 +02:00
|
|
|
|
|
|
|
while (1) {
|
2022-05-30 15:05:57 +02:00
|
|
|
struct bt_conn_tx *tx = NULL;
|
2019-11-28 14:11:57 +02:00
|
|
|
unsigned int key;
|
|
|
|
bt_conn_tx_cb_t cb;
|
|
|
|
void *user_data;
|
|
|
|
|
|
|
|
key = irq_lock();
|
2022-05-30 15:05:57 +02:00
|
|
|
if (!sys_slist_is_empty(&conn->tx_complete)) {
|
2023-07-21 10:22:32 +02:00
|
|
|
const sys_snode_t *node = sys_slist_get_not_empty(&conn->tx_complete);
|
|
|
|
|
|
|
|
tx = CONTAINER_OF(node, struct bt_conn_tx, node);
|
2019-11-28 14:11:57 +02:00
|
|
|
}
|
|
|
|
irq_unlock(key);
|
|
|
|
|
2022-05-30 15:05:57 +02:00
|
|
|
if (!tx) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("tx %p cb %p user_data %p", tx, tx->cb, tx->user_data);
|
2019-11-28 14:11:57 +02:00
|
|
|
|
|
|
|
/* Copy over the params */
|
|
|
|
cb = tx->cb;
|
|
|
|
user_data = tx->user_data;
|
|
|
|
|
|
|
|
/* Free up TX notify since there may be user waiting */
|
|
|
|
tx_free(tx);
|
|
|
|
|
|
|
|
/* Run the callback, at this point it should be safe to
|
|
|
|
* allocate new buffers since the TX should have been
|
|
|
|
* unblocked by tx_free.
|
|
|
|
*/
|
2023-07-21 10:22:32 +02:00
|
|
|
if (cb) {
|
|
|
|
cb(conn, user_data, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_DBG("raise TX IRQ");
|
|
|
|
bt_tx_irq_raise();
|
2019-11-28 14:11:57 +02:00
|
|
|
}
|
|
|
|
}
|
2024-02-01 08:26:21 +01:00
|
|
|
#endif /* CONFIG_BT_CONN_TX */
|
2019-11-28 14:11:57 +02:00
|
|
|
|
2020-05-11 15:13:59 -07:00
|
|
|
struct bt_conn *bt_conn_new(struct bt_conn *conns, size_t size)
|
2015-09-01 18:06:35 +02:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_conn *conn = NULL;
|
|
|
|
int i;
|
2015-09-01 18:06:35 +02:00
|
|
|
|
2020-05-11 15:13:59 -07:00
|
|
|
for (i = 0; i < size; i++) {
|
2020-11-19 17:11:09 +01:00
|
|
|
if (atomic_cas(&conns[i].ref, 0, 1)) {
|
2016-03-21 15:12:57 +01:00
|
|
|
conn = &conns[i];
|
|
|
|
break;
|
|
|
|
}
|
2015-09-01 18:06:35 +02:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (!conn) {
|
|
|
|
return NULL;
|
2015-09-01 18:06:35 +02:00
|
|
|
}
|
2016-03-21 15:12:57 +01:00
|
|
|
|
2020-11-19 17:11:09 +01:00
|
|
|
(void)memset(conn, 0, offsetof(struct bt_conn, ref));
|
2020-05-11 15:13:59 -07:00
|
|
|
|
2021-06-22 15:32:51 +02:00
|
|
|
#if defined(CONFIG_BT_CONN)
|
2021-04-20 11:20:29 -07:00
|
|
|
k_work_init_delayable(&conn->deferred_work, deferred_work);
|
2021-06-22 15:32:51 +02:00
|
|
|
#endif /* CONFIG_BT_CONN */
|
2021-11-18 14:26:32 +01:00
|
|
|
#if defined(CONFIG_BT_CONN_TX)
|
2021-11-18 14:13:15 +01:00
|
|
|
k_work_init(&conn->tx_complete_work, tx_complete_work);
|
2021-11-18 14:26:32 +01:00
|
|
|
#endif /* CONFIG_BT_CONN_TX */
|
2021-04-20 11:20:29 -07:00
|
|
|
|
2020-05-11 15:13:59 -07:00
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_conn_reset_rx_state(struct bt_conn *conn)
|
2015-11-25 11:51:25 +01:00
|
|
|
{
|
2020-07-28 11:05:17 +02:00
|
|
|
if (!conn->rx) {
|
2016-03-21 15:12:57 +01:00
|
|
|
return;
|
2015-11-25 15:16:10 +01:00
|
|
|
}
|
2015-11-25 11:51:25 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
net_buf_unref(conn->rx);
|
|
|
|
conn->rx = NULL;
|
2015-11-25 11:51:25 +01:00
|
|
|
}
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2024-07-11 15:04:25 +02:00
|
|
|
static void bt_acl_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags)
|
2016-03-09 15:13:33 +01:00
|
|
|
{
|
2020-09-04 08:10:38 +02:00
|
|
|
uint16_t acl_total_len;
|
2020-05-11 15:13:59 -07:00
|
|
|
|
2024-07-11 15:04:25 +02:00
|
|
|
bt_acl_set_ncp_sent(buf, false);
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
/* Check packet boundary flags */
|
|
|
|
switch (flags) {
|
|
|
|
case BT_ACL_START:
|
2020-07-27 10:38:23 +02:00
|
|
|
if (conn->rx) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Unexpected first L2CAP frame");
|
2020-07-27 10:38:23 +02:00
|
|
|
bt_conn_reset_rx_state(conn);
|
|
|
|
}
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("First, len %u final %u", buf->len,
|
|
|
|
(buf->len < sizeof(uint16_t)) ? 0 : sys_get_le16(buf->data));
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2024-07-11 15:04:25 +02:00
|
|
|
conn->rx = net_buf_ref(buf);
|
2016-03-21 15:12:57 +01:00
|
|
|
break;
|
|
|
|
case BT_ACL_CONT:
|
2020-07-27 10:38:23 +02:00
|
|
|
if (!conn->rx) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Unexpected L2CAP continuation");
|
2016-03-21 15:12:57 +01:00
|
|
|
bt_conn_reset_rx_state(conn);
|
|
|
|
net_buf_unref(buf);
|
|
|
|
return;
|
|
|
|
}
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2020-07-27 10:38:23 +02:00
|
|
|
if (!buf->len) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Empty ACL_CONT");
|
2020-07-27 10:38:23 +02:00
|
|
|
net_buf_unref(buf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (buf->len > net_buf_tailroom(conn->rx)) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Not enough buffer space for L2CAP data");
|
2021-11-08 16:29:51 +01:00
|
|
|
|
|
|
|
/* Frame is not complete but we still pass it to L2CAP
|
|
|
|
* so that it may handle error on protocol level
|
|
|
|
* eg disconnect channel.
|
|
|
|
*/
|
|
|
|
bt_l2cap_recv(conn, conn->rx, false);
|
|
|
|
conn->rx = NULL;
|
2016-03-21 15:12:57 +01:00
|
|
|
net_buf_unref(buf);
|
|
|
|
return;
|
|
|
|
}
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2016-12-25 09:55:58 +02:00
|
|
|
net_buf_add_mem(conn->rx, buf->data, buf->len);
|
2016-03-21 15:12:57 +01:00
|
|
|
break;
|
|
|
|
default:
|
2019-11-19 17:06:12 +01:00
|
|
|
/* BT_ACL_START_NO_FLUSH and BT_ACL_COMPLETE are not allowed on
|
|
|
|
* LE-U from Controller to Host.
|
|
|
|
* Only BT_ACL_POINT_TO_POINT is supported.
|
|
|
|
*/
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Unexpected ACL flags (0x%02x)", flags);
|
2016-03-21 15:12:57 +01:00
|
|
|
bt_conn_reset_rx_state(conn);
|
|
|
|
net_buf_unref(buf);
|
|
|
|
return;
|
2016-03-09 15:13:33 +01:00
|
|
|
}
|
|
|
|
|
2020-07-28 11:05:17 +02:00
|
|
|
if (conn->rx->len < sizeof(uint16_t)) {
|
2021-06-23 17:41:14 +02:00
|
|
|
/* Still not enough data received to retrieve the L2CAP header
|
2020-07-28 11:05:17 +02:00
|
|
|
* length field.
|
|
|
|
*/
|
2024-07-11 15:04:25 +02:00
|
|
|
bt_send_one_host_num_completed_packets(conn->handle);
|
|
|
|
bt_acl_set_ncp_sent(buf, true);
|
|
|
|
net_buf_unref(buf);
|
|
|
|
|
2020-07-28 11:05:17 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2020-09-18 13:38:55 +02:00
|
|
|
acl_total_len = sys_get_le16(conn->rx->data) + sizeof(struct bt_l2cap_hdr);
|
2020-07-28 11:05:17 +02:00
|
|
|
|
|
|
|
if (conn->rx->len < acl_total_len) {
|
|
|
|
/* L2CAP frame not complete. */
|
2024-07-11 15:04:25 +02:00
|
|
|
bt_send_one_host_num_completed_packets(conn->handle);
|
|
|
|
bt_acl_set_ncp_sent(buf, true);
|
|
|
|
net_buf_unref(buf);
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
return;
|
2016-03-09 15:13:33 +01:00
|
|
|
}
|
|
|
|
|
2024-07-11 15:04:25 +02:00
|
|
|
net_buf_unref(buf);
|
|
|
|
|
2020-07-28 11:05:17 +02:00
|
|
|
if (conn->rx->len > acl_total_len) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("ACL len mismatch (%u > %u)", conn->rx->len, acl_total_len);
|
2020-07-28 11:05:17 +02:00
|
|
|
bt_conn_reset_rx_state(conn);
|
|
|
|
return;
|
|
|
|
}
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2020-07-28 11:05:17 +02:00
|
|
|
/* L2CAP frame complete. */
|
|
|
|
buf = conn->rx;
|
|
|
|
conn->rx = NULL;
|
|
|
|
|
2024-07-11 15:04:25 +02:00
|
|
|
__ASSERT(buf->ref == 1, "buf->ref %d", buf->ref);
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Successfully parsed %u byte L2CAP packet", buf->len);
|
2021-11-08 16:29:51 +01:00
|
|
|
bt_l2cap_recv(conn, buf, true);
|
2016-03-09 15:13:33 +01:00
|
|
|
}
|
|
|
|
|
2024-02-01 08:26:21 +01:00
|
|
|
static void wait_for_tx_work(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_BT_CONN_TX)
|
2024-03-12 11:46:48 +01:00
|
|
|
LOG_DBG("conn %p", conn);
|
2024-02-01 08:26:21 +01:00
|
|
|
|
2024-05-09 15:26:11 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_RECV_WORKQ_SYS) ||
|
|
|
|
k_current_get() == k_work_queue_thread_get(&k_sys_work_q)) {
|
2024-03-12 11:46:48 +01:00
|
|
|
tx_notify(conn);
|
|
|
|
} else {
|
|
|
|
struct k_work_sync sync;
|
2024-05-02 22:46:53 +02:00
|
|
|
int err;
|
2024-02-01 08:26:21 +01:00
|
|
|
|
2024-05-02 22:46:53 +02:00
|
|
|
err = k_work_submit(&conn->tx_complete_work);
|
|
|
|
__ASSERT(err >= 0, "couldn't submit (err %d)", err);
|
|
|
|
|
2024-03-12 11:46:48 +01:00
|
|
|
k_work_flush(&conn->tx_complete_work, &sync);
|
|
|
|
}
|
2024-05-02 22:46:53 +02:00
|
|
|
LOG_DBG("done");
|
2024-02-01 08:26:21 +01:00
|
|
|
#else
|
|
|
|
ARG_UNUSED(conn);
|
|
|
|
#endif /* CONFIG_BT_CONN_TX */
|
|
|
|
}
|
|
|
|
|
2021-06-24 15:02:14 +02:00
|
|
|
void bt_conn_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags)
|
|
|
|
{
|
|
|
|
/* Make sure we notify any pending TX callbacks before processing
|
|
|
|
* new data for this connection.
|
2024-02-01 08:26:21 +01:00
|
|
|
*
|
|
|
|
* Always do so from the same context for sanity. In this case that will
|
|
|
|
* be the system workqueue.
|
2021-06-24 15:02:14 +02:00
|
|
|
*/
|
2024-02-01 08:26:21 +01:00
|
|
|
wait_for_tx_work(conn);
|
2021-06-24 15:02:14 +02:00
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("handle %u len %u flags %02x", conn->handle, buf->len, flags);
|
2021-06-24 15:02:14 +02:00
|
|
|
|
2024-02-28 14:51:47 +01:00
|
|
|
if (IS_ENABLED(CONFIG_BT_ISO_RX) && conn->type == BT_CONN_TYPE_ISO) {
|
2021-06-24 15:02:14 +02:00
|
|
|
bt_iso_recv(conn, buf, flags);
|
|
|
|
return;
|
|
|
|
} else if (IS_ENABLED(CONFIG_BT_CONN)) {
|
|
|
|
bt_acl_recv(conn, buf, flags);
|
|
|
|
} else {
|
|
|
|
__ASSERT(false, "Invalid connection type %u", conn->type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
static bool dont_have_tx_context(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
return k_fifo_is_empty(&free_tx);
|
|
|
|
}
|
|
|
|
|
2019-11-23 00:08:46 +02:00
|
|
|
static struct bt_conn_tx *conn_tx_alloc(void)
|
2016-03-09 15:13:33 +01:00
|
|
|
{
|
2023-07-14 16:29:13 +02:00
|
|
|
struct bt_conn_tx *ret = k_fifo_get(&free_tx, K_NO_WAIT);
|
2019-11-23 12:56:44 +02:00
|
|
|
|
2023-07-14 16:29:13 +02:00
|
|
|
LOG_DBG("%p", ret);
|
2017-03-17 08:02:57 +02:00
|
|
|
|
2023-07-14 16:29:13 +02:00
|
|
|
return ret;
|
2019-08-01 18:02:14 +03:00
|
|
|
}
|
|
|
|
|
2020-05-11 15:13:59 -07:00
|
|
|
enum {
|
|
|
|
FRAG_START,
|
|
|
|
FRAG_CONT,
|
|
|
|
FRAG_SINGLE,
|
|
|
|
FRAG_END
|
|
|
|
};
|
|
|
|
|
|
|
|
static int send_acl(struct bt_conn *conn, struct net_buf *buf, uint8_t flags)
|
|
|
|
{
|
|
|
|
struct bt_hci_acl_hdr *hdr;
|
|
|
|
|
|
|
|
switch (flags) {
|
|
|
|
case FRAG_START:
|
|
|
|
case FRAG_SINGLE:
|
|
|
|
flags = BT_ACL_START_NO_FLUSH;
|
|
|
|
break;
|
|
|
|
case FRAG_CONT:
|
|
|
|
case FRAG_END:
|
|
|
|
flags = BT_ACL_CONT;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
hdr = net_buf_push(buf, sizeof(*hdr));
|
|
|
|
hdr->handle = sys_cpu_to_le16(bt_acl_handle_pack(conn->handle, flags));
|
|
|
|
hdr->len = sys_cpu_to_le16(buf->len - sizeof(*hdr));
|
|
|
|
|
|
|
|
bt_buf_set_type(buf, BT_BUF_ACL_OUT);
|
|
|
|
|
|
|
|
return bt_send(buf);
|
|
|
|
}
|
|
|
|
|
2024-08-05 11:38:34 +02:00
|
|
|
static enum bt_iso_timestamp contains_iso_timestamp(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
enum bt_iso_timestamp ts;
|
|
|
|
|
|
|
|
if (net_buf_headroom(buf) ==
|
|
|
|
(BT_BUF_ISO_SIZE(0) - sizeof(struct bt_hci_iso_sdu_ts_hdr))) {
|
|
|
|
ts = BT_ISO_TS_PRESENT;
|
|
|
|
} else {
|
|
|
|
ts = BT_ISO_TS_ABSENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ts;
|
|
|
|
}
|
|
|
|
|
2020-05-11 15:13:59 -07:00
|
|
|
static int send_iso(struct bt_conn *conn, struct net_buf *buf, uint8_t flags)
|
|
|
|
{
|
|
|
|
struct bt_hci_iso_hdr *hdr;
|
2023-07-21 10:22:32 +02:00
|
|
|
enum bt_iso_timestamp ts;
|
2020-05-11 15:13:59 -07:00
|
|
|
|
|
|
|
switch (flags) {
|
|
|
|
case FRAG_START:
|
|
|
|
flags = BT_ISO_START;
|
|
|
|
break;
|
|
|
|
case FRAG_CONT:
|
|
|
|
flags = BT_ISO_CONT;
|
|
|
|
break;
|
|
|
|
case FRAG_SINGLE:
|
|
|
|
flags = BT_ISO_SINGLE;
|
|
|
|
break;
|
|
|
|
case FRAG_END:
|
|
|
|
flags = BT_ISO_END;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* The TS bit is set by `iso.c:conn_iso_send`. This special byte
|
|
|
|
* prepends the whole SDU, and won't be there for individual fragments.
|
|
|
|
*
|
|
|
|
* Conveniently, it is only legal to set the TS bit on the first HCI
|
|
|
|
* fragment, so we don't have to pass this extra metadata around for
|
|
|
|
* every fragment, only the first one.
|
|
|
|
*/
|
|
|
|
if (flags == BT_ISO_SINGLE || flags == BT_ISO_START) {
|
2024-08-05 11:38:34 +02:00
|
|
|
ts = contains_iso_timestamp(buf);
|
2023-07-21 10:22:32 +02:00
|
|
|
} else {
|
|
|
|
ts = BT_ISO_TS_ABSENT;
|
|
|
|
}
|
2023-04-24 11:05:06 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
hdr = net_buf_push(buf, sizeof(*hdr));
|
2023-04-24 11:05:06 +02:00
|
|
|
hdr->handle = sys_cpu_to_le16(bt_iso_handle_pack(conn->handle, flags, ts));
|
2020-05-11 15:13:59 -07:00
|
|
|
hdr->len = sys_cpu_to_le16(buf->len - sizeof(*hdr));
|
|
|
|
|
|
|
|
bt_buf_set_type(buf, BT_BUF_ISO_OUT);
|
|
|
|
|
|
|
|
return bt_send(buf);
|
|
|
|
}
|
|
|
|
|
2022-11-21 13:06:07 +01:00
|
|
|
static inline uint16_t conn_mtu(struct bt_conn *conn)
|
|
|
|
{
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
2022-12-16 18:40:15 +01:00
|
|
|
if (conn->type == BT_CONN_TYPE_BR ||
|
|
|
|
(conn->type != BT_CONN_TYPE_ISO && !bt_dev.le.acl_mtu)) {
|
2022-11-21 13:06:07 +01:00
|
|
|
return bt_dev.br.mtu;
|
|
|
|
}
|
2024-03-01 18:45:44 +08:00
|
|
|
#endif /* CONFIG_BT_CLASSIC */
|
2022-11-21 13:06:07 +01:00
|
|
|
#if defined(CONFIG_BT_ISO)
|
2022-12-16 18:37:15 +01:00
|
|
|
if (conn->type == BT_CONN_TYPE_ISO) {
|
2022-11-21 13:06:07 +01:00
|
|
|
return bt_dev.le.iso_mtu;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_ISO */
|
|
|
|
#if defined(CONFIG_BT_CONN)
|
|
|
|
return bt_dev.le.acl_mtu;
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif /* CONFIG_BT_CONN */
|
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
static bool is_classic_conn(struct bt_conn *conn)
|
2016-01-29 16:12:55 +01:00
|
|
|
{
|
2023-07-21 10:22:32 +02:00
|
|
|
return (IS_ENABLED(CONFIG_BT_CLASSIC) &&
|
|
|
|
conn->type == BT_CONN_TYPE_BR);
|
|
|
|
}
|
2016-01-29 16:12:55 +01:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
static bool is_iso_tx_conn(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
return IS_ENABLED(CONFIG_BT_ISO_TX) &&
|
|
|
|
conn->type == BT_CONN_TYPE_ISO;
|
|
|
|
}
|
2019-11-23 00:08:46 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
static bool is_le_conn(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
return IS_ENABLED(CONFIG_BT_CONN) && conn->type == BT_CONN_TYPE_LE;
|
2016-01-29 16:12:55 +01:00
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
static bool is_acl_conn(struct bt_conn *conn)
|
2023-07-18 10:39:44 +02:00
|
|
|
{
|
2023-07-21 10:22:32 +02:00
|
|
|
return is_le_conn(conn) || is_classic_conn(conn);
|
2023-07-18 10:39:44 +02:00
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
static int send_buf(struct bt_conn *conn, struct net_buf *buf,
|
2024-05-21 17:13:31 +02:00
|
|
|
size_t len, void *cb, void *ud)
|
2016-01-29 16:12:55 +01:00
|
|
|
{
|
2023-07-21 10:22:32 +02:00
|
|
|
struct net_buf *frag = NULL;
|
2023-07-14 16:29:13 +02:00
|
|
|
struct bt_conn_tx *tx = NULL;
|
2023-07-21 10:22:32 +02:00
|
|
|
uint8_t flags;
|
|
|
|
int err;
|
2023-07-14 16:29:13 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
if (buf->len == 0) {
|
|
|
|
__ASSERT_NO_MSG(0);
|
2023-07-18 10:39:44 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
return -EMSGSIZE;
|
2016-01-29 16:12:55 +01:00
|
|
|
}
|
2022-11-21 13:06:07 +01:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
if (bt_buf_has_view(buf)) {
|
|
|
|
__ASSERT_NO_MSG(0);
|
|
|
|
|
|
|
|
return -EIO;
|
2024-02-08 14:35:13 +01:00
|
|
|
}
|
|
|
|
|
2024-07-30 17:10:03 +02:00
|
|
|
LOG_DBG("conn %p buf %p len %u buf->len %u cb %p ud %p",
|
|
|
|
conn, buf, len, buf->len, cb, ud);
|
2023-07-18 10:39:44 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* Acquire the right to send 1 packet to the controller */
|
|
|
|
if (k_sem_take(bt_conn_get_pkts(conn), K_NO_WAIT)) {
|
|
|
|
/* This shouldn't happen now that we acquire the resources
|
|
|
|
* before calling `send_buf` (in `get_conn_ready`). We say
|
|
|
|
* "acquire" as `tx_processor()` is not re-entrant and the
|
|
|
|
* thread is non-preemptible. So the sem value shouldn't change.
|
|
|
|
*/
|
|
|
|
__ASSERT(0, "No controller bufs");
|
2023-07-18 10:39:44 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2023-07-18 10:39:44 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* Allocate and set the TX context */
|
|
|
|
tx = conn_tx_alloc();
|
2023-07-18 10:39:44 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* See big comment above */
|
|
|
|
if (!tx) {
|
|
|
|
__ASSERT(0, "No TX context");
|
2023-07-18 10:39:44 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2022-11-21 13:06:07 +01:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
tx->cb = cb;
|
|
|
|
tx->user_data = ud;
|
2023-07-14 16:29:13 +02:00
|
|
|
|
2024-05-21 17:13:31 +02:00
|
|
|
uint16_t frag_len = MIN(conn_mtu(conn), len);
|
2023-07-14 16:29:13 +02:00
|
|
|
|
2024-05-21 17:13:31 +02:00
|
|
|
__ASSERT_NO_MSG(buf->ref == 1);
|
2023-07-21 10:22:32 +02:00
|
|
|
|
2024-05-21 17:13:31 +02:00
|
|
|
if (buf->len > frag_len) {
|
|
|
|
LOG_DBG("keep %p around", buf);
|
|
|
|
frag = get_data_frag(net_buf_ref(buf), frag_len);
|
|
|
|
} else {
|
|
|
|
LOG_DBG("move %p ref in", buf);
|
|
|
|
/* Move the ref into `frag` for the last TX. That way `buf` will
|
|
|
|
* get destroyed when `frag` is destroyed.
|
2022-11-21 13:06:07 +01:00
|
|
|
*/
|
2023-07-21 10:22:32 +02:00
|
|
|
frag = get_data_frag(buf, frag_len);
|
2024-05-21 17:13:31 +02:00
|
|
|
}
|
2016-02-01 12:41:04 +01:00
|
|
|
|
2024-06-07 11:18:19 +02:00
|
|
|
/* Caller is supposed to check we have all resources to send */
|
|
|
|
__ASSERT_NO_MSG(frag != NULL);
|
|
|
|
|
2024-05-21 17:13:31 +02:00
|
|
|
/* If the current buffer doesn't fit a controller buffer */
|
|
|
|
if (len > conn_mtu(conn)) {
|
2023-07-21 10:22:32 +02:00
|
|
|
flags = conn->next_is_frag ? FRAG_CONT : FRAG_START;
|
|
|
|
conn->next_is_frag = true;
|
|
|
|
} else {
|
|
|
|
flags = conn->next_is_frag ? FRAG_END : FRAG_SINGLE;
|
|
|
|
conn->next_is_frag = false;
|
2016-02-01 12:41:04 +01:00
|
|
|
}
|
|
|
|
|
2024-05-21 17:13:31 +02:00
|
|
|
LOG_DBG("send frag: buf %p len %d", buf, frag_len);
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* At this point, the buffer is either a fragment or a full HCI packet.
|
|
|
|
* The flags are also valid.
|
|
|
|
*/
|
|
|
|
LOG_DBG("conn %p buf %p len %u flags 0x%02x",
|
2024-05-21 17:13:31 +02:00
|
|
|
conn, frag, frag->len, flags);
|
2016-02-01 12:41:04 +01:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* Keep track of sent buffers. We have to append _before_
|
|
|
|
* sending, as we might get pre-empted if the HCI driver calls
|
|
|
|
* k_yield() before returning.
|
|
|
|
*
|
|
|
|
* In that case, the controller could also send a num-complete-packets
|
|
|
|
* event and our handler will be confused that there is no corresponding
|
|
|
|
* callback node in the `tx_pending` list.
|
|
|
|
*/
|
|
|
|
atomic_inc(&conn->in_ll);
|
|
|
|
sys_slist_append(&conn->tx_pending, &tx->node);
|
2016-02-01 12:41:04 +01:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
if (is_iso_tx_conn(conn)) {
|
2024-05-21 17:13:31 +02:00
|
|
|
err = send_iso(conn, frag, flags);
|
2023-07-21 10:22:32 +02:00
|
|
|
} else if (is_acl_conn(conn)) {
|
2024-05-21 17:13:31 +02:00
|
|
|
err = send_acl(conn, frag, flags);
|
2023-07-21 10:22:32 +02:00
|
|
|
} else {
|
|
|
|
err = -EINVAL; /* Some animals disable asserts (╯°□°)╯︵ ┻━┻ */
|
|
|
|
__ASSERT(false, "Invalid connection type %u", conn->type);
|
2023-07-18 10:39:44 +02:00
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
if (!err) {
|
|
|
|
return 0;
|
2016-02-01 12:41:04 +01:00
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* Remove buf from pending list */
|
|
|
|
atomic_dec(&conn->in_ll);
|
|
|
|
(void)sys_slist_find_and_remove(&conn->tx_pending, &tx->node);
|
2022-11-15 12:04:30 +01:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
LOG_ERR("Unable to send to driver (err %d)", err);
|
2022-11-15 12:04:30 +01:00
|
|
|
|
2024-05-21 17:13:31 +02:00
|
|
|
/* If we get here, something has seriously gone wrong: the `parent` buf
|
|
|
|
* (of which the current fragment belongs) should also be destroyed.
|
2023-07-21 10:22:32 +02:00
|
|
|
*/
|
2024-05-21 17:13:31 +02:00
|
|
|
net_buf_unref(frag);
|
2016-03-21 15:12:57 +01:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* `buf` might not get destroyed right away, and its `tx`
|
|
|
|
* pointer will still be reachable. Make sure that we don't try
|
|
|
|
* to use the destroyed context later.
|
|
|
|
*/
|
|
|
|
conn_tx_destroy(conn, tx);
|
|
|
|
k_sem_give(bt_conn_get_pkts(conn));
|
2023-07-18 10:39:44 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* Merge HCI driver errors */
|
|
|
|
return -EIO;
|
2016-02-01 12:41:04 +01:00
|
|
|
}
|
2016-02-24 14:58:03 +01:00
|
|
|
|
2017-08-21 10:49:29 +03:00
|
|
|
static struct k_poll_signal conn_change =
|
|
|
|
K_POLL_SIGNAL_INITIALIZER(conn_change);
|
2017-02-02 08:24:28 +02:00
|
|
|
|
2022-11-02 16:58:34 +00:00
|
|
|
static void conn_destroy(struct bt_conn *conn, void *data)
|
|
|
|
{
|
2023-02-09 10:30:13 +00:00
|
|
|
if (conn->state == BT_CONN_CONNECTED ||
|
|
|
|
conn->state == BT_CONN_DISCONNECTING) {
|
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECT_COMPLETE);
|
|
|
|
}
|
2022-11-02 16:58:34 +00:00
|
|
|
|
2024-05-14 14:54:04 +02:00
|
|
|
if (conn->state != BT_CONN_DISCONNECTED) {
|
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
|
|
|
}
|
2022-11-02 16:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_conn_cleanup_all(void)
|
|
|
|
{
|
|
|
|
bt_conn_foreach(BT_CONN_TYPE_ALL, conn_destroy, NULL);
|
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
#if defined(CONFIG_BT_CONN)
|
|
|
|
/* Returns true if L2CAP has data to send on this conn */
|
|
|
|
static bool acl_has_data(struct bt_conn *conn)
|
2020-05-11 15:13:59 -07:00
|
|
|
{
|
2023-07-21 10:22:32 +02:00
|
|
|
return sys_slist_peek_head(&conn->l2cap_data_ready) != NULL;
|
|
|
|
}
|
|
|
|
#endif /* defined(CONFIG_BT_CONN) */
|
|
|
|
|
|
|
|
/* Connection "Scheduler" of sorts:
|
|
|
|
*
|
|
|
|
* Will try to get the optimal number of queued buffers for the connection.
|
|
|
|
*
|
|
|
|
* Partitions the controller's buffers to each connection according to some
|
|
|
|
* heuristic. This is made to be tunable, fairness, simplicity, throughput etc.
|
|
|
|
*
|
|
|
|
* In the future, this will be a hook exposed to the application.
|
|
|
|
*/
|
|
|
|
static bool should_stop_tx(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
LOG_DBG("%p", conn);
|
|
|
|
|
2024-06-28 09:15:35 +02:00
|
|
|
if (conn->state != BT_CONN_CONNECTED) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* TODO: This function should be overridable by the application: they
|
|
|
|
* should be able to provide their own heuristic.
|
|
|
|
*/
|
|
|
|
if (!conn->has_data(conn)) {
|
|
|
|
LOG_DBG("No more data for %p", conn);
|
|
|
|
return true;
|
2020-05-11 15:13:59 -07:00
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* Queue only 3 buffers per-conn for now */
|
|
|
|
if (atomic_get(&conn->in_ll) < 3) {
|
|
|
|
/* The goal of this heuristic is to allow the link-layer to
|
|
|
|
* extend an ACL connection event as long as the application
|
|
|
|
* layer can provide data.
|
|
|
|
*
|
|
|
|
* Here we chose three buffers, as some LLs need two enqueued
|
|
|
|
* packets to be able to set the more-data bit, and one more
|
|
|
|
* buffer to allow refilling by the app while one of them is
|
|
|
|
* being sent over-the-air.
|
|
|
|
*/
|
|
|
|
return false;
|
2020-05-11 15:13:59 -07:00
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_conn_data_ready(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
LOG_DBG("DR");
|
|
|
|
|
|
|
|
/* The TX processor will call the `pull_cb` to get the buf */
|
|
|
|
if (!atomic_set(&conn->_conn_ready_lock, 1)) {
|
2024-06-28 09:15:35 +02:00
|
|
|
/* Attach a reference to the `bt_dev.le.conn_ready` list.
|
|
|
|
*
|
|
|
|
* This reference will be consumed when the conn is popped off
|
|
|
|
* the list (in `get_conn_ready`).
|
|
|
|
*/
|
|
|
|
bt_conn_ref(conn);
|
2023-07-21 10:22:32 +02:00
|
|
|
sys_slist_append(&bt_dev.le.conn_ready,
|
|
|
|
&conn->_conn_ready);
|
|
|
|
LOG_DBG("raised");
|
|
|
|
} else {
|
|
|
|
LOG_DBG("already in list");
|
2020-05-11 15:13:59 -07:00
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* Kick the TX processor */
|
|
|
|
bt_tx_irq_raise();
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool cannot_send_to_controller(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
return k_sem_count_get(bt_conn_get_pkts(conn)) == 0;
|
|
|
|
}
|
2020-05-11 15:13:59 -07:00
|
|
|
|
2024-06-07 11:18:19 +02:00
|
|
|
static bool dont_have_viewbufs(void)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_BT_CONN_TX)
|
|
|
|
/* The LIFO only tracks buffers that have been destroyed at least once,
|
|
|
|
* hence the uninit check beforehand.
|
|
|
|
*/
|
|
|
|
if (fragments.uninit_count > 0) {
|
|
|
|
/* If there are uninitialized bufs, we are guaranteed allocation. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* In practice k_fifo == k_lifo ABI. */
|
|
|
|
return k_fifo_is_empty(&fragments.free);
|
|
|
|
|
|
|
|
#else /* !CONFIG_BT_CONN_TX */
|
|
|
|
return false;
|
|
|
|
#endif /* CONFIG_BT_CONN_TX */
|
|
|
|
}
|
|
|
|
|
2024-07-30 17:32:36 +02:00
|
|
|
__maybe_unused static bool dont_have_methods(struct bt_conn *conn)
|
2023-07-21 10:22:32 +02:00
|
|
|
{
|
|
|
|
return (conn->tx_data_pull == NULL) ||
|
|
|
|
(conn->get_and_clear_cb == NULL) ||
|
|
|
|
(conn->has_data == NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_conn *get_conn_ready(void)
|
|
|
|
{
|
|
|
|
/* Here we only peek: we pop the conn (and insert it at the back if it
|
|
|
|
* still has data) after the QoS function returns false.
|
2022-12-18 16:00:44 +05:30
|
|
|
*/
|
2023-07-21 10:22:32 +02:00
|
|
|
sys_snode_t *node = sys_slist_peek_head(&bt_dev.le.conn_ready);
|
2022-12-18 16:00:44 +05:30
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
if (node == NULL) {
|
|
|
|
return NULL;
|
2022-12-18 16:00:44 +05:30
|
|
|
}
|
|
|
|
|
2024-06-28 09:15:35 +02:00
|
|
|
/* `conn` borrows from the list node. That node is _not_ popped yet.
|
|
|
|
*
|
|
|
|
* If we end up not popping that conn off the list, we have to make sure
|
|
|
|
* to increase the refcount before returning a pointer to that
|
|
|
|
* connection out of this function.
|
|
|
|
*/
|
2023-07-21 10:22:32 +02:00
|
|
|
struct bt_conn *conn = CONTAINER_OF(node, struct bt_conn, _conn_ready);
|
2022-11-15 12:05:50 +01:00
|
|
|
|
2024-06-07 11:18:19 +02:00
|
|
|
if (dont_have_viewbufs()) {
|
|
|
|
/* We will get scheduled again when the (view) buffers are freed. If you
|
|
|
|
* hit this a lot, try increasing `CONFIG_BT_CONN_FRAG_COUNT`
|
|
|
|
*/
|
|
|
|
LOG_DBG("no view bufs");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
if (cannot_send_to_controller(conn)) {
|
|
|
|
/* We will get scheduled again when the buffers are freed. */
|
|
|
|
LOG_DBG("no LL bufs for %p", conn);
|
|
|
|
return NULL;
|
2022-11-15 12:05:50 +01:00
|
|
|
}
|
2020-05-11 15:13:59 -07:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
if (dont_have_tx_context(conn)) {
|
|
|
|
/* We will get scheduled again when TX contexts are available. */
|
|
|
|
LOG_DBG("no TX contexts");
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-05-11 15:13:59 -07:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
CHECKIF(dont_have_methods(conn)) {
|
|
|
|
LOG_DBG("conn %p (type %d) is missing mandatory methods",
|
|
|
|
conn, conn->type);
|
2017-02-02 08:24:28 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2017-02-02 08:24:28 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
if (should_stop_tx(conn)) {
|
2024-06-28 09:15:35 +02:00
|
|
|
/* Move reference off the list and into the `conn` variable. */
|
2024-05-27 17:34:03 +02:00
|
|
|
__maybe_unused sys_snode_t *s = sys_slist_get(&bt_dev.le.conn_ready);
|
2022-07-11 14:34:13 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
__ASSERT_NO_MSG(s == node);
|
2024-05-27 17:34:03 +02:00
|
|
|
(void)atomic_set(&conn->_conn_ready_lock, 0);
|
2023-07-21 10:22:32 +02:00
|
|
|
|
|
|
|
/* Append connection to list if it still has data */
|
|
|
|
if (conn->has_data(conn)) {
|
|
|
|
LOG_DBG("appending %p to back of TX queue", conn);
|
|
|
|
bt_conn_data_ready(conn);
|
2017-02-02 08:24:28 +02:00
|
|
|
}
|
2024-06-28 09:15:35 +02:00
|
|
|
|
|
|
|
return conn;
|
2020-05-11 15:13:59 -07:00
|
|
|
}
|
2016-02-24 14:58:03 +01:00
|
|
|
|
2024-06-28 09:15:35 +02:00
|
|
|
return bt_conn_ref(conn);
|
2023-07-21 10:22:32 +02:00
|
|
|
}
|
2017-02-10 08:49:19 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* Crazy that this file is compiled even if this is not true, but here we are. */
|
|
|
|
#if defined(CONFIG_BT_CONN)
|
|
|
|
static void acl_get_and_clear_cb(struct bt_conn *conn, struct net_buf *buf,
|
|
|
|
bt_conn_tx_cb_t *cb, void **ud)
|
|
|
|
{
|
|
|
|
__ASSERT_NO_MSG(is_acl_conn(conn));
|
|
|
|
|
|
|
|
*cb = closure_cb(buf->user_data);
|
|
|
|
*ud = closure_data(buf->user_data);
|
|
|
|
memset(buf->user_data, 0, buf->user_data_size);
|
|
|
|
}
|
|
|
|
#endif /* defined(CONFIG_BT_CONN) */
|
|
|
|
|
|
|
|
/* Acts as a "null-routed" bt_send(). This fn will decrease the refcount of
|
|
|
|
* `buf` and call the user callback with an error code.
|
|
|
|
*/
|
|
|
|
static void destroy_and_callback(struct bt_conn *conn,
|
|
|
|
struct net_buf *buf,
|
|
|
|
bt_conn_tx_cb_t cb,
|
|
|
|
void *ud)
|
|
|
|
{
|
|
|
|
if (!cb) {
|
|
|
|
conn->get_and_clear_cb(conn, buf, &cb, &ud);
|
2017-02-02 08:24:28 +02:00
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
LOG_DBG("pop: cb %p userdata %p", cb, ud);
|
|
|
|
|
|
|
|
/* bt_send() would've done an unref. Do it here also, so the buffer is
|
|
|
|
* hopefully destroyed and the user callback can allocate a new one.
|
|
|
|
*/
|
|
|
|
net_buf_unref(buf);
|
|
|
|
|
|
|
|
if (cb) {
|
|
|
|
cb(conn, ud, -ESHUTDOWN);
|
|
|
|
}
|
2017-02-02 08:24:28 +02:00
|
|
|
}
|
|
|
|
|
2023-08-01 13:25:13 +02:00
|
|
|
static volatile bool _suspend_tx;
|
|
|
|
|
|
|
|
#if defined(CONFIG_BT_TESTING)
|
|
|
|
void bt_conn_suspend_tx(bool suspend)
|
|
|
|
{
|
|
|
|
_suspend_tx = suspend;
|
|
|
|
|
|
|
|
LOG_DBG("%sing all data TX", suspend ? "suspend" : "resum");
|
|
|
|
|
|
|
|
bt_tx_irq_raise();
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_TESTING */
|
|
|
|
|
|
|
|
void bt_conn_tx_processor(void)
|
2017-02-02 08:24:28 +02:00
|
|
|
{
|
2023-07-21 10:22:32 +02:00
|
|
|
LOG_DBG("start");
|
|
|
|
struct bt_conn *conn;
|
2017-02-02 08:24:28 +02:00
|
|
|
struct net_buf *buf;
|
2023-07-21 10:22:32 +02:00
|
|
|
bt_conn_tx_cb_t cb = NULL;
|
2024-05-21 17:13:31 +02:00
|
|
|
size_t buf_len;
|
2023-07-21 10:22:32 +02:00
|
|
|
void *ud = NULL;
|
2017-02-02 08:24:28 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
if (!IS_ENABLED(CONFIG_BT_CONN_TX)) {
|
|
|
|
/* Mom, can we have a real compiler? */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-01 13:25:13 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_TESTING) && _suspend_tx) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
conn = get_conn_ready();
|
2017-02-02 08:24:28 +02:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
if (!conn) {
|
|
|
|
LOG_DBG("no connection wants to do stuff");
|
2017-02-02 08:24:28 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
LOG_DBG("processing conn %p", conn);
|
2022-11-15 12:04:30 +01:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
if (conn->state != BT_CONN_CONNECTED) {
|
2024-06-28 09:15:35 +02:00
|
|
|
LOG_WRN("conn %p: not connected", conn);
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* Call the user callbacks & destroy (final-unref) the buffers
|
|
|
|
* we were supposed to send.
|
|
|
|
*/
|
2024-05-21 17:13:31 +02:00
|
|
|
buf = conn->tx_data_pull(conn, SIZE_MAX, &buf_len);
|
2023-07-21 10:22:32 +02:00
|
|
|
while (buf) {
|
|
|
|
destroy_and_callback(conn, buf, cb, ud);
|
2024-05-21 17:13:31 +02:00
|
|
|
buf = conn->tx_data_pull(conn, SIZE_MAX, &buf_len);
|
2023-07-21 10:22:32 +02:00
|
|
|
}
|
2024-06-28 09:15:35 +02:00
|
|
|
|
|
|
|
goto exit;
|
2023-07-21 10:22:32 +02:00
|
|
|
}
|
2022-11-15 12:04:30 +01:00
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
/* now that we are guaranteed resources, we can pull data from the upper
|
|
|
|
* layer (L2CAP or ISO).
|
2024-02-08 14:37:39 +01:00
|
|
|
*/
|
2024-05-21 17:13:31 +02:00
|
|
|
buf = conn->tx_data_pull(conn, conn_mtu(conn), &buf_len);
|
2023-07-21 10:22:32 +02:00
|
|
|
if (!buf) {
|
|
|
|
/* Either there is no more data, or the buffer is already in-use
|
|
|
|
* by a view on it. In both cases, the TX processor will be
|
|
|
|
* triggered again, either by the view's destroy callback, or by
|
|
|
|
* the upper layer when it has more data.
|
|
|
|
*/
|
|
|
|
LOG_DBG("no buf returned");
|
2024-06-28 09:15:35 +02:00
|
|
|
|
|
|
|
goto exit;
|
2023-07-21 10:22:32 +02:00
|
|
|
}
|
2022-07-28 08:52:09 +02:00
|
|
|
|
2024-05-21 17:13:31 +02:00
|
|
|
bool last_buf = conn_mtu(conn) >= buf_len;
|
2023-07-21 10:22:32 +02:00
|
|
|
|
|
|
|
if (last_buf) {
|
|
|
|
/* Only pull the callback info from the last buffer.
|
|
|
|
* We still allocate one TX context per-fragment though.
|
|
|
|
*/
|
|
|
|
conn->get_and_clear_cb(conn, buf, &cb, &ud);
|
|
|
|
LOG_DBG("pop: cb %p userdata %p", cb, ud);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_DBG("TX process: conn %p buf %p (%s)",
|
|
|
|
conn, buf, last_buf ? "last" : "frag");
|
|
|
|
|
2024-05-21 17:13:31 +02:00
|
|
|
int err = send_buf(conn, buf, buf_len, cb, ud);
|
2023-07-21 10:22:32 +02:00
|
|
|
|
|
|
|
if (err) {
|
|
|
|
/* -EIO means `unrecoverable error`. It can be an assertion that
|
|
|
|
* failed or an error from the HCI driver.
|
|
|
|
*
|
|
|
|
* -ENOMEM means we thought we had all the resources to send the
|
|
|
|
* buf (ie. TX context + controller buffer) but one of them was
|
|
|
|
* not available. This is likely due to a failure of
|
|
|
|
* assumption, likely that we have been pre-empted somehow and
|
|
|
|
* that `tx_processor()` has been re-entered.
|
|
|
|
*
|
|
|
|
* In both cases, we destroy the buffer and mark the connection
|
|
|
|
* as dead.
|
|
|
|
*/
|
|
|
|
LOG_ERR("Fatal error (%d). Disconnecting %p", err, conn);
|
|
|
|
destroy_and_callback(conn, buf, cb, ud);
|
|
|
|
bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
|
|
|
|
2024-06-28 09:15:35 +02:00
|
|
|
goto exit;
|
2016-03-21 15:12:57 +01:00
|
|
|
}
|
2023-07-21 10:22:32 +02:00
|
|
|
|
|
|
|
/* Always kick the TX work. It will self-suspend if it doesn't get
|
|
|
|
* resources or there is nothing left to send.
|
|
|
|
*/
|
2023-08-01 13:25:13 +02:00
|
|
|
bt_tx_irq_raise();
|
2024-06-28 09:15:35 +02:00
|
|
|
|
|
|
|
exit:
|
|
|
|
/* Give back the ref that `get_conn_ready()` gave us */
|
|
|
|
bt_conn_unref(conn);
|
2017-02-02 08:24:28 +02:00
|
|
|
}
|
|
|
|
|
2017-03-17 08:02:57 +02:00
|
|
|
static void process_unack_tx(struct bt_conn *conn)
|
|
|
|
{
|
2023-07-21 10:22:32 +02:00
|
|
|
LOG_DBG("%p", conn);
|
|
|
|
|
2017-03-17 08:02:57 +02:00
|
|
|
/* Return any unacknowledged packets */
|
|
|
|
while (1) {
|
2019-11-23 00:08:46 +02:00
|
|
|
struct bt_conn_tx *tx;
|
2017-03-17 08:02:57 +02:00
|
|
|
sys_snode_t *node;
|
2019-11-23 00:08:46 +02:00
|
|
|
|
2017-03-17 08:02:57 +02:00
|
|
|
node = sys_slist_get(&conn->tx_pending);
|
|
|
|
|
|
|
|
if (!node) {
|
2024-08-14 09:40:50 +02:00
|
|
|
bt_tx_irq_raise();
|
2023-07-21 10:22:32 +02:00
|
|
|
return;
|
2017-03-17 08:02:57 +02:00
|
|
|
}
|
|
|
|
|
2019-11-23 00:08:46 +02:00
|
|
|
tx = CONTAINER_OF(node, struct bt_conn_tx, node);
|
|
|
|
|
2022-05-31 13:42:22 +02:00
|
|
|
conn_tx_destroy(conn, tx);
|
2017-03-17 08:02:57 +02:00
|
|
|
k_sem_give(bt_conn_get_pkts(conn));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-11 15:13:59 -07:00
|
|
|
struct bt_conn *conn_lookup_handle(struct bt_conn *conns, size_t size,
|
|
|
|
uint16_t handle)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < size; i++) {
|
2020-11-19 17:11:09 +01:00
|
|
|
struct bt_conn *conn = bt_conn_ref(&conns[i]);
|
|
|
|
|
|
|
|
if (!conn) {
|
2020-05-11 15:13:59 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We only care about connections with a valid handle */
|
2020-11-19 17:11:09 +01:00
|
|
|
if (!bt_conn_is_handle_valid(conn)) {
|
|
|
|
bt_conn_unref(conn);
|
2020-05-11 15:13:59 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-11-19 17:11:09 +01:00
|
|
|
if (conn->handle != handle) {
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
continue;
|
2020-05-11 15:13:59 -07:00
|
|
|
}
|
2020-11-19 17:11:09 +01:00
|
|
|
|
|
|
|
return conn;
|
2020-05-11 15:13:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-06-19 18:56:13 +02:00
|
|
|
void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state)
|
2015-04-28 10:39:50 +03:00
|
|
|
{
|
2015-06-23 14:38:24 +02:00
|
|
|
bt_conn_state_t old_state;
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("%s -> %s", state2str(conn->state), state2str(state));
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2015-06-19 18:56:13 +02:00
|
|
|
if (conn->state == state) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("no transition %s", state2str(state));
|
2015-04-28 10:39:50 +03:00
|
|
|
return;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2015-06-23 14:38:24 +02:00
|
|
|
old_state = conn->state;
|
2015-06-19 18:56:13 +02:00
|
|
|
conn->state = state;
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2015-07-22 13:03:51 +03:00
|
|
|
/* Actions needed for exiting the old state */
|
|
|
|
switch (old_state) {
|
|
|
|
case BT_CONN_DISCONNECTED:
|
|
|
|
/* Take a reference for the first state transition after
|
2015-11-25 10:48:33 +01:00
|
|
|
* bt_conn_add_le() and keep it until reaching DISCONNECTED
|
2015-07-22 13:03:51 +03:00
|
|
|
* again.
|
|
|
|
*/
|
2021-03-18 15:00:40 -07:00
|
|
|
if (conn->type != BT_CONN_TYPE_ISO) {
|
|
|
|
bt_conn_ref(conn);
|
|
|
|
}
|
2015-07-22 13:03:51 +03:00
|
|
|
break;
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_INITIATING:
|
2017-08-09 09:21:11 +03:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
|
2017-01-31 09:41:35 +02:00
|
|
|
conn->type == BT_CONN_TYPE_LE) {
|
2021-04-14 18:57:40 +02:00
|
|
|
k_work_cancel_delayable(&conn->deferred_work);
|
2015-07-22 13:03:51 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2015-07-08 10:55:51 +03:00
|
|
|
}
|
|
|
|
|
2015-07-22 13:03:51 +03:00
|
|
|
/* Actions needed for entering the new state */
|
2016-03-21 14:48:40 +01:00
|
|
|
switch (conn->state) {
|
2015-06-19 18:56:13 +02:00
|
|
|
case BT_CONN_CONNECTED:
|
2017-02-15 15:08:25 +05:30
|
|
|
if (conn->type == BT_CONN_TYPE_SCO) {
|
2024-02-27 15:27:59 +08:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CLASSIC)) {
|
|
|
|
bt_sco_connected(conn);
|
|
|
|
}
|
2017-02-15 15:08:25 +05:30
|
|
|
break;
|
|
|
|
}
|
2018-11-02 12:35:30 -07:00
|
|
|
k_poll_signal_raise(&conn_change, 0);
|
2015-08-23 20:47:29 +02:00
|
|
|
|
2020-05-11 15:13:59 -07:00
|
|
|
if (IS_ENABLED(CONFIG_BT_ISO) &&
|
|
|
|
conn->type == BT_CONN_TYPE_ISO) {
|
|
|
|
bt_iso_connected(conn);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-06-24 15:28:56 +02:00
|
|
|
#if defined(CONFIG_BT_CONN)
|
2017-03-21 15:48:03 +02:00
|
|
|
sys_slist_init(&conn->channels);
|
|
|
|
|
2020-10-13 13:13:16 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) &&
|
2021-09-14 12:28:45 +02:00
|
|
|
conn->role == BT_CONN_ROLE_PERIPHERAL) {
|
2022-10-13 07:49:44 +05:30
|
|
|
|
|
|
|
#if defined(CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS)
|
2023-03-22 16:59:16 +01:00
|
|
|
if (conn->type == BT_CONN_TYPE_LE) {
|
|
|
|
conn->le.conn_param_retry_countdown =
|
|
|
|
CONFIG_BT_CONN_PARAM_RETRY_COUNT;
|
|
|
|
}
|
2022-10-13 07:49:44 +05:30
|
|
|
#endif /* CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS */
|
|
|
|
|
2021-04-14 18:57:40 +02:00
|
|
|
k_work_schedule(&conn->deferred_work,
|
|
|
|
CONN_UPDATE_TIMEOUT);
|
2020-10-13 13:13:16 +02:00
|
|
|
}
|
2021-06-24 15:28:56 +02:00
|
|
|
#endif /* CONFIG_BT_CONN */
|
2020-10-13 13:13:16 +02:00
|
|
|
|
2015-06-19 18:56:13 +02:00
|
|
|
break;
|
|
|
|
case BT_CONN_DISCONNECTED:
|
2021-06-24 15:28:56 +02:00
|
|
|
#if defined(CONFIG_BT_CONN)
|
2017-02-15 15:18:13 +05:30
|
|
|
if (conn->type == BT_CONN_TYPE_SCO) {
|
2024-02-27 15:27:59 +08:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CLASSIC)) {
|
|
|
|
bt_sco_disconnected(conn);
|
|
|
|
}
|
2017-02-15 15:18:13 +05:30
|
|
|
bt_conn_unref(conn);
|
|
|
|
break;
|
|
|
|
}
|
2019-09-27 14:53:40 +02:00
|
|
|
|
2015-10-28 20:17:20 +02:00
|
|
|
/* Notify disconnection and queue a dummy buffer to wake
|
2016-11-11 10:06:05 +02:00
|
|
|
* up and stop the tx thread for states where it was
|
2015-10-28 20:17:20 +02:00
|
|
|
* running.
|
2015-07-03 12:05:23 +02:00
|
|
|
*/
|
2020-03-03 11:02:35 +01:00
|
|
|
switch (old_state) {
|
2020-06-03 14:48:04 +02:00
|
|
|
case BT_CONN_DISCONNECT_COMPLETE:
|
2024-02-01 08:26:21 +01:00
|
|
|
wait_for_tx_work(conn);
|
2017-02-02 08:24:28 +02:00
|
|
|
|
2024-08-08 08:40:02 +02:00
|
|
|
bt_conn_reset_rx_state(conn);
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
LOG_DBG("trigger disconnect work");
|
|
|
|
k_work_reschedule(&conn->deferred_work, K_NO_WAIT);
|
|
|
|
|
2019-06-17 19:26:47 +03:00
|
|
|
/* The last ref will be dropped during cleanup */
|
2020-03-03 11:02:35 +01:00
|
|
|
break;
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_INITIATING:
|
2020-01-31 14:04:31 +01:00
|
|
|
/* LE Create Connection command failed. This might be
|
|
|
|
* directly from the API, don't notify application in
|
|
|
|
* this case.
|
|
|
|
*/
|
|
|
|
if (conn->err) {
|
|
|
|
notify_connected(conn);
|
|
|
|
}
|
2020-03-03 11:02:35 +01:00
|
|
|
|
2017-02-02 08:24:28 +02:00
|
|
|
bt_conn_unref(conn);
|
2020-03-03 11:02:35 +01:00
|
|
|
break;
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_SCAN_BEFORE_INITIATING:
|
|
|
|
/* This indicates that connection establishment
|
2020-01-07 12:40:30 +01:00
|
|
|
* has been stopped. This could either be triggered by
|
|
|
|
* the application through bt_conn_disconnect or by
|
2020-03-30 19:23:16 +10:00
|
|
|
* timeout set by bt_conn_le_create_param.timeout.
|
2020-01-07 12:40:30 +01:00
|
|
|
*/
|
2024-06-03 12:49:05 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CENTRAL)) {
|
|
|
|
int err = bt_le_scan_user_remove(BT_LE_SCAN_USER_CONN);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
LOG_WRN("Error while removing conn user from scanner (%d)",
|
|
|
|
err);
|
|
|
|
}
|
2017-02-14 21:49:17 +01:00
|
|
|
|
2024-06-03 12:49:05 +02:00
|
|
|
if (conn->err) {
|
|
|
|
notify_connected(conn);
|
|
|
|
}
|
|
|
|
}
|
2018-08-20 14:44:42 +02:00
|
|
|
bt_conn_unref(conn);
|
2020-03-03 11:02:35 +01:00
|
|
|
break;
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_ADV_DIR_CONNECTABLE:
|
2018-08-20 14:44:42 +02:00
|
|
|
/* this indicate Directed advertising stopped */
|
|
|
|
if (conn->err) {
|
|
|
|
notify_connected(conn);
|
|
|
|
}
|
|
|
|
|
2017-02-02 08:24:28 +02:00
|
|
|
bt_conn_unref(conn);
|
2020-03-03 11:02:35 +01:00
|
|
|
break;
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_INITIATING_FILTER_LIST:
|
2020-01-07 12:40:30 +01:00
|
|
|
/* this indicates LE Create Connection with filter
|
|
|
|
* policy has been stopped. This can only be triggered
|
|
|
|
* by the application, so don't notify.
|
|
|
|
*/
|
|
|
|
bt_conn_unref(conn);
|
2020-03-03 11:02:35 +01:00
|
|
|
break;
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_ADV_CONNECTABLE:
|
2020-01-07 14:16:49 +01:00
|
|
|
/* This can only happen when application stops the
|
|
|
|
* advertiser, conn->err is never set in this case.
|
|
|
|
*/
|
|
|
|
bt_conn_unref(conn);
|
2020-03-03 11:02:35 +01:00
|
|
|
break;
|
2020-06-03 14:48:04 +02:00
|
|
|
case BT_CONN_CONNECTED:
|
2022-02-22 15:16:34 +01:00
|
|
|
case BT_CONN_DISCONNECTING:
|
2020-03-03 11:02:35 +01:00
|
|
|
case BT_CONN_DISCONNECTED:
|
2020-06-03 14:48:04 +02:00
|
|
|
/* Cannot happen. */
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Invalid (%u) old state", state);
|
2020-03-03 11:02:35 +01:00
|
|
|
break;
|
2015-07-03 12:05:23 +02:00
|
|
|
}
|
2020-01-07 12:40:30 +01:00
|
|
|
break;
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_INITIATING_FILTER_LIST:
|
2015-06-19 18:56:13 +02:00
|
|
|
break;
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_ADV_CONNECTABLE:
|
2020-01-07 14:16:49 +01:00
|
|
|
break;
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_SCAN_BEFORE_INITIATING:
|
2015-07-22 13:03:51 +03:00
|
|
|
break;
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_ADV_DIR_CONNECTABLE:
|
2018-08-20 14:44:42 +02:00
|
|
|
break;
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_INITIATING:
|
2017-02-15 15:08:25 +05:30
|
|
|
if (conn->type == BT_CONN_TYPE_SCO) {
|
|
|
|
break;
|
|
|
|
}
|
2016-01-11 17:24:43 +01:00
|
|
|
/*
|
|
|
|
* Timer is needed only for LE. For other link types controller
|
|
|
|
* will handle connection timeout.
|
|
|
|
*/
|
2017-08-09 09:21:11 +03:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
|
2023-03-30 14:06:14 +02:00
|
|
|
conn->type == BT_CONN_TYPE_LE &&
|
|
|
|
bt_dev.create_param.timeout != 0) {
|
2021-04-14 18:57:40 +02:00
|
|
|
k_work_schedule(&conn->deferred_work,
|
|
|
|
K_MSEC(10 * bt_dev.create_param.timeout));
|
2016-01-11 17:24:43 +01:00
|
|
|
}
|
|
|
|
|
2015-07-22 13:03:51 +03:00
|
|
|
break;
|
2022-02-22 15:16:34 +01:00
|
|
|
case BT_CONN_DISCONNECTING:
|
2015-06-19 18:56:13 +02:00
|
|
|
break;
|
2021-08-02 20:06:12 +02:00
|
|
|
#endif /* CONFIG_BT_CONN */
|
2020-06-03 14:48:04 +02:00
|
|
|
case BT_CONN_DISCONNECT_COMPLETE:
|
2024-03-19 17:38:34 +01:00
|
|
|
if (conn->err == BT_HCI_ERR_CONN_FAIL_TO_ESTAB) {
|
|
|
|
/* No ACK or data was ever received. The peripheral may be
|
|
|
|
* unaware of the connection attempt.
|
|
|
|
*
|
|
|
|
* Beware of confusing higher layer errors. Anything that looks
|
|
|
|
* like it's from the remote is synthetic.
|
|
|
|
*/
|
|
|
|
LOG_WRN("conn %p failed to establish. RF noise?", conn);
|
|
|
|
}
|
|
|
|
|
2020-06-03 14:48:04 +02:00
|
|
|
process_unack_tx(conn);
|
|
|
|
break;
|
2015-06-19 18:56:13 +02:00
|
|
|
default:
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("no valid (%u) state was set", state);
|
2015-06-19 10:52:58 +02:00
|
|
|
|
2015-06-19 18:56:13 +02:00
|
|
|
break;
|
|
|
|
}
|
2015-06-19 10:52:58 +02:00
|
|
|
}
|
|
|
|
|
2023-06-28 17:02:51 +02:00
|
|
|
struct bt_conn *bt_conn_lookup_handle(uint16_t handle, enum bt_conn_type type)
|
2015-04-28 10:39:50 +03:00
|
|
|
{
|
2020-05-11 15:13:59 -07:00
|
|
|
struct bt_conn *conn;
|
2015-05-05 10:50:14 +03:00
|
|
|
|
2021-06-24 14:49:44 +02:00
|
|
|
#if defined(CONFIG_BT_CONN)
|
2020-05-11 15:13:59 -07:00
|
|
|
conn = conn_lookup_handle(acl_conns, ARRAY_SIZE(acl_conns), handle);
|
|
|
|
if (conn) {
|
2023-03-22 16:59:16 +01:00
|
|
|
goto found;
|
2015-04-28 10:39:50 +03:00
|
|
|
}
|
2021-06-24 14:49:44 +02:00
|
|
|
#endif /* CONFIG_BT_CONN */
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2020-05-11 15:13:59 -07:00
|
|
|
#if defined(CONFIG_BT_ISO)
|
|
|
|
conn = conn_lookup_handle(iso_conns, ARRAY_SIZE(iso_conns), handle);
|
|
|
|
if (conn) {
|
2023-03-22 16:59:16 +01:00
|
|
|
goto found;
|
2020-05-11 15:13:59 -07:00
|
|
|
}
|
|
|
|
#endif
|
2017-02-15 15:18:13 +05:30
|
|
|
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
2020-05-11 15:13:59 -07:00
|
|
|
conn = conn_lookup_handle(sco_conns, ARRAY_SIZE(sco_conns), handle);
|
|
|
|
if (conn) {
|
2023-03-22 16:59:16 +01:00
|
|
|
goto found;
|
2017-02-15 15:18:13 +05:30
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2023-03-22 16:59:16 +01:00
|
|
|
found:
|
|
|
|
if (conn) {
|
|
|
|
if (type & conn->type) {
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
LOG_WRN("incompatible handle %u", handle);
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-07-17 15:26:45 +02:00
|
|
|
struct bt_conn *bt_hci_conn_lookup_handle(uint16_t handle)
|
|
|
|
{
|
|
|
|
return bt_conn_lookup_handle(handle, BT_CONN_TYPE_ALL);
|
|
|
|
}
|
|
|
|
|
2023-06-28 17:02:51 +02:00
|
|
|
void bt_conn_foreach(enum bt_conn_type type,
|
|
|
|
void (*func)(struct bt_conn *conn, void *data),
|
2019-07-09 15:17:07 +02:00
|
|
|
void *data)
|
2016-11-04 21:34:05 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2021-06-24 14:49:44 +02:00
|
|
|
#if defined(CONFIG_BT_CONN)
|
2020-05-11 15:13:59 -07:00
|
|
|
for (i = 0; i < ARRAY_SIZE(acl_conns); i++) {
|
2020-11-19 17:11:09 +01:00
|
|
|
struct bt_conn *conn = bt_conn_ref(&acl_conns[i]);
|
|
|
|
|
|
|
|
if (!conn) {
|
2016-11-04 21:34:05 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-11-19 17:11:09 +01:00
|
|
|
if (!(conn->type & type)) {
|
|
|
|
bt_conn_unref(conn);
|
2018-07-18 13:45:44 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-11-19 17:11:09 +01:00
|
|
|
func(conn, data);
|
|
|
|
bt_conn_unref(conn);
|
2019-07-09 15:17:07 +02:00
|
|
|
}
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
2019-07-09 15:17:07 +02:00
|
|
|
if (type & BT_CONN_TYPE_SCO) {
|
|
|
|
for (i = 0; i < ARRAY_SIZE(sco_conns); i++) {
|
2020-11-19 17:11:09 +01:00
|
|
|
struct bt_conn *conn = bt_conn_ref(&sco_conns[i]);
|
|
|
|
|
|
|
|
if (!conn) {
|
2019-07-09 15:17:07 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-11-19 17:11:09 +01:00
|
|
|
func(conn, data);
|
|
|
|
bt_conn_unref(conn);
|
2016-11-04 21:34:05 +02:00
|
|
|
}
|
|
|
|
}
|
2024-03-01 18:45:44 +08:00
|
|
|
#endif /* defined(CONFIG_BT_CLASSIC) */
|
2021-06-24 14:49:44 +02:00
|
|
|
#endif /* CONFIG_BT_CONN */
|
2020-05-11 15:13:59 -07:00
|
|
|
|
|
|
|
#if defined(CONFIG_BT_ISO)
|
|
|
|
if (type & BT_CONN_TYPE_ISO) {
|
|
|
|
for (i = 0; i < ARRAY_SIZE(iso_conns); i++) {
|
2020-11-19 17:11:09 +01:00
|
|
|
struct bt_conn *conn = bt_conn_ref(&iso_conns[i]);
|
|
|
|
|
|
|
|
if (!conn) {
|
2020-05-11 15:13:59 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-11-19 17:11:09 +01:00
|
|
|
func(conn, data);
|
|
|
|
bt_conn_unref(conn);
|
2020-05-11 15:13:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* defined(CONFIG_BT_ISO) */
|
2019-07-09 15:17:07 +02:00
|
|
|
}
|
|
|
|
|
2015-10-23 12:45:33 +03:00
|
|
|
struct bt_conn *bt_conn_ref(struct bt_conn *conn)
|
2015-04-28 10:39:50 +03:00
|
|
|
{
|
2020-11-30 13:38:49 +01:00
|
|
|
atomic_val_t old;
|
2015-06-23 14:38:24 +02:00
|
|
|
|
2022-09-19 10:58:13 +02:00
|
|
|
__ASSERT_NO_MSG(conn);
|
|
|
|
|
2020-11-30 13:38:49 +01:00
|
|
|
/* Reference counter must be checked to avoid incrementing ref from
|
|
|
|
* zero, then we should return NULL instead.
|
|
|
|
* Loop on clear-and-set in case someone has modified the reference
|
|
|
|
* count since the read, and start over again when that happens.
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
old = atomic_get(&conn->ref);
|
|
|
|
|
|
|
|
if (!old) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} while (!atomic_cas(&conn->ref, old, old + 1));
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("handle %u ref %ld -> %ld", conn->handle, old, old + 1);
|
2015-06-26 14:52:55 +02:00
|
|
|
|
2015-04-28 10:39:50 +03:00
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
2015-10-23 12:45:33 +03:00
|
|
|
void bt_conn_unref(struct bt_conn *conn)
|
2015-04-28 10:39:50 +03:00
|
|
|
{
|
2021-03-18 15:00:40 -07:00
|
|
|
atomic_val_t old;
|
2024-01-29 16:31:50 -05:00
|
|
|
bool deallocated;
|
|
|
|
enum bt_conn_type conn_type;
|
|
|
|
uint8_t conn_role;
|
|
|
|
uint16_t conn_handle;
|
|
|
|
|
|
|
|
__ASSERT(conn, "Invalid connection reference");
|
|
|
|
|
|
|
|
/* Storing parameters of interest so we don't access the object
|
|
|
|
* after decrementing its ref-count
|
|
|
|
*/
|
|
|
|
conn_type = conn->type;
|
|
|
|
conn_role = conn->role;
|
|
|
|
conn_handle = conn->handle;
|
2021-03-18 15:00:40 -07:00
|
|
|
|
|
|
|
old = atomic_dec(&conn->ref);
|
2024-01-29 16:31:50 -05:00
|
|
|
/* Prevent from accessing connection object */
|
|
|
|
conn = NULL;
|
|
|
|
deallocated = (atomic_get(&old) == 1);
|
2015-06-26 14:52:55 +02:00
|
|
|
|
2024-01-29 16:31:50 -05:00
|
|
|
LOG_DBG("handle %u ref %ld -> %ld", conn_handle, old, (old - 1));
|
2020-06-03 22:25:39 +02:00
|
|
|
|
2020-12-18 10:51:58 +01:00
|
|
|
__ASSERT(old > 0, "Conn reference counter is 0");
|
|
|
|
|
2024-01-29 16:31:50 -05:00
|
|
|
/* Slot has been freed and can be taken. No guarantees are made on requests
|
|
|
|
* to claim connection object as only the first claim will be served.
|
|
|
|
*/
|
|
|
|
if (deallocated) {
|
|
|
|
notify_recycled_conn_slot();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn_type == BT_CONN_TYPE_LE &&
|
|
|
|
conn_role == BT_CONN_ROLE_PERIPHERAL && deallocated) {
|
2020-06-03 22:25:39 +02:00
|
|
|
bt_le_adv_resume();
|
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
}
|
2015-06-18 09:36:59 +02:00
|
|
|
|
2022-03-25 13:50:48 +01:00
|
|
|
uint8_t bt_conn_index(const struct bt_conn *conn)
|
2021-06-24 14:44:52 +02:00
|
|
|
{
|
2021-06-24 14:49:44 +02:00
|
|
|
ptrdiff_t index = 0;
|
2021-06-24 14:44:52 +02:00
|
|
|
|
|
|
|
switch (conn->type) {
|
|
|
|
#if defined(CONFIG_BT_ISO)
|
|
|
|
case BT_CONN_TYPE_ISO:
|
|
|
|
index = conn - iso_conns;
|
|
|
|
__ASSERT(index >= 0 && index < ARRAY_SIZE(iso_conns),
|
|
|
|
"Invalid bt_conn pointer");
|
|
|
|
break;
|
|
|
|
#endif
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
2021-06-24 14:44:52 +02:00
|
|
|
case BT_CONN_TYPE_SCO:
|
|
|
|
index = conn - sco_conns;
|
|
|
|
__ASSERT(index >= 0 && index < ARRAY_SIZE(sco_conns),
|
|
|
|
"Invalid bt_conn pointer");
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
2021-06-24 14:49:44 +02:00
|
|
|
#if defined(CONFIG_BT_CONN)
|
2021-06-24 14:44:52 +02:00
|
|
|
index = conn - acl_conns;
|
|
|
|
__ASSERT(index >= 0 && index < ARRAY_SIZE(acl_conns),
|
|
|
|
"Invalid bt_conn pointer");
|
2021-06-24 14:49:44 +02:00
|
|
|
#else
|
|
|
|
__ASSERT(false, "Invalid connection type %u", conn->type);
|
|
|
|
#endif /* CONFIG_BT_CONN */
|
2021-06-24 14:44:52 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (uint8_t)index;
|
|
|
|
}
|
|
|
|
|
2021-08-12 22:09:16 +02:00
|
|
|
|
|
|
|
#if defined(CONFIG_NET_BUF_LOG)
|
|
|
|
struct net_buf *bt_conn_create_pdu_timeout_debug(struct net_buf_pool *pool,
|
|
|
|
size_t reserve,
|
|
|
|
k_timeout_t timeout,
|
|
|
|
const char *func, int line)
|
|
|
|
#else
|
|
|
|
struct net_buf *bt_conn_create_pdu_timeout(struct net_buf_pool *pool,
|
|
|
|
size_t reserve, k_timeout_t timeout)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* PDU must not be allocated from ISR as we block with 'K_FOREVER'
|
|
|
|
* during the allocation
|
|
|
|
*/
|
|
|
|
__ASSERT_NO_MSG(!k_is_in_isr());
|
|
|
|
|
2024-04-18 16:49:28 +02:00
|
|
|
if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT) &&
|
|
|
|
k_current_get() == k_work_queue_thread_get(&k_sys_work_q)) {
|
|
|
|
LOG_DBG("Timeout discarded. No blocking in syswq.");
|
|
|
|
timeout = K_NO_WAIT;
|
|
|
|
}
|
|
|
|
|
2021-08-12 22:09:16 +02:00
|
|
|
if (!pool) {
|
|
|
|
#if defined(CONFIG_BT_CONN)
|
|
|
|
pool = &acl_tx_pool;
|
|
|
|
#else
|
|
|
|
return NULL;
|
|
|
|
#endif /* CONFIG_BT_CONN */
|
|
|
|
}
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CONN_LOG_LEVEL_DBG)) {
|
2021-08-12 22:09:16 +02:00
|
|
|
#if defined(CONFIG_NET_BUF_LOG)
|
|
|
|
buf = net_buf_alloc_fixed_debug(pool, K_NO_WAIT, func, line);
|
|
|
|
#else
|
|
|
|
buf = net_buf_alloc(pool, K_NO_WAIT);
|
|
|
|
#endif
|
|
|
|
if (!buf) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Unable to allocate buffer with K_NO_WAIT");
|
2021-08-12 22:09:16 +02:00
|
|
|
#if defined(CONFIG_NET_BUF_LOG)
|
|
|
|
buf = net_buf_alloc_fixed_debug(pool, timeout, func,
|
|
|
|
line);
|
|
|
|
#else
|
|
|
|
buf = net_buf_alloc(pool, timeout);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
#if defined(CONFIG_NET_BUF_LOG)
|
|
|
|
buf = net_buf_alloc_fixed_debug(pool, timeout, func,
|
|
|
|
line);
|
|
|
|
#else
|
|
|
|
buf = net_buf_alloc(pool, timeout);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!buf) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Unable to allocate buffer within timeout");
|
2021-08-12 22:09:16 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
reserve += sizeof(struct bt_hci_acl_hdr) + BT_BUF_RESERVE;
|
|
|
|
net_buf_reserve(buf, reserve);
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2021-11-18 14:26:32 +01:00
|
|
|
#if defined(CONFIG_BT_CONN_TX)
|
2021-11-18 14:13:15 +01:00
|
|
|
static void tx_complete_work(struct k_work *work)
|
|
|
|
{
|
|
|
|
struct bt_conn *conn = CONTAINER_OF(work, struct bt_conn,
|
|
|
|
tx_complete_work);
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
LOG_DBG("conn %p", conn);
|
|
|
|
|
2021-11-18 14:13:15 +01:00
|
|
|
tx_notify(conn);
|
|
|
|
}
|
2021-11-18 14:26:32 +01:00
|
|
|
#endif /* CONFIG_BT_CONN_TX */
|
2021-11-18 14:13:15 +01:00
|
|
|
|
2024-01-29 16:31:50 -05:00
|
|
|
static void notify_recycled_conn_slot(void)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_BT_CONN)
|
2024-06-10 14:30:04 +02:00
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
2024-06-10 14:30:04 +02:00
|
|
|
if (callback->recycled) {
|
|
|
|
callback->recycled();
|
2024-01-29 16:31:50 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb) {
|
|
|
|
if (cb->recycled) {
|
|
|
|
cb->recycled();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-07-21 10:22:32 +02:00
|
|
|
#if !defined(CONFIG_BT_CONN)
|
|
|
|
int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(conn);
|
|
|
|
ARG_UNUSED(reason);
|
|
|
|
|
|
|
|
/* Dummy implementation to satisfy the compiler */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* !CONFIG_BT_CONN */
|
|
|
|
|
2021-06-24 14:44:52 +02:00
|
|
|
/* Group Connected BT_CONN only in this */
|
|
|
|
#if defined(CONFIG_BT_CONN)
|
2024-08-28 15:12:10 +02:00
|
|
|
/* We don't want the application to get a PHY update callback upon connection
|
|
|
|
* establishment on 2M PHY. Therefore we must prevent issuing LE Set PHY
|
|
|
|
* in this scenario.
|
|
|
|
*/
|
|
|
|
static bool skip_auto_phy_update_on_conn_establishment(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_BT_USER_PHY_UPDATE)
|
|
|
|
if (IS_ENABLED(CONFIG_BT_AUTO_PHY_UPDATE) &&
|
|
|
|
IS_ENABLED(CONFIG_BT_EXT_ADV) &&
|
|
|
|
BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features)) {
|
|
|
|
if (conn->le.phy.tx_phy == BT_HCI_LE_PHY_2M &&
|
|
|
|
conn->le.phy.rx_phy == BT_HCI_LE_PHY_2M) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
ARG_UNUSED(conn);
|
|
|
|
#endif /* defined(CONFIG_BT_USER_PHY_UPDATE) */
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void perform_auto_initiated_procedures(struct bt_conn *conn, void *unused)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
ARG_UNUSED(unused);
|
|
|
|
|
|
|
|
LOG_DBG("[%p] Running auto-initiated procedures", conn);
|
|
|
|
|
|
|
|
if (conn->state != BT_CONN_CONNECTED) {
|
|
|
|
/* It is possible that connection was disconnected directly from
|
|
|
|
* connected callback so we must check state before doing
|
|
|
|
* connection parameters update.
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (atomic_test_and_set_bit(conn->flags, BT_CONN_AUTO_INIT_PROCEDURES_DONE)) {
|
|
|
|
/* We have already run the auto-initiated procedures */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!atomic_test_bit(conn->flags, BT_CONN_LE_FEATURES_EXCHANGED) &&
|
|
|
|
((conn->role == BT_HCI_ROLE_CENTRAL) ||
|
|
|
|
BT_FEAT_LE_PER_INIT_FEAT_XCHG(bt_dev.le.features))) {
|
|
|
|
err = bt_hci_le_read_remote_features(conn);
|
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed read remote features (%d)", err);
|
|
|
|
}
|
|
|
|
if (conn->state != BT_CONN_CONNECTED) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_REMOTE_VERSION) &&
|
|
|
|
!atomic_test_bit(conn->flags, BT_CONN_AUTO_VERSION_INFO)) {
|
|
|
|
err = bt_hci_read_remote_version(conn);
|
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed read remote version (%d)", err);
|
|
|
|
}
|
|
|
|
if (conn->state != BT_CONN_CONNECTED) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_AUTO_PHY_UPDATE) &&
|
|
|
|
BT_FEAT_LE_PHY_2M(bt_dev.le.features) &&
|
|
|
|
!skip_auto_phy_update_on_conn_establishment(conn)) {
|
|
|
|
err = bt_le_set_phy(conn, 0U, BT_HCI_LE_PHY_PREFER_2M,
|
|
|
|
BT_HCI_LE_PHY_PREFER_2M,
|
|
|
|
BT_HCI_LE_PHY_CODED_ANY);
|
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed LE Set PHY (%d)", err);
|
|
|
|
}
|
|
|
|
if (conn->state != BT_CONN_CONNECTED) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_AUTO_DATA_LEN_UPDATE) &&
|
|
|
|
BT_FEAT_LE_DLE(bt_dev.le.features)) {
|
|
|
|
if (bt_drv_quirk_no_auto_dle()) {
|
|
|
|
uint16_t tx_octets, tx_time;
|
|
|
|
|
|
|
|
err = bt_hci_le_read_max_data_len(&tx_octets, &tx_time);
|
|
|
|
if (!err) {
|
|
|
|
err = bt_le_set_data_len(conn,
|
|
|
|
tx_octets, tx_time);
|
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed to set data len (%d)", err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* No need to auto-initiate DLE procedure.
|
|
|
|
* It is done by the controller.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_DBG("[%p] Successfully ran auto-initiated procedures", conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Executes procedures after a connection is established:
|
|
|
|
* - read remote features
|
|
|
|
* - read remote version
|
|
|
|
* - update PHY
|
|
|
|
* - update data length
|
|
|
|
*/
|
|
|
|
static void auto_initiated_procedures(struct k_work *unused)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(unused);
|
|
|
|
|
|
|
|
bt_conn_foreach(BT_CONN_TYPE_LE, perform_auto_initiated_procedures, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static K_WORK_DEFINE(procedures_on_connect, auto_initiated_procedures);
|
|
|
|
|
|
|
|
static void schedule_auto_initiated_procedures(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
LOG_DBG("[%p] Scheduling auto-init procedures", conn);
|
|
|
|
k_work_submit(&procedures_on_connect);
|
|
|
|
}
|
2021-06-24 14:44:52 +02:00
|
|
|
|
2021-06-24 14:55:19 +02:00
|
|
|
void bt_conn_connected(struct bt_conn *conn)
|
|
|
|
{
|
2024-08-28 15:12:10 +02:00
|
|
|
schedule_auto_initiated_procedures(conn);
|
2021-06-24 14:55:19 +02:00
|
|
|
bt_l2cap_connected(conn);
|
|
|
|
notify_connected(conn);
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
static int conn_disconnect(struct bt_conn *conn, uint8_t reason)
|
2015-07-15 12:31:08 +03:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2020-01-15 14:30:27 +01:00
|
|
|
err = bt_hci_disconnect(conn->handle, reason);
|
2015-07-15 12:31:08 +03:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2021-03-03 14:22:11 -08:00
|
|
|
if (conn->state == BT_CONN_CONNECTED) {
|
2022-02-22 15:16:34 +01:00
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTING);
|
2021-03-03 14:22:11 -08:00
|
|
|
}
|
2015-07-15 12:31:08 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason)
|
2015-07-15 12:31:08 +03:00
|
|
|
{
|
|
|
|
/* Disconnection is initiated by us, so auto connection shall
|
|
|
|
* be disabled. Otherwise the passive scan would be enabled
|
|
|
|
* and we could send LE Create Connection as soon as the remote
|
|
|
|
* starts advertising.
|
|
|
|
*/
|
2021-09-14 12:28:45 +02:00
|
|
|
#if !defined(CONFIG_BT_FILTER_ACCEPT_LIST)
|
2017-08-09 09:21:11 +03:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
|
2017-01-17 19:03:55 +02:00
|
|
|
conn->type == BT_CONN_TYPE_LE) {
|
2015-12-07 12:05:57 +02:00
|
|
|
bt_le_set_auto_conn(&conn->le.dst, NULL);
|
2015-12-04 10:34:12 +02:00
|
|
|
}
|
2021-09-14 12:28:45 +02:00
|
|
|
#endif /* !defined(CONFIG_BT_FILTER_ACCEPT_LIST) */
|
2015-07-15 12:31:08 +03:00
|
|
|
|
|
|
|
switch (conn->state) {
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_SCAN_BEFORE_INITIATING:
|
2017-04-07 21:28:58 +03:00
|
|
|
conn->err = reason;
|
2015-07-15 12:31:08 +03:00
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
2018-06-21 13:44:02 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CENTRAL)) {
|
2024-06-03 12:49:05 +02:00
|
|
|
return bt_le_scan_user_add(BT_LE_SCAN_USER_CONN);
|
2018-06-21 13:44:02 +02:00
|
|
|
}
|
2015-07-15 12:31:08 +03:00
|
|
|
return 0;
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_INITIATING:
|
2023-08-17 15:38:19 +02:00
|
|
|
if (conn->type == BT_CONN_TYPE_LE) {
|
|
|
|
if (IS_ENABLED(CONFIG_BT_CENTRAL)) {
|
|
|
|
k_work_cancel_delayable(&conn->deferred_work);
|
|
|
|
return bt_le_create_conn_cancel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if defined(CONFIG_BT_ISO)
|
|
|
|
else if (conn->type == BT_CONN_TYPE_ISO) {
|
|
|
|
return conn_disconnect(conn, reason);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_ISO */
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
2023-08-17 15:38:19 +02:00
|
|
|
else if (conn->type == BT_CONN_TYPE_BR) {
|
2016-03-14 10:20:04 +01:00
|
|
|
return bt_hci_connect_br_cancel(conn);
|
|
|
|
}
|
2024-03-01 18:45:44 +08:00
|
|
|
#endif /* CONFIG_BT_CLASSIC */
|
2023-08-17 15:38:19 +02:00
|
|
|
else {
|
|
|
|
__ASSERT(false, "Invalid conn type %u", conn->type);
|
2017-01-31 09:41:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2015-07-15 12:31:08 +03:00
|
|
|
case BT_CONN_CONNECTED:
|
2020-01-15 14:30:27 +01:00
|
|
|
return conn_disconnect(conn, reason);
|
2022-02-22 15:16:34 +01:00
|
|
|
case BT_CONN_DISCONNECTING:
|
2015-07-15 12:31:08 +03:00
|
|
|
return 0;
|
|
|
|
case BT_CONN_DISCONNECTED:
|
|
|
|
default:
|
|
|
|
return -ENOTCONN;
|
|
|
|
}
|
|
|
|
}
|
2015-07-15 13:55:32 +03:00
|
|
|
|
2021-06-22 16:56:37 +02:00
|
|
|
static void notify_connected(struct bt_conn *conn)
|
|
|
|
{
|
2024-06-10 14:30:04 +02:00
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
|
|
|
|
2024-06-10 14:30:04 +02:00
|
|
|
if (callback->connected) {
|
|
|
|
callback->connected(conn, conn->err);
|
2021-06-22 16:56:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-04 23:05:54 +01:00
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb) {
|
2021-06-09 23:52:33 -07:00
|
|
|
if (cb->connected) {
|
|
|
|
cb->connected(conn, conn->err);
|
|
|
|
}
|
|
|
|
}
|
2021-06-22 16:56:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void notify_disconnected(struct bt_conn *conn)
|
|
|
|
{
|
2024-06-10 14:30:04 +02:00
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
2024-06-10 14:30:04 +02:00
|
|
|
if (callback->disconnected) {
|
|
|
|
callback->disconnected(conn, conn->err);
|
2021-06-22 16:56:37 +02:00
|
|
|
}
|
|
|
|
}
|
2021-06-09 23:52:33 -07:00
|
|
|
|
2021-08-04 23:05:54 +01:00
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb) {
|
2021-06-09 23:52:33 -07:00
|
|
|
if (cb->disconnected) {
|
|
|
|
cb->disconnected(conn, conn->err);
|
|
|
|
}
|
|
|
|
}
|
2021-06-22 16:56:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_BT_REMOTE_INFO)
|
|
|
|
void notify_remote_info(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
struct bt_conn_remote_info remote_info;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = bt_conn_get_remote_info(conn, &remote_info);
|
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Notify remote info failed %d", err);
|
2021-06-22 16:56:37 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:30:04 +02:00
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
2024-06-10 14:30:04 +02:00
|
|
|
if (callback->remote_info_available) {
|
|
|
|
callback->remote_info_available(conn, &remote_info);
|
2021-06-22 16:56:37 +02:00
|
|
|
}
|
|
|
|
}
|
2021-06-09 23:52:33 -07:00
|
|
|
|
2021-08-04 23:05:54 +01:00
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb) {
|
2021-06-09 23:52:33 -07:00
|
|
|
if (cb->remote_info_available) {
|
|
|
|
cb->remote_info_available(conn, &remote_info);
|
|
|
|
}
|
|
|
|
}
|
2021-06-22 16:56:37 +02:00
|
|
|
}
|
|
|
|
#endif /* defined(CONFIG_BT_REMOTE_INFO) */
|
|
|
|
|
|
|
|
void notify_le_param_updated(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
/* If new connection parameters meet requirement of pending
|
2021-09-17 13:49:15 +02:00
|
|
|
* parameters don't send peripheral conn param request anymore on timeout
|
2021-06-22 16:56:37 +02:00
|
|
|
*/
|
2021-09-17 13:49:15 +02:00
|
|
|
if (atomic_test_bit(conn->flags, BT_CONN_PERIPHERAL_PARAM_SET) &&
|
2021-06-22 16:56:37 +02:00
|
|
|
conn->le.interval >= conn->le.interval_min &&
|
|
|
|
conn->le.interval <= conn->le.interval_max &&
|
|
|
|
conn->le.latency == conn->le.pending_latency &&
|
|
|
|
conn->le.timeout == conn->le.pending_timeout) {
|
2021-09-17 13:49:15 +02:00
|
|
|
atomic_clear_bit(conn->flags, BT_CONN_PERIPHERAL_PARAM_SET);
|
2021-06-22 16:56:37 +02:00
|
|
|
}
|
|
|
|
|
2024-06-10 14:30:04 +02:00
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
2024-06-10 14:30:04 +02:00
|
|
|
if (callback->le_param_updated) {
|
|
|
|
callback->le_param_updated(conn, conn->le.interval,
|
|
|
|
conn->le.latency,
|
|
|
|
conn->le.timeout);
|
2021-06-22 16:56:37 +02:00
|
|
|
}
|
|
|
|
}
|
2021-06-09 23:52:33 -07:00
|
|
|
|
2021-08-04 23:05:54 +01:00
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb) {
|
2021-06-09 23:52:33 -07:00
|
|
|
if (cb->le_param_updated) {
|
|
|
|
cb->le_param_updated(conn, conn->le.interval,
|
|
|
|
conn->le.latency,
|
|
|
|
conn->le.timeout);
|
|
|
|
}
|
|
|
|
}
|
2021-06-22 16:56:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
|
|
|
|
void notify_le_data_len_updated(struct bt_conn *conn)
|
|
|
|
{
|
2024-06-10 14:30:04 +02:00
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
2024-06-10 14:30:04 +02:00
|
|
|
if (callback->le_data_len_updated) {
|
|
|
|
callback->le_data_len_updated(conn, &conn->le.data_len);
|
2021-06-22 16:56:37 +02:00
|
|
|
}
|
|
|
|
}
|
2021-06-09 23:52:33 -07:00
|
|
|
|
2021-08-04 23:05:54 +01:00
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb) {
|
2021-06-09 23:52:33 -07:00
|
|
|
if (cb->le_data_len_updated) {
|
|
|
|
cb->le_data_len_updated(conn, &conn->le.data_len);
|
|
|
|
}
|
|
|
|
}
|
2021-06-22 16:56:37 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(CONFIG_BT_USER_PHY_UPDATE)
|
|
|
|
void notify_le_phy_updated(struct bt_conn *conn)
|
|
|
|
{
|
2024-06-10 14:30:04 +02:00
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
2024-06-10 14:30:04 +02:00
|
|
|
if (callback->le_phy_updated) {
|
|
|
|
callback->le_phy_updated(conn, &conn->le.phy);
|
2021-06-22 16:56:37 +02:00
|
|
|
}
|
|
|
|
}
|
2021-06-09 23:52:33 -07:00
|
|
|
|
2021-08-04 23:05:54 +01:00
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb) {
|
2021-06-09 23:52:33 -07:00
|
|
|
if (cb->le_phy_updated) {
|
|
|
|
cb->le_phy_updated(conn, &conn->le.phy);
|
|
|
|
}
|
|
|
|
}
|
2021-06-22 16:56:37 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-06-22 15:36:00 +02:00
|
|
|
bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
|
|
|
|
{
|
|
|
|
if (!bt_le_conn_params_valid(param)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:30:04 +02:00
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
2024-06-10 14:30:04 +02:00
|
|
|
if (!callback->le_param_req) {
|
2021-06-22 15:36:00 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:30:04 +02:00
|
|
|
if (!callback->le_param_req(conn, param)) {
|
2021-06-22 15:36:00 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The callback may modify the parameters so we need to
|
|
|
|
* double-check that it returned valid parameters.
|
|
|
|
*/
|
|
|
|
if (!bt_le_conn_params_valid(param)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-04 23:05:54 +01:00
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb) {
|
2021-06-09 23:52:33 -07:00
|
|
|
if (!cb->le_param_req) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cb->le_param_req(conn, param)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The callback may modify the parameters so we need to
|
|
|
|
* double-check that it returned valid parameters.
|
|
|
|
*/
|
|
|
|
if (!bt_le_conn_params_valid(param)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-22 15:36:00 +02:00
|
|
|
/* Default to accepting if there's no app callback */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int send_conn_le_param_update(struct bt_conn *conn,
|
|
|
|
const struct bt_le_conn_param *param)
|
|
|
|
{
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("conn %p features 0x%02x params (%d-%d %d %d)", conn, conn->le.features[0],
|
|
|
|
param->interval_min, param->interval_max, param->latency, param->timeout);
|
2021-06-22 15:36:00 +02:00
|
|
|
|
|
|
|
/* Proceed only if connection parameters contains valid values*/
|
|
|
|
if (!bt_le_conn_params_valid(param)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Use LE connection parameter request if both local and remote support
|
2021-09-17 13:49:15 +02:00
|
|
|
* it; or if local role is central then use LE connection update.
|
2021-06-22 15:36:00 +02:00
|
|
|
*/
|
|
|
|
if ((BT_FEAT_LE_CONN_PARAM_REQ_PROC(bt_dev.le.features) &&
|
|
|
|
BT_FEAT_LE_CONN_PARAM_REQ_PROC(conn->le.features) &&
|
2021-09-17 13:49:15 +02:00
|
|
|
!atomic_test_bit(conn->flags, BT_CONN_PERIPHERAL_PARAM_L2CAP)) ||
|
2021-09-16 10:43:02 +02:00
|
|
|
(conn->role == BT_HCI_ROLE_CENTRAL)) {
|
2021-06-22 15:36:00 +02:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = bt_conn_le_conn_update(conn, param);
|
|
|
|
|
|
|
|
/* store those in case of fallback to L2CAP */
|
|
|
|
if (rc == 0) {
|
2021-09-22 10:16:50 -05:00
|
|
|
conn->le.interval_min = param->interval_min;
|
|
|
|
conn->le.interval_max = param->interval_max;
|
2021-06-22 15:36:00 +02:00
|
|
|
conn->le.pending_latency = param->latency;
|
|
|
|
conn->le.pending_timeout = param->timeout;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-09-17 13:49:15 +02:00
|
|
|
/* If remote central does not support LL Connection Parameters Request
|
2021-06-22 15:36:00 +02:00
|
|
|
* Procedure
|
|
|
|
*/
|
|
|
|
return bt_l2cap_update_conn_param(conn, param);
|
|
|
|
}
|
|
|
|
|
2021-08-25 18:32:27 +02:00
|
|
|
#if defined(CONFIG_BT_ISO_UNICAST)
|
2021-06-22 15:32:51 +02:00
|
|
|
static struct bt_conn *conn_lookup_iso(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(iso_conns); i++) {
|
2021-08-24 14:21:08 +02:00
|
|
|
struct bt_conn *iso = bt_conn_ref(&iso_conns[i]);
|
2021-06-22 15:32:51 +02:00
|
|
|
|
2021-08-24 14:21:08 +02:00
|
|
|
if (iso == NULL) {
|
2021-06-22 15:32:51 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-08-24 14:21:08 +02:00
|
|
|
if (iso->iso.acl == conn) {
|
|
|
|
return iso;
|
2021-06-22 15:32:51 +02:00
|
|
|
}
|
|
|
|
|
2021-08-24 14:21:08 +02:00
|
|
|
bt_conn_unref(iso);
|
2021-06-22 15:32:51 +02:00
|
|
|
}
|
2021-08-25 18:32:27 +02:00
|
|
|
|
2021-06-22 15:32:51 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2021-08-25 18:32:27 +02:00
|
|
|
#endif /* CONFIG_BT_ISO */
|
2021-06-22 15:32:51 +02:00
|
|
|
|
2024-02-27 15:27:59 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
|
|
|
static struct bt_conn *conn_lookup_sco(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(sco_conns); i++) {
|
|
|
|
struct bt_conn *sco = bt_conn_ref(&sco_conns[i]);
|
|
|
|
|
|
|
|
if (sco == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sco->sco.acl == conn) {
|
|
|
|
return sco;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_unref(sco);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_CLASSIC */
|
|
|
|
|
2021-06-22 15:32:51 +02:00
|
|
|
static void deferred_work(struct k_work *work)
|
|
|
|
{
|
2022-01-19 12:07:51 +08:00
|
|
|
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
|
|
|
|
struct bt_conn *conn = CONTAINER_OF(dwork, struct bt_conn, deferred_work);
|
2021-06-22 15:32:51 +02:00
|
|
|
const struct bt_le_conn_param *param;
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("conn %p", conn);
|
2021-06-22 15:32:51 +02:00
|
|
|
|
|
|
|
if (conn->state == BT_CONN_DISCONNECTED) {
|
2021-08-25 18:32:27 +02:00
|
|
|
#if defined(CONFIG_BT_ISO_UNICAST)
|
|
|
|
struct bt_conn *iso;
|
2021-06-22 15:32:51 +02:00
|
|
|
|
2021-08-25 18:32:27 +02:00
|
|
|
if (conn->type == BT_CONN_TYPE_ISO) {
|
2021-09-24 12:21:58 +02:00
|
|
|
/* bt_iso_disconnected is responsible for unref'ing the
|
|
|
|
* connection pointer, as it is conditional on whether
|
|
|
|
* the connection is a central or peripheral.
|
|
|
|
*/
|
2021-08-25 18:32:27 +02:00
|
|
|
bt_iso_disconnected(conn);
|
|
|
|
return;
|
|
|
|
}
|
2021-06-22 15:32:51 +02:00
|
|
|
|
2021-08-25 18:32:27 +02:00
|
|
|
/* Mark all ISO channels associated
|
|
|
|
* with ACL conn as not connected, and
|
|
|
|
* remove ACL reference
|
|
|
|
*/
|
|
|
|
iso = conn_lookup_iso(conn);
|
|
|
|
while (iso != NULL) {
|
|
|
|
struct bt_iso_chan *chan = iso->iso.chan;
|
2021-06-22 15:32:51 +02:00
|
|
|
|
2021-08-25 18:32:27 +02:00
|
|
|
if (chan != NULL) {
|
2022-02-22 15:28:35 +01:00
|
|
|
bt_iso_chan_set_state(chan,
|
2022-02-22 15:30:30 +01:00
|
|
|
BT_ISO_STATE_DISCONNECTING);
|
2021-06-22 15:32:51 +02:00
|
|
|
}
|
2021-08-25 18:32:27 +02:00
|
|
|
|
|
|
|
bt_iso_cleanup_acl(iso);
|
|
|
|
|
|
|
|
bt_conn_unref(iso);
|
|
|
|
iso = conn_lookup_iso(conn);
|
2021-06-22 15:32:51 +02:00
|
|
|
}
|
2021-08-25 18:32:27 +02:00
|
|
|
#endif
|
2024-02-27 15:27:59 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
|
|
|
struct bt_conn *sco;
|
|
|
|
|
|
|
|
/* Mark all SCO channels associated
|
|
|
|
* with ACL conn as not connected, and
|
|
|
|
* remove ACL reference
|
|
|
|
*/
|
|
|
|
sco = conn_lookup_sco(conn);
|
|
|
|
while (sco != NULL) {
|
|
|
|
struct bt_sco_chan *chan = sco->sco.chan;
|
|
|
|
|
|
|
|
if (chan != NULL) {
|
|
|
|
bt_sco_chan_set_state(chan,
|
|
|
|
BT_SCO_STATE_DISCONNECTING);
|
|
|
|
}
|
2021-06-22 15:32:51 +02:00
|
|
|
|
2024-02-27 15:27:59 +08:00
|
|
|
bt_sco_cleanup_acl(sco);
|
|
|
|
|
|
|
|
bt_conn_unref(sco);
|
|
|
|
sco = conn_lookup_sco(conn);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_CLASSIC */
|
2021-06-22 15:32:51 +02:00
|
|
|
bt_l2cap_disconnected(conn);
|
|
|
|
notify_disconnected(conn);
|
|
|
|
|
|
|
|
/* Release the reference we took for the very first
|
|
|
|
* state transition.
|
|
|
|
*/
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->type != BT_CONN_TYPE_LE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
|
2021-09-14 12:28:45 +02:00
|
|
|
conn->role == BT_CONN_ROLE_CENTRAL) {
|
2021-06-22 15:32:51 +02:00
|
|
|
/* we don't call bt_conn_disconnect as it would also clear
|
|
|
|
* auto connect flag if it was set, instead just cancel
|
|
|
|
* connection directly
|
|
|
|
*/
|
|
|
|
bt_le_create_conn_cancel();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if application set own params use those, otherwise use defaults. */
|
|
|
|
if (atomic_test_and_clear_bit(conn->flags,
|
2021-09-17 13:49:15 +02:00
|
|
|
BT_CONN_PERIPHERAL_PARAM_SET)) {
|
2022-10-13 07:49:44 +05:30
|
|
|
int err;
|
|
|
|
|
2021-06-22 15:32:51 +02:00
|
|
|
param = BT_LE_CONN_PARAM(conn->le.interval_min,
|
|
|
|
conn->le.interval_max,
|
|
|
|
conn->le.pending_latency,
|
|
|
|
conn->le.pending_timeout);
|
2022-10-13 07:49:44 +05:30
|
|
|
|
|
|
|
err = send_conn_le_param_update(conn, param);
|
|
|
|
if (!err) {
|
|
|
|
atomic_clear_bit(conn->flags,
|
|
|
|
BT_CONN_PERIPHERAL_PARAM_AUTO_UPDATE);
|
|
|
|
} else {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Send LE param update failed (err %d)", err);
|
2022-10-13 07:49:44 +05:30
|
|
|
}
|
2021-06-22 15:32:51 +02:00
|
|
|
} else if (IS_ENABLED(CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS)) {
|
|
|
|
#if defined(CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS)
|
2022-10-13 07:49:44 +05:30
|
|
|
int err;
|
|
|
|
|
2021-06-22 15:32:51 +02:00
|
|
|
param = BT_LE_CONN_PARAM(
|
|
|
|
CONFIG_BT_PERIPHERAL_PREF_MIN_INT,
|
|
|
|
CONFIG_BT_PERIPHERAL_PREF_MAX_INT,
|
2021-09-17 13:49:15 +02:00
|
|
|
CONFIG_BT_PERIPHERAL_PREF_LATENCY,
|
2021-06-22 15:32:51 +02:00
|
|
|
CONFIG_BT_PERIPHERAL_PREF_TIMEOUT);
|
2022-10-13 07:49:44 +05:30
|
|
|
|
|
|
|
err = send_conn_le_param_update(conn, param);
|
|
|
|
if (!err) {
|
|
|
|
atomic_set_bit(conn->flags,
|
|
|
|
BT_CONN_PERIPHERAL_PARAM_AUTO_UPDATE);
|
|
|
|
} else {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Send auto LE param update failed (err %d)",
|
2022-10-13 07:49:44 +05:30
|
|
|
err);
|
|
|
|
}
|
2021-06-22 15:32:51 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2021-09-17 13:49:15 +02:00
|
|
|
atomic_set_bit(conn->flags, BT_CONN_PERIPHERAL_PARAM_UPDATE);
|
2021-06-22 15:32:51 +02:00
|
|
|
}
|
|
|
|
|
2021-06-22 15:31:45 +02:00
|
|
|
static struct bt_conn *acl_conn_new(void)
|
|
|
|
{
|
|
|
|
return bt_conn_new(acl_conns, ARRAY_SIZE(acl_conns));
|
|
|
|
}
|
|
|
|
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
2021-06-22 15:30:10 +02:00
|
|
|
void bt_sco_cleanup(struct bt_conn *sco_conn)
|
|
|
|
{
|
2024-02-27 15:27:59 +08:00
|
|
|
bt_sco_cleanup_acl(sco_conn);
|
2021-06-22 15:30:10 +02:00
|
|
|
bt_conn_unref(sco_conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct bt_conn *sco_conn_new(void)
|
|
|
|
{
|
|
|
|
return bt_conn_new(sco_conns, ARRAY_SIZE(sco_conns));
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_conn *bt_conn_create_br(const bt_addr_t *peer,
|
|
|
|
const struct bt_br_conn_param *param)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_connect *cp;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_addr_br(peer);
|
|
|
|
if (conn) {
|
|
|
|
switch (conn->state) {
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_INITIATING:
|
2021-06-22 15:30:10 +02:00
|
|
|
case BT_CONN_CONNECTED:
|
|
|
|
return conn;
|
|
|
|
default:
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
conn = bt_conn_add_br(peer);
|
|
|
|
if (!conn) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_CONNECT, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
|
|
|
|
(void)memset(cp, 0, sizeof(*cp));
|
|
|
|
|
|
|
|
memcpy(&cp->bdaddr, peer, sizeof(cp->bdaddr));
|
|
|
|
cp->packet_type = sys_cpu_to_le16(0xcc18); /* DM1 DH1 DM3 DH5 DM5 DH5 */
|
|
|
|
cp->pscan_rep_mode = 0x02; /* R2 */
|
|
|
|
cp->allow_role_switch = param->allow_role_switch ? 0x01 : 0x00;
|
|
|
|
cp->clock_offset = 0x0000; /* TODO used cached clock offset */
|
|
|
|
|
|
|
|
if (bt_hci_cmd_send_sync(BT_HCI_OP_CONNECT, buf, NULL) < 0) {
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-04-19 12:30:54 +02:00
|
|
|
bt_conn_set_state(conn, BT_CONN_INITIATING);
|
2021-09-14 12:28:45 +02:00
|
|
|
conn->role = BT_CONN_ROLE_CENTRAL;
|
2021-06-22 15:30:10 +02:00
|
|
|
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_conn *bt_conn_lookup_addr_sco(const bt_addr_t *peer)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(sco_conns); i++) {
|
|
|
|
struct bt_conn *conn = bt_conn_ref(&sco_conns[i]);
|
|
|
|
|
|
|
|
if (!conn) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->type != BT_CONN_TYPE_SCO) {
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-05-08 14:09:45 +02:00
|
|
|
if (!bt_addr_eq(peer, &conn->sco.acl->br.dst)) {
|
2021-06-22 15:30:10 +02:00
|
|
|
bt_conn_unref(conn);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_conn *bt_conn_lookup_addr_br(const bt_addr_t *peer)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(acl_conns); i++) {
|
|
|
|
struct bt_conn *conn = bt_conn_ref(&acl_conns[i]);
|
|
|
|
|
|
|
|
if (!conn) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->type != BT_CONN_TYPE_BR) {
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-05-08 14:09:45 +02:00
|
|
|
if (!bt_addr_eq(peer, &conn->br.dst)) {
|
2021-06-22 15:30:10 +02:00
|
|
|
bt_conn_unref(conn);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_conn *bt_conn_add_sco(const bt_addr_t *peer, int link_type)
|
|
|
|
{
|
|
|
|
struct bt_conn *sco_conn = sco_conn_new();
|
|
|
|
|
|
|
|
if (!sco_conn) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sco_conn->sco.acl = bt_conn_lookup_addr_br(peer);
|
2023-02-03 14:07:12 +01:00
|
|
|
if (!sco_conn->sco.acl) {
|
|
|
|
bt_conn_unref(sco_conn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-06-22 15:30:10 +02:00
|
|
|
sco_conn->type = BT_CONN_TYPE_SCO;
|
|
|
|
|
|
|
|
if (link_type == BT_HCI_SCO) {
|
|
|
|
if (BT_FEAT_LMP_ESCO_CAPABLE(bt_dev.features)) {
|
|
|
|
sco_conn->sco.pkt_type = (bt_dev.br.esco_pkt_type &
|
|
|
|
ESCO_PKT_MASK);
|
|
|
|
} else {
|
|
|
|
sco_conn->sco.pkt_type = (bt_dev.br.esco_pkt_type &
|
|
|
|
SCO_PKT_MASK);
|
|
|
|
}
|
|
|
|
} else if (link_type == BT_HCI_ESCO) {
|
|
|
|
sco_conn->sco.pkt_type = (bt_dev.br.esco_pkt_type &
|
|
|
|
~EDR_ESCO_PKT_MASK);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sco_conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_conn *bt_conn_add_br(const bt_addr_t *peer)
|
|
|
|
{
|
|
|
|
struct bt_conn *conn = acl_conn_new();
|
|
|
|
|
|
|
|
if (!conn) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_addr_copy(&conn->br.dst, peer);
|
|
|
|
conn->type = BT_CONN_TYPE_BR;
|
2023-07-21 10:22:32 +02:00
|
|
|
conn->tx_data_pull = l2cap_br_data_pull;
|
|
|
|
conn->get_and_clear_cb = acl_get_and_clear_cb;
|
|
|
|
conn->has_data = acl_has_data;
|
2021-06-22 15:30:10 +02:00
|
|
|
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bt_hci_connect_br_cancel(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_connect_cancel *cp;
|
|
|
|
struct bt_hci_rp_connect_cancel *rp;
|
|
|
|
struct net_buf *buf, *rsp;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_CONNECT_CANCEL, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
memcpy(&cp->bdaddr, &conn->br.dst, sizeof(cp->bdaddr));
|
|
|
|
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_CONNECT_CANCEL, buf, &rsp);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
rp = (void *)rsp->data;
|
|
|
|
|
|
|
|
err = rp->status ? -EIO : 0;
|
|
|
|
|
|
|
|
net_buf_unref(rsp);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2024-03-01 18:45:44 +08:00
|
|
|
#endif /* CONFIG_BT_CLASSIC */
|
2021-06-22 15:30:10 +02:00
|
|
|
|
2021-06-22 15:28:41 +02:00
|
|
|
#if defined(CONFIG_BT_SMP)
|
2023-03-27 14:40:42 +02:00
|
|
|
bool bt_conn_ltk_present(const struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
const struct bt_keys *keys = conn->le.keys;
|
|
|
|
|
2023-03-29 12:04:24 +02:00
|
|
|
if (!keys) {
|
|
|
|
keys = bt_keys_find_addr(conn->id, &conn->le.dst);
|
|
|
|
}
|
|
|
|
|
2023-03-27 14:40:42 +02:00
|
|
|
if (keys) {
|
|
|
|
if (conn->role == BT_HCI_ROLE_CENTRAL) {
|
|
|
|
return keys->keys & (BT_KEYS_LTK_P256 | BT_KEYS_PERIPH_LTK);
|
|
|
|
} else {
|
|
|
|
return keys->keys & (BT_KEYS_LTK_P256 | BT_KEYS_LTK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-06-22 15:28:41 +02:00
|
|
|
void bt_conn_identity_resolved(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
const bt_addr_le_t *rpa;
|
|
|
|
|
2021-09-16 10:43:02 +02:00
|
|
|
if (conn->role == BT_HCI_ROLE_CENTRAL) {
|
2021-06-22 15:28:41 +02:00
|
|
|
rpa = &conn->le.resp_addr;
|
|
|
|
} else {
|
|
|
|
rpa = &conn->le.init_addr;
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:30:04 +02:00
|
|
|
|
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
2024-06-10 14:30:04 +02:00
|
|
|
if (callback->identity_resolved) {
|
|
|
|
callback->identity_resolved(conn, rpa, &conn->le.dst);
|
2021-06-22 15:28:41 +02:00
|
|
|
}
|
|
|
|
}
|
2021-06-09 23:52:33 -07:00
|
|
|
|
2021-08-04 23:05:54 +01:00
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb) {
|
2021-06-09 23:52:33 -07:00
|
|
|
if (cb->identity_resolved) {
|
|
|
|
cb->identity_resolved(conn, rpa, &conn->le.dst);
|
|
|
|
}
|
|
|
|
}
|
2021-06-22 15:28:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int bt_conn_le_start_encryption(struct bt_conn *conn, uint8_t rand[8],
|
|
|
|
uint8_t ediv[2], const uint8_t *ltk, size_t len)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_le_start_encryption *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
2023-07-17 11:06:06 -07:00
|
|
|
if (len > sizeof(cp->ltk)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-06-22 15:28:41 +02:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_START_ENCRYPTION, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = sys_cpu_to_le16(conn->handle);
|
|
|
|
memcpy(&cp->rand, rand, sizeof(cp->rand));
|
|
|
|
memcpy(&cp->ediv, ediv, sizeof(cp->ediv));
|
|
|
|
|
|
|
|
memcpy(cp->ltk, ltk, len);
|
|
|
|
if (len < sizeof(cp->ltk)) {
|
|
|
|
(void)memset(cp->ltk + len, 0, sizeof(cp->ltk) - len);
|
|
|
|
}
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_START_ENCRYPTION, buf, NULL);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_SMP */
|
|
|
|
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_CLASSIC)
|
2022-07-12 09:47:46 +02:00
|
|
|
uint8_t bt_conn_enc_key_size(const struct bt_conn *conn)
|
2021-06-22 15:28:41 +02:00
|
|
|
{
|
|
|
|
if (!conn->encrypt) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-03-01 18:45:44 +08:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CLASSIC) &&
|
2021-06-22 15:28:41 +02:00
|
|
|
conn->type == BT_CONN_TYPE_BR) {
|
|
|
|
struct bt_hci_cp_read_encryption_key_size *cp;
|
|
|
|
struct bt_hci_rp_read_encryption_key_size *rp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
struct net_buf *rsp;
|
|
|
|
uint8_t key_size;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE,
|
|
|
|
sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = sys_cpu_to_le16(conn->handle);
|
|
|
|
|
|
|
|
if (bt_hci_cmd_send_sync(BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE,
|
|
|
|
buf, &rsp)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
rp = (void *)rsp->data;
|
|
|
|
|
|
|
|
key_size = rp->status ? 0 : rp->key_size;
|
|
|
|
|
|
|
|
net_buf_unref(rsp);
|
|
|
|
|
|
|
|
return key_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_SMP)) {
|
|
|
|
return conn->le.keys ? conn->le.keys->enc_size : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void reset_pairing(struct bt_conn *conn)
|
|
|
|
{
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
2021-06-22 15:28:41 +02:00
|
|
|
if (conn->type == BT_CONN_TYPE_BR) {
|
|
|
|
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);
|
|
|
|
}
|
2024-03-01 18:45:44 +08:00
|
|
|
#endif /* CONFIG_BT_CLASSIC */
|
2021-06-22 15:28:41 +02:00
|
|
|
|
|
|
|
/* Reset required security level to current operational */
|
|
|
|
conn->required_sec_level = conn->sec_level;
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_conn_security_changed(struct bt_conn *conn, uint8_t hci_err,
|
|
|
|
enum bt_security_err err)
|
|
|
|
{
|
|
|
|
reset_pairing(conn);
|
|
|
|
bt_l2cap_security_changed(conn, hci_err);
|
2021-12-21 16:52:51 +01:00
|
|
|
if (IS_ENABLED(CONFIG_BT_ISO_CENTRAL)) {
|
|
|
|
bt_iso_security_changed(conn, hci_err);
|
|
|
|
}
|
2021-06-22 15:28:41 +02:00
|
|
|
|
2024-06-10 14:30:04 +02:00
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
2024-06-10 14:30:04 +02:00
|
|
|
if (callback->security_changed) {
|
|
|
|
callback->security_changed(conn, conn->sec_level, err);
|
2021-06-22 15:28:41 +02:00
|
|
|
}
|
|
|
|
}
|
2021-06-09 23:52:33 -07:00
|
|
|
|
2021-08-04 23:05:54 +01:00
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb) {
|
2021-06-09 23:52:33 -07:00
|
|
|
if (cb->security_changed) {
|
|
|
|
cb->security_changed(conn, conn->sec_level, err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-19 17:11:01 +01:00
|
|
|
#if defined(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
2021-06-22 15:28:41 +02:00
|
|
|
if (!err && conn->sec_level >= BT_SECURITY_L2) {
|
|
|
|
if (conn->type == BT_CONN_TYPE_LE) {
|
|
|
|
bt_keys_update_usage(conn->id, bt_conn_get_dst(conn));
|
|
|
|
}
|
|
|
|
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
2021-06-22 15:28:41 +02:00
|
|
|
if (conn->type == BT_CONN_TYPE_BR) {
|
|
|
|
bt_keys_link_key_update_usage(&conn->br.dst);
|
|
|
|
}
|
2024-03-01 18:45:44 +08:00
|
|
|
#endif /* CONFIG_BT_CLASSIC */
|
2021-06-22 15:28:41 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static int start_security(struct bt_conn *conn)
|
|
|
|
{
|
2024-03-01 18:45:44 +08:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CLASSIC) && conn->type == BT_CONN_TYPE_BR) {
|
2021-06-22 15:28:41 +02:00
|
|
|
return bt_ssp_start_security(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_SMP)) {
|
|
|
|
return bt_smp_start_security(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_conn_set_security(struct bt_conn *conn, bt_security_t sec)
|
|
|
|
{
|
2023-10-04 20:29:11 +11:00
|
|
|
bool force_pair;
|
2021-06-22 15:28:41 +02:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (conn->state != BT_CONN_CONNECTED) {
|
|
|
|
return -ENOTCONN;
|
|
|
|
}
|
|
|
|
|
2023-10-04 20:29:11 +11:00
|
|
|
force_pair = sec & BT_SECURITY_FORCE_PAIR;
|
|
|
|
sec &= ~BT_SECURITY_FORCE_PAIR;
|
|
|
|
|
2021-06-22 15:28:41 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_SMP_SC_ONLY)) {
|
|
|
|
sec = BT_SECURITY_L4;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)) {
|
|
|
|
sec = BT_SECURITY_L3;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* nothing to do */
|
2023-10-04 20:29:11 +11:00
|
|
|
if (!force_pair && (conn->sec_level >= sec || conn->required_sec_level >= sec)) {
|
2021-06-22 15:28:41 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-10-04 20:29:11 +11:00
|
|
|
atomic_set_bit_to(conn->flags, BT_CONN_FORCE_PAIR, force_pair);
|
|
|
|
conn->required_sec_level = sec;
|
2021-06-22 15:28:41 +02:00
|
|
|
|
|
|
|
err = start_security(conn);
|
|
|
|
|
|
|
|
/* reset required security level in case of error */
|
|
|
|
if (err) {
|
|
|
|
conn->required_sec_level = conn->sec_level;
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-07-12 09:47:46 +02:00
|
|
|
bt_security_t bt_conn_get_security(const struct bt_conn *conn)
|
2021-06-22 15:28:41 +02:00
|
|
|
{
|
|
|
|
return conn->sec_level;
|
|
|
|
}
|
|
|
|
#else
|
2022-07-12 09:47:46 +02:00
|
|
|
bt_security_t bt_conn_get_security(const struct bt_conn *conn)
|
2021-06-22 15:28:41 +02:00
|
|
|
{
|
|
|
|
return BT_SECURITY_L1;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_SMP */
|
|
|
|
|
2024-06-12 13:02:13 +02:00
|
|
|
int bt_conn_cb_register(struct bt_conn_cb *cb)
|
2021-06-22 15:13:41 +02:00
|
|
|
{
|
2024-06-12 13:02:13 +02:00
|
|
|
if (sys_slist_find(&conn_cbs, &cb->_node, NULL)) {
|
|
|
|
return -EEXIST;
|
2024-06-10 14:06:27 +02:00
|
|
|
}
|
2024-06-12 13:02:13 +02:00
|
|
|
|
|
|
|
sys_slist_append(&conn_cbs, &cb->_node);
|
|
|
|
|
|
|
|
return 0;
|
2021-06-22 15:13:41 +02:00
|
|
|
}
|
|
|
|
|
2023-10-31 15:01:49 +08:00
|
|
|
int bt_conn_cb_unregister(struct bt_conn_cb *cb)
|
|
|
|
{
|
|
|
|
CHECKIF(cb == NULL) {
|
|
|
|
return -EINVAL;
|
2024-03-12 15:55:02 +01:00
|
|
|
}
|
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
if (!sys_slist_find_and_remove(&conn_cbs, &cb->_node)) {
|
2024-03-12 15:55:02 +01:00
|
|
|
return -ENOENT;
|
2023-10-31 15:01:49 +08:00
|
|
|
}
|
|
|
|
|
2024-06-10 14:30:04 +02:00
|
|
|
return 0;
|
2023-10-31 15:01:49 +08:00
|
|
|
}
|
|
|
|
|
2021-06-22 15:12:39 +02:00
|
|
|
bool bt_conn_exists_le(uint8_t id, const bt_addr_le_t *peer)
|
|
|
|
{
|
|
|
|
struct bt_conn *conn = bt_conn_lookup_addr_le(id, peer);
|
|
|
|
|
|
|
|
if (conn) {
|
|
|
|
/* Connection object already exists.
|
|
|
|
* If the connection state is not "disconnected",then the
|
|
|
|
* connection was created but has not yet been disconnected.
|
|
|
|
* If the connection state is "disconnected" then the connection
|
|
|
|
* still has valid references. The last reference of the stack
|
|
|
|
* is released after the disconnected callback.
|
|
|
|
*/
|
2023-09-14 10:22:43 +02:00
|
|
|
LOG_WRN("Found valid connection (%p) with address %s in %s state ", conn,
|
|
|
|
bt_addr_le_str(peer), state2str(conn->state));
|
2021-06-22 15:12:39 +02:00
|
|
|
bt_conn_unref(conn);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_conn *bt_conn_add_le(uint8_t id, const bt_addr_le_t *peer)
|
|
|
|
{
|
|
|
|
struct bt_conn *conn = acl_conn_new();
|
|
|
|
|
|
|
|
if (!conn) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn->id = id;
|
|
|
|
bt_addr_le_copy(&conn->le.dst, peer);
|
|
|
|
#if defined(CONFIG_BT_SMP)
|
|
|
|
conn->sec_level = BT_SECURITY_L1;
|
|
|
|
conn->required_sec_level = BT_SECURITY_L1;
|
|
|
|
#endif /* CONFIG_BT_SMP */
|
|
|
|
conn->type = BT_CONN_TYPE_LE;
|
2023-07-21 10:22:32 +02:00
|
|
|
conn->tx_data_pull = l2cap_data_pull;
|
|
|
|
conn->get_and_clear_cb = acl_get_and_clear_cb;
|
|
|
|
conn->has_data = acl_has_data;
|
2021-06-22 15:12:39 +02:00
|
|
|
conn->le.interval_min = BT_GAP_INIT_CONN_INT_MIN;
|
|
|
|
conn->le.interval_max = BT_GAP_INIT_CONN_INT_MAX;
|
|
|
|
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
2021-06-22 15:10:32 +02:00
|
|
|
bool bt_conn_is_peer_addr_le(const struct bt_conn *conn, uint8_t id,
|
|
|
|
const bt_addr_le_t *peer)
|
|
|
|
{
|
|
|
|
if (id != conn->id) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check against conn dst address as it may be the identity address */
|
2022-09-20 10:57:54 +02:00
|
|
|
if (bt_addr_le_eq(peer, &conn->le.dst)) {
|
2021-06-22 15:10:32 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check against initial connection address */
|
2021-09-16 10:43:02 +02:00
|
|
|
if (conn->role == BT_HCI_ROLE_CENTRAL) {
|
2022-09-20 11:02:15 +02:00
|
|
|
return bt_addr_le_eq(peer, &conn->le.resp_addr);
|
2021-06-22 15:10:32 +02:00
|
|
|
}
|
|
|
|
|
2022-09-20 11:02:15 +02:00
|
|
|
return bt_addr_le_eq(peer, &conn->le.init_addr);
|
2021-06-22 15:10:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_conn *bt_conn_lookup_addr_le(uint8_t id, const bt_addr_le_t *peer)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(acl_conns); i++) {
|
|
|
|
struct bt_conn *conn = bt_conn_ref(&acl_conns[i]);
|
|
|
|
|
|
|
|
if (!conn) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->type != BT_CONN_TYPE_LE) {
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bt_conn_is_peer_addr_le(conn, id, peer)) {
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_conn *bt_conn_lookup_state_le(uint8_t id, const bt_addr_le_t *peer,
|
|
|
|
const bt_conn_state_t state)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(acl_conns); i++) {
|
|
|
|
struct bt_conn *conn = bt_conn_ref(&acl_conns[i]);
|
|
|
|
|
|
|
|
if (!conn) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->type != BT_CONN_TYPE_LE) {
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (peer && !bt_conn_is_peer_addr_le(conn, id, peer)) {
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(conn->state == state && conn->id == id)) {
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-06-22 15:08:49 +02:00
|
|
|
const bt_addr_le_t *bt_conn_get_dst(const struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
return &conn->le.dst;
|
|
|
|
}
|
|
|
|
|
2022-02-07 14:41:03 +01:00
|
|
|
static enum bt_conn_state conn_internal_to_public_state(bt_conn_state_t state)
|
|
|
|
{
|
|
|
|
switch (state) {
|
|
|
|
case BT_CONN_DISCONNECTED:
|
|
|
|
case BT_CONN_DISCONNECT_COMPLETE:
|
|
|
|
return BT_CONN_STATE_DISCONNECTED;
|
2024-04-19 12:30:54 +02:00
|
|
|
case BT_CONN_SCAN_BEFORE_INITIATING:
|
|
|
|
case BT_CONN_INITIATING_FILTER_LIST:
|
|
|
|
case BT_CONN_ADV_CONNECTABLE:
|
|
|
|
case BT_CONN_ADV_DIR_CONNECTABLE:
|
|
|
|
case BT_CONN_INITIATING:
|
2022-02-07 14:41:03 +01:00
|
|
|
return BT_CONN_STATE_CONNECTING;
|
|
|
|
case BT_CONN_CONNECTED:
|
|
|
|
return BT_CONN_STATE_CONNECTED;
|
2022-02-22 15:16:34 +01:00
|
|
|
case BT_CONN_DISCONNECTING:
|
2022-02-07 14:41:03 +01:00
|
|
|
return BT_CONN_STATE_DISCONNECTING;
|
|
|
|
default:
|
|
|
|
__ASSERT(false, "Invalid conn state %u", state);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-22 15:07:56 +02:00
|
|
|
int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info)
|
|
|
|
{
|
|
|
|
info->type = conn->type;
|
|
|
|
info->role = conn->role;
|
|
|
|
info->id = conn->id;
|
2022-02-07 14:41:03 +01:00
|
|
|
info->state = conn_internal_to_public_state(conn->state);
|
2022-07-12 10:04:37 +02:00
|
|
|
info->security.flags = 0;
|
|
|
|
info->security.level = bt_conn_get_security(conn);
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_CLASSIC)
|
2022-07-12 10:04:37 +02:00
|
|
|
info->security.enc_key_size = bt_conn_enc_key_size(conn);
|
|
|
|
#else
|
|
|
|
info->security.enc_key_size = 0;
|
2024-03-01 18:45:44 +08:00
|
|
|
#endif /* CONFIG_BT_SMP || CONFIG_BT_CLASSIC */
|
2021-06-22 15:07:56 +02:00
|
|
|
|
|
|
|
switch (conn->type) {
|
|
|
|
case BT_CONN_TYPE_LE:
|
|
|
|
info->le.dst = &conn->le.dst;
|
|
|
|
info->le.src = &bt_dev.id_addr[conn->id];
|
2021-09-16 10:43:02 +02:00
|
|
|
if (conn->role == BT_HCI_ROLE_CENTRAL) {
|
2021-06-22 15:07:56 +02:00
|
|
|
info->le.local = &conn->le.init_addr;
|
|
|
|
info->le.remote = &conn->le.resp_addr;
|
|
|
|
} else {
|
|
|
|
info->le.local = &conn->le.resp_addr;
|
|
|
|
info->le.remote = &conn->le.init_addr;
|
|
|
|
}
|
|
|
|
info->le.interval = conn->le.interval;
|
|
|
|
info->le.latency = conn->le.latency;
|
|
|
|
info->le.timeout = conn->le.timeout;
|
|
|
|
#if defined(CONFIG_BT_USER_PHY_UPDATE)
|
|
|
|
info->le.phy = &conn->le.phy;
|
|
|
|
#endif
|
|
|
|
#if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
|
|
|
|
info->le.data_len = &conn->le.data_len;
|
2024-07-30 16:57:48 +01:00
|
|
|
#endif
|
|
|
|
#if defined(CONFIG_BT_SUBRATING)
|
|
|
|
info->le.subrate = &conn->le.subrate;
|
2021-06-22 15:07:56 +02:00
|
|
|
#endif
|
2022-07-12 10:04:37 +02:00
|
|
|
if (conn->le.keys && (conn->le.keys->flags & BT_KEYS_SC)) {
|
|
|
|
info->security.flags |= BT_SECURITY_FLAG_SC;
|
|
|
|
}
|
|
|
|
if (conn->le.keys && (conn->le.keys->flags & BT_KEYS_OOB)) {
|
|
|
|
info->security.flags |= BT_SECURITY_FLAG_OOB;
|
|
|
|
}
|
2021-06-22 15:07:56 +02:00
|
|
|
return 0;
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
2021-06-22 15:07:56 +02:00
|
|
|
case BT_CONN_TYPE_BR:
|
|
|
|
info->br.dst = &conn->br.dst;
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
#if defined(CONFIG_BT_ISO)
|
|
|
|
case BT_CONN_TYPE_ISO:
|
2021-11-17 14:20:53 +01:00
|
|
|
if (IS_ENABLED(CONFIG_BT_ISO_UNICAST) &&
|
2023-03-02 12:59:11 +01:00
|
|
|
conn->iso.info.type == BT_ISO_CHAN_TYPE_CONNECTED && conn->iso.acl != NULL) {
|
2021-06-22 15:07:56 +02:00
|
|
|
info->le.dst = &conn->iso.acl->le.dst;
|
|
|
|
info->le.src = &bt_dev.id_addr[conn->iso.acl->id];
|
|
|
|
} else {
|
|
|
|
info->le.src = BT_ADDR_LE_NONE;
|
|
|
|
info->le.dst = BT_ADDR_LE_NONE;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
#endif
|
2023-06-28 17:02:51 +02:00
|
|
|
default:
|
|
|
|
break;
|
2021-06-22 15:07:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_conn_get_remote_info(struct bt_conn *conn,
|
|
|
|
struct bt_conn_remote_info *remote_info)
|
|
|
|
{
|
2024-08-29 10:57:20 +02:00
|
|
|
if (!atomic_test_bit(conn->flags, BT_CONN_LE_FEATURES_EXCHANGED) ||
|
2021-06-22 15:07:56 +02:00
|
|
|
(IS_ENABLED(CONFIG_BT_REMOTE_VERSION) &&
|
|
|
|
!atomic_test_bit(conn->flags, BT_CONN_AUTO_VERSION_INFO))) {
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
remote_info->type = conn->type;
|
|
|
|
#if defined(CONFIG_BT_REMOTE_VERSION)
|
|
|
|
/* The conn->rv values will be just zeroes if the operation failed */
|
|
|
|
remote_info->version = conn->rv.version;
|
|
|
|
remote_info->manufacturer = conn->rv.manufacturer;
|
|
|
|
remote_info->subversion = conn->rv.subversion;
|
|
|
|
#else
|
|
|
|
remote_info->version = 0;
|
|
|
|
remote_info->manufacturer = 0;
|
|
|
|
remote_info->subversion = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
switch (conn->type) {
|
|
|
|
case BT_CONN_TYPE_LE:
|
|
|
|
remote_info->le.features = conn->le.features;
|
|
|
|
return 0;
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
2021-06-22 15:07:56 +02:00
|
|
|
case BT_CONN_TYPE_BR:
|
|
|
|
/* TODO: Make sure the HCI commands to read br features and
|
|
|
|
* extended features has finished. */
|
|
|
|
return -ENOTSUP;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-22 15:06:34 +02:00
|
|
|
/* Read Transmit Power Level HCI command */
|
|
|
|
static int bt_conn_get_tx_power_level(struct bt_conn *conn, uint8_t type,
|
|
|
|
int8_t *tx_power_level)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
struct bt_hci_rp_read_tx_power_level *rp;
|
|
|
|
struct net_buf *rsp;
|
|
|
|
struct bt_hci_cp_read_tx_power_level *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_READ_TX_POWER_LEVEL, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->type = type;
|
|
|
|
cp->handle = sys_cpu_to_le16(conn->handle);
|
|
|
|
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_TX_POWER_LEVEL, buf, &rsp);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
rp = (void *) rsp->data;
|
|
|
|
*tx_power_level = rp->tx_power_level;
|
|
|
|
net_buf_unref(rsp);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-11-16 09:09:26 +01:00
|
|
|
#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL)
|
|
|
|
void notify_tx_power_report(struct bt_conn *conn,
|
|
|
|
struct bt_conn_le_tx_power_report report)
|
|
|
|
{
|
2024-06-10 14:30:04 +02:00
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
2024-06-10 14:30:04 +02:00
|
|
|
if (callback->tx_power_report) {
|
|
|
|
callback->tx_power_report(conn, &report);
|
2023-11-16 09:09:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb)
|
|
|
|
{
|
|
|
|
if (cb->tx_power_report) {
|
|
|
|
cb->tx_power_report(conn, &report);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_conn_le_enhanced_get_tx_power_level(struct bt_conn *conn,
|
|
|
|
struct bt_conn_le_tx_power *tx_power)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
struct bt_hci_rp_le_read_tx_power_level *rp;
|
|
|
|
struct net_buf *rsp;
|
|
|
|
struct bt_hci_cp_le_read_tx_power_level *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
if (!tx_power->phy) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_ENH_READ_TX_POWER_LEVEL, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = sys_cpu_to_le16(conn->handle);
|
|
|
|
cp->phy = tx_power->phy;
|
|
|
|
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_ENH_READ_TX_POWER_LEVEL, buf, &rsp);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
rp = (void *) rsp->data;
|
|
|
|
tx_power->phy = rp->phy;
|
|
|
|
tx_power->current_level = rp->current_tx_power_level;
|
|
|
|
tx_power->max_level = rp->max_tx_power_level;
|
|
|
|
net_buf_unref(rsp);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_conn_le_get_remote_tx_power_level(struct bt_conn *conn,
|
|
|
|
enum bt_conn_le_tx_power_phy phy)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_le_read_tx_power_level *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
if (!phy) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_READ_REMOTE_TX_POWER_LEVEL, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = sys_cpu_to_le16(conn->handle);
|
|
|
|
cp->phy = phy;
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_REMOTE_TX_POWER_LEVEL, buf, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_conn_le_set_tx_power_report_enable(struct bt_conn *conn,
|
|
|
|
bool local_enable,
|
|
|
|
bool remote_enable)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_le_set_tx_power_report_enable *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_TX_POWER_REPORT_ENABLE, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = sys_cpu_to_le16(conn->handle);
|
|
|
|
cp->local_enable = local_enable ? BT_HCI_LE_TX_POWER_REPORT_ENABLE :
|
|
|
|
BT_HCI_LE_TX_POWER_REPORT_DISABLE;
|
|
|
|
cp->remote_enable = remote_enable ? BT_HCI_LE_TX_POWER_REPORT_ENABLE :
|
|
|
|
BT_HCI_LE_TX_POWER_REPORT_DISABLE;
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_TX_POWER_REPORT_ENABLE, buf, NULL);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_TRANSMIT_POWER_CONTROL */
|
|
|
|
|
2021-06-22 15:06:34 +02:00
|
|
|
int bt_conn_le_get_tx_power_level(struct bt_conn *conn,
|
|
|
|
struct bt_conn_le_tx_power *tx_power_level)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (tx_power_level->phy != 0) {
|
2023-11-16 09:09:26 +01:00
|
|
|
if (IS_ENABLED(CONFIG_BT_TRANSMIT_POWER_CONTROL)) {
|
|
|
|
return bt_conn_le_enhanced_get_tx_power_level(conn, tx_power_level);
|
|
|
|
} else {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
2021-06-22 15:06:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
err = bt_conn_get_tx_power_level(conn, BT_TX_POWER_LEVEL_CURRENT,
|
|
|
|
&tx_power_level->current_level);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bt_conn_get_tx_power_level(conn, BT_TX_POWER_LEVEL_MAX,
|
|
|
|
&tx_power_level->max_level);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2024-06-04 10:33:43 +01:00
|
|
|
#if defined(CONFIG_BT_PATH_LOSS_MONITORING)
|
|
|
|
void notify_path_loss_threshold_report(struct bt_conn *conn,
|
|
|
|
struct bt_conn_le_path_loss_threshold_report report)
|
|
|
|
{
|
2024-06-10 14:30:04 +02:00
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
2024-07-22 15:52:04 +01:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
2024-06-10 14:30:04 +02:00
|
|
|
if (callback->path_loss_threshold_report) {
|
|
|
|
callback->path_loss_threshold_report(conn, &report);
|
2024-06-04 10:33:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb)
|
|
|
|
{
|
|
|
|
if (cb->path_loss_threshold_report) {
|
|
|
|
cb->path_loss_threshold_report(conn, &report);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_conn_le_set_path_loss_mon_param(struct bt_conn *conn,
|
|
|
|
const struct bt_conn_le_path_loss_reporting_param *params)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_le_set_path_loss_reporting_parameters *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_PATH_LOSS_REPORTING_PARAMETERS, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = sys_cpu_to_le16(conn->handle);
|
|
|
|
cp->high_threshold = params->high_threshold;
|
|
|
|
cp->high_hysteresis = params->high_hysteresis;
|
|
|
|
cp->low_threshold = params->low_threshold;
|
|
|
|
cp->low_hysteresis = params->low_hysteresis;
|
|
|
|
cp->min_time_spent = sys_cpu_to_le16(params->min_time_spent);
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_PATH_LOSS_REPORTING_PARAMETERS, buf, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_conn_le_set_path_loss_mon_enable(struct bt_conn *conn, bool reporting_enable)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_le_set_path_loss_reporting_enable *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_PATH_LOSS_REPORTING_ENABLE, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = sys_cpu_to_le16(conn->handle);
|
|
|
|
cp->enable = reporting_enable ? BT_HCI_LE_PATH_LOSS_REPORTING_ENABLE :
|
|
|
|
BT_HCI_LE_PATH_LOSS_REPORTING_DISABLE;
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_PATH_LOSS_REPORTING_ENABLE, buf, NULL);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_PATH_LOSS_MONITORING */
|
|
|
|
|
2024-07-30 16:57:48 +01:00
|
|
|
#if defined(CONFIG_BT_SUBRATING)
|
|
|
|
void notify_subrate_change(struct bt_conn *conn,
|
|
|
|
const struct bt_conn_le_subrate_changed params)
|
|
|
|
{
|
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
|
|
|
if (callback->subrate_changed) {
|
|
|
|
callback->subrate_changed(conn, ¶ms);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb)
|
|
|
|
{
|
|
|
|
if (cb->subrate_changed) {
|
|
|
|
cb->subrate_changed(conn, ¶ms);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool le_subrate_common_params_valid(const struct bt_conn_le_subrate_param *param)
|
|
|
|
{
|
|
|
|
/* All limits according to BT Core spec 5.4 [Vol 4, Part E, 7.8.123] */
|
|
|
|
|
|
|
|
if (param->subrate_min < 0x0001 || param->subrate_min > 0x01F4 ||
|
|
|
|
param->subrate_max < 0x0001 || param->subrate_max > 0x01F4 ||
|
|
|
|
param->subrate_min > param->subrate_max) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (param->max_latency > 0x01F3 ||
|
|
|
|
param->subrate_max * (param->max_latency + 1) > 500) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (param->continuation_number > 0x01F3 ||
|
|
|
|
param->continuation_number >= param->subrate_max) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (param->supervision_timeout < 0x000A ||
|
|
|
|
param->supervision_timeout > 0xC80) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_conn_le_subrate_set_defaults(const struct bt_conn_le_subrate_param *params)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_le_set_default_subrate *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
if (!IS_ENABLED(CONFIG_BT_CENTRAL)) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!le_subrate_common_params_valid(params)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_DEFAULT_SUBRATE, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->subrate_min = sys_cpu_to_le16(params->subrate_min);
|
|
|
|
cp->subrate_max = sys_cpu_to_le16(params->subrate_max);
|
|
|
|
cp->max_latency = sys_cpu_to_le16(params->max_latency);
|
|
|
|
cp->continuation_number = sys_cpu_to_le16(params->continuation_number);
|
|
|
|
cp->supervision_timeout = sys_cpu_to_le16(params->supervision_timeout);
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_DEFAULT_SUBRATE, buf, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_conn_le_subrate_request(struct bt_conn *conn,
|
|
|
|
const struct bt_conn_le_subrate_param *params)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_le_subrate_request *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
if (!le_subrate_common_params_valid(params)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SUBRATE_REQUEST, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = sys_cpu_to_le16(conn->handle);
|
|
|
|
cp->subrate_min = sys_cpu_to_le16(params->subrate_min);
|
|
|
|
cp->subrate_max = sys_cpu_to_le16(params->subrate_max);
|
|
|
|
cp->max_latency = sys_cpu_to_le16(params->max_latency);
|
|
|
|
cp->continuation_number = sys_cpu_to_le16(params->continuation_number);
|
|
|
|
cp->supervision_timeout = sys_cpu_to_le16(params->supervision_timeout);
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SUBRATE_REQUEST, buf, NULL);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_SUBRATING */
|
|
|
|
|
2021-06-22 15:04:04 +02:00
|
|
|
int bt_conn_le_param_update(struct bt_conn *conn,
|
|
|
|
const struct bt_le_conn_param *param)
|
|
|
|
{
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("conn %p features 0x%02x params (%d-%d %d %d)", conn, conn->le.features[0],
|
|
|
|
param->interval_min, param->interval_max, param->latency, param->timeout);
|
2021-06-22 15:04:04 +02:00
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
|
2021-09-14 12:28:45 +02:00
|
|
|
conn->role == BT_CONN_ROLE_CENTRAL) {
|
2021-06-22 15:04:04 +02:00
|
|
|
return send_conn_le_param_update(conn, param);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_PERIPHERAL)) {
|
2021-09-17 13:49:15 +02:00
|
|
|
/* if peripheral conn param update timer expired just send request */
|
|
|
|
if (atomic_test_bit(conn->flags, BT_CONN_PERIPHERAL_PARAM_UPDATE)) {
|
2021-06-22 15:04:04 +02:00
|
|
|
return send_conn_le_param_update(conn, param);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* store new conn params to be used by update timer */
|
|
|
|
conn->le.interval_min = param->interval_min;
|
|
|
|
conn->le.interval_max = param->interval_max;
|
|
|
|
conn->le.pending_latency = param->latency;
|
|
|
|
conn->le.pending_timeout = param->timeout;
|
2021-09-17 13:49:15 +02:00
|
|
|
atomic_set_bit(conn->flags, BT_CONN_PERIPHERAL_PARAM_SET);
|
2021-06-22 15:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-06-22 15:03:21 +02:00
|
|
|
#if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
|
|
|
|
int bt_conn_le_data_len_update(struct bt_conn *conn,
|
|
|
|
const struct bt_conn_le_data_len_param *param)
|
|
|
|
{
|
|
|
|
if (conn->le.data_len.tx_max_len == param->tx_max_len &&
|
|
|
|
conn->le.data_len.tx_max_time == param->tx_max_time) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bt_le_set_data_len(conn, param->tx_max_len, param->tx_max_time);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_USER_DATA_LEN_UPDATE */
|
|
|
|
|
2021-06-22 15:02:39 +02:00
|
|
|
#if defined(CONFIG_BT_USER_PHY_UPDATE)
|
|
|
|
int bt_conn_le_phy_update(struct bt_conn *conn,
|
|
|
|
const struct bt_conn_le_phy_param *param)
|
|
|
|
{
|
|
|
|
uint8_t phy_opts, all_phys;
|
|
|
|
|
|
|
|
if ((param->options & BT_CONN_LE_PHY_OPT_CODED_S2) &&
|
|
|
|
(param->options & BT_CONN_LE_PHY_OPT_CODED_S8)) {
|
|
|
|
phy_opts = BT_HCI_LE_PHY_CODED_ANY;
|
|
|
|
} else if (param->options & BT_CONN_LE_PHY_OPT_CODED_S2) {
|
|
|
|
phy_opts = BT_HCI_LE_PHY_CODED_S2;
|
|
|
|
} else if (param->options & BT_CONN_LE_PHY_OPT_CODED_S8) {
|
|
|
|
phy_opts = BT_HCI_LE_PHY_CODED_S8;
|
|
|
|
} else {
|
|
|
|
phy_opts = BT_HCI_LE_PHY_CODED_ANY;
|
|
|
|
}
|
|
|
|
|
|
|
|
all_phys = 0U;
|
|
|
|
if (param->pref_tx_phy == BT_GAP_LE_PHY_NONE) {
|
|
|
|
all_phys |= BT_HCI_LE_PHY_TX_ANY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (param->pref_rx_phy == BT_GAP_LE_PHY_NONE) {
|
|
|
|
all_phys |= BT_HCI_LE_PHY_RX_ANY;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bt_le_set_phy(conn, all_phys, param->pref_tx_phy,
|
|
|
|
param->pref_rx_phy, phy_opts);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_CENTRAL)
|
2016-05-03 13:03:44 +03:00
|
|
|
static void bt_conn_set_param_le(struct bt_conn *conn,
|
|
|
|
const struct bt_le_conn_param *param)
|
|
|
|
{
|
2019-08-14 10:11:20 +02:00
|
|
|
conn->le.interval_min = param->interval_min;
|
2016-05-03 13:03:44 +03:00
|
|
|
conn->le.interval_max = param->interval_max;
|
|
|
|
conn->le.latency = param->latency;
|
|
|
|
conn->le.timeout = param->timeout;
|
|
|
|
}
|
|
|
|
|
2020-03-30 19:23:16 +10:00
|
|
|
static void create_param_setup(const struct bt_conn_le_create_param *param)
|
|
|
|
{
|
|
|
|
bt_dev.create_param = *param;
|
|
|
|
|
|
|
|
bt_dev.create_param.timeout =
|
|
|
|
(bt_dev.create_param.timeout != 0) ?
|
|
|
|
bt_dev.create_param.timeout :
|
|
|
|
(MSEC_PER_SEC / 10) * CONFIG_BT_CREATE_CONN_TIMEOUT;
|
|
|
|
|
|
|
|
bt_dev.create_param.interval_coded =
|
|
|
|
(bt_dev.create_param.interval_coded != 0) ?
|
|
|
|
bt_dev.create_param.interval_coded :
|
|
|
|
bt_dev.create_param.interval;
|
|
|
|
|
|
|
|
bt_dev.create_param.window_coded =
|
|
|
|
(bt_dev.create_param.window_coded != 0) ?
|
|
|
|
bt_dev.create_param.window_coded :
|
|
|
|
bt_dev.create_param.window;
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:28:45 +02:00
|
|
|
#if defined(CONFIG_BT_FILTER_ACCEPT_LIST)
|
2020-02-01 18:13:05 +01:00
|
|
|
int bt_conn_le_create_auto(const struct bt_conn_le_create_param *create_param,
|
|
|
|
const struct bt_le_conn_param *param)
|
2019-07-22 13:13:38 +02:00
|
|
|
{
|
|
|
|
struct bt_conn *conn;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
|
2020-01-13 14:43:09 +01:00
|
|
|
return -EAGAIN;
|
2019-07-22 13:13:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!bt_le_conn_params_valid(param)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-02-19 18:48:53 +01:00
|
|
|
conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, BT_ADDR_LE_NONE,
|
2024-04-19 12:30:54 +02:00
|
|
|
BT_CONN_INITIATING_FILTER_LIST);
|
2020-01-15 13:10:54 +01:00
|
|
|
if (conn) {
|
|
|
|
bt_conn_unref(conn);
|
2019-07-22 13:13:38 +02:00
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
2020-01-15 13:10:54 +01:00
|
|
|
/* Scanning either to connect or explicit scan, either case scanner was
|
|
|
|
* started by application and should not be stopped.
|
|
|
|
*/
|
2024-04-30 15:35:20 +02:00
|
|
|
if (!BT_LE_STATES_SCAN_INIT(bt_dev.le.states) &&
|
|
|
|
atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) {
|
2019-07-22 13:13:38 +02:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-01-15 13:10:54 +01:00
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING)) {
|
2019-07-22 13:13:38 +02:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-03-08 14:24:34 +01:00
|
|
|
if (!bt_id_scan_random_addr_check()) {
|
2019-12-29 18:47:53 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-01-07 12:40:30 +01:00
|
|
|
conn = bt_conn_add_le(BT_ID_DEFAULT, BT_ADDR_LE_NONE);
|
|
|
|
if (!conn) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2020-01-15 13:10:54 +01:00
|
|
|
bt_conn_set_param_le(conn, param);
|
2020-03-30 19:23:16 +10:00
|
|
|
create_param_setup(create_param);
|
2020-02-03 12:37:29 +01:00
|
|
|
|
|
|
|
atomic_set_bit(conn->flags, BT_CONN_AUTO_CONNECT);
|
2024-04-19 12:30:54 +02:00
|
|
|
bt_conn_set_state(conn, BT_CONN_INITIATING_FILTER_LIST);
|
2020-01-07 12:40:30 +01:00
|
|
|
|
2020-01-15 13:10:54 +01:00
|
|
|
err = bt_le_create_conn(conn);
|
2019-07-22 13:13:38 +02:00
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Failed to start filtered scan");
|
2020-01-31 14:04:31 +01:00
|
|
|
conn->err = 0;
|
2020-01-07 12:40:30 +01:00
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
|
|
|
bt_conn_unref(conn);
|
2019-07-22 13:13:38 +02:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-01-07 12:40:30 +01:00
|
|
|
/* Since we don't give the application a reference to manage in
|
|
|
|
* this case, we need to release this reference here.
|
|
|
|
*/
|
|
|
|
bt_conn_unref(conn);
|
2019-07-22 13:13:38 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_conn_create_auto_stop(void)
|
|
|
|
{
|
2020-01-07 12:40:30 +01:00
|
|
|
struct bt_conn *conn;
|
2019-11-21 17:49:55 +01:00
|
|
|
int err;
|
|
|
|
|
2019-07-22 13:13:38 +02:00
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-02-19 18:48:53 +01:00
|
|
|
conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, BT_ADDR_LE_NONE,
|
2024-04-19 12:30:54 +02:00
|
|
|
BT_CONN_INITIATING_FILTER_LIST);
|
2020-01-15 13:10:54 +01:00
|
|
|
if (!conn) {
|
2019-07-22 13:13:38 +02:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-01-15 13:10:54 +01:00
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING)) {
|
|
|
|
return -EINVAL;
|
2020-01-07 12:40:30 +01:00
|
|
|
}
|
|
|
|
|
2020-01-15 13:10:54 +01:00
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
|
|
|
|
err = bt_le_create_conn_cancel();
|
2019-07-22 13:13:38 +02:00
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Failed to stop initiator");
|
2019-07-22 13:13:38 +02:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2021-09-14 12:28:45 +02:00
|
|
|
#endif /* defined(CONFIG_BT_FILTER_ACCEPT_LIST) */
|
2019-07-22 13:13:38 +02:00
|
|
|
|
2023-03-30 14:06:14 +02:00
|
|
|
static int conn_le_create_common_checks(const bt_addr_le_t *peer,
|
|
|
|
const struct bt_le_conn_param *conn_param)
|
2015-07-15 13:55:32 +03:00
|
|
|
{
|
|
|
|
|
2019-03-22 12:48:32 +02:00
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
|
2024-06-03 12:49:05 +02:00
|
|
|
LOG_DBG("Conn check failed: BT dev not ready.");
|
2020-02-01 18:13:05 +01:00
|
|
|
return -EAGAIN;
|
2019-03-22 12:48:32 +02:00
|
|
|
}
|
|
|
|
|
2020-02-01 18:13:05 +01:00
|
|
|
if (!bt_le_conn_params_valid(conn_param)) {
|
2024-06-03 12:49:05 +02:00
|
|
|
LOG_DBG("Conn check failed: invalid parameters.");
|
2020-02-01 18:13:05 +01:00
|
|
|
return -EINVAL;
|
2015-12-05 22:47:23 +02:00
|
|
|
}
|
|
|
|
|
2024-06-03 12:49:05 +02:00
|
|
|
if (!BT_LE_STATES_SCAN_INIT(bt_dev.le.states) && bt_le_explicit_scanner_running()) {
|
|
|
|
LOG_DBG("Conn check failed: scanner was explicitly requested.");
|
2021-03-17 11:22:20 +01:00
|
|
|
return -EAGAIN;
|
2015-12-03 19:45:46 +02:00
|
|
|
}
|
|
|
|
|
2020-01-15 13:10:54 +01:00
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING)) {
|
2024-06-03 12:49:05 +02:00
|
|
|
LOG_DBG("Conn check failed: device is already initiating.");
|
2020-02-01 18:13:05 +01:00
|
|
|
return -EALREADY;
|
2019-07-22 13:13:38 +02:00
|
|
|
}
|
|
|
|
|
2021-03-08 14:24:34 +01:00
|
|
|
if (!bt_id_scan_random_addr_check()) {
|
2024-06-03 12:49:05 +02:00
|
|
|
LOG_DBG("Conn check failed: invalid random address.");
|
2020-02-01 18:13:05 +01:00
|
|
|
return -EINVAL;
|
2019-12-29 18:47:53 +01:00
|
|
|
}
|
|
|
|
|
2020-04-09 20:06:02 +02:00
|
|
|
if (bt_conn_exists_le(BT_ID_DEFAULT, peer)) {
|
2024-06-03 12:49:05 +02:00
|
|
|
LOG_DBG("Conn check failed: ACL connection already exists.");
|
2020-02-01 18:13:05 +01:00
|
|
|
return -EINVAL;
|
2015-07-15 13:55:32 +03:00
|
|
|
}
|
|
|
|
|
2023-03-30 14:06:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct bt_conn *conn_le_create_helper(const bt_addr_le_t *peer,
|
|
|
|
const struct bt_le_conn_param *conn_param)
|
|
|
|
{
|
|
|
|
bt_addr_le_t dst;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
2023-01-11 17:40:02 +01:00
|
|
|
if (bt_addr_le_is_resolved(peer)) {
|
|
|
|
bt_addr_le_copy_resolved(&dst, peer);
|
2019-08-02 16:04:01 +02:00
|
|
|
} else {
|
|
|
|
bt_addr_le_copy(&dst, bt_lookup_id_addr(BT_ID_DEFAULT, peer));
|
|
|
|
}
|
|
|
|
|
2019-09-11 13:40:50 +03:00
|
|
|
/* Only default identity supported for now */
|
|
|
|
conn = bt_conn_add_le(BT_ID_DEFAULT, &dst);
|
2015-07-15 13:55:32 +03:00
|
|
|
if (!conn) {
|
2023-03-30 14:06:14 +02:00
|
|
|
return NULL;
|
2015-07-15 13:55:32 +03:00
|
|
|
}
|
|
|
|
|
2020-02-01 18:13:05 +01:00
|
|
|
bt_conn_set_param_le(conn, conn_param);
|
2023-03-30 14:06:14 +02:00
|
|
|
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_conn_le_create(const bt_addr_le_t *peer, const struct bt_conn_le_create_param *create_param,
|
|
|
|
const struct bt_le_conn_param *conn_param, struct bt_conn **ret_conn)
|
|
|
|
{
|
|
|
|
struct bt_conn *conn;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = conn_le_create_common_checks(peer, conn_param);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn = conn_le_create_helper(peer, conn_param);
|
|
|
|
if (!conn) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2020-03-30 19:23:16 +10:00
|
|
|
create_param_setup(create_param);
|
2015-12-05 15:32:58 +02:00
|
|
|
|
2020-01-06 14:32:07 +01:00
|
|
|
#if defined(CONFIG_BT_SMP)
|
2023-01-20 13:08:12 +01:00
|
|
|
if (bt_dev.le.rl_entries > bt_dev.le.rl_size) {
|
2022-07-22 16:58:13 +02:00
|
|
|
/* Use host-based identity resolving. */
|
2024-04-19 12:30:54 +02:00
|
|
|
bt_conn_set_state(conn, BT_CONN_SCAN_BEFORE_INITIATING);
|
2020-01-06 14:32:07 +01:00
|
|
|
|
2024-06-03 12:49:05 +02:00
|
|
|
err = bt_le_scan_user_add(BT_LE_SCAN_USER_CONN);
|
2020-02-01 18:13:05 +01:00
|
|
|
if (err) {
|
2024-06-03 12:49:05 +02:00
|
|
|
bt_le_scan_user_remove(BT_LE_SCAN_USER_CONN);
|
2020-02-03 12:06:11 +01:00
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
|
2020-02-01 18:13:05 +01:00
|
|
|
return err;
|
2020-02-03 12:06:11 +01:00
|
|
|
}
|
2015-07-15 13:55:32 +03:00
|
|
|
|
2020-02-01 18:13:05 +01:00
|
|
|
*ret_conn = conn;
|
|
|
|
return 0;
|
2020-01-06 14:32:07 +01:00
|
|
|
}
|
|
|
|
#endif
|
2020-01-15 14:32:59 +01:00
|
|
|
|
2024-04-19 12:30:54 +02:00
|
|
|
bt_conn_set_state(conn, BT_CONN_INITIATING);
|
2020-01-15 13:09:27 +01:00
|
|
|
|
2020-02-01 18:13:05 +01:00
|
|
|
err = bt_le_create_conn(conn);
|
|
|
|
if (err) {
|
2020-01-31 14:04:31 +01:00
|
|
|
conn->err = 0;
|
2020-01-06 14:32:07 +01:00
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
|
2024-06-03 12:49:05 +02:00
|
|
|
/* Best-effort attempt to inform the scanner that the initiator stopped. */
|
|
|
|
int scan_check_err = bt_le_scan_user_add(BT_LE_SCAN_USER_NONE);
|
|
|
|
|
|
|
|
if (scan_check_err) {
|
|
|
|
LOG_WRN("Error while updating the scanner (%d)", scan_check_err);
|
|
|
|
}
|
2020-02-01 18:13:05 +01:00
|
|
|
return err;
|
2020-01-06 14:32:07 +01:00
|
|
|
}
|
|
|
|
|
2020-02-01 18:13:05 +01:00
|
|
|
*ret_conn = conn;
|
|
|
|
return 0;
|
2015-07-15 13:55:32 +03:00
|
|
|
}
|
2015-07-15 14:04:52 +03:00
|
|
|
|
2023-03-30 14:06:14 +02:00
|
|
|
int bt_conn_le_create_synced(const struct bt_le_ext_adv *adv,
|
|
|
|
const struct bt_conn_le_create_synced_param *synced_param,
|
|
|
|
const struct bt_le_conn_param *conn_param, struct bt_conn **ret_conn)
|
|
|
|
{
|
|
|
|
struct bt_conn *conn;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = conn_le_create_common_checks(synced_param->peer, conn_param);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!atomic_test_bit(adv->flags, BT_PER_ADV_ENABLED)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!BT_FEAT_LE_PAWR_ADVERTISER(bt_dev.le.features)) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (synced_param->subevent >= BT_HCI_PAWR_SUBEVENT_MAX) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn = conn_le_create_helper(synced_param->peer, conn_param);
|
|
|
|
if (!conn) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The connection creation timeout is not really useful for PAwR.
|
|
|
|
* The controller will give a result for the connection attempt
|
|
|
|
* within a periodic interval. We do not know the periodic interval
|
|
|
|
* used, so disable the timeout.
|
|
|
|
*/
|
|
|
|
bt_dev.create_param.timeout = 0;
|
2024-04-19 12:30:54 +02:00
|
|
|
bt_conn_set_state(conn, BT_CONN_INITIATING);
|
2023-03-30 14:06:14 +02:00
|
|
|
|
|
|
|
err = bt_le_create_conn_synced(conn, adv, synced_param->subevent);
|
|
|
|
if (err) {
|
|
|
|
conn->err = 0;
|
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ret_conn = conn;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:28:45 +02:00
|
|
|
#if !defined(CONFIG_BT_FILTER_ACCEPT_LIST)
|
2018-10-02 15:44:49 +02:00
|
|
|
int bt_le_set_auto_conn(const bt_addr_le_t *addr,
|
2016-01-14 15:10:22 +02:00
|
|
|
const struct bt_le_conn_param *param)
|
|
|
|
{
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
2019-11-23 10:32:19 +01:00
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
|
|
|
|
return -EAGAIN;
|
|
|
|
}
|
|
|
|
|
2017-01-13 13:20:22 +02:00
|
|
|
if (param && !bt_le_conn_params_valid(param)) {
|
2016-01-14 15:10:22 +02:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-03-08 14:24:34 +01:00
|
|
|
if (!bt_id_scan_random_addr_check()) {
|
2019-12-29 18:47:53 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2019-09-11 13:40:50 +03:00
|
|
|
/* Only default identity is supported */
|
2018-07-04 12:58:10 +03:00
|
|
|
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr);
|
2016-01-14 15:10:22 +02:00
|
|
|
if (!conn) {
|
2019-09-11 13:40:50 +03:00
|
|
|
conn = bt_conn_add_le(BT_ID_DEFAULT, addr);
|
2016-01-14 15:10:22 +02:00
|
|
|
if (!conn) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (param) {
|
|
|
|
bt_conn_set_param_le(conn, param);
|
|
|
|
|
|
|
|
if (!atomic_test_and_set_bit(conn->flags,
|
|
|
|
BT_CONN_AUTO_CONNECT)) {
|
|
|
|
bt_conn_ref(conn);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (atomic_test_and_clear_bit(conn->flags,
|
|
|
|
BT_CONN_AUTO_CONNECT)) {
|
|
|
|
bt_conn_unref(conn);
|
2024-04-19 12:30:54 +02:00
|
|
|
if (conn->state == BT_CONN_SCAN_BEFORE_INITIATING) {
|
2016-01-14 15:10:22 +02:00
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-03 12:49:05 +02:00
|
|
|
int err = 0;
|
2016-01-14 15:10:22 +02:00
|
|
|
if (conn->state == BT_CONN_DISCONNECTED &&
|
|
|
|
atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
|
|
|
|
if (param) {
|
2024-04-19 12:30:54 +02:00
|
|
|
bt_conn_set_state(conn, BT_CONN_SCAN_BEFORE_INITIATING);
|
2024-06-03 12:49:05 +02:00
|
|
|
err = bt_le_scan_user_add(BT_LE_SCAN_USER_CONN);
|
2016-01-14 15:10:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
|
2024-06-03 12:49:05 +02:00
|
|
|
return err;
|
2016-01-14 15:10:22 +02:00
|
|
|
}
|
2021-09-14 12:28:45 +02:00
|
|
|
#endif /* !defined(CONFIG_BT_FILTER_ACCEPT_LIST) */
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_CENTRAL */
|
2016-01-14 15:10:22 +02:00
|
|
|
|
2021-06-22 14:59:38 +02:00
|
|
|
int bt_conn_le_conn_update(struct bt_conn *conn,
|
|
|
|
const struct bt_le_conn_param *param)
|
|
|
|
{
|
|
|
|
struct hci_cp_le_conn_update *conn_update;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CONN_UPDATE,
|
|
|
|
sizeof(*conn_update));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn_update = net_buf_add(buf, sizeof(*conn_update));
|
|
|
|
(void)memset(conn_update, 0, sizeof(*conn_update));
|
|
|
|
conn_update->handle = sys_cpu_to_le16(conn->handle);
|
|
|
|
conn_update->conn_interval_min = sys_cpu_to_le16(param->interval_min);
|
|
|
|
conn_update->conn_interval_max = sys_cpu_to_le16(param->interval_max);
|
|
|
|
conn_update->conn_latency = sys_cpu_to_le16(param->latency);
|
|
|
|
conn_update->supervision_timeout = sys_cpu_to_le16(param->timeout);
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CONN_UPDATE, buf, NULL);
|
|
|
|
}
|
|
|
|
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_CLASSIC)
|
2016-01-14 22:12:28 +02:00
|
|
|
int bt_conn_auth_cb_register(const struct bt_conn_auth_cb *cb)
|
2016-01-14 17:32:53 +02:00
|
|
|
{
|
|
|
|
if (!cb) {
|
|
|
|
bt_auth = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bt_auth) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
2018-07-30 20:26:48 +03:00
|
|
|
/* The cancel callback must always be provided if the app provides
|
|
|
|
* interactive callbacks.
|
|
|
|
*/
|
|
|
|
if (!cb->cancel &&
|
|
|
|
(cb->passkey_display || cb->passkey_entry || cb->passkey_confirm ||
|
2024-03-01 18:45:44 +08:00
|
|
|
#if defined(CONFIG_BT_CLASSIC)
|
2018-07-30 20:26:48 +03:00
|
|
|
cb->pincode_entry ||
|
|
|
|
#endif
|
|
|
|
cb->pairing_confirm)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-01-14 17:32:53 +02:00
|
|
|
bt_auth = cb;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-06-13 11:40:38 +02:00
|
|
|
#if defined(CONFIG_BT_SMP)
|
|
|
|
int bt_conn_auth_cb_overlay(struct bt_conn *conn, const struct bt_conn_auth_cb *cb)
|
|
|
|
{
|
2023-05-16 14:00:11 +02:00
|
|
|
CHECKIF(conn == NULL) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2022-06-13 11:40:38 +02:00
|
|
|
/* The cancel callback must always be provided if the app provides
|
|
|
|
* interactive callbacks.
|
|
|
|
*/
|
2023-05-16 14:00:11 +02:00
|
|
|
if (cb && !cb->cancel &&
|
2022-06-13 11:40:38 +02:00
|
|
|
(cb->passkey_display || cb->passkey_entry || cb->passkey_confirm ||
|
|
|
|
cb->pairing_confirm)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->type == BT_CONN_TYPE_LE) {
|
|
|
|
return bt_smp_auth_cb_overlay(conn, cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-03-08 14:33:56 +01:00
|
|
|
int bt_conn_auth_info_cb_register(struct bt_conn_auth_info_cb *cb)
|
|
|
|
{
|
|
|
|
CHECKIF(cb == NULL) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:06:27 +02:00
|
|
|
if (sys_slist_find(&bt_auth_info_cbs, &cb->node, NULL)) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
2022-03-08 14:33:56 +01:00
|
|
|
sys_slist_append(&bt_auth_info_cbs, &cb->node);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_conn_auth_info_cb_unregister(struct bt_conn_auth_info_cb *cb)
|
|
|
|
{
|
|
|
|
CHECKIF(cb == NULL) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sys_slist_find_and_remove(&bt_auth_info_cbs, &cb->node)) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-14 22:12:28 +02:00
|
|
|
int bt_conn_auth_passkey_entry(struct bt_conn *conn, unsigned int passkey)
|
2016-01-14 17:32:53 +02:00
|
|
|
{
|
2017-08-09 09:21:11 +03:00
|
|
|
if (IS_ENABLED(CONFIG_BT_SMP) && conn->type == BT_CONN_TYPE_LE) {
|
2022-06-13 11:40:38 +02:00
|
|
|
return bt_smp_auth_passkey_entry(conn, passkey);
|
2016-01-14 17:32:53 +02:00
|
|
|
}
|
2017-01-17 19:03:55 +02:00
|
|
|
|
2024-03-01 18:45:44 +08:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CLASSIC) && conn->type == BT_CONN_TYPE_BR) {
|
2022-06-13 11:40:38 +02:00
|
|
|
if (!bt_auth) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-07-16 17:04:18 +02:00
|
|
|
return bt_ssp_auth_passkey_entry(conn, passkey);
|
2016-02-24 14:58:03 +01:00
|
|
|
}
|
2016-01-14 17:32:53 +02:00
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2023-01-10 21:56:09 +01:00
|
|
|
#if defined(CONFIG_BT_PASSKEY_KEYPRESS)
|
|
|
|
int bt_conn_auth_keypress_notify(struct bt_conn *conn,
|
|
|
|
enum bt_conn_auth_keypress type)
|
|
|
|
{
|
|
|
|
if (IS_ENABLED(CONFIG_BT_SMP) && conn->type == BT_CONN_TYPE_LE) {
|
|
|
|
return bt_smp_auth_keypress_notify(conn, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_ERR("Not implemented for conn type %d", conn->type);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-03-08 14:43:10 +01:00
|
|
|
int bt_conn_auth_passkey_confirm(struct bt_conn *conn)
|
2016-01-14 17:32:53 +02:00
|
|
|
{
|
2022-06-13 11:40:38 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_SMP) && conn->type == BT_CONN_TYPE_LE) {
|
2016-03-08 14:43:10 +01:00
|
|
|
return bt_smp_auth_passkey_confirm(conn);
|
2016-01-14 17:32:53 +02:00
|
|
|
}
|
2017-01-17 19:03:55 +02:00
|
|
|
|
2024-03-01 18:45:44 +08:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CLASSIC) && conn->type == BT_CONN_TYPE_BR) {
|
2022-06-13 11:40:38 +02:00
|
|
|
if (!bt_auth) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-07-16 17:04:18 +02:00
|
|
|
return bt_ssp_auth_passkey_confirm(conn);
|
2016-02-01 12:41:04 +01:00
|
|
|
}
|
2016-01-14 17:32:53 +02:00
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-01-14 22:12:28 +02:00
|
|
|
int bt_conn_auth_cancel(struct bt_conn *conn)
|
2016-01-14 17:32:53 +02:00
|
|
|
{
|
2017-08-09 09:21:11 +03:00
|
|
|
if (IS_ENABLED(CONFIG_BT_SMP) && conn->type == BT_CONN_TYPE_LE) {
|
2016-01-14 17:32:53 +02:00
|
|
|
return bt_smp_auth_cancel(conn);
|
|
|
|
}
|
2017-01-17 19:03:55 +02:00
|
|
|
|
2024-03-01 18:45:44 +08:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CLASSIC) && conn->type == BT_CONN_TYPE_BR) {
|
2022-06-13 11:40:38 +02:00
|
|
|
if (!bt_auth) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-07-16 17:04:18 +02:00
|
|
|
return bt_ssp_auth_cancel(conn);
|
2016-01-14 17:32:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2016-02-08 10:53:03 +01:00
|
|
|
|
|
|
|
int bt_conn_auth_pairing_confirm(struct bt_conn *conn)
|
|
|
|
{
|
2022-06-13 11:40:38 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_SMP) && conn->type == BT_CONN_TYPE_LE) {
|
|
|
|
return bt_smp_auth_pairing_confirm(conn);
|
2016-02-08 10:53:03 +01:00
|
|
|
}
|
|
|
|
|
2024-03-01 18:45:44 +08:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CLASSIC) && conn->type == BT_CONN_TYPE_BR) {
|
2022-06-13 11:40:38 +02:00
|
|
|
if (!bt_auth) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-07-16 17:04:18 +02:00
|
|
|
return bt_ssp_auth_pairing_confirm(conn);
|
2016-02-08 10:53:03 +01:00
|
|
|
}
|
2022-06-13 11:40:38 +02:00
|
|
|
|
|
|
|
return -EINVAL;
|
2016-02-08 10:53:03 +01:00
|
|
|
}
|
2024-03-01 18:45:44 +08:00
|
|
|
#endif /* CONFIG_BT_SMP || CONFIG_BT_CLASSIC */
|
2016-01-14 17:32:53 +02:00
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
struct bt_conn *bt_conn_lookup_index(uint8_t index)
|
2017-10-12 14:02:29 +03:00
|
|
|
{
|
2020-05-11 15:13:59 -07:00
|
|
|
if (index >= ARRAY_SIZE(acl_conns)) {
|
2017-10-12 14:02:29 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-11-19 17:11:09 +01:00
|
|
|
return bt_conn_ref(&acl_conns[index]);
|
2017-10-12 14:02:29 +03:00
|
|
|
}
|
|
|
|
|
2015-11-03 17:15:40 +02:00
|
|
|
int bt_conn_init(void)
|
|
|
|
{
|
2017-03-17 08:02:57 +02:00
|
|
|
int err, i;
|
|
|
|
|
2022-10-25 17:24:07 +01:00
|
|
|
k_fifo_init(&free_tx);
|
2017-03-17 08:02:57 +02:00
|
|
|
for (i = 0; i < ARRAY_SIZE(conn_tx); i++) {
|
2019-05-28 15:39:35 +03:00
|
|
|
k_fifo_put(&free_tx, &conn_tx[i]);
|
2017-03-17 08:02:57 +02:00
|
|
|
}
|
2015-11-03 17:15:40 +02:00
|
|
|
|
|
|
|
bt_att_init();
|
|
|
|
|
|
|
|
err = bt_smp_init();
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_l2cap_init();
|
|
|
|
|
2017-01-17 19:03:55 +02:00
|
|
|
/* Initialize background scan */
|
2017-08-09 09:21:11 +03:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CENTRAL)) {
|
2020-05-11 15:13:59 -07:00
|
|
|
for (i = 0; i < ARRAY_SIZE(acl_conns); i++) {
|
2020-11-19 17:11:09 +01:00
|
|
|
struct bt_conn *conn = bt_conn_ref(&acl_conns[i]);
|
2017-01-17 19:03:55 +02:00
|
|
|
|
2020-11-19 17:11:09 +01:00
|
|
|
if (!conn) {
|
2017-01-17 19:03:55 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:28:45 +02:00
|
|
|
#if !defined(CONFIG_BT_FILTER_ACCEPT_LIST)
|
2017-01-17 19:03:55 +02:00
|
|
|
if (atomic_test_bit(conn->flags,
|
|
|
|
BT_CONN_AUTO_CONNECT)) {
|
2018-07-04 12:58:10 +03:00
|
|
|
/* Only the default identity is supported */
|
|
|
|
conn->id = BT_ID_DEFAULT;
|
2022-02-22 15:16:34 +01:00
|
|
|
bt_conn_set_state(conn,
|
2024-04-19 12:30:54 +02:00
|
|
|
BT_CONN_SCAN_BEFORE_INITIATING);
|
2017-01-17 19:03:55 +02:00
|
|
|
}
|
2021-09-14 12:28:45 +02:00
|
|
|
#endif /* !defined(CONFIG_BT_FILTER_ACCEPT_LIST) */
|
2020-11-19 17:11:09 +01:00
|
|
|
|
|
|
|
bt_conn_unref(conn);
|
2017-01-17 19:03:55 +02:00
|
|
|
}
|
|
|
|
}
|
2015-12-04 11:38:50 +02:00
|
|
|
|
2015-11-03 17:15:40 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2021-06-22 14:50:35 +02:00
|
|
|
|
2021-11-24 14:12:07 +01:00
|
|
|
#if defined(CONFIG_BT_DF_CONNECTION_CTE_RX)
|
2022-07-21 14:56:51 +02:00
|
|
|
void bt_hci_le_df_connection_iq_report_common(uint8_t event, struct net_buf *buf)
|
2021-11-24 14:12:07 +01:00
|
|
|
{
|
|
|
|
struct bt_df_conn_iq_samples_report iq_report;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
int err;
|
|
|
|
|
2022-07-21 14:56:51 +02:00
|
|
|
if (event == BT_HCI_EVT_LE_CONNECTION_IQ_REPORT) {
|
|
|
|
err = hci_df_prepare_connection_iq_report(buf, &iq_report, &conn);
|
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Prepare CTE conn IQ report failed %d", err);
|
2022-07-21 14:56:51 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (IS_ENABLED(CONFIG_BT_DF_VS_CONN_IQ_REPORT_16_BITS_IQ_SAMPLES) &&
|
|
|
|
event == BT_HCI_EVT_VS_LE_CONNECTION_IQ_REPORT) {
|
|
|
|
err = hci_df_vs_prepare_connection_iq_report(buf, &iq_report, &conn);
|
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Prepare CTE conn IQ report failed %d", err);
|
2022-07-21 14:56:51 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Unhandled VS connection IQ report");
|
2021-11-24 14:12:07 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:30:04 +02:00
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
2024-06-10 14:30:04 +02:00
|
|
|
if (callback->cte_report_cb) {
|
|
|
|
callback->cte_report_cb(conn, &iq_report);
|
2021-11-24 14:12:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb)
|
|
|
|
{
|
|
|
|
if (cb->cte_report_cb) {
|
|
|
|
cb->cte_report_cb(conn, &iq_report);
|
|
|
|
}
|
|
|
|
}
|
2022-01-08 14:13:20 +01:00
|
|
|
|
|
|
|
bt_conn_unref(conn);
|
2021-11-24 14:12:07 +01:00
|
|
|
}
|
2022-07-21 14:56:51 +02:00
|
|
|
|
|
|
|
void bt_hci_le_df_connection_iq_report(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
bt_hci_le_df_connection_iq_report_common(BT_HCI_EVT_LE_CONNECTION_IQ_REPORT, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_BT_DF_VS_CONN_IQ_REPORT_16_BITS_IQ_SAMPLES)
|
|
|
|
void bt_hci_le_vs_df_connection_iq_report(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
bt_hci_le_df_connection_iq_report_common(BT_HCI_EVT_VS_LE_CONNECTION_IQ_REPORT, buf);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_DF_VS_CONN_IQ_REPORT_16_BITS_IQ_SAMPLES */
|
2021-11-24 14:12:07 +01:00
|
|
|
#endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */
|
|
|
|
|
2022-01-08 14:06:49 +01:00
|
|
|
#if defined(CONFIG_BT_DF_CONNECTION_CTE_REQ)
|
|
|
|
void bt_hci_le_df_cte_req_failed(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_df_conn_iq_samples_report iq_report;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = hci_df_prepare_conn_cte_req_failed(buf, &iq_report, &conn);
|
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Prepare CTE REQ failed IQ report failed %d", err);
|
2022-01-08 14:06:49 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:30:04 +02:00
|
|
|
struct bt_conn_cb *callback;
|
|
|
|
|
2024-06-10 14:34:44 +02:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
|
2024-06-10 14:30:04 +02:00
|
|
|
if (callback->cte_report_cb) {
|
|
|
|
callback->cte_report_cb(conn, &iq_report);
|
2022-01-08 14:06:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
STRUCT_SECTION_FOREACH(bt_conn_cb, cb)
|
|
|
|
{
|
|
|
|
if (cb->cte_report_cb) {
|
|
|
|
cb->cte_report_cb(conn, &iq_report);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_DF_CONNECTION_CTE_REQ */
|
|
|
|
|
2021-06-22 14:50:35 +02:00
|
|
|
#endif /* CONFIG_BT_CONN */
|