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
|
|
|
*/
|
|
|
|
|
2016-10-21 12:04:56 +02:00
|
|
|
#include <zephyr.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>
|
2019-06-25 12:25:32 -04:00
|
|
|
#include <sys/atomic.h>
|
2019-06-26 10:33:41 -04:00
|
|
|
#include <sys/byteorder.h>
|
2019-06-26 10:33:55 -04:00
|
|
|
#include <sys/util.h>
|
2019-06-26 10:33:52 -04:00
|
|
|
#include <sys/slist.h>
|
2019-06-26 10:42:45 -04:00
|
|
|
#include <debug/stack.h>
|
2019-06-26 10:33:39 -04:00
|
|
|
#include <sys/__assert.h>
|
2015-04-28 10:39:50 +03:00
|
|
|
|
|
|
|
#include <bluetooth/hci.h>
|
|
|
|
#include <bluetooth/bluetooth.h>
|
2016-01-14 15:02:54 +02:00
|
|
|
#include <bluetooth/conn.h>
|
2016-10-27 16:55:01 +03:00
|
|
|
#include <bluetooth/hci_driver.h>
|
2016-08-02 16:23:26 +03:00
|
|
|
#include <bluetooth/att.h>
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_CONN)
|
2018-07-17 10:35:52 +03:00
|
|
|
#define LOG_MODULE_NAME bt_conn
|
2017-05-10 16:27:16 +02:00
|
|
|
#include "common/log.h"
|
|
|
|
|
2015-04-28 10:39:50 +03:00
|
|
|
#include "hci_core.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"
|
2016-02-17 11:18:10 +02:00
|
|
|
#include "att_internal.h"
|
2019-02-18 09:03:33 +01:00
|
|
|
#include "gatt_internal.h"
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2019-11-26 20:54:58 +02:00
|
|
|
struct tx_meta {
|
|
|
|
struct bt_conn_tx *tx;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define tx_data(buf) ((struct tx_meta *)net_buf_user_data(buf))
|
|
|
|
|
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),
|
2019-11-26 20:54:58 +02:00
|
|
|
sizeof(struct tx_meta), NULL);
|
2015-11-05 15:46:25 +02:00
|
|
|
|
2018-02-09 21:44:01 +02:00
|
|
|
#if CONFIG_BT_L2CAP_TX_FRAG_COUNT > 0
|
|
|
|
|
|
|
|
#if defined(BT_CTLR_TX_BUFFER_SIZE)
|
|
|
|
#define FRAG_SIZE BT_L2CAP_BUF_SIZE(BT_CTLR_TX_BUFFER_SIZE - 4)
|
|
|
|
#else
|
|
|
|
#define FRAG_SIZE BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Dedicated pool for fragment buffers in case queued up TX buffers don't
|
|
|
|
* fit the controllers buffer size. We can't use the acl_tx_pool for the
|
|
|
|
* fragmentation, since it's possible that pool is empty and all buffers
|
|
|
|
* are queued up in the TX queue. In such a situation, trying to allocate
|
|
|
|
* another buffer from the acl_tx_pool would result in a deadlock.
|
|
|
|
*/
|
|
|
|
NET_BUF_POOL_FIXED_DEFINE(frag_pool, CONFIG_BT_L2CAP_TX_FRAG_COUNT, FRAG_SIZE,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
#endif /* CONFIG_BT_L2CAP_TX_FRAG_COUNT > 0 */
|
|
|
|
|
2015-07-22 13:03:51 +03:00
|
|
|
/* How long until we cancel HCI_LE_Create_Connection */
|
2018-09-27 21:03:03 +02:00
|
|
|
#define CONN_TIMEOUT K_SECONDS(CONFIG_BT_CREATE_CONN_TIMEOUT)
|
2015-07-22 13:03:51 +03:00
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
|
2016-01-14 22:12:28 +02:00
|
|
|
const struct bt_conn_auth_cb *bt_auth;
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
|
2016-01-14 17:32:53 +02:00
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
static struct bt_conn conns[CONFIG_BT_MAX_CONN];
|
2015-08-23 20:47:29 +02:00
|
|
|
static struct bt_conn_cb *callback_list;
|
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];
|
2019-05-28 15:39:35 +03:00
|
|
|
K_FIFO_DEFINE(free_tx);
|
2017-03-17 08:02:57 +02:00
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_BREDR)
|
|
|
|
static struct bt_conn sco_conns[CONFIG_BT_MAX_SCO_CONN];
|
Bluetooth: HFP HF: SCO: Accept eSCO conn request
1. Accept the incoming Synchronous connection request and establish
a new sco connection object.
2. Enable sco conn complete in event_mask
> HCI Event: Connect Request (0x04) plen 10 [hci0] 126.198264
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Class: 0x7a020c
Major class: Phone (cellular, cordless, payphone, modem)
Minor class: Smart phone
Networking (LAN, Ad hoc)
Capturing (Scanner, Microphone)
Object Transfer (v-Inbox, v-Folder)
Audio (Speaker, Microphone, Headset)
Telephony (Cordless telephony, Modem, Headset)
Link type: eSCO (0x02)
< HCI Command: Accept Synchronous Co.. (0x01|0x0029) plen 21
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Transmit bandwidth: 8000
Receive bandwidth: 8000
Max latency: 7
Setting: 0x0060
Input Coding: Linear
Input Data Format: 2's complement
Input Sample Size: 16-bit
# of bits padding at MSB: 0
Air Coding Format: CVSD
Retransmission effort: Optimize for power consumption (0x01)
Packet type: 0x0006
HV2 may be used
HV3 may be used
> HCI Event: Command Status (0x0f) plen 4 [hci0] 126.205171
Accept Synchronous Connection Request (0x01|0x0029) ncmd 1
Status: Success (0x00)
Change-Id: I71597aef94e945a9c07be1960994ad20c1b44bb3
Signed-off-by: Sathish Narasimman <sathish.narasimman@intel.com>
2017-02-15 14:29:11 +05:30
|
|
|
|
2016-01-29 16:12:55 +01:00
|
|
|
enum pairing_method {
|
2016-03-21 14:01:19 +01:00
|
|
|
LEGACY, /* Legacy (pre-SSP) pairing */
|
2016-01-29 16:12:55 +01:00
|
|
|
JUST_WORKS, /* JustWorks pairing */
|
|
|
|
PASSKEY_INPUT, /* Passkey Entry input */
|
|
|
|
PASSKEY_DISPLAY, /* Passkey Entry display */
|
|
|
|
PASSKEY_CONFIRM, /* Passkey confirm */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* based on table 5.7, Core Spec 4.2, Vol.3 Part C, 5.2.2.6 */
|
2017-04-20 12:00:29 -05:00
|
|
|
static const u8_t ssp_method[4 /* remote */][4 /* local */] = {
|
2016-01-29 16:12:55 +01:00
|
|
|
{ JUST_WORKS, JUST_WORKS, PASSKEY_INPUT, JUST_WORKS },
|
|
|
|
{ JUST_WORKS, PASSKEY_CONFIRM, PASSKEY_INPUT, JUST_WORKS },
|
|
|
|
{ PASSKEY_DISPLAY, PASSKEY_DISPLAY, PASSKEY_INPUT, JUST_WORKS },
|
|
|
|
{ JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS },
|
|
|
|
};
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_BREDR */
|
2016-01-29 16:12:55 +01:00
|
|
|
|
2017-03-19 13:35:09 +02:00
|
|
|
struct k_sem *bt_conn_get_pkts(struct bt_conn *conn)
|
|
|
|
{
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_BREDR)
|
2017-03-19 13:35:09 +02:00
|
|
|
if (conn->type == BT_CONN_TYPE_BR || !bt_dev.le.mtu) {
|
|
|
|
return &bt_dev.br.pkts;
|
|
|
|
}
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_BREDR */
|
2017-03-19 13:35:09 +02:00
|
|
|
|
|
|
|
return &bt_dev.le.pkts;
|
|
|
|
}
|
|
|
|
|
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";
|
2015-07-02 11:16:55 +02:00
|
|
|
case BT_CONN_CONNECT_SCAN:
|
|
|
|
return "connect-scan";
|
2018-08-20 14:44:42 +02:00
|
|
|
case BT_CONN_CONNECT_DIR_ADV:
|
|
|
|
return "connect-dir-adv";
|
2020-01-07 12:40:30 +01:00
|
|
|
case BT_CONN_CONNECT_AUTO:
|
|
|
|
return "connect-auto";
|
2015-06-19 23:03:18 +02:00
|
|
|
case BT_CONN_CONNECT:
|
|
|
|
return "connect";
|
|
|
|
case BT_CONN_CONNECTED:
|
|
|
|
return "connected";
|
|
|
|
case BT_CONN_DISCONNECT:
|
|
|
|
return "disconnect";
|
|
|
|
default:
|
|
|
|
return "(unknown)";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-05 15:46:52 +02:00
|
|
|
static void notify_connected(struct bt_conn *conn)
|
2015-08-23 20:47:29 +02:00
|
|
|
{
|
|
|
|
struct bt_conn_cb *cb;
|
|
|
|
|
|
|
|
for (cb = callback_list; cb; cb = cb->_next) {
|
|
|
|
if (cb->connected) {
|
2016-01-14 11:17:32 +02:00
|
|
|
cb->connected(conn, conn->err);
|
2015-08-23 20:47:29 +02:00
|
|
|
}
|
|
|
|
}
|
2019-02-18 09:03:33 +01:00
|
|
|
|
2019-04-16 15:01:19 +02:00
|
|
|
if (!conn->err) {
|
|
|
|
bt_gatt_connected(conn);
|
|
|
|
}
|
2015-08-23 20:47:29 +02:00
|
|
|
}
|
|
|
|
|
2015-10-05 15:46:52 +02:00
|
|
|
static void notify_disconnected(struct bt_conn *conn)
|
2015-08-23 20:47:29 +02:00
|
|
|
{
|
|
|
|
struct bt_conn_cb *cb;
|
|
|
|
|
|
|
|
for (cb = callback_list; cb; cb = cb->_next) {
|
|
|
|
if (cb->disconnected) {
|
2016-01-14 11:17:32 +02:00
|
|
|
cb->disconnected(conn, conn->err);
|
2015-08-23 20:47:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-27 14:53:40 +02:00
|
|
|
#if defined(CONFIG_BT_REMOTE_INFO)
|
|
|
|
void notify_remote_info(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
struct bt_conn_remote_info remote_info;
|
|
|
|
struct bt_conn_cb *cb;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = bt_conn_get_remote_info(conn, &remote_info);
|
|
|
|
if (err) {
|
|
|
|
BT_DBG("Notify remote info failed %d", err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (cb = callback_list; cb; cb = cb->_next) {
|
|
|
|
if (cb->remote_info_available) {
|
|
|
|
cb->remote_info_available(conn, &remote_info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* defined(CONFIG_BT_REMOTE_INFO) */
|
|
|
|
|
2016-02-02 12:48:42 +01:00
|
|
|
void notify_le_param_updated(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
struct bt_conn_cb *cb;
|
|
|
|
|
2018-11-14 13:21:37 +01:00
|
|
|
/* If new connection parameters meet requirement of pending
|
|
|
|
* parameters don't send slave conn param request anymore on timeout
|
|
|
|
*/
|
|
|
|
if (atomic_test_bit(conn->flags, BT_CONN_SLAVE_PARAM_SET) &&
|
|
|
|
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) {
|
|
|
|
atomic_clear_bit(conn->flags, BT_CONN_SLAVE_PARAM_SET);
|
|
|
|
}
|
|
|
|
|
2016-02-02 12:48:42 +01:00
|
|
|
for (cb = callback_list; cb; cb = cb->_next) {
|
|
|
|
if (cb->le_param_updated) {
|
|
|
|
cb->le_param_updated(conn, conn->le.interval,
|
|
|
|
conn->le.latency,
|
|
|
|
conn->le.timeout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-16 13:26:53 +02:00
|
|
|
bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
|
|
|
|
{
|
|
|
|
struct bt_conn_cb *cb;
|
|
|
|
|
|
|
|
if (!bt_le_conn_params_valid(param)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (cb = callback_list; cb; cb = cb->_next) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Default to accepting if there's no app callback */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-09-24 08:18:57 +02:00
|
|
|
static int send_conn_le_param_update(struct bt_conn *conn,
|
|
|
|
const struct bt_le_conn_param *param)
|
|
|
|
{
|
|
|
|
BT_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);
|
|
|
|
|
2019-12-06 10:18:55 +01:00
|
|
|
/* Proceed only if connection parameters contains valid values*/
|
|
|
|
if (!bt_le_conn_params_valid(param)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2018-09-24 08:18:57 +02:00
|
|
|
/* Use LE connection parameter request if both local and remote support
|
|
|
|
* it; or if local role is master then use LE connection update.
|
|
|
|
*/
|
|
|
|
if ((BT_FEAT_LE_CONN_PARAM_REQ_PROC(bt_dev.le.features) &&
|
2018-11-06 13:48:07 +01:00
|
|
|
BT_FEAT_LE_CONN_PARAM_REQ_PROC(conn->le.features) &&
|
|
|
|
!atomic_test_bit(conn->flags, BT_CONN_SLAVE_PARAM_L2CAP)) ||
|
|
|
|
(conn->role == BT_HCI_ROLE_MASTER)) {
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = bt_conn_le_conn_update(conn, param);
|
|
|
|
|
|
|
|
/* store those in case of fallback to L2CAP */
|
|
|
|
if (rc == 0) {
|
|
|
|
conn->le.pending_latency = param->latency;
|
|
|
|
conn->le.pending_timeout = param->timeout;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
2018-09-24 08:18:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If remote master does not support LL Connection Parameters Request
|
|
|
|
* Procedure
|
|
|
|
*/
|
|
|
|
return bt_l2cap_update_conn_param(conn, param);
|
|
|
|
}
|
|
|
|
|
2019-11-28 14:11:57 +02:00
|
|
|
static void tx_free(struct bt_conn_tx *tx)
|
|
|
|
{
|
|
|
|
tx->cb = NULL;
|
|
|
|
tx->user_data = NULL;
|
|
|
|
tx->pending_no_cb = 0U;
|
|
|
|
k_fifo_put(&free_tx, tx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tx_notify(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
BT_DBG("conn %p", conn);
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct bt_conn_tx *tx;
|
|
|
|
unsigned int key;
|
|
|
|
bt_conn_tx_cb_t cb;
|
|
|
|
void *user_data;
|
|
|
|
|
|
|
|
key = irq_lock();
|
|
|
|
if (sys_slist_is_empty(&conn->tx_complete)) {
|
|
|
|
irq_unlock(key);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
tx = (void *)sys_slist_get_not_empty(&conn->tx_complete);
|
|
|
|
irq_unlock(key);
|
|
|
|
|
|
|
|
BT_DBG("tx %p cb %p user_data %p", tx, tx->cb, tx->user_data);
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
cb(conn, user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tx_complete_work(struct k_work *work)
|
|
|
|
{
|
|
|
|
struct bt_conn *conn = CONTAINER_OF(work, struct bt_conn,
|
|
|
|
tx_complete_work);
|
|
|
|
|
|
|
|
BT_DBG("conn %p", conn);
|
|
|
|
|
|
|
|
tx_notify(conn);
|
|
|
|
}
|
|
|
|
|
2019-06-17 19:26:47 +03:00
|
|
|
static void conn_update_timeout(struct k_work *work)
|
2016-05-23 16:17:20 +03:00
|
|
|
{
|
2019-06-17 19:26:47 +03:00
|
|
|
struct bt_conn *conn = CONTAINER_OF(work, struct bt_conn, update_work);
|
2016-05-23 16:17:20 +03:00
|
|
|
const struct bt_le_conn_param *param;
|
|
|
|
|
2018-09-24 08:18:57 +02:00
|
|
|
BT_DBG("conn %p", conn);
|
|
|
|
|
2019-06-17 19:26:47 +03:00
|
|
|
if (conn->state == BT_CONN_DISCONNECTED) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
|
2018-09-24 08:18:57 +02:00
|
|
|
conn->role == BT_CONN_ROLE_MASTER) {
|
2018-10-01 09:44:50 +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_hci_cmd_send(BT_HCI_OP_LE_CREATE_CONN_CANCEL, NULL);
|
2017-01-31 09:41:35 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-04 10:38:49 +01:00
|
|
|
if (IS_ENABLED(CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS)) {
|
|
|
|
#if defined(CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS)
|
|
|
|
/* if application set own params use those, otherwise
|
|
|
|
* use defaults
|
|
|
|
*/
|
|
|
|
if (atomic_test_and_clear_bit(conn->flags,
|
|
|
|
BT_CONN_SLAVE_PARAM_SET)) {
|
|
|
|
param = BT_LE_CONN_PARAM(conn->le.interval_min,
|
|
|
|
conn->le.interval_max,
|
|
|
|
conn->le.pending_latency,
|
|
|
|
conn->le.pending_timeout);
|
|
|
|
send_conn_le_param_update(conn, param);
|
|
|
|
} else {
|
|
|
|
param = BT_LE_CONN_PARAM(
|
|
|
|
CONFIG_BT_PERIPHERAL_PREF_MIN_INT,
|
|
|
|
CONFIG_BT_PERIPHERAL_PREF_MAX_INT,
|
|
|
|
CONFIG_BT_PERIPHERAL_PREF_SLAVE_LATENCY,
|
|
|
|
CONFIG_BT_PERIPHERAL_PREF_TIMEOUT);
|
|
|
|
send_conn_le_param_update(conn, param);
|
|
|
|
}
|
2018-09-24 11:20:20 +02:00
|
|
|
#else
|
2019-12-04 10:38:49 +01:00
|
|
|
/* update only if application set own params */
|
|
|
|
if (atomic_test_and_clear_bit(conn->flags,
|
|
|
|
BT_CONN_SLAVE_PARAM_SET)) {
|
|
|
|
param = BT_LE_CONN_PARAM(conn->le.interval_min,
|
|
|
|
conn->le.interval_max,
|
|
|
|
conn->le.latency,
|
|
|
|
conn->le.timeout);
|
|
|
|
send_conn_le_param_update(conn, param);
|
|
|
|
}
|
2018-09-24 11:20:20 +02:00
|
|
|
#endif
|
2019-12-04 10:38:49 +01:00
|
|
|
}
|
2018-09-24 08:18:57 +02:00
|
|
|
|
|
|
|
atomic_set_bit(conn->flags, BT_CONN_SLAVE_PARAM_UPDATE);
|
2016-05-23 16:17:20 +03:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
static struct bt_conn *conn_new(void)
|
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
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
for (i = 0; i < ARRAY_SIZE(conns); i++) {
|
|
|
|
if (!atomic_get(&conns[i].ref)) {
|
|
|
|
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
|
|
|
|
2018-09-11 19:09:03 -07:00
|
|
|
(void)memset(conn, 0, sizeof(*conn));
|
2019-06-17 19:26:47 +03:00
|
|
|
k_delayed_work_init(&conn->update_work, conn_update_timeout);
|
2016-03-21 15:12:57 +01:00
|
|
|
|
2019-11-28 14:11:57 +02:00
|
|
|
k_work_init(&conn->tx_complete_work, tx_complete_work);
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
atomic_set(&conn->ref, 1);
|
|
|
|
|
|
|
|
return conn;
|
2015-09-01 18:06:35 +02:00
|
|
|
}
|
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_BREDR)
|
2017-02-15 15:18:13 +05:30
|
|
|
void bt_sco_cleanup(struct bt_conn *sco_conn)
|
|
|
|
{
|
|
|
|
bt_conn_unref(sco_conn->sco.acl);
|
|
|
|
sco_conn->sco.acl = NULL;
|
|
|
|
bt_conn_unref(sco_conn);
|
|
|
|
}
|
|
|
|
|
Bluetooth: HFP HF: SCO: Accept eSCO conn request
1. Accept the incoming Synchronous connection request and establish
a new sco connection object.
2. Enable sco conn complete in event_mask
> HCI Event: Connect Request (0x04) plen 10 [hci0] 126.198264
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Class: 0x7a020c
Major class: Phone (cellular, cordless, payphone, modem)
Minor class: Smart phone
Networking (LAN, Ad hoc)
Capturing (Scanner, Microphone)
Object Transfer (v-Inbox, v-Folder)
Audio (Speaker, Microphone, Headset)
Telephony (Cordless telephony, Modem, Headset)
Link type: eSCO (0x02)
< HCI Command: Accept Synchronous Co.. (0x01|0x0029) plen 21
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Transmit bandwidth: 8000
Receive bandwidth: 8000
Max latency: 7
Setting: 0x0060
Input Coding: Linear
Input Data Format: 2's complement
Input Sample Size: 16-bit
# of bits padding at MSB: 0
Air Coding Format: CVSD
Retransmission effort: Optimize for power consumption (0x01)
Packet type: 0x0006
HV2 may be used
HV3 may be used
> HCI Event: Command Status (0x0f) plen 4 [hci0] 126.205171
Accept Synchronous Connection Request (0x01|0x0029) ncmd 1
Status: Success (0x00)
Change-Id: I71597aef94e945a9c07be1960994ad20c1b44bb3
Signed-off-by: Sathish Narasimman <sathish.narasimman@intel.com>
2017-02-15 14:29:11 +05:30
|
|
|
static struct bt_conn *sco_conn_new(void)
|
|
|
|
{
|
|
|
|
struct bt_conn *sco_conn = NULL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(sco_conns); i++) {
|
|
|
|
if (!atomic_get(&sco_conns[i].ref)) {
|
|
|
|
sco_conn = &sco_conns[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sco_conn) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-09-11 19:09:03 -07:00
|
|
|
(void)memset(sco_conn, 0, sizeof(*sco_conn));
|
Bluetooth: HFP HF: SCO: Accept eSCO conn request
1. Accept the incoming Synchronous connection request and establish
a new sco connection object.
2. Enable sco conn complete in event_mask
> HCI Event: Connect Request (0x04) plen 10 [hci0] 126.198264
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Class: 0x7a020c
Major class: Phone (cellular, cordless, payphone, modem)
Minor class: Smart phone
Networking (LAN, Ad hoc)
Capturing (Scanner, Microphone)
Object Transfer (v-Inbox, v-Folder)
Audio (Speaker, Microphone, Headset)
Telephony (Cordless telephony, Modem, Headset)
Link type: eSCO (0x02)
< HCI Command: Accept Synchronous Co.. (0x01|0x0029) plen 21
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Transmit bandwidth: 8000
Receive bandwidth: 8000
Max latency: 7
Setting: 0x0060
Input Coding: Linear
Input Data Format: 2's complement
Input Sample Size: 16-bit
# of bits padding at MSB: 0
Air Coding Format: CVSD
Retransmission effort: Optimize for power consumption (0x01)
Packet type: 0x0006
HV2 may be used
HV3 may be used
> HCI Event: Command Status (0x0f) plen 4 [hci0] 126.205171
Accept Synchronous Connection Request (0x01|0x0029) ncmd 1
Status: Success (0x00)
Change-Id: I71597aef94e945a9c07be1960994ad20c1b44bb3
Signed-off-by: Sathish Narasimman <sathish.narasimman@intel.com>
2017-02-15 14:29:11 +05:30
|
|
|
|
|
|
|
atomic_set(&sco_conn->ref, 1);
|
|
|
|
|
|
|
|
return sco_conn;
|
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_conn *bt_conn_create_br(const bt_addr_t *peer,
|
|
|
|
const struct bt_br_conn_param *param)
|
2015-10-02 12:39:11 +02:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_hci_cp_connect *cp;
|
|
|
|
struct bt_conn *conn;
|
2015-10-28 10:39:02 +02:00
|
|
|
struct net_buf *buf;
|
2015-10-02 12:39:11 +02:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
conn = bt_conn_lookup_addr_br(peer);
|
|
|
|
if (conn) {
|
|
|
|
switch (conn->state) {
|
|
|
|
case BT_CONN_CONNECT:
|
|
|
|
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));
|
2015-10-02 12:39:11 +02:00
|
|
|
if (!buf) {
|
2016-03-21 15:12:57 +01:00
|
|
|
bt_conn_unref(conn);
|
|
|
|
return NULL;
|
2015-10-02 12:39:11 +02:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:39:02 +02:00
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
2015-10-07 15:41:19 +02:00
|
|
|
|
2018-09-11 19:09:03 -07:00
|
|
|
(void)memset(cp, 0, sizeof(*cp));
|
2016-03-21 15:12:57 +01:00
|
|
|
|
|
|
|
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;
|
2015-10-07 15:41:19 +02:00
|
|
|
}
|
2015-10-02 12:39:11 +02:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
bt_conn_set_state(conn, BT_CONN_CONNECT);
|
|
|
|
conn->role = BT_CONN_ROLE_MASTER;
|
2016-02-19 12:05:19 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
return conn;
|
2016-02-19 12:05:19 +01:00
|
|
|
}
|
|
|
|
|
2017-03-06 12:16:28 +05:30
|
|
|
struct bt_conn *bt_conn_create_sco(const bt_addr_t *peer)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_setup_sync_conn *cp;
|
|
|
|
struct bt_conn *sco_conn;
|
|
|
|
struct net_buf *buf;
|
|
|
|
int link_type;
|
|
|
|
|
|
|
|
sco_conn = bt_conn_lookup_addr_sco(peer);
|
|
|
|
if (sco_conn) {
|
|
|
|
switch (sco_conn->state) {
|
|
|
|
case BT_CONN_CONNECT:
|
|
|
|
case BT_CONN_CONNECTED:
|
|
|
|
return sco_conn;
|
|
|
|
default:
|
|
|
|
bt_conn_unref(sco_conn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (BT_FEAT_LMP_ESCO_CAPABLE(bt_dev.features)) {
|
|
|
|
link_type = BT_HCI_ESCO;
|
|
|
|
} else {
|
|
|
|
link_type = BT_HCI_SCO;
|
|
|
|
}
|
|
|
|
|
|
|
|
sco_conn = bt_conn_add_sco(peer, link_type);
|
|
|
|
if (!sco_conn) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_SETUP_SYNC_CONN, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
bt_sco_cleanup(sco_conn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
|
2018-09-11 19:09:03 -07:00
|
|
|
(void)memset(cp, 0, sizeof(*cp));
|
2017-03-06 12:16:28 +05:30
|
|
|
|
|
|
|
BT_ERR("handle : %x", sco_conn->sco.acl->handle);
|
|
|
|
|
|
|
|
cp->handle = sco_conn->sco.acl->handle;
|
|
|
|
cp->pkt_type = sco_conn->sco.pkt_type;
|
|
|
|
cp->tx_bandwidth = 0x00001f40;
|
|
|
|
cp->rx_bandwidth = 0x00001f40;
|
|
|
|
cp->max_latency = 0x0007;
|
|
|
|
cp->retrans_effort = 0x01;
|
|
|
|
cp->content_format = BT_VOICE_CVSD_16BIT;
|
|
|
|
|
|
|
|
if (bt_hci_cmd_send_sync(BT_HCI_OP_SETUP_SYNC_CONN, buf,
|
|
|
|
NULL) < 0) {
|
|
|
|
bt_sco_cleanup(sco_conn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_set_state(sco_conn, BT_CONN_CONNECT);
|
|
|
|
|
|
|
|
return sco_conn;
|
|
|
|
}
|
|
|
|
|
2017-02-15 15:08:25 +05:30
|
|
|
struct bt_conn *bt_conn_lookup_addr_sco(const bt_addr_t *peer)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(sco_conns); i++) {
|
|
|
|
if (!atomic_get(&sco_conns[i].ref)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sco_conns[i].type != BT_CONN_TYPE_SCO) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-03-16 13:43:15 +05:30
|
|
|
if (!bt_addr_cmp(peer, &sco_conns[i].sco.acl->br.dst)) {
|
2017-02-15 15:08:25 +05:30
|
|
|
return bt_conn_ref(&sco_conns[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_conn *bt_conn_lookup_addr_br(const bt_addr_t *peer)
|
2016-02-19 12:05:19 +01:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
int i;
|
2016-02-19 12:05:19 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
for (i = 0; i < ARRAY_SIZE(conns); i++) {
|
|
|
|
if (!atomic_get(&conns[i].ref)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conns[i].type != BT_CONN_TYPE_BR) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bt_addr_cmp(peer, &conns[i].br.dst)) {
|
|
|
|
return bt_conn_ref(&conns[i]);
|
2016-02-19 12:05:19 +01:00
|
|
|
}
|
|
|
|
}
|
2016-03-21 15:12:57 +01:00
|
|
|
|
|
|
|
return NULL;
|
2016-02-19 12:05:19 +01:00
|
|
|
}
|
2015-10-02 12:39:11 +02:00
|
|
|
|
Bluetooth: HFP HF: SCO: Accept eSCO conn request
1. Accept the incoming Synchronous connection request and establish
a new sco connection object.
2. Enable sco conn complete in event_mask
> HCI Event: Connect Request (0x04) plen 10 [hci0] 126.198264
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Class: 0x7a020c
Major class: Phone (cellular, cordless, payphone, modem)
Minor class: Smart phone
Networking (LAN, Ad hoc)
Capturing (Scanner, Microphone)
Object Transfer (v-Inbox, v-Folder)
Audio (Speaker, Microphone, Headset)
Telephony (Cordless telephony, Modem, Headset)
Link type: eSCO (0x02)
< HCI Command: Accept Synchronous Co.. (0x01|0x0029) plen 21
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Transmit bandwidth: 8000
Receive bandwidth: 8000
Max latency: 7
Setting: 0x0060
Input Coding: Linear
Input Data Format: 2's complement
Input Sample Size: 16-bit
# of bits padding at MSB: 0
Air Coding Format: CVSD
Retransmission effort: Optimize for power consumption (0x01)
Packet type: 0x0006
HV2 may be used
HV3 may be used
> HCI Event: Command Status (0x0f) plen 4 [hci0] 126.205171
Accept Synchronous Connection Request (0x01|0x0029) ncmd 1
Status: Success (0x00)
Change-Id: I71597aef94e945a9c07be1960994ad20c1b44bb3
Signed-off-by: Sathish Narasimman <sathish.narasimman@intel.com>
2017-02-15 14:29:11 +05:30
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-03-16 13:43:15 +05:30
|
|
|
sco_conn->sco.acl = bt_conn_lookup_addr_br(peer);
|
Bluetooth: HFP HF: SCO: Accept eSCO conn request
1. Accept the incoming Synchronous connection request and establish
a new sco connection object.
2. Enable sco conn complete in event_mask
> HCI Event: Connect Request (0x04) plen 10 [hci0] 126.198264
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Class: 0x7a020c
Major class: Phone (cellular, cordless, payphone, modem)
Minor class: Smart phone
Networking (LAN, Ad hoc)
Capturing (Scanner, Microphone)
Object Transfer (v-Inbox, v-Folder)
Audio (Speaker, Microphone, Headset)
Telephony (Cordless telephony, Modem, Headset)
Link type: eSCO (0x02)
< HCI Command: Accept Synchronous Co.. (0x01|0x0029) plen 21
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Transmit bandwidth: 8000
Receive bandwidth: 8000
Max latency: 7
Setting: 0x0060
Input Coding: Linear
Input Data Format: 2's complement
Input Sample Size: 16-bit
# of bits padding at MSB: 0
Air Coding Format: CVSD
Retransmission effort: Optimize for power consumption (0x01)
Packet type: 0x0006
HV2 may be used
HV3 may be used
> HCI Event: Command Status (0x0f) plen 4 [hci0] 126.205171
Accept Synchronous Connection Request (0x01|0x0029) ncmd 1
Status: Success (0x00)
Change-Id: I71597aef94e945a9c07be1960994ad20c1b44bb3
Signed-off-by: Sathish Narasimman <sathish.narasimman@intel.com>
2017-02-15 14:29:11 +05:30
|
|
|
sco_conn->type = BT_CONN_TYPE_SCO;
|
|
|
|
|
|
|
|
if (link_type == BT_HCI_SCO) {
|
|
|
|
if (BT_FEAT_LMP_ESCO_CAPABLE(bt_dev.features)) {
|
2017-04-21 13:47:08 +03:00
|
|
|
sco_conn->sco.pkt_type = (bt_dev.br.esco_pkt_type &
|
Bluetooth: HFP HF: SCO: Accept eSCO conn request
1. Accept the incoming Synchronous connection request and establish
a new sco connection object.
2. Enable sco conn complete in event_mask
> HCI Event: Connect Request (0x04) plen 10 [hci0] 126.198264
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Class: 0x7a020c
Major class: Phone (cellular, cordless, payphone, modem)
Minor class: Smart phone
Networking (LAN, Ad hoc)
Capturing (Scanner, Microphone)
Object Transfer (v-Inbox, v-Folder)
Audio (Speaker, Microphone, Headset)
Telephony (Cordless telephony, Modem, Headset)
Link type: eSCO (0x02)
< HCI Command: Accept Synchronous Co.. (0x01|0x0029) plen 21
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Transmit bandwidth: 8000
Receive bandwidth: 8000
Max latency: 7
Setting: 0x0060
Input Coding: Linear
Input Data Format: 2's complement
Input Sample Size: 16-bit
# of bits padding at MSB: 0
Air Coding Format: CVSD
Retransmission effort: Optimize for power consumption (0x01)
Packet type: 0x0006
HV2 may be used
HV3 may be used
> HCI Event: Command Status (0x0f) plen 4 [hci0] 126.205171
Accept Synchronous Connection Request (0x01|0x0029) ncmd 1
Status: Success (0x00)
Change-Id: I71597aef94e945a9c07be1960994ad20c1b44bb3
Signed-off-by: Sathish Narasimman <sathish.narasimman@intel.com>
2017-02-15 14:29:11 +05:30
|
|
|
ESCO_PKT_MASK);
|
|
|
|
} else {
|
2017-04-21 13:47:08 +03:00
|
|
|
sco_conn->sco.pkt_type = (bt_dev.br.esco_pkt_type &
|
Bluetooth: HFP HF: SCO: Accept eSCO conn request
1. Accept the incoming Synchronous connection request and establish
a new sco connection object.
2. Enable sco conn complete in event_mask
> HCI Event: Connect Request (0x04) plen 10 [hci0] 126.198264
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Class: 0x7a020c
Major class: Phone (cellular, cordless, payphone, modem)
Minor class: Smart phone
Networking (LAN, Ad hoc)
Capturing (Scanner, Microphone)
Object Transfer (v-Inbox, v-Folder)
Audio (Speaker, Microphone, Headset)
Telephony (Cordless telephony, Modem, Headset)
Link type: eSCO (0x02)
< HCI Command: Accept Synchronous Co.. (0x01|0x0029) plen 21
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Transmit bandwidth: 8000
Receive bandwidth: 8000
Max latency: 7
Setting: 0x0060
Input Coding: Linear
Input Data Format: 2's complement
Input Sample Size: 16-bit
# of bits padding at MSB: 0
Air Coding Format: CVSD
Retransmission effort: Optimize for power consumption (0x01)
Packet type: 0x0006
HV2 may be used
HV3 may be used
> HCI Event: Command Status (0x0f) plen 4 [hci0] 126.205171
Accept Synchronous Connection Request (0x01|0x0029) ncmd 1
Status: Success (0x00)
Change-Id: I71597aef94e945a9c07be1960994ad20c1b44bb3
Signed-off-by: Sathish Narasimman <sathish.narasimman@intel.com>
2017-02-15 14:29:11 +05:30
|
|
|
SCO_PKT_MASK);
|
|
|
|
}
|
|
|
|
} else if (link_type == BT_HCI_ESCO) {
|
2017-04-21 13:47:08 +03:00
|
|
|
sco_conn->sco.pkt_type = (bt_dev.br.esco_pkt_type &
|
Bluetooth: HFP HF: SCO: Accept eSCO conn request
1. Accept the incoming Synchronous connection request and establish
a new sco connection object.
2. Enable sco conn complete in event_mask
> HCI Event: Connect Request (0x04) plen 10 [hci0] 126.198264
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Class: 0x7a020c
Major class: Phone (cellular, cordless, payphone, modem)
Minor class: Smart phone
Networking (LAN, Ad hoc)
Capturing (Scanner, Microphone)
Object Transfer (v-Inbox, v-Folder)
Audio (Speaker, Microphone, Headset)
Telephony (Cordless telephony, Modem, Headset)
Link type: eSCO (0x02)
< HCI Command: Accept Synchronous Co.. (0x01|0x0029) plen 21
Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
Transmit bandwidth: 8000
Receive bandwidth: 8000
Max latency: 7
Setting: 0x0060
Input Coding: Linear
Input Data Format: 2's complement
Input Sample Size: 16-bit
# of bits padding at MSB: 0
Air Coding Format: CVSD
Retransmission effort: Optimize for power consumption (0x01)
Packet type: 0x0006
HV2 may be used
HV3 may be used
> HCI Event: Command Status (0x0f) plen 4 [hci0] 126.205171
Accept Synchronous Connection Request (0x01|0x0029) ncmd 1
Status: Success (0x00)
Change-Id: I71597aef94e945a9c07be1960994ad20c1b44bb3
Signed-off-by: Sathish Narasimman <sathish.narasimman@intel.com>
2017-02-15 14:29:11 +05:30
|
|
|
~EDR_ESCO_PKT_MASK);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sco_conn;
|
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_conn *bt_conn_add_br(const bt_addr_t *peer)
|
2015-10-13 18:53:21 +02:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_conn *conn = conn_new();
|
2016-02-19 12:16:38 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (!conn) {
|
|
|
|
return NULL;
|
2016-02-19 12:16:38 +01:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
bt_addr_copy(&conn->br.dst, peer);
|
|
|
|
conn->type = BT_CONN_TYPE_BR;
|
2015-10-13 18:53:21 +02:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
return conn;
|
|
|
|
}
|
2015-10-13 18:53:21 +02:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
static int pin_code_neg_reply(const bt_addr_t *bdaddr)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_pin_code_neg_reply *cp;
|
|
|
|
struct net_buf *buf;
|
2015-10-13 18:53:21 +02:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
BT_DBG("");
|
2015-11-19 16:51:17 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_PIN_CODE_NEG_REPLY, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
2015-10-13 18:53:21 +02:00
|
|
|
}
|
2016-03-21 15:12:57 +01:00
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
bt_addr_copy(&cp->bdaddr, bdaddr);
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_PIN_CODE_NEG_REPLY, buf, NULL);
|
|
|
|
}
|
|
|
|
|
2017-04-20 12:00:29 -05:00
|
|
|
static int pin_code_reply(struct bt_conn *conn, const char *pin, u8_t len)
|
2016-03-21 15:12:57 +01:00
|
|
|
{
|
|
|
|
struct bt_hci_cp_pin_code_reply *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
BT_DBG("");
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_PIN_CODE_REPLY, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
2015-10-13 18:53:21 +02:00
|
|
|
}
|
2016-03-21 15:12:57 +01:00
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
|
|
|
|
bt_addr_copy(&cp->bdaddr, &conn->br.dst);
|
|
|
|
cp->pin_len = len;
|
Bluetooth: Fix compiler warnings/errors related to string casts
Fix the following compiler warnings/errors that show up with llvm:
tests/bluetooth/shell/src/main.c:594:2: error:
initializing 'const uint8_t *' (aka 'const unsigned char *') with an
expression of type 'char [11]' converts between pointers to integer types
with different sign [-Werror,-Wpointer-sign]
BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/bluetooth/bluetooth.h:93:11: note: expanded
from macro 'BT_DATA'
.data = (_data), \
^~~~~~~
1 error generated.
net/bluetooth/hci_core.c:1759:22: error: passing
'uint8_t [248]' to parameter of type 'const char *' converts between
pointers to integer types with different sign [-Werror,-Wpointer-sign]
name_len = strlen(evt->name);
^~~~~~~~~
lib/libc/minimal/include/string.h:32:34: note: passing
argument to parameter 's' here
extern size_t strlen(const char *s);
^
CC net/bluetooth/log.o
net/bluetooth/hci_core.c:3136:10: error: passing
'uint8_t [248]' to parameter of type 'char *' converts between pointers to
integer types with different sign [-Werror,-Wpointer-sign]
strncpy(name_cp->local_name, CONFIG_BLUETOOTH_BREDR_NAME,
^~~~~~~~~~~~~~~~~~~
lib/libc/minimal/include/string.h:30:39: note: passing
argument to parameter 'd' here
extern char *strncpy(char *_Restrict d, const char *_Restrict s, size_t n);
net/bluetooth/conn.c:301:10: error: passing
'uint8_t [16]' to parameter of type 'char *' converts between pointers to
integer types with different sign [-Werror,-Wpointer-sign]
strncpy(cp->pin_code, pin, sizeof(cp->pin_code));
^~~~~~~~~~~~
lib/libc/minimal/include/string.h:30:39: note: passing
argument to parameter 'd' here
extern char *strncpy(char *_Restrict d, const char *_Restrict s, size_t n);
Change-Id: I342131c6c2b25445382b2317d673561c4087096b
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2016-10-04 10:21:42 +03:00
|
|
|
strncpy((char *)cp->pin_code, pin, sizeof(cp->pin_code));
|
2016-03-21 15:12:57 +01:00
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_PIN_CODE_REPLY, buf, NULL);
|
2015-10-13 18:53:21 +02:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
int bt_conn_auth_pincode_entry(struct bt_conn *conn, const char *pin)
|
2015-10-02 12:39:11 +02:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
size_t len;
|
2015-10-07 17:09:24 +02:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (!bt_auth) {
|
|
|
|
return -EINVAL;
|
2015-10-02 12:39:11 +02:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (conn->type != BT_CONN_TYPE_BR) {
|
|
|
|
return -EINVAL;
|
2015-12-08 16:59:19 +01:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
len = strlen(pin);
|
|
|
|
if (len > 16) {
|
|
|
|
return -EINVAL;
|
2015-10-02 12:39:11 +02:00
|
|
|
}
|
|
|
|
|
2019-08-26 15:50:48 +02:00
|
|
|
if (conn->required_sec_level == BT_SECURITY_L3 && len < 16) {
|
2016-03-21 15:12:57 +01:00
|
|
|
BT_WARN("PIN code for %s is not 16 bytes wide",
|
|
|
|
bt_addr_str(&conn->br.dst));
|
|
|
|
return -EPERM;
|
|
|
|
}
|
2015-10-02 12:39:11 +02:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
/* Allow user send entered PIN to remote, then reset user state. */
|
|
|
|
if (!atomic_test_and_clear_bit(conn->flags, BT_CONN_USER)) {
|
|
|
|
return -EPERM;
|
|
|
|
}
|
2015-10-07 17:09:24 +02:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (len == 16) {
|
|
|
|
atomic_set_bit(conn->flags, BT_CONN_BR_LEGACY_SECURE);
|
2015-10-07 17:09:24 +02:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
return pin_code_reply(conn, pin, len);
|
2015-10-02 12:39:11 +02:00
|
|
|
}
|
2015-09-01 18:16:54 +02:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
void bt_conn_pin_code_req(struct bt_conn *conn)
|
2015-08-23 20:47:29 +02:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
if (bt_auth && bt_auth->pincode_entry) {
|
|
|
|
bool secure = false;
|
|
|
|
|
2019-08-26 15:50:48 +02:00
|
|
|
if (conn->required_sec_level == BT_SECURITY_L3) {
|
2016-03-21 15:12:57 +01:00
|
|
|
secure = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_set_bit(conn->flags, BT_CONN_USER);
|
|
|
|
atomic_set_bit(conn->flags, BT_CONN_BR_PAIRING);
|
|
|
|
bt_auth->pincode_entry(conn, secure);
|
|
|
|
} else {
|
|
|
|
pin_code_neg_reply(&conn->br.dst);
|
|
|
|
}
|
2015-08-23 20:47:29 +02:00
|
|
|
}
|
|
|
|
|
2017-04-20 12:00:29 -05:00
|
|
|
u8_t bt_conn_get_io_capa(void)
|
2015-04-28 10:39:50 +03:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
if (!bt_auth) {
|
|
|
|
return BT_IO_NO_INPUT_OUTPUT;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (bt_auth->passkey_confirm && bt_auth->passkey_display) {
|
|
|
|
return BT_IO_DISPLAY_YESNO;
|
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (bt_auth->passkey_entry) {
|
|
|
|
return BT_IO_KEYBOARD_ONLY;
|
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (bt_auth->passkey_display) {
|
|
|
|
return BT_IO_DISPLAY_ONLY;
|
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
return BT_IO_NO_INPUT_OUTPUT;
|
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2017-04-20 12:00:29 -05:00
|
|
|
static u8_t ssp_pair_method(const struct bt_conn *conn)
|
2016-03-21 15:12:57 +01:00
|
|
|
{
|
|
|
|
return ssp_method[conn->br.remote_io_capa][bt_conn_get_io_capa()];
|
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2017-04-20 12:00:29 -05:00
|
|
|
u8_t bt_conn_ssp_get_auth(const struct bt_conn *conn)
|
2016-03-21 15:12:57 +01:00
|
|
|
{
|
|
|
|
/* Validate no bond auth request, and if valid use it. */
|
|
|
|
if ((conn->br.remote_auth == BT_HCI_NO_BONDING) ||
|
|
|
|
((conn->br.remote_auth == BT_HCI_NO_BONDING_MITM) &&
|
|
|
|
(ssp_pair_method(conn) > JUST_WORKS))) {
|
|
|
|
return conn->br.remote_auth;
|
2015-04-28 10:39:50 +03:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
/* Local & remote have enough IO capabilities to get MITM protection. */
|
|
|
|
if (ssp_pair_method(conn) > JUST_WORKS) {
|
|
|
|
return conn->br.remote_auth | BT_MITM;
|
2015-04-28 10:39:50 +03:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
/* No MITM protection possible so ignore remote MITM requirement. */
|
|
|
|
return (conn->br.remote_auth & ~BT_MITM);
|
2015-04-28 10:39:50 +03:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
static int ssp_confirm_reply(struct bt_conn *conn)
|
2015-04-28 10:39:50 +03:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_hci_cp_user_confirm_reply *cp;
|
|
|
|
struct net_buf *buf;
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
BT_DBG("");
|
2016-04-09 11:29:50 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_USER_CONFIRM_REPLY, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
2015-07-15 13:53:17 +03:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
bt_addr_copy(&cp->bdaddr, &conn->br.dst);
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_USER_CONFIRM_REPLY, buf, NULL);
|
2015-11-05 22:11:44 +02:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
static int ssp_confirm_neg_reply(struct bt_conn *conn)
|
2015-11-05 22:11:44 +02:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_hci_cp_user_confirm_reply *cp;
|
|
|
|
struct net_buf *buf;
|
2015-11-05 22:11:44 +02:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
BT_DBG("");
|
2015-05-05 12:26:59 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_USER_CONFIRM_NEG_REPLY, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
2015-11-05 22:11:44 +02:00
|
|
|
}
|
2015-05-05 12:26:59 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
bt_addr_copy(&cp->bdaddr, &conn->br.dst);
|
2015-05-05 11:06:54 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_USER_CONFIRM_NEG_REPLY, buf,
|
|
|
|
NULL);
|
|
|
|
}
|
2016-04-09 11:29:50 +03:00
|
|
|
|
2019-07-04 12:03:57 +02:00
|
|
|
void bt_conn_ssp_auth_complete(struct bt_conn *conn, u8_t status)
|
|
|
|
{
|
|
|
|
if (!status) {
|
|
|
|
bool bond = !atomic_test_bit(conn->flags, BT_CONN_BR_NOBOND);
|
|
|
|
|
|
|
|
if (bt_auth && bt_auth->pairing_complete) {
|
|
|
|
bt_auth->pairing_complete(conn, bond);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (bt_auth && bt_auth->pairing_failed) {
|
|
|
|
bt_auth->pairing_failed(conn, status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-20 12:00:29 -05:00
|
|
|
void bt_conn_ssp_auth(struct bt_conn *conn, u32_t passkey)
|
2016-03-21 15:12:57 +01:00
|
|
|
{
|
|
|
|
conn->br.pairing_method = ssp_pair_method(conn);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If local required security is HIGH then MITM is mandatory.
|
|
|
|
* MITM protection is no achievable when SSP 'justworks' is applied.
|
|
|
|
*/
|
2019-08-26 15:50:48 +02:00
|
|
|
if (conn->required_sec_level > BT_SECURITY_L2 &&
|
2016-03-21 15:12:57 +01:00
|
|
|
conn->br.pairing_method == JUST_WORKS) {
|
|
|
|
BT_DBG("MITM protection infeasible for required security");
|
|
|
|
ssp_confirm_neg_reply(conn);
|
|
|
|
return;
|
2015-11-05 22:11:44 +02:00
|
|
|
}
|
2015-05-05 12:26:59 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
switch (conn->br.pairing_method) {
|
|
|
|
case PASSKEY_CONFIRM:
|
|
|
|
atomic_set_bit(conn->flags, BT_CONN_USER);
|
|
|
|
bt_auth->passkey_confirm(conn, passkey);
|
|
|
|
break;
|
|
|
|
case PASSKEY_DISPLAY:
|
|
|
|
atomic_set_bit(conn->flags, BT_CONN_USER);
|
|
|
|
bt_auth->passkey_display(conn, passkey);
|
|
|
|
break;
|
|
|
|
case PASSKEY_INPUT:
|
|
|
|
atomic_set_bit(conn->flags, BT_CONN_USER);
|
|
|
|
bt_auth->passkey_entry(conn);
|
|
|
|
break;
|
2016-02-08 10:53:03 +01:00
|
|
|
case JUST_WORKS:
|
2016-03-22 12:52:49 +01:00
|
|
|
/*
|
|
|
|
* When local host works as pairing acceptor and 'justworks'
|
|
|
|
* model is applied then notify user about such pairing request.
|
|
|
|
* [BT Core 4.2 table 5.7, Vol 3, Part C, 5.2.2.6]
|
|
|
|
*/
|
|
|
|
if (bt_auth && bt_auth->pairing_confirm &&
|
|
|
|
!atomic_test_bit(conn->flags,
|
|
|
|
BT_CONN_BR_PAIRING_INITIATOR)) {
|
2016-02-08 10:53:03 +01:00
|
|
|
atomic_set_bit(conn->flags, BT_CONN_USER);
|
|
|
|
bt_auth->pairing_confirm(conn);
|
|
|
|
break;
|
|
|
|
}
|
2016-03-21 15:12:57 +01:00
|
|
|
ssp_confirm_reply(conn);
|
|
|
|
break;
|
2016-02-08 10:53:03 +01:00
|
|
|
default:
|
|
|
|
break;
|
2015-11-06 09:21:02 +02:00
|
|
|
}
|
2015-11-05 22:11:44 +02:00
|
|
|
}
|
2015-05-05 12:26:59 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
static int ssp_passkey_reply(struct bt_conn *conn, unsigned int passkey)
|
2015-11-19 12:01:58 +01:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_hci_cp_user_passkey_reply *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
BT_DBG("");
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_USER_PASSKEY_REPLY, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
2015-11-23 12:29:39 +01:00
|
|
|
}
|
2015-11-25 15:26:23 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
bt_addr_copy(&cp->bdaddr, &conn->br.dst);
|
|
|
|
cp->passkey = sys_cpu_to_le32(passkey);
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_USER_PASSKEY_REPLY, buf, NULL);
|
2015-11-19 12:01:58 +01:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
static int ssp_passkey_neg_reply(struct bt_conn *conn)
|
2015-11-05 22:11:44 +02:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_hci_cp_user_passkey_neg_reply *cp;
|
|
|
|
struct net_buf *buf;
|
2015-05-05 12:26:59 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
BT_DBG("");
|
2015-05-05 12:26:59 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_USER_PASSKEY_NEG_REPLY, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
2015-11-05 22:11:44 +02:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
bt_addr_copy(&cp->bdaddr, &conn->br.dst);
|
2015-11-06 09:27:39 +02:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_USER_PASSKEY_NEG_REPLY, buf,
|
|
|
|
NULL);
|
2015-11-05 22:11:44 +02:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
static int bt_hci_connect_br_cancel(struct bt_conn *conn)
|
2015-11-05 22:11:44 +02:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_hci_cp_connect_cancel *cp;
|
|
|
|
struct bt_hci_rp_connect_cancel *rp;
|
|
|
|
struct net_buf *buf, *rsp;
|
|
|
|
int err;
|
2015-05-05 12:26:59 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_CONNECT_CANCEL, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
2015-11-05 22:11:44 +02:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
memcpy(&cp->bdaddr, &conn->br.dst, sizeof(cp->bdaddr));
|
2015-05-05 12:26:59 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_CONNECT_CANCEL, buf, &rsp);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
2015-05-05 12:26:59 +03:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
rp = (void *)rsp->data;
|
2015-11-05 22:11:44 +02:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
err = rp->status ? -EIO : 0;
|
2015-11-05 22:11:44 +02:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
net_buf_unref(rsp);
|
|
|
|
|
|
|
|
return err;
|
2015-04-28 10:39:50 +03:00
|
|
|
}
|
2016-03-18 14:13:23 +01:00
|
|
|
|
|
|
|
static int conn_auth(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_auth_requested *auth;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
BT_DBG("");
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_AUTH_REQUESTED, sizeof(*auth));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
auth = net_buf_add(buf, sizeof(*auth));
|
|
|
|
auth->handle = sys_cpu_to_le16(conn->handle);
|
|
|
|
|
|
|
|
atomic_set_bit(conn->flags, BT_CONN_BR_PAIRING_INITIATOR);
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_AUTH_REQUESTED, buf, NULL);
|
|
|
|
}
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_BREDR */
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_SMP)
|
2016-03-21 15:12:57 +01:00
|
|
|
void bt_conn_identity_resolved(struct bt_conn *conn)
|
2015-04-28 10:39:50 +03:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
const bt_addr_le_t *rpa;
|
|
|
|
struct bt_conn_cb *cb;
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (conn->role == BT_HCI_ROLE_MASTER) {
|
|
|
|
rpa = &conn->le.resp_addr;
|
|
|
|
} else {
|
|
|
|
rpa = &conn->le.init_addr;
|
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
for (cb = callback_list; cb; cb = cb->_next) {
|
|
|
|
if (cb->identity_resolved) {
|
|
|
|
cb->identity_resolved(conn, rpa, &conn->le.dst);
|
2015-09-15 17:57:00 +03:00
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
}
|
2016-03-21 15:12:57 +01:00
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2018-06-22 10:34:45 +02:00
|
|
|
int bt_conn_le_start_encryption(struct bt_conn *conn, u8_t rand[8],
|
|
|
|
u8_t ediv[2], const u8_t *ltk, size_t len)
|
2016-03-21 15:12:57 +01:00
|
|
|
{
|
|
|
|
struct bt_hci_cp_le_start_encryption *cp;
|
|
|
|
struct net_buf *buf;
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_START_ENCRYPTION, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = sys_cpu_to_le16(conn->handle);
|
2018-04-27 20:28:20 +03:00
|
|
|
memcpy(&cp->rand, rand, sizeof(cp->rand));
|
2018-06-22 10:34:45 +02:00
|
|
|
memcpy(&cp->ediv, ediv, sizeof(cp->ediv));
|
2016-03-21 15:12:57 +01:00
|
|
|
|
|
|
|
memcpy(cp->ltk, ltk, len);
|
|
|
|
if (len < sizeof(cp->ltk)) {
|
2018-09-11 19:09:03 -07:00
|
|
|
(void)memset(cp->ltk + len, 0, sizeof(cp->ltk) - len);
|
2015-09-15 17:19:45 +03:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_START_ENCRYPTION, buf, NULL);
|
|
|
|
}
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_SMP */
|
2015-05-23 20:38:23 +03:00
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
|
2017-04-20 12:00:29 -05:00
|
|
|
u8_t bt_conn_enc_key_size(struct bt_conn *conn)
|
2016-03-21 15:12:57 +01:00
|
|
|
{
|
2016-09-13 16:38:54 +02:00
|
|
|
if (!conn->encrypt) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
if (IS_ENABLED(CONFIG_BT_BREDR) &&
|
2017-01-17 19:03:55 +02:00
|
|
|
conn->type == BT_CONN_TYPE_BR) {
|
2016-09-13 16:38:54 +02:00
|
|
|
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;
|
2017-04-20 12:00:29 -05:00
|
|
|
u8_t key_size;
|
2016-09-13 16:38:54 +02:00
|
|
|
|
|
|
|
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;
|
2016-08-08 16:40:30 +02:00
|
|
|
}
|
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
if (IS_ENABLED(CONFIG_BT_SMP)) {
|
2017-01-17 19:03:55 +02:00
|
|
|
return conn->le.keys ? conn->le.keys->enc_size : 0;
|
|
|
|
}
|
|
|
|
|
2016-08-08 16:40:30 +02:00
|
|
|
return 0;
|
2015-04-28 10:39:50 +03:00
|
|
|
}
|
|
|
|
|
2019-08-19 16:20:59 +02:00
|
|
|
void bt_conn_security_changed(struct bt_conn *conn, enum bt_security_err err)
|
2015-04-28 10:39:50 +03:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_conn_cb *cb;
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
for (cb = callback_list; cb; cb = cb->_next) {
|
|
|
|
if (cb->security_changed) {
|
2019-08-19 16:20:59 +02:00
|
|
|
cb->security_changed(conn, conn->sec_level, err);
|
2015-04-28 10:39:50 +03:00
|
|
|
}
|
|
|
|
}
|
2019-09-26 17:27:50 +03:00
|
|
|
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
|
|
|
if (!err && conn->sec_level >= BT_SECURITY_L2) {
|
|
|
|
bt_keys_update_usage(conn->id, bt_conn_get_dst(conn));
|
|
|
|
}
|
|
|
|
#endif
|
2015-11-25 11:23:54 +01:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
static int start_security(struct bt_conn *conn)
|
2015-11-25 11:23:54 +01:00
|
|
|
{
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_BREDR)
|
2016-03-21 15:12:57 +01:00
|
|
|
if (conn->type == BT_CONN_TYPE_BR) {
|
|
|
|
if (atomic_test_bit(conn->flags, BT_CONN_BR_PAIRING)) {
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
2015-11-25 11:23:54 +01:00
|
|
|
|
2019-08-26 15:50:48 +02:00
|
|
|
if (conn->required_sec_level > BT_SECURITY_L3) {
|
2016-03-18 14:13:23 +01:00
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bt_conn_get_io_capa() == BT_IO_NO_INPUT_OUTPUT &&
|
2019-08-26 15:50:48 +02:00
|
|
|
conn->required_sec_level > BT_SECURITY_L2) {
|
2016-03-18 14:13:23 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return conn_auth(conn);
|
2015-11-25 15:16:10 +01:00
|
|
|
}
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_BREDR */
|
2015-11-25 11:23:54 +01:00
|
|
|
|
2019-09-24 13:55:09 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_SMP)) {
|
|
|
|
return bt_smp_start_security(conn);
|
2016-03-21 15:12:57 +01:00
|
|
|
}
|
2019-09-24 13:55:09 +02:00
|
|
|
|
|
|
|
return -EINVAL;
|
2015-04-28 10:39:50 +03:00
|
|
|
}
|
|
|
|
|
2019-08-26 15:53:20 +02:00
|
|
|
int bt_conn_set_security(struct bt_conn *conn, bt_security_t sec)
|
2016-03-14 10:20:04 +01:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
int err;
|
2016-03-14 10:20:04 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (conn->state != BT_CONN_CONNECTED) {
|
|
|
|
return -ENOTCONN;
|
2016-03-14 10:20:04 +01:00
|
|
|
}
|
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
if (IS_ENABLED(CONFIG_BT_SMP_SC_ONLY) &&
|
2019-08-26 15:50:48 +02:00
|
|
|
sec < BT_SECURITY_L4) {
|
2016-03-21 15:12:57 +01:00
|
|
|
return -EOPNOTSUPP;
|
2016-03-14 10:20:04 +01:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
/* nothing to do */
|
|
|
|
if (conn->sec_level >= sec || conn->required_sec_level >= sec) {
|
|
|
|
return 0;
|
2016-03-14 10:20:04 +01:00
|
|
|
}
|
|
|
|
|
2019-08-21 10:51:14 +02:00
|
|
|
atomic_set_bit_to(conn->flags, BT_CONN_FORCE_PAIR,
|
|
|
|
sec & BT_SECURITY_FORCE_PAIR);
|
|
|
|
conn->required_sec_level = sec & ~BT_SECURITY_FORCE_PAIR;
|
2016-03-14 10:20:04 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
err = start_security(conn);
|
2016-03-14 10:20:04 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
/* reset required security level in case of error */
|
|
|
|
if (err) {
|
|
|
|
conn->required_sec_level = conn->sec_level;
|
2016-03-14 10:20:04 +01:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
return err;
|
2016-03-14 10:20:04 +01:00
|
|
|
}
|
2019-09-17 16:50:51 +03:00
|
|
|
|
|
|
|
bt_security_t bt_conn_get_security(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
return conn->sec_level;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
bt_security_t bt_conn_get_security(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
return BT_SECURITY_L1;
|
|
|
|
}
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_SMP */
|
2016-03-14 10:20:04 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
void bt_conn_cb_register(struct bt_conn_cb *cb)
|
2015-12-03 17:05:51 +01:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
cb->_next = callback_list;
|
|
|
|
callback_list = cb;
|
2015-12-03 17:05:51 +01:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
static void bt_conn_reset_rx_state(struct bt_conn *conn)
|
2015-11-25 11:51:25 +01:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
if (!conn->rx_len) {
|
|
|
|
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;
|
2018-11-29 11:23:03 -08:00
|
|
|
conn->rx_len = 0U;
|
2015-11-25 11:51:25 +01:00
|
|
|
}
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2017-04-20 12:00:29 -05:00
|
|
|
void bt_conn_recv(struct bt_conn *conn, struct net_buf *buf, u8_t flags)
|
2016-03-09 15:13:33 +01:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_l2cap_hdr *hdr;
|
2017-04-20 12:00:29 -05:00
|
|
|
u16_t len;
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2019-11-28 14:11:57 +02:00
|
|
|
/* Make sure we notify any pending TX callbacks before processing
|
|
|
|
* new data for this connection.
|
|
|
|
*/
|
|
|
|
tx_notify(conn);
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
BT_DBG("handle %u len %u flags %02x", conn->handle, buf->len, flags);
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
/* Check packet boundary flags */
|
|
|
|
switch (flags) {
|
|
|
|
case BT_ACL_START:
|
|
|
|
hdr = (void *)buf->data;
|
|
|
|
len = sys_le16_to_cpu(hdr->len);
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
BT_DBG("First, len %u final %u", buf->len, len);
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (conn->rx_len) {
|
|
|
|
BT_ERR("Unexpected first L2CAP frame");
|
|
|
|
bt_conn_reset_rx_state(conn);
|
|
|
|
}
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
conn->rx_len = (sizeof(*hdr) + len) - buf->len;
|
|
|
|
BT_DBG("rx_len %u", conn->rx_len);
|
|
|
|
if (conn->rx_len) {
|
|
|
|
conn->rx = buf;
|
|
|
|
return;
|
|
|
|
}
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
break;
|
|
|
|
case BT_ACL_CONT:
|
|
|
|
if (!conn->rx_len) {
|
|
|
|
BT_ERR("Unexpected L2CAP continuation");
|
|
|
|
bt_conn_reset_rx_state(conn);
|
|
|
|
net_buf_unref(buf);
|
|
|
|
return;
|
|
|
|
}
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (buf->len > conn->rx_len) {
|
|
|
|
BT_ERR("L2CAP data overflow");
|
|
|
|
bt_conn_reset_rx_state(conn);
|
|
|
|
net_buf_unref(buf);
|
|
|
|
return;
|
|
|
|
}
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
BT_DBG("Cont, len %u rx_len %u", buf->len, conn->rx_len);
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (buf->len > net_buf_tailroom(conn->rx)) {
|
|
|
|
BT_ERR("Not enough buffer space for L2CAP data");
|
|
|
|
bt_conn_reset_rx_state(conn);
|
|
|
|
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
|
|
|
conn->rx_len -= buf->len;
|
|
|
|
net_buf_unref(buf);
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (conn->rx_len) {
|
|
|
|
return;
|
|
|
|
}
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
buf = conn->rx;
|
|
|
|
conn->rx = NULL;
|
2018-11-29 11:23:03 -08:00
|
|
|
conn->rx_len = 0U;
|
2016-03-09 15:13:33 +01:00
|
|
|
|
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.
|
|
|
|
*/
|
2016-03-21 15:12:57 +01:00
|
|
|
BT_ERR("Unexpected ACL flags (0x%02x)", flags);
|
|
|
|
bt_conn_reset_rx_state(conn);
|
|
|
|
net_buf_unref(buf);
|
|
|
|
return;
|
2016-03-09 15:13:33 +01:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
hdr = (void *)buf->data;
|
|
|
|
len = sys_le16_to_cpu(hdr->len);
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (sizeof(*hdr) + len != buf->len) {
|
|
|
|
BT_ERR("ACL len mismatch (%u != %u)", len, buf->len);
|
|
|
|
net_buf_unref(buf);
|
|
|
|
return;
|
2016-03-09 15:13:33 +01:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
BT_DBG("Successfully parsed %u byte L2CAP packet", buf->len);
|
2016-03-09 15:13:33 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
bt_l2cap_recv(conn, buf);
|
2016-03-09 15:13:33 +01:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2019-11-23 12:56:44 +02:00
|
|
|
/* The TX context always get freed in the system workqueue,
|
|
|
|
* so if we're in the same workqueue but there are no immediate
|
|
|
|
* contexts available, there's no chance we'll get one by waiting.
|
|
|
|
*/
|
|
|
|
if (k_current_get() == &k_sys_work_q.thread) {
|
|
|
|
return k_fifo_get(&free_tx, K_NO_WAIT);
|
|
|
|
}
|
|
|
|
|
2019-11-23 00:08:46 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_DEBUG_CONN)) {
|
|
|
|
struct bt_conn_tx *tx = k_fifo_get(&free_tx, K_NO_WAIT);
|
2017-03-17 08:02:57 +02:00
|
|
|
|
2019-11-23 12:56:44 +02:00
|
|
|
if (tx) {
|
|
|
|
return tx;
|
2019-11-23 00:08:46 +02:00
|
|
|
}
|
2016-01-29 16:12:55 +01:00
|
|
|
|
2019-11-23 12:56:44 +02:00
|
|
|
BT_WARN("Unable to get an immediate free conn_tx");
|
2019-08-01 18:02:14 +03:00
|
|
|
}
|
|
|
|
|
2019-11-23 00:08:46 +02:00
|
|
|
return k_fifo_get(&free_tx, K_FOREVER);
|
2019-08-01 18:02:14 +03:00
|
|
|
}
|
|
|
|
|
2019-11-23 00:08:46 +02:00
|
|
|
int bt_conn_send_cb(struct bt_conn *conn, struct net_buf *buf,
|
|
|
|
bt_conn_tx_cb_t cb, void *user_data)
|
2017-03-17 08:02:57 +02:00
|
|
|
{
|
|
|
|
struct bt_conn_tx *tx;
|
|
|
|
|
2019-11-23 00:08:46 +02:00
|
|
|
BT_DBG("conn handle %u buf len %u cb %p user_data %p", conn->handle,
|
|
|
|
buf->len, cb, user_data);
|
2017-07-06 19:23:24 +03:00
|
|
|
|
2019-11-23 00:08:46 +02:00
|
|
|
if (conn->state != BT_CONN_CONNECTED) {
|
|
|
|
BT_ERR("not connected!");
|
|
|
|
net_buf_unref(buf);
|
|
|
|
return -ENOTCONN;
|
2017-07-06 19:23:24 +03:00
|
|
|
}
|
2017-03-17 08:02:57 +02:00
|
|
|
|
2019-11-23 00:08:46 +02:00
|
|
|
if (cb) {
|
|
|
|
tx = conn_tx_alloc();
|
2019-11-23 12:56:44 +02:00
|
|
|
if (!tx) {
|
|
|
|
BT_ERR("Unable to allocate TX context");
|
|
|
|
net_buf_unref(buf);
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that we're still connected after blocking */
|
|
|
|
if (conn->state != BT_CONN_CONNECTED) {
|
|
|
|
BT_WARN("Disconnected while allocating context");
|
|
|
|
net_buf_unref(buf);
|
|
|
|
tx_free(tx);
|
|
|
|
return -ENOTCONN;
|
|
|
|
}
|
|
|
|
|
2019-11-23 00:08:46 +02:00
|
|
|
tx->cb = cb;
|
|
|
|
tx->user_data = user_data;
|
|
|
|
tx->pending_no_cb = 0U;
|
2017-03-17 08:02:57 +02:00
|
|
|
|
2019-11-23 00:08:46 +02:00
|
|
|
tx_data(buf)->tx = tx;
|
2019-08-01 16:34:26 +03:00
|
|
|
} else {
|
2019-11-23 00:08:46 +02:00
|
|
|
tx_data(buf)->tx = NULL;
|
2019-08-01 16:34:26 +03:00
|
|
|
}
|
|
|
|
|
2019-11-23 00:08:46 +02:00
|
|
|
net_buf_put(&conn->tx_queue, buf);
|
|
|
|
return 0;
|
2017-03-17 08:02:57 +02:00
|
|
|
}
|
|
|
|
|
2017-04-20 12:00:29 -05:00
|
|
|
static bool send_frag(struct bt_conn *conn, struct net_buf *buf, u8_t flags,
|
2016-03-21 15:12:57 +01:00
|
|
|
bool always_consume)
|
2016-01-29 16:12:55 +01:00
|
|
|
{
|
2019-11-23 00:08:46 +02:00
|
|
|
struct bt_conn_tx *tx = tx_data(buf)->tx;
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_hci_acl_hdr *hdr;
|
2019-11-23 00:08:46 +02:00
|
|
|
u32_t *pending_no_cb;
|
|
|
|
unsigned int key;
|
2016-03-21 15:12:57 +01:00
|
|
|
int err;
|
2016-01-29 16:12:55 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
BT_DBG("conn %p buf %p len %u flags 0x%02x", conn, buf, buf->len,
|
|
|
|
flags);
|
2016-01-29 16:12:55 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
/* Wait until the controller can accept ACL packets */
|
2016-10-27 11:32:30 +02:00
|
|
|
k_sem_take(bt_conn_get_pkts(conn), K_FOREVER);
|
2016-03-21 15:12:57 +01:00
|
|
|
|
|
|
|
/* Check for disconnection while waiting for pkts_sem */
|
|
|
|
if (conn->state != BT_CONN_CONNECTED) {
|
|
|
|
goto fail;
|
2016-01-29 16:12:55 +01:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
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));
|
|
|
|
|
2019-05-21 14:52:16 +03:00
|
|
|
/* Add to pending, it must be done before bt_buf_set_type */
|
2019-11-23 00:08:46 +02:00
|
|
|
key = irq_lock();
|
|
|
|
if (tx) {
|
|
|
|
sys_slist_append(&conn->tx_pending, &tx->node);
|
|
|
|
} else {
|
|
|
|
struct bt_conn_tx *tail_tx;
|
|
|
|
|
|
|
|
tail_tx = (void *)sys_slist_peek_tail(&conn->tx_pending);
|
|
|
|
if (tail_tx) {
|
|
|
|
pending_no_cb = &tail_tx->pending_no_cb;
|
|
|
|
} else {
|
|
|
|
pending_no_cb = &conn->pending_no_cb;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*pending_no_cb)++;
|
|
|
|
}
|
|
|
|
irq_unlock(key);
|
2016-03-21 15:12:57 +01:00
|
|
|
|
2019-05-21 14:52:16 +03:00
|
|
|
bt_buf_set_type(buf, BT_BUF_ACL_OUT);
|
2017-06-22 15:52:35 +03:00
|
|
|
|
2016-04-20 14:46:48 +03:00
|
|
|
err = bt_send(buf);
|
2016-03-21 15:12:57 +01:00
|
|
|
if (err) {
|
|
|
|
BT_ERR("Unable to send to driver (err %d)", err);
|
2019-11-23 00:08:46 +02:00
|
|
|
key = irq_lock();
|
|
|
|
/* Roll back the pending TX info */
|
|
|
|
if (tx) {
|
|
|
|
sys_slist_find_and_remove(&conn->tx_pending, &tx->node);
|
|
|
|
} else {
|
|
|
|
__ASSERT_NO_MSG(*pending_no_cb > 0);
|
|
|
|
(*pending_no_cb)--;
|
|
|
|
}
|
|
|
|
irq_unlock(key);
|
2016-03-21 15:12:57 +01:00
|
|
|
goto fail;
|
2016-01-29 16:12:55 +01:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
return true;
|
2016-01-29 16:12:55 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
fail:
|
2016-10-27 11:32:30 +02:00
|
|
|
k_sem_give(bt_conn_get_pkts(conn));
|
2019-11-23 00:08:46 +02:00
|
|
|
if (tx) {
|
|
|
|
tx_free(tx);
|
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (always_consume) {
|
|
|
|
net_buf_unref(buf);
|
|
|
|
}
|
|
|
|
return false;
|
2016-01-29 16:12:55 +01:00
|
|
|
}
|
|
|
|
|
2017-04-20 12:00:29 -05:00
|
|
|
static inline u16_t conn_mtu(struct bt_conn *conn)
|
2016-01-29 16:12:55 +01:00
|
|
|
{
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_BREDR)
|
2016-03-21 15:12:57 +01:00
|
|
|
if (conn->type == BT_CONN_TYPE_BR || !bt_dev.le.mtu) {
|
|
|
|
return bt_dev.br.mtu;
|
2016-01-29 16:12:55 +01:00
|
|
|
}
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_BREDR */
|
2016-01-29 16:12:55 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
return bt_dev.le.mtu;
|
2016-01-29 16:12:55 +01:00
|
|
|
}
|
2016-02-01 12:41:04 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
static struct net_buf *create_frag(struct bt_conn *conn, struct net_buf *buf)
|
2016-02-01 12:41:04 +01:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
struct net_buf *frag;
|
2017-04-20 12:00:29 -05:00
|
|
|
u16_t frag_len;
|
2016-02-01 12:41:04 +01:00
|
|
|
|
2019-11-14 16:07:00 +02:00
|
|
|
frag = bt_conn_create_frag(0);
|
2016-02-01 12:41:04 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (conn->state != BT_CONN_CONNECTED) {
|
|
|
|
net_buf_unref(frag);
|
|
|
|
return NULL;
|
2016-02-01 12:41:04 +01:00
|
|
|
}
|
|
|
|
|
2017-03-17 08:02:57 +02:00
|
|
|
/* Fragments never have a TX completion callback */
|
2019-11-23 00:08:46 +02:00
|
|
|
tx_data(frag)->tx = NULL;
|
2017-03-17 08:02:57 +02:00
|
|
|
|
2019-02-11 17:14:19 +00:00
|
|
|
frag_len = MIN(conn_mtu(conn), net_buf_tailroom(frag));
|
2016-02-01 12:41:04 +01:00
|
|
|
|
2016-12-28 14:10:06 +02:00
|
|
|
net_buf_add_mem(frag, buf->data, frag_len);
|
2016-03-21 15:12:57 +01:00
|
|
|
net_buf_pull(buf, frag_len);
|
|
|
|
|
|
|
|
return frag;
|
2016-02-01 12:41:04 +01:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
static bool send_buf(struct bt_conn *conn, struct net_buf *buf)
|
2016-02-01 12:41:04 +01:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
struct net_buf *frag;
|
2016-02-01 12:41:04 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
BT_DBG("conn %p buf %p len %u", conn, buf, buf->len);
|
2016-02-01 12:41:04 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
/* Send directly if the packet fits the ACL MTU */
|
|
|
|
if (buf->len <= conn_mtu(conn)) {
|
|
|
|
return send_frag(conn, buf, BT_ACL_START_NO_FLUSH, false);
|
2016-02-01 12:41:04 +01:00
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
/* Create & enqueue first fragment */
|
|
|
|
frag = create_frag(conn, buf);
|
|
|
|
if (!frag) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-02-01 12:41:04 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (!send_frag(conn, frag, BT_ACL_START_NO_FLUSH, true)) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-02-01 12:41:04 +01:00
|
|
|
|
2016-02-24 11:38:20 +01:00
|
|
|
/*
|
2016-03-21 15:12:57 +01:00
|
|
|
* Send the fragments. For the last one simply use the original
|
|
|
|
* buffer (which works since we've used net_buf_pull on it.
|
2016-02-24 11:38:20 +01:00
|
|
|
*/
|
2016-03-21 15:12:57 +01:00
|
|
|
while (buf->len > conn_mtu(conn)) {
|
|
|
|
frag = create_frag(conn, buf);
|
|
|
|
if (!frag) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-02-01 12:41:04 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (!send_frag(conn, frag, BT_ACL_CONT, true)) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-02-01 12:41:04 +01:00
|
|
|
}
|
2016-03-21 15:12:57 +01:00
|
|
|
|
|
|
|
return send_frag(conn, buf, BT_ACL_CONT, false);
|
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
|
|
|
|
2017-02-10 08:49:19 +02:00
|
|
|
static void conn_cleanup(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
/* Give back any allocated buffers */
|
|
|
|
while ((buf = net_buf_get(&conn->tx_queue, K_NO_WAIT))) {
|
2019-11-23 00:08:46 +02:00
|
|
|
if (tx_data(buf)->tx) {
|
|
|
|
tx_free(tx_data(buf)->tx);
|
|
|
|
}
|
|
|
|
|
2017-02-10 08:49:19 +02:00
|
|
|
net_buf_unref(buf);
|
|
|
|
}
|
|
|
|
|
2017-03-17 08:02:57 +02:00
|
|
|
__ASSERT(sys_slist_is_empty(&conn->tx_pending), "Pending TX packets");
|
2019-11-23 00:08:46 +02:00
|
|
|
__ASSERT_NO_MSG(conn->pending_no_cb == 0);
|
2017-10-13 15:45:32 +03:00
|
|
|
|
2017-02-10 08:49:19 +02:00
|
|
|
bt_conn_reset_rx_state(conn);
|
|
|
|
|
2019-06-17 19:26:47 +03:00
|
|
|
k_delayed_work_submit(&conn->update_work, K_NO_WAIT);
|
2017-02-10 08:49:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-02 14:39:28 +02:00
|
|
|
int bt_conn_prepare_events(struct k_poll_event events[])
|
2016-02-24 14:58:03 +01:00
|
|
|
{
|
2017-02-02 08:24:28 +02:00
|
|
|
int i, ev_count = 0;
|
|
|
|
|
|
|
|
BT_DBG("");
|
|
|
|
|
2019-03-26 19:57:45 -06:00
|
|
|
conn_change.signaled = 0U;
|
2017-02-02 08:24:28 +02:00
|
|
|
k_poll_event_init(&events[ev_count++], K_POLL_TYPE_SIGNAL,
|
|
|
|
K_POLL_MODE_NOTIFY_ONLY, &conn_change);
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(conns); i++) {
|
|
|
|
struct bt_conn *conn = &conns[i];
|
2016-02-24 14:58:03 +01:00
|
|
|
|
2017-02-02 08:24:28 +02:00
|
|
|
if (!atomic_get(&conn->ref)) {
|
|
|
|
continue;
|
|
|
|
}
|
2016-02-24 14:58:03 +01:00
|
|
|
|
2017-02-10 08:49:19 +02:00
|
|
|
if (conn->state == BT_CONN_DISCONNECTED &&
|
|
|
|
atomic_test_and_clear_bit(conn->flags, BT_CONN_CLEANUP)) {
|
|
|
|
conn_cleanup(conn);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (conn->state != BT_CONN_CONNECTED) {
|
2017-02-02 08:24:28 +02:00
|
|
|
continue;
|
2016-03-21 15:12:57 +01:00
|
|
|
}
|
|
|
|
|
2017-02-02 08:24:28 +02:00
|
|
|
BT_DBG("Adding conn %p to poll list", conn);
|
|
|
|
|
2017-03-17 08:02:57 +02:00
|
|
|
k_poll_event_init(&events[ev_count],
|
|
|
|
K_POLL_TYPE_FIFO_DATA_AVAILABLE,
|
|
|
|
K_POLL_MODE_NOTIFY_ONLY,
|
2017-07-06 12:27:11 +03:00
|
|
|
&conn->tx_queue);
|
|
|
|
events[ev_count++].tag = BT_EVENT_CONN_TX_QUEUE;
|
2017-02-02 08:24:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return ev_count;
|
|
|
|
}
|
|
|
|
|
2017-02-02 14:39:28 +02:00
|
|
|
void bt_conn_process_tx(struct bt_conn *conn)
|
2017-02-02 08:24:28 +02:00
|
|
|
{
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
BT_DBG("conn %p", conn);
|
|
|
|
|
2017-02-10 08:49:19 +02:00
|
|
|
if (conn->state == BT_CONN_DISCONNECTED &&
|
|
|
|
atomic_test_and_clear_bit(conn->flags, BT_CONN_CLEANUP)) {
|
2017-02-02 08:24:28 +02:00
|
|
|
BT_DBG("handle %u disconnected - cleaning up", conn->handle);
|
2017-02-10 08:49:19 +02:00
|
|
|
conn_cleanup(conn);
|
2017-02-02 08:24:28 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get next ACL packet for connection */
|
|
|
|
buf = net_buf_get(&conn->tx_queue, K_NO_WAIT);
|
|
|
|
BT_ASSERT(buf);
|
|
|
|
if (!send_buf(conn, buf)) {
|
2016-03-21 15:12:57 +01:00
|
|
|
net_buf_unref(buf);
|
|
|
|
}
|
2017-02-02 08:24:28 +02:00
|
|
|
}
|
|
|
|
|
2019-09-11 13:40:50 +03:00
|
|
|
struct bt_conn *bt_conn_add_le(u8_t id, const bt_addr_le_t *peer)
|
2016-02-24 14:58:03 +01:00
|
|
|
{
|
2016-03-21 15:12:57 +01:00
|
|
|
struct bt_conn *conn = conn_new();
|
2016-02-24 14:58:03 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
if (!conn) {
|
|
|
|
return NULL;
|
2016-02-24 14:58:03 +01:00
|
|
|
}
|
|
|
|
|
2019-09-11 13:40:50 +03:00
|
|
|
conn->id = id;
|
2016-03-21 15:12:57 +01:00
|
|
|
bt_addr_le_copy(&conn->le.dst, peer);
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_SMP)
|
2019-08-26 15:50:48 +02:00
|
|
|
conn->sec_level = BT_SECURITY_L1;
|
|
|
|
conn->required_sec_level = BT_SECURITY_L1;
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_SMP */
|
2016-03-21 15:12:57 +01:00
|
|
|
conn->type = BT_CONN_TYPE_LE;
|
|
|
|
conn->le.interval_min = BT_GAP_INIT_CONN_INT_MIN;
|
|
|
|
conn->le.interval_max = BT_GAP_INIT_CONN_INT_MAX;
|
2016-02-24 14:58:03 +01:00
|
|
|
|
2016-03-21 15:12:57 +01:00
|
|
|
return conn;
|
2016-02-24 14:58:03 +01:00
|
|
|
}
|
2015-11-25 11:51:25 +01:00
|
|
|
|
2017-03-17 08:02:57 +02:00
|
|
|
static void process_unack_tx(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
/* 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;
|
|
|
|
unsigned int key;
|
|
|
|
|
|
|
|
key = irq_lock();
|
2019-11-23 00:08:46 +02:00
|
|
|
|
|
|
|
if (conn->pending_no_cb) {
|
|
|
|
conn->pending_no_cb--;
|
|
|
|
irq_unlock(key);
|
|
|
|
k_sem_give(bt_conn_get_pkts(conn));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-03-17 08:02:57 +02:00
|
|
|
node = sys_slist_get(&conn->tx_pending);
|
|
|
|
irq_unlock(key);
|
|
|
|
|
|
|
|
if (!node) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-11-23 00:08:46 +02:00
|
|
|
tx = CONTAINER_OF(node, struct bt_conn_tx, node);
|
|
|
|
|
|
|
|
key = irq_lock();
|
|
|
|
conn->pending_no_cb = tx->pending_no_cb;
|
|
|
|
tx->pending_no_cb = 0U;
|
|
|
|
irq_unlock(key);
|
|
|
|
|
|
|
|
tx_free(tx);
|
2017-03-17 08:02:57 +02:00
|
|
|
|
|
|
|
k_sem_give(bt_conn_get_pkts(conn));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_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) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_WARN("no transition");
|
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.
|
|
|
|
*/
|
2015-10-23 12:45:33 +03:00
|
|
|
bt_conn_ref(conn);
|
2015-07-22 13:03:51 +03:00
|
|
|
break;
|
|
|
|
case BT_CONN_CONNECT:
|
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) {
|
2019-06-17 19:26:47 +03:00
|
|
|
k_delayed_work_cancel(&conn->update_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) {
|
|
|
|
/* TODO: Notify sco connected */
|
|
|
|
break;
|
|
|
|
}
|
2016-11-10 10:45:10 +01:00
|
|
|
k_fifo_init(&conn->tx_queue);
|
2018-11-02 12:35:30 -07:00
|
|
|
k_poll_signal_raise(&conn_change, 0);
|
2015-08-23 20:47:29 +02:00
|
|
|
|
2017-03-21 15:48:03 +02:00
|
|
|
sys_slist_init(&conn->channels);
|
|
|
|
|
2015-08-23 20:47:29 +02:00
|
|
|
bt_l2cap_connected(conn);
|
2015-10-05 15:46:52 +02:00
|
|
|
notify_connected(conn);
|
2015-06-19 18:56:13 +02:00
|
|
|
break;
|
|
|
|
case BT_CONN_DISCONNECTED:
|
2017-02-15 15:18:13 +05:30
|
|
|
if (conn->type == BT_CONN_TYPE_SCO) {
|
|
|
|
/* TODO: Notify sco disconnected */
|
|
|
|
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
|
|
|
*/
|
|
|
|
if (old_state == BT_CONN_CONNECTED ||
|
|
|
|
old_state == BT_CONN_DISCONNECT) {
|
2017-03-17 08:02:57 +02:00
|
|
|
process_unack_tx(conn);
|
2019-11-28 14:11:57 +02:00
|
|
|
tx_notify(conn);
|
2017-02-02 08:24:28 +02:00
|
|
|
|
|
|
|
/* Cancel Connection Update if it is pending */
|
|
|
|
if (conn->type == BT_CONN_TYPE_LE) {
|
2019-06-17 19:26:47 +03:00
|
|
|
k_delayed_work_cancel(&conn->update_work);
|
2017-02-02 08:24:28 +02:00
|
|
|
}
|
|
|
|
|
2017-02-10 08:49:19 +02:00
|
|
|
atomic_set_bit(conn->flags, BT_CONN_CLEANUP);
|
2018-11-02 12:35:30 -07:00
|
|
|
k_poll_signal_raise(&conn_change, 0);
|
2019-06-17 19:26:47 +03:00
|
|
|
/* The last ref will be dropped during cleanup */
|
2016-01-14 11:17:32 +02:00
|
|
|
} else if (old_state == BT_CONN_CONNECT) {
|
|
|
|
/* conn->err will be set in this case */
|
|
|
|
notify_connected(conn);
|
2017-02-02 08:24:28 +02:00
|
|
|
bt_conn_unref(conn);
|
2017-02-14 21:49:17 +01:00
|
|
|
} else if (old_state == BT_CONN_CONNECT_SCAN) {
|
2020-01-07 12:40:30 +01:00
|
|
|
/* this indicate LE Create Connection with peer address
|
|
|
|
* has been stopped. This could either be triggered by
|
|
|
|
* the application through bt_conn_disconnect or by
|
|
|
|
* timeout set by CONFIG_BT_CREATE_CONN_TIMEOUT.
|
|
|
|
*/
|
2017-02-14 21:49:17 +01:00
|
|
|
if (conn->err) {
|
|
|
|
notify_connected(conn);
|
|
|
|
}
|
|
|
|
|
2018-08-20 14:44:42 +02:00
|
|
|
bt_conn_unref(conn);
|
|
|
|
} else if (old_state == BT_CONN_CONNECT_DIR_ADV) {
|
|
|
|
/* this indicate Directed advertising stopped */
|
|
|
|
if (conn->err) {
|
|
|
|
notify_connected(conn);
|
|
|
|
}
|
|
|
|
|
2017-02-02 08:24:28 +02:00
|
|
|
bt_conn_unref(conn);
|
2020-01-07 12:40:30 +01:00
|
|
|
} else if (old_state == BT_CONN_CONNECT_AUTO) {
|
|
|
|
/* 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);
|
2015-07-03 12:05:23 +02:00
|
|
|
}
|
2020-01-07 12:40:30 +01:00
|
|
|
break;
|
|
|
|
case BT_CONN_CONNECT_AUTO:
|
2015-06-19 18:56:13 +02:00
|
|
|
break;
|
2015-07-02 11:16:55 +02:00
|
|
|
case BT_CONN_CONNECT_SCAN:
|
2015-07-22 13:03:51 +03:00
|
|
|
break;
|
2018-08-20 14:44:42 +02:00
|
|
|
case BT_CONN_CONNECT_DIR_ADV:
|
|
|
|
break;
|
2015-06-19 18:56:13 +02:00
|
|
|
case BT_CONN_CONNECT:
|
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) &&
|
2017-01-31 09:41:35 +02:00
|
|
|
conn->type == BT_CONN_TYPE_LE) {
|
2019-06-17 19:26:47 +03:00
|
|
|
k_delayed_work_submit(&conn->update_work, CONN_TIMEOUT);
|
2016-01-11 17:24:43 +01:00
|
|
|
}
|
|
|
|
|
2015-07-22 13:03:51 +03:00
|
|
|
break;
|
2015-06-19 18:56:13 +02:00
|
|
|
case BT_CONN_DISCONNECT:
|
|
|
|
break;
|
|
|
|
default:
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_WARN("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
|
|
|
}
|
|
|
|
|
2017-04-20 12:00:29 -05:00
|
|
|
struct bt_conn *bt_conn_lookup_handle(u16_t handle)
|
2015-04-28 10:39:50 +03:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2015-05-21 13:21:08 +03:00
|
|
|
for (i = 0; i < ARRAY_SIZE(conns); i++) {
|
2015-08-19 18:44:32 +02:00
|
|
|
if (!atomic_get(&conns[i].ref)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-07-08 11:00:13 +03:00
|
|
|
/* We only care about connections with a valid handle */
|
|
|
|
if (conns[i].state != BT_CONN_CONNECTED &&
|
|
|
|
conns[i].state != BT_CONN_DISCONNECT) {
|
2015-04-28 10:39:50 +03:00
|
|
|
continue;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (conns[i].handle == handle) {
|
2015-10-23 12:45:33 +03:00
|
|
|
return bt_conn_ref(&conns[i]);
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
}
|
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_BREDR)
|
2017-02-15 15:18:13 +05:30
|
|
|
for (i = 0; i < ARRAY_SIZE(sco_conns); i++) {
|
|
|
|
if (!atomic_get(&sco_conns[i].ref)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We only care about connections with a valid handle */
|
|
|
|
if (sco_conns[i].state != BT_CONN_CONNECTED &&
|
|
|
|
sco_conns[i].state != BT_CONN_DISCONNECT) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sco_conns[i].handle == handle) {
|
|
|
|
return bt_conn_ref(&sco_conns[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-04-28 10:39:50 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-30 14:22:23 +02:00
|
|
|
int bt_conn_addr_le_cmp(const struct bt_conn *conn, const bt_addr_le_t *peer)
|
|
|
|
{
|
|
|
|
/* Check against conn dst address as it may be the identity address */
|
|
|
|
if (!bt_addr_le_cmp(peer, &conn->le.dst)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check against initial connection address */
|
|
|
|
if (conn->role == BT_HCI_ROLE_MASTER) {
|
|
|
|
return bt_addr_le_cmp(peer, &conn->le.resp_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return bt_addr_le_cmp(peer, &conn->le.init_addr);
|
|
|
|
}
|
|
|
|
|
2018-07-04 12:58:10 +03:00
|
|
|
struct bt_conn *bt_conn_lookup_addr_le(u8_t id, const bt_addr_le_t *peer)
|
2015-05-26 14:25:03 +03:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(conns); i++) {
|
2015-08-19 18:44:32 +02:00
|
|
|
if (!atomic_get(&conns[i].ref)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-12-07 10:42:57 +02:00
|
|
|
if (conns[i].type != BT_CONN_TYPE_LE) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-07-04 12:58:10 +03:00
|
|
|
if (conns[i].id == id &&
|
|
|
|
!bt_conn_addr_le_cmp(&conns[i], peer)) {
|
2015-10-23 12:45:33 +03:00
|
|
|
return bt_conn_ref(&conns[i]);
|
2015-05-26 14:25:03 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-25 11:31:17 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-12-07 10:45:41 +02:00
|
|
|
struct bt_conn *bt_conn_lookup_state_le(const bt_addr_le_t *peer,
|
|
|
|
const bt_conn_state_t state)
|
2015-06-25 11:31:17 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(conns); i++) {
|
2015-08-19 18:44:32 +02:00
|
|
|
if (!atomic_get(&conns[i].ref)) {
|
2015-07-01 18:16:35 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-12-07 10:45:41 +02:00
|
|
|
if (conns[i].type != BT_CONN_TYPE_LE) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-11-30 14:22:23 +02:00
|
|
|
if (peer && bt_conn_addr_le_cmp(&conns[i], peer)) {
|
2015-06-25 11:31:17 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conns[i].state == state) {
|
2015-10-23 12:45:33 +03:00
|
|
|
return bt_conn_ref(&conns[i]);
|
2015-06-25 11:31:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-26 14:25:03 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-07-09 15:17:07 +02:00
|
|
|
void bt_conn_foreach(int type, void (*func)(struct bt_conn *conn, void *data),
|
|
|
|
void *data)
|
2016-11-04 21:34:05 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(conns); i++) {
|
2019-07-09 15:17:07 +02:00
|
|
|
if (!atomic_get(&conns[i].ref)) {
|
2016-11-04 21:34:05 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-07-09 15:17:07 +02:00
|
|
|
if (!(conns[i].type & type)) {
|
2018-07-18 13:45:44 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-07-09 15:17:07 +02:00
|
|
|
func(&conns[i], data);
|
|
|
|
}
|
|
|
|
#if defined(CONFIG_BT_BREDR)
|
|
|
|
if (type & BT_CONN_TYPE_SCO) {
|
|
|
|
for (i = 0; i < ARRAY_SIZE(sco_conns); i++) {
|
|
|
|
if (!atomic_get(&sco_conns[i].ref)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
func(&sco_conns[i], data);
|
2016-11-04 21:34:05 +02:00
|
|
|
}
|
|
|
|
}
|
2019-07-09 15:17:07 +02:00
|
|
|
#endif /* defined(CONFIG_BT_BREDR) */
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2015-06-23 14:38:24 +02:00
|
|
|
atomic_inc(&conn->ref);
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("handle %u ref %u", conn->handle, atomic_get(&conn->ref));
|
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
|
|
|
{
|
2015-08-19 18:44:32 +02:00
|
|
|
atomic_dec(&conn->ref);
|
2015-06-26 14:52:55 +02:00
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("handle %u ref %u", conn->handle, atomic_get(&conn->ref));
|
2015-04-28 10:39:50 +03:00
|
|
|
}
|
2015-06-18 09:36:59 +02:00
|
|
|
|
|
|
|
const bt_addr_le_t *bt_conn_get_dst(const struct bt_conn *conn)
|
|
|
|
{
|
2015-11-03 12:19:01 +01:00
|
|
|
return &conn->le.dst;
|
2015-06-18 09:36:59 +02:00
|
|
|
}
|
2015-06-25 11:08:57 +02:00
|
|
|
|
2015-11-27 15:00:52 +02:00
|
|
|
int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info)
|
|
|
|
{
|
|
|
|
info->type = conn->type;
|
2016-02-11 13:15:55 +02:00
|
|
|
info->role = conn->role;
|
2018-07-04 12:58:10 +03:00
|
|
|
info->id = conn->id;
|
2015-11-27 15:00:52 +02:00
|
|
|
|
|
|
|
switch (conn->type) {
|
|
|
|
case BT_CONN_TYPE_LE:
|
2019-08-07 09:46:11 +02:00
|
|
|
info->le.dst = &conn->le.dst;
|
|
|
|
info->le.src = &bt_dev.id_addr[conn->id];
|
2015-11-27 15:00:52 +02:00
|
|
|
if (conn->role == BT_HCI_ROLE_MASTER) {
|
2019-08-07 09:46:11 +02:00
|
|
|
info->le.local = &conn->le.init_addr;
|
|
|
|
info->le.remote = &conn->le.resp_addr;
|
2015-11-27 15:00:52 +02:00
|
|
|
} else {
|
2019-08-07 09:46:11 +02:00
|
|
|
info->le.local = &conn->le.resp_addr;
|
|
|
|
info->le.remote = &conn->le.init_addr;
|
2015-11-27 15:00:52 +02:00
|
|
|
}
|
2016-02-03 10:32:23 +01:00
|
|
|
info->le.interval = conn->le.interval;
|
|
|
|
info->le.latency = conn->le.latency;
|
|
|
|
info->le.timeout = conn->le.timeout;
|
2015-11-27 15:00:52 +02:00
|
|
|
return 0;
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_BREDR)
|
2015-12-16 12:32:09 +01:00
|
|
|
case BT_CONN_TYPE_BR:
|
|
|
|
info->br.dst = &conn->br.dst;
|
|
|
|
return 0;
|
|
|
|
#endif
|
2015-11-27 15:00:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2019-09-27 14:53:40 +02:00
|
|
|
int bt_conn_get_remote_info(struct bt_conn *conn,
|
|
|
|
struct bt_conn_remote_info *remote_info)
|
|
|
|
{
|
|
|
|
if (!atomic_test_bit(conn->flags, BT_CONN_AUTO_FEATURE_EXCH) ||
|
|
|
|
(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;
|
|
|
|
#if defined(CONFIG_BT_BREDR)
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-20 12:00:29 -05:00
|
|
|
static int bt_hci_disconnect(struct bt_conn *conn, u8_t reason)
|
2015-07-15 12:31:08 +03:00
|
|
|
{
|
2015-10-28 10:39:02 +02:00
|
|
|
struct net_buf *buf;
|
2015-07-15 12:31:08 +03:00
|
|
|
struct bt_hci_cp_disconnect *disconn;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_DISCONNECT, sizeof(*disconn));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:39:02 +02:00
|
|
|
disconn = net_buf_add(buf, sizeof(*disconn));
|
2015-07-15 12:31:08 +03:00
|
|
|
disconn->handle = sys_cpu_to_le16(conn->handle);
|
|
|
|
disconn->reason = reason;
|
|
|
|
|
|
|
|
err = bt_hci_cmd_send(BT_HCI_OP_DISCONNECT, buf);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECT);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-02 12:48:42 +01:00
|
|
|
int bt_conn_le_param_update(struct bt_conn *conn,
|
|
|
|
const struct bt_le_conn_param *param)
|
|
|
|
{
|
2016-12-06 19:21:12 +02:00
|
|
|
BT_DBG("conn %p features 0x%02x params (%d-%d %d %d)", conn,
|
2017-05-06 07:08:56 +02:00
|
|
|
conn->le.features[0], param->interval_min,
|
2016-12-06 19:21:12 +02:00
|
|
|
param->interval_max, param->latency, param->timeout);
|
2016-05-03 13:03:44 +03:00
|
|
|
|
|
|
|
/* Check if there's a need to update conn params */
|
|
|
|
if (conn->le.interval >= param->interval_min &&
|
2017-03-17 10:49:31 +01:00
|
|
|
conn->le.interval <= param->interval_max &&
|
|
|
|
conn->le.latency == param->latency &&
|
|
|
|
conn->le.timeout == param->timeout) {
|
2018-11-14 13:21:37 +01:00
|
|
|
atomic_clear_bit(conn->flags, BT_CONN_SLAVE_PARAM_SET);
|
2016-05-03 13:03:44 +03:00
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
2018-09-24 08:18:57 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
|
|
|
|
conn->role == BT_CONN_ROLE_MASTER) {
|
|
|
|
return send_conn_le_param_update(conn, param);
|
|
|
|
}
|
2016-05-23 16:17:20 +03:00
|
|
|
|
2018-09-24 08:18:57 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_PERIPHERAL)) {
|
|
|
|
/* if slave conn param update timer expired just send request */
|
|
|
|
if (atomic_test_bit(conn->flags, BT_CONN_SLAVE_PARAM_UPDATE)) {
|
|
|
|
return send_conn_le_param_update(conn, param);
|
|
|
|
}
|
|
|
|
|
2018-11-06 13:48:07 +01:00
|
|
|
/* store new conn params to be used by update timer */
|
2018-09-24 08:18:57 +02:00
|
|
|
conn->le.interval_min = param->interval_min;
|
|
|
|
conn->le.interval_max = param->interval_max;
|
2018-11-06 13:48:07 +01:00
|
|
|
conn->le.pending_latency = param->latency;
|
|
|
|
conn->le.pending_timeout = param->timeout;
|
2018-09-24 11:20:20 +02:00
|
|
|
atomic_set_bit(conn->flags, BT_CONN_SLAVE_PARAM_SET);
|
2016-05-03 13:03:44 +03:00
|
|
|
}
|
|
|
|
|
2018-09-24 08:18:57 +02:00
|
|
|
return 0;
|
2016-02-02 12:48:42 +01:00
|
|
|
}
|
|
|
|
|
2017-04-20 12:00:29 -05:00
|
|
|
int bt_conn_disconnect(struct bt_conn *conn, u8_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.
|
|
|
|
*/
|
2019-07-22 13:13:38 +02:00
|
|
|
#if !defined(CONFIG_BT_WHITELIST)
|
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
|
|
|
}
|
2019-07-22 13:13:38 +02:00
|
|
|
#endif /* !defined(CONFIG_BT_WHITELIST) */
|
2015-07-15 12:31:08 +03:00
|
|
|
|
|
|
|
switch (conn->state) {
|
|
|
|
case BT_CONN_CONNECT_SCAN:
|
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)) {
|
|
|
|
bt_le_scan_update(false);
|
|
|
|
}
|
2015-07-15 12:31:08 +03:00
|
|
|
return 0;
|
2018-08-20 14:44:42 +02:00
|
|
|
case BT_CONN_CONNECT_DIR_ADV:
|
|
|
|
conn->err = reason;
|
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
|
|
|
if (IS_ENABLED(CONFIG_BT_PERIPHERAL)) {
|
|
|
|
/* User should unref connection object when receiving
|
|
|
|
* error in connection callback.
|
|
|
|
*/
|
|
|
|
return bt_le_adv_stop();
|
|
|
|
}
|
|
|
|
return 0;
|
2015-07-15 12:31:08 +03:00
|
|
|
case BT_CONN_CONNECT:
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_BREDR)
|
2016-03-14 10:20:04 +01:00
|
|
|
if (conn->type == BT_CONN_TYPE_BR) {
|
|
|
|
return bt_hci_connect_br_cancel(conn);
|
|
|
|
}
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_BREDR */
|
2016-03-14 10:20:04 +01:00
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CENTRAL)) {
|
2019-06-17 19:26:47 +03:00
|
|
|
k_delayed_work_cancel(&conn->update_work);
|
2017-01-31 09:41:35 +02:00
|
|
|
return bt_hci_cmd_send(BT_HCI_OP_LE_CREATE_CONN_CANCEL,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2015-07-15 12:31:08 +03:00
|
|
|
case BT_CONN_CONNECTED:
|
|
|
|
return bt_hci_disconnect(conn, reason);
|
|
|
|
case BT_CONN_DISCONNECT:
|
|
|
|
return 0;
|
|
|
|
case BT_CONN_DISCONNECTED:
|
|
|
|
default:
|
|
|
|
return -ENOTCONN;
|
|
|
|
}
|
|
|
|
}
|
2015-07-15 13:55:32 +03:00
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-07-22 13:13:38 +02:00
|
|
|
#if defined(CONFIG_BT_WHITELIST)
|
|
|
|
int bt_conn_create_auto_le(const struct bt_le_conn_param *param)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_AUTO_CONN)) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't start initiator if we have general discovery procedure. */
|
|
|
|
conn = bt_conn_lookup_state_le(NULL, BT_CONN_CONNECT_SCAN);
|
|
|
|
if (conn) {
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't start initiator if we have direct discovery procedure. */
|
|
|
|
conn = bt_conn_lookup_state_le(NULL, BT_CONN_CONNECT);
|
|
|
|
if (conn) {
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_set_state(conn, BT_CONN_CONNECT_AUTO);
|
|
|
|
|
2019-07-22 13:13:38 +02:00
|
|
|
err = bt_le_auto_conn(param);
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("Failed to start whitelist scan");
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_AUTO_CONN)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-01-07 12:40:30 +01:00
|
|
|
conn = bt_conn_lookup_state_le(BT_ADDR_LE_NONE, BT_CONN_CONNECT_AUTO);
|
|
|
|
if (conn) {
|
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
}
|
|
|
|
|
2019-11-21 17:49:55 +01:00
|
|
|
err = bt_le_auto_conn_cancel();
|
2019-07-22 13:13:38 +02:00
|
|
|
if (err) {
|
|
|
|
BT_ERR("Failed to stop initiator");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* defined(CONFIG_BT_WHITELIST) */
|
|
|
|
|
2015-12-05 15:32:58 +02:00
|
|
|
struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer,
|
|
|
|
const struct bt_le_conn_param *param)
|
2015-07-15 13:55:32 +03:00
|
|
|
{
|
|
|
|
struct bt_conn *conn;
|
2019-08-02 16:04:01 +02:00
|
|
|
bt_addr_le_t dst;
|
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)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-01-13 13:20:22 +02:00
|
|
|
if (!bt_le_conn_params_valid(param)) {
|
2015-12-05 22:47:23 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-12-03 19:45:46 +02:00
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-07-22 13:13:38 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_WHITELIST) &&
|
|
|
|
atomic_test_bit(bt_dev.flags, BT_DEV_AUTO_CONN)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-07-04 12:58:10 +03:00
|
|
|
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, peer);
|
2015-07-15 13:55:32 +03:00
|
|
|
if (conn) {
|
|
|
|
switch (conn->state) {
|
|
|
|
case BT_CONN_CONNECT_SCAN:
|
2015-12-05 21:39:44 +02:00
|
|
|
bt_conn_set_param_le(conn, param);
|
2015-12-05 15:32:58 +02:00
|
|
|
return conn;
|
2015-07-15 13:55:32 +03:00
|
|
|
case BT_CONN_CONNECT:
|
|
|
|
case BT_CONN_CONNECTED:
|
|
|
|
return conn;
|
2019-06-17 19:26:47 +03:00
|
|
|
case BT_CONN_DISCONNECTED:
|
|
|
|
BT_WARN("Found valid but disconnected conn object");
|
|
|
|
goto start_scan;
|
2015-07-15 13:55:32 +03:00
|
|
|
default:
|
2015-10-23 12:45:33 +03:00
|
|
|
bt_conn_unref(conn);
|
2015-07-15 13:55:32 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-02 16:04:01 +02:00
|
|
|
if (peer->type == BT_ADDR_LE_PUBLIC_ID ||
|
|
|
|
peer->type == BT_ADDR_LE_RANDOM_ID) {
|
|
|
|
bt_addr_le_copy(&dst, peer);
|
|
|
|
dst.type -= BT_ADDR_LE_PUBLIC_ID;
|
|
|
|
} 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) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-06-17 19:26:47 +03:00
|
|
|
start_scan:
|
2015-12-05 21:39:44 +02:00
|
|
|
bt_conn_set_param_le(conn, param);
|
2015-12-05 15:32:58 +02:00
|
|
|
|
2020-01-06 14:32:07 +01:00
|
|
|
#if defined(CONFIG_BT_SMP)
|
|
|
|
if (!bt_dev.le.rl_size || bt_dev.le.rl_entries > bt_dev.le.rl_size) {
|
|
|
|
bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN);
|
|
|
|
|
|
|
|
bt_le_scan_update(true);
|
2015-07-15 13:55:32 +03:00
|
|
|
|
2020-01-06 14:32:07 +01:00
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (bt_le_direct_conn(conn)) {
|
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
|
|
|
|
bt_le_scan_update(false);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_set_state(conn, BT_CONN_CONNECT);
|
2015-07-15 13:55:32 +03:00
|
|
|
|
|
|
|
return conn;
|
|
|
|
}
|
2015-07-15 14:04:52 +03:00
|
|
|
|
2019-07-22 13:13:38 +02:00
|
|
|
#if !defined(CONFIG_BT_WHITELIST)
|
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;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
if (conn->state == BT_CONN_CONNECT_SCAN) {
|
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->state == BT_CONN_DISCONNECTED &&
|
|
|
|
atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
|
|
|
|
if (param) {
|
|
|
|
bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN);
|
|
|
|
}
|
|
|
|
bt_le_scan_update(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-07-22 13:13:38 +02:00
|
|
|
#endif /* !defined(CONFIG_BT_WHITELIST) */
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_CENTRAL */
|
2016-01-14 15:10:22 +02:00
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_PERIPHERAL)
|
2016-01-14 23:08:34 +02:00
|
|
|
struct bt_conn *bt_conn_create_slave_le(const bt_addr_le_t *peer,
|
|
|
|
const struct bt_le_adv_param *param)
|
|
|
|
{
|
2018-08-20 14:44:42 +02:00
|
|
|
int err;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
struct bt_le_adv_param param_int;
|
|
|
|
|
|
|
|
memcpy(¶m_int, param, sizeof(param_int));
|
|
|
|
param_int.options |= (BT_LE_ADV_OPT_CONNECTABLE |
|
|
|
|
BT_LE_ADV_OPT_ONE_TIME);
|
|
|
|
|
2019-04-17 17:32:08 +02:00
|
|
|
conn = bt_conn_lookup_addr_le(param->id, peer);
|
2018-08-20 14:44:42 +02:00
|
|
|
if (conn) {
|
|
|
|
switch (conn->state) {
|
|
|
|
case BT_CONN_CONNECT_DIR_ADV:
|
|
|
|
case BT_CONN_CONNECTED:
|
|
|
|
return conn;
|
2019-06-17 19:26:47 +03:00
|
|
|
case BT_CONN_DISCONNECTED:
|
|
|
|
BT_WARN("Found valid but disconnected conn object");
|
|
|
|
goto start_adv;
|
2018-08-20 14:44:42 +02:00
|
|
|
default:
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-11 13:40:50 +03:00
|
|
|
conn = bt_conn_add_le(param->id, peer);
|
2018-08-20 14:44:42 +02:00
|
|
|
if (!conn) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-06-17 19:26:47 +03:00
|
|
|
start_adv:
|
2018-08-20 14:44:42 +02:00
|
|
|
bt_conn_set_state(conn, BT_CONN_CONNECT_DIR_ADV);
|
|
|
|
|
|
|
|
err = bt_le_adv_start_internal(¶m_int, NULL, 0, NULL, 0, peer);
|
|
|
|
if (err) {
|
|
|
|
BT_WARN("Directed advertising could not be started: %d", err);
|
|
|
|
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return conn;
|
2016-01-14 23:08:34 +02:00
|
|
|
}
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_PERIPHERAL */
|
2016-01-14 23:08:34 +02:00
|
|
|
|
2016-02-02 12:48:42 +01:00
|
|
|
int bt_conn_le_conn_update(struct bt_conn *conn,
|
|
|
|
const struct bt_le_conn_param *param)
|
2015-07-15 14:08:53 +03:00
|
|
|
{
|
|
|
|
struct hci_cp_le_conn_update *conn_update;
|
2015-10-28 10:39:02 +02:00
|
|
|
struct net_buf *buf;
|
2015-07-15 14:08:53 +03:00
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CONN_UPDATE,
|
|
|
|
sizeof(*conn_update));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:39:02 +02:00
|
|
|
conn_update = net_buf_add(buf, sizeof(*conn_update));
|
2018-09-11 19:09:03 -07:00
|
|
|
(void)memset(conn_update, 0, sizeof(*conn_update));
|
2015-07-15 14:08:53 +03:00
|
|
|
conn_update->handle = sys_cpu_to_le16(conn->handle);
|
2016-02-02 12:48:42 +01:00
|
|
|
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);
|
2015-07-15 14:08:53 +03:00
|
|
|
|
2019-11-18 14:28:18 +01:00
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CONN_UPDATE, buf, NULL);
|
2015-07-15 14:08:53 +03:00
|
|
|
}
|
2015-11-03 14:01:34 +01:00
|
|
|
|
2019-11-14 16:07:00 +02:00
|
|
|
#if defined(CONFIG_NET_BUF_LOG)
|
|
|
|
struct net_buf *bt_conn_create_frag_timeout_debug(size_t reserve, s32_t timeout,
|
|
|
|
const char *func, int line)
|
|
|
|
#else
|
|
|
|
struct net_buf *bt_conn_create_frag_timeout(size_t reserve, s32_t timeout)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
struct net_buf_pool *pool = NULL;
|
|
|
|
|
|
|
|
#if CONFIG_BT_L2CAP_TX_FRAG_COUNT > 0
|
|
|
|
pool = &frag_pool;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_BUF_LOG)
|
|
|
|
return bt_conn_create_pdu_timeout_debug(pool, reserve, timeout,
|
|
|
|
func, line);
|
|
|
|
#else
|
|
|
|
return bt_conn_create_pdu_timeout(pool, reserve, timeout);
|
|
|
|
#endif /* CONFIG_NET_BUF_LOG */
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_BUF_LOG)
|
|
|
|
struct net_buf *bt_conn_create_pdu_timeout_debug(struct net_buf_pool *pool,
|
|
|
|
size_t reserve, s32_t timeout,
|
|
|
|
const char *func, int line)
|
|
|
|
#else
|
2019-08-27 14:23:54 +03:00
|
|
|
struct net_buf *bt_conn_create_pdu_timeout(struct net_buf_pool *pool,
|
|
|
|
size_t reserve, s32_t timeout)
|
2019-11-14 16:07:00 +02:00
|
|
|
#endif
|
2015-11-05 15:46:25 +02:00
|
|
|
{
|
2016-10-18 23:24:51 +03:00
|
|
|
struct net_buf *buf;
|
2018-08-16 17:56:49 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* PDU must not be allocated from ISR as we block with 'K_FOREVER'
|
|
|
|
* during the allocation
|
|
|
|
*/
|
|
|
|
__ASSERT_NO_MSG(!k_is_in_isr());
|
2016-10-18 23:24:51 +03:00
|
|
|
|
2017-01-07 17:05:58 +02:00
|
|
|
if (!pool) {
|
|
|
|
pool = &acl_tx_pool;
|
|
|
|
}
|
|
|
|
|
2019-11-23 12:56:44 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_DEBUG_CONN)) {
|
2019-11-14 16:07:00 +02:00
|
|
|
#if defined(CONFIG_NET_BUF_LOG)
|
|
|
|
buf = net_buf_alloc_fixed_debug(pool, K_NO_WAIT, func, line);
|
|
|
|
#else
|
2019-08-01 16:34:26 +03:00
|
|
|
buf = net_buf_alloc(pool, K_NO_WAIT);
|
2019-11-14 16:07:00 +02:00
|
|
|
#endif
|
2019-08-01 16:34:26 +03:00
|
|
|
if (!buf) {
|
2019-08-27 14:23:54 +03:00
|
|
|
BT_WARN("Unable to allocate buffer with K_NO_WAIT");
|
2019-11-14 16:07:00 +02:00
|
|
|
#if defined(CONFIG_NET_BUF_LOG)
|
|
|
|
buf = net_buf_alloc_fixed_debug(pool, timeout, func,
|
|
|
|
line);
|
|
|
|
#else
|
2019-08-27 14:23:54 +03:00
|
|
|
buf = net_buf_alloc(pool, timeout);
|
2019-11-14 16:07:00 +02:00
|
|
|
#endif
|
2019-08-01 16:34:26 +03:00
|
|
|
}
|
|
|
|
} else {
|
2019-11-14 16:07:00 +02:00
|
|
|
#if defined(CONFIG_NET_BUF_LOG)
|
|
|
|
buf = net_buf_alloc_fixed_debug(pool, timeout, func,
|
|
|
|
line);
|
|
|
|
#else
|
2019-08-27 14:23:54 +03:00
|
|
|
buf = net_buf_alloc(pool, timeout);
|
2019-11-14 16:07:00 +02:00
|
|
|
#endif
|
2019-08-01 16:34:26 +03:00
|
|
|
}
|
|
|
|
|
2019-08-27 14:23:54 +03:00
|
|
|
if (!buf) {
|
|
|
|
BT_WARN("Unable to allocate buffer: timeout %d", timeout);
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-02-07 10:53:40 +01:00
|
|
|
|
2019-11-12 17:02:13 +02:00
|
|
|
reserve += sizeof(struct bt_hci_acl_hdr) + BT_BUF_RESERVE;
|
2017-02-07 10:53:40 +01:00
|
|
|
net_buf_reserve(buf, reserve);
|
2015-11-05 15:46:25 +02:00
|
|
|
|
2016-10-18 23:24:51 +03:00
|
|
|
return buf;
|
2015-11-05 15:46:25 +02:00
|
|
|
}
|
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
|
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 ||
|
|
|
|
#if defined(CONFIG_BT_BREDR)
|
|
|
|
cb->pincode_entry ||
|
|
|
|
#endif
|
|
|
|
cb->pairing_confirm)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-01-14 17:32:53 +02:00
|
|
|
bt_auth = cb;
|
|
|
|
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
|
|
|
{
|
|
|
|
if (!bt_auth) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2017-01-17 19:03:55 +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
|
|
|
bt_smp_auth_passkey_entry(conn, passkey);
|
|
|
|
return 0;
|
|
|
|
}
|
2017-01-17 19:03:55 +02:00
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_BREDR)
|
2016-02-24 14:58:03 +01:00
|
|
|
if (conn->type == BT_CONN_TYPE_BR) {
|
2016-03-09 14:39:34 +01:00
|
|
|
/* User entered passkey, reset user state. */
|
|
|
|
if (!atomic_test_and_clear_bit(conn->flags, BT_CONN_USER)) {
|
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
|
2016-03-29 10:39:44 +02:00
|
|
|
if (conn->br.pairing_method == PASSKEY_INPUT) {
|
2016-02-24 14:58:03 +01:00
|
|
|
return ssp_passkey_reply(conn, passkey);
|
|
|
|
}
|
|
|
|
}
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_BREDR */
|
2016-01-14 17:32:53 +02:00
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
|
|
|
if (!bt_auth) {
|
|
|
|
return -EINVAL;
|
2017-01-17 19:03:55 +02:00
|
|
|
}
|
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
if (IS_ENABLED(CONFIG_BT_SMP) &&
|
2017-01-17 19:03:55 +02:00
|
|
|
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
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_BREDR)
|
2016-02-01 12:41:04 +01:00
|
|
|
if (conn->type == BT_CONN_TYPE_BR) {
|
2016-02-24 11:54:14 +01:00
|
|
|
/* Allow user confirm passkey value, then reset user state. */
|
|
|
|
if (!atomic_test_and_clear_bit(conn->flags, BT_CONN_USER)) {
|
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
|
2016-02-01 12:41:04 +01:00
|
|
|
return ssp_confirm_reply(conn);
|
|
|
|
}
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_BREDR */
|
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
|
|
|
{
|
|
|
|
if (!bt_auth) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2017-01-17 19:03:55 +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
|
|
|
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_BREDR)
|
2016-01-14 17:32:53 +02:00
|
|
|
if (conn->type == BT_CONN_TYPE_BR) {
|
2016-01-13 15:34:19 +01:00
|
|
|
/* Allow user cancel authentication, then reset user state. */
|
|
|
|
if (!atomic_test_and_clear_bit(conn->flags, BT_CONN_USER)) {
|
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
|
2016-03-21 14:01:19 +01:00
|
|
|
switch (conn->br.pairing_method) {
|
|
|
|
case JUST_WORKS:
|
|
|
|
case PASSKEY_CONFIRM:
|
2016-02-01 12:41:04 +01:00
|
|
|
return ssp_confirm_neg_reply(conn);
|
2016-03-21 14:01:19 +01:00
|
|
|
case PASSKEY_INPUT:
|
2016-02-24 14:58:03 +01:00
|
|
|
return ssp_passkey_neg_reply(conn);
|
2016-03-21 14:01:19 +01:00
|
|
|
case PASSKEY_DISPLAY:
|
2016-03-21 13:38:45 +01:00
|
|
|
return bt_conn_disconnect(conn,
|
2019-08-26 17:27:54 +02:00
|
|
|
BT_HCI_ERR_AUTH_FAIL);
|
2016-03-21 14:01:19 +01:00
|
|
|
case LEGACY:
|
|
|
|
return pin_code_neg_reply(&conn->br.dst);
|
|
|
|
default:
|
|
|
|
break;
|
2016-03-21 13:38:45 +01:00
|
|
|
}
|
2016-01-14 17:32:53 +02:00
|
|
|
}
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_BREDR */
|
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)
|
|
|
|
{
|
|
|
|
if (!bt_auth) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (conn->type) {
|
2017-08-09 09:21:11 +03:00
|
|
|
#if defined(CONFIG_BT_SMP)
|
2016-02-08 10:53:03 +01:00
|
|
|
case BT_CONN_TYPE_LE:
|
|
|
|
return bt_smp_auth_pairing_confirm(conn);
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_SMP */
|
|
|
|
#if defined(CONFIG_BT_BREDR)
|
2016-02-08 10:53:03 +01:00
|
|
|
case BT_CONN_TYPE_BR:
|
|
|
|
return ssp_confirm_reply(conn);
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_BREDR */
|
2016-02-08 10:53:03 +01:00
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
2017-08-09 09:21:11 +03:00
|
|
|
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
|
2016-01-14 17:32:53 +02:00
|
|
|
|
2018-11-26 09:10:06 +01:00
|
|
|
u8_t bt_conn_index(struct bt_conn *conn)
|
2017-10-12 14:02:29 +03:00
|
|
|
{
|
2018-11-26 09:10:06 +01:00
|
|
|
u8_t index = conn - conns;
|
|
|
|
|
|
|
|
__ASSERT(index < CONFIG_BT_MAX_CONN, "Invalid bt_conn pointer");
|
|
|
|
return index;
|
2017-10-12 14:02:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_conn *bt_conn_lookup_id(u8_t id)
|
|
|
|
{
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
|
|
|
if (id >= ARRAY_SIZE(conns)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn = &conns[id];
|
|
|
|
|
|
|
|
if (!atomic_get(&conn->ref)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bt_conn_ref(conn);
|
|
|
|
}
|
|
|
|
|
2015-11-03 17:15:40 +02:00
|
|
|
int bt_conn_init(void)
|
|
|
|
{
|
2017-03-17 08:02:57 +02:00
|
|
|
int err, i;
|
|
|
|
|
|
|
|
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)) {
|
2017-01-17 19:03:55 +02:00
|
|
|
for (i = 0; i < ARRAY_SIZE(conns); i++) {
|
|
|
|
struct bt_conn *conn = &conns[i];
|
|
|
|
|
|
|
|
if (!atomic_get(&conn->ref)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2017-01-17 19:03:55 +02:00
|
|
|
bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-12-04 11:38:50 +02:00
|
|
|
|
2015-11-03 17:15:40 +02:00
|
|
|
return 0;
|
|
|
|
}
|