2015-04-14 14:38:13 +03:00
|
|
|
/* hci_core.c - HCI core Bluetooth handling */
|
|
|
|
|
|
|
|
/*
|
2016-06-10 12:10:18 +03:00
|
|
|
* Copyright (c) 2015-2016 Intel Corporation
|
2015-04-14 14:38:13 +03:00
|
|
|
*
|
2015-10-06 11:00:37 -05:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2015-04-14 14:38:13 +03:00
|
|
|
*
|
2015-10-06 11:00:37 -05:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2015-04-14 14:38:13 +03:00
|
|
|
*
|
2015-10-06 11:00:37 -05:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
2015-04-14 14:38:13 +03:00
|
|
|
*/
|
|
|
|
|
2015-04-14 15:04:46 +03:00
|
|
|
#include <nanokernel.h>
|
2015-06-03 10:35:58 -04:00
|
|
|
#include <arch/cpu.h>
|
2015-04-14 15:04:46 +03:00
|
|
|
#include <toolchain.h>
|
2015-05-25 22:59:53 +03:00
|
|
|
#include <sections.h>
|
2015-04-14 15:04:46 +03:00
|
|
|
#include <string.h>
|
2015-05-08 20:53:39 +02:00
|
|
|
#include <stdio.h>
|
2015-04-14 15:04:46 +03:00
|
|
|
#include <errno.h>
|
2015-09-15 10:08:04 +02:00
|
|
|
#include <atomic.h>
|
2015-05-21 15:25:14 +03:00
|
|
|
#include <misc/util.h>
|
2015-04-14 15:04:46 +03:00
|
|
|
#include <misc/byteorder.h>
|
2016-03-16 09:53:11 +02:00
|
|
|
#include <misc/stack.h>
|
2015-04-14 15:04:46 +03:00
|
|
|
|
2016-04-18 15:02:32 +03:00
|
|
|
#ifdef CONFIG_MICROKERNEL
|
|
|
|
#include <microkernel.h>
|
|
|
|
#endif
|
|
|
|
|
2015-06-16 17:25:37 +03:00
|
|
|
#include <bluetooth/log.h>
|
2015-04-14 14:38:13 +03:00
|
|
|
#include <bluetooth/bluetooth.h>
|
2016-01-14 15:02:54 +02:00
|
|
|
#include <bluetooth/conn.h>
|
2015-05-25 09:13:33 +03:00
|
|
|
#include <bluetooth/hci.h>
|
2015-09-15 10:08:04 +02:00
|
|
|
#include <bluetooth/driver.h>
|
2016-04-01 21:44:38 +03:00
|
|
|
#include <bluetooth/storage.h>
|
2015-04-14 14:38:13 +03:00
|
|
|
|
2016-02-08 17:14:58 +01:00
|
|
|
#include <tinycrypt/hmac_prng.h>
|
|
|
|
#include <tinycrypt/utils.h>
|
|
|
|
|
2015-05-30 18:05:26 +07:00
|
|
|
#include "keys.h"
|
2016-04-20 17:54:07 +03:00
|
|
|
#include "monitor.h"
|
2015-11-06 17:04:22 +02:00
|
|
|
#include "hci_core.h"
|
2016-05-24 17:15:03 +02:00
|
|
|
#include "hci_ecc.h"
|
2016-06-30 20:05:36 +03:00
|
|
|
#include "ecc.h"
|
2015-11-06 17:04:22 +02:00
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
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-10-28 16:02:17 +01:00
|
|
|
#include "smp.h"
|
2016-02-19 12:05:19 +01:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
2015-10-28 16:02:17 +01:00
|
|
|
|
2015-04-24 12:02:36 +03:00
|
|
|
#if !defined(CONFIG_BLUETOOTH_DEBUG_HCI_CORE)
|
|
|
|
#undef BT_DBG
|
|
|
|
#define BT_DBG(fmt, ...)
|
|
|
|
#endif
|
|
|
|
|
2016-05-23 16:17:20 +03:00
|
|
|
/* Peripheral timeout to initialize Connection Parameter Update procedure */
|
|
|
|
#define CONN_UPDATE_TIMEOUT (5 * sys_clock_ticks_per_sec)
|
|
|
|
|
2015-04-14 15:32:32 +03:00
|
|
|
/* Stacks for the fibers */
|
2016-02-12 12:59:55 +02:00
|
|
|
static BT_STACK_NOINIT(rx_fiber_stack, CONFIG_BLUETOOTH_RX_STACK_SIZE);
|
2015-05-26 13:20:54 +03:00
|
|
|
static BT_STACK_NOINIT(cmd_tx_fiber_stack, 256);
|
2015-04-14 15:32:32 +03:00
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
struct bt_dev bt_dev;
|
2015-04-14 15:32:32 +03:00
|
|
|
|
2016-04-05 10:14:32 +03:00
|
|
|
const struct bt_storage *bt_storage;
|
2016-04-01 21:44:38 +03:00
|
|
|
|
2015-06-02 17:28:00 +02:00
|
|
|
static bt_le_scan_cb_t *scan_dev_found_cb;
|
2015-06-02 21:12:17 +02:00
|
|
|
|
2016-07-03 17:06:49 +03:00
|
|
|
static uint8_t pub_key[64];
|
2016-06-30 20:05:36 +03:00
|
|
|
static struct bt_pub_key_cb *pub_key_cb;
|
|
|
|
static bt_dh_key_cb_t dh_key_cb;
|
|
|
|
|
2016-03-10 11:58:56 +01:00
|
|
|
#if defined(CONFIG_BLUETOOTH_BREDR)
|
|
|
|
static bt_br_discovery_cb_t *discovery_cb;
|
|
|
|
struct bt_br_discovery_result *discovery_results;
|
|
|
|
static size_t discovery_results_size;
|
|
|
|
static size_t discovery_results_count;
|
|
|
|
#endif /* CONFIG_BLUETOOTH_BREDR */
|
|
|
|
|
2015-10-29 17:05:30 +02:00
|
|
|
struct cmd_data {
|
2016-04-09 11:29:50 +03:00
|
|
|
/** BT_BUF_CMD */
|
|
|
|
uint8_t type;
|
|
|
|
|
2015-10-28 21:14:31 +02:00
|
|
|
/** The command OpCode that the buffer contains */
|
|
|
|
uint16_t opcode;
|
|
|
|
|
|
|
|
/** Used by bt_hci_cmd_send_sync. Initially contains the waiting
|
|
|
|
* semaphore, as the semaphore is given back contains the bt_buf
|
|
|
|
* for the return parameters.
|
|
|
|
*/
|
|
|
|
void *sync;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2015-10-29 17:05:30 +02:00
|
|
|
struct acl_data {
|
2016-04-09 11:29:50 +03:00
|
|
|
/** BT_BUF_ACL_IN */
|
|
|
|
uint8_t type;
|
|
|
|
|
2015-10-28 21:14:31 +02:00
|
|
|
/** ACL connection handle */
|
|
|
|
uint16_t handle;
|
|
|
|
};
|
|
|
|
|
2015-10-29 17:05:30 +02:00
|
|
|
#define cmd(buf) ((struct cmd_data *)net_buf_user_data(buf))
|
|
|
|
#define acl(buf) ((struct acl_data *)net_buf_user_data(buf))
|
2015-10-28 20:39:45 +02:00
|
|
|
|
2015-10-29 16:58:18 +02:00
|
|
|
/* HCI command buffers */
|
2015-11-06 12:44:40 +02:00
|
|
|
#define CMD_BUF_SIZE (CONFIG_BLUETOOTH_HCI_SEND_RESERVE + \
|
|
|
|
sizeof(struct bt_hci_cmd_hdr) + \
|
|
|
|
CONFIG_BLUETOOTH_MAX_CMD_LEN)
|
2015-10-29 16:58:18 +02:00
|
|
|
static struct nano_fifo avail_hci_cmd;
|
2015-11-06 12:44:40 +02:00
|
|
|
static NET_BUF_POOL(hci_cmd_pool, CONFIG_BLUETOOTH_HCI_CMD_COUNT, CMD_BUF_SIZE,
|
|
|
|
&avail_hci_cmd, NULL, sizeof(struct cmd_data));
|
2015-10-28 15:14:46 +02:00
|
|
|
|
2016-04-09 11:29:50 +03:00
|
|
|
#if defined(CONFIG_BLUETOOTH_HOST_BUFFERS)
|
2015-10-29 16:58:18 +02:00
|
|
|
/* HCI event buffers */
|
|
|
|
static struct nano_fifo avail_hci_evt;
|
2016-04-09 13:53:17 +03:00
|
|
|
static NET_BUF_POOL(hci_evt_pool, CONFIG_BLUETOOTH_HCI_EVT_COUNT,
|
|
|
|
BT_BUF_EVT_SIZE, &avail_hci_evt, NULL,
|
|
|
|
BT_BUF_USER_DATA_MIN);
|
2016-06-28 16:48:01 +02:00
|
|
|
/*
|
|
|
|
* This priority pool is to handle HCI events that must not be dropped
|
|
|
|
* (currently this is Command Status, Command Complete and Number of
|
|
|
|
* Complete Packets) if running low on buffers. Buffers from this pool are not
|
|
|
|
* allowed to be passed to RX fiber and must be returned from bt_recv().
|
|
|
|
*/
|
|
|
|
static struct nano_fifo avail_prio_hci_evt;
|
|
|
|
static NET_BUF_POOL(hci_evt_prio_pool, 1,
|
|
|
|
BT_BUF_EVT_SIZE, &avail_prio_hci_evt, NULL,
|
|
|
|
BT_BUF_USER_DATA_MIN);
|
|
|
|
|
2016-04-09 11:29:50 +03:00
|
|
|
#endif /* CONFIG_BLUETOOTH_HOST_BUFFERS */
|
2015-10-29 16:58:18 +02:00
|
|
|
|
2016-02-08 17:14:58 +01:00
|
|
|
static struct tc_hmac_prng_struct prng;
|
|
|
|
|
2016-04-09 11:29:50 +03:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN) && defined(CONFIG_BLUETOOTH_HOST_BUFFERS)
|
2015-10-28 15:14:46 +02:00
|
|
|
static void report_completed_packet(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
|
|
|
|
struct bt_hci_cp_host_num_completed_packets *cp;
|
2015-10-29 17:05:30 +02:00
|
|
|
uint16_t handle = acl(buf)->handle;
|
2015-10-28 15:14:46 +02:00
|
|
|
struct bt_hci_handle_count *hc;
|
|
|
|
|
2015-11-03 20:47:54 +02:00
|
|
|
nano_fifo_put(buf->free, buf);
|
|
|
|
|
2016-04-01 08:41:39 +03:00
|
|
|
/* Do nothing if controller to host flow control is not supported */
|
|
|
|
if (!(bt_dev.supported_commands[10] & 0x20)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("Reporting completed packet for handle %u", handle);
|
|
|
|
|
2015-10-28 15:14:46 +02:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS,
|
|
|
|
sizeof(*cp) + sizeof(*hc));
|
|
|
|
if (!buf) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Unable to allocate new HCI command");
|
2015-10-28 15:14:46 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->num_handles = sys_cpu_to_le16(1);
|
|
|
|
|
|
|
|
hc = net_buf_add(buf, sizeof(*hc));
|
2015-10-29 07:40:56 +02:00
|
|
|
hc->handle = sys_cpu_to_le16(handle);
|
2015-10-28 15:14:46 +02:00
|
|
|
hc->count = sys_cpu_to_le16(1);
|
|
|
|
|
|
|
|
bt_hci_cmd_send(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS, buf);
|
|
|
|
}
|
|
|
|
|
2015-10-28 20:39:45 +02:00
|
|
|
static struct nano_fifo avail_acl_in;
|
2015-10-29 14:45:02 +02:00
|
|
|
static NET_BUF_POOL(acl_in_pool, CONFIG_BLUETOOTH_ACL_IN_COUNT,
|
2016-04-09 13:53:17 +03:00
|
|
|
BT_BUF_ACL_IN_SIZE, &avail_acl_in, report_completed_packet,
|
2015-11-06 12:19:26 +02:00
|
|
|
sizeof(struct acl_data));
|
2016-04-09 11:29:50 +03:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN && CONFIG_BLUETOOTH_HOST_BUFFERS */
|
2015-10-28 15:14:46 +02:00
|
|
|
|
2015-05-25 09:13:33 +03:00
|
|
|
#if defined(CONFIG_BLUETOOTH_DEBUG)
|
|
|
|
const char *bt_addr_str(const bt_addr_t *addr)
|
|
|
|
{
|
|
|
|
static char bufs[2][18];
|
|
|
|
static uint8_t cur;
|
|
|
|
char *str;
|
|
|
|
|
|
|
|
str = bufs[cur++];
|
|
|
|
cur %= ARRAY_SIZE(bufs);
|
2015-06-17 15:46:38 +02:00
|
|
|
bt_addr_to_str(addr, str, sizeof(bufs[cur]));
|
2015-05-25 09:13:33 +03:00
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *bt_addr_le_str(const bt_addr_le_t *addr)
|
2015-05-08 20:53:39 +02:00
|
|
|
{
|
2015-05-25 09:13:33 +03:00
|
|
|
static char bufs[2][27];
|
|
|
|
static uint8_t cur;
|
2015-06-17 15:46:38 +02:00
|
|
|
char *str;
|
2015-05-25 09:13:33 +03:00
|
|
|
|
|
|
|
str = bufs[cur++];
|
|
|
|
cur %= ARRAY_SIZE(bufs);
|
2015-06-17 15:46:38 +02:00
|
|
|
bt_addr_le_to_str(addr, str, sizeof(bufs[cur]));
|
2015-05-08 20:53:39 +02:00
|
|
|
|
2015-05-25 09:13:33 +03:00
|
|
|
return str;
|
2015-05-08 20:53:39 +02:00
|
|
|
}
|
2015-05-25 09:13:33 +03:00
|
|
|
#endif /* CONFIG_BLUETOOTH_DEBUG */
|
2015-05-08 20:53:39 +02:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
struct net_buf *bt_hci_cmd_create(uint16_t opcode, uint8_t param_len)
|
2015-04-14 15:41:55 +03:00
|
|
|
{
|
|
|
|
struct bt_hci_cmd_hdr *hdr;
|
2015-10-28 10:34:15 +02:00
|
|
|
struct net_buf *buf;
|
2015-04-14 15:41:55 +03:00
|
|
|
|
2016-03-14 12:35:39 +02:00
|
|
|
BT_DBG("opcode 0x%04x param_len %u", opcode, param_len);
|
2015-04-14 15:41:55 +03:00
|
|
|
|
2015-11-05 19:41:45 +02:00
|
|
|
buf = net_buf_get(&avail_hci_cmd, CONFIG_BLUETOOTH_HCI_SEND_RESERVE);
|
2015-04-14 15:41:55 +03:00
|
|
|
if (!buf) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Cannot get free buffer");
|
2015-04-14 15:41:55 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("buf %p", buf);
|
2015-04-14 15:41:55 +03:00
|
|
|
|
2016-04-09 11:29:50 +03:00
|
|
|
cmd(buf)->type = BT_BUF_CMD;
|
2015-10-29 17:05:30 +02:00
|
|
|
cmd(buf)->opcode = opcode;
|
|
|
|
cmd(buf)->sync = NULL;
|
2015-04-14 15:41:55 +03:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
hdr = net_buf_add(buf, sizeof(*hdr));
|
2015-04-14 15:41:55 +03:00
|
|
|
hdr->opcode = sys_cpu_to_le16(opcode);
|
|
|
|
hdr->param_len = param_len;
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
int bt_hci_cmd_send(uint16_t opcode, struct net_buf *buf)
|
2015-04-14 15:41:55 +03:00
|
|
|
{
|
|
|
|
if (!buf) {
|
|
|
|
buf = bt_hci_cmd_create(opcode, 0);
|
2015-05-05 10:50:14 +03:00
|
|
|
if (!buf) {
|
2015-04-14 15:41:55 +03:00
|
|
|
return -ENOBUFS;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-14 15:41:55 +03:00
|
|
|
}
|
|
|
|
|
2016-03-14 12:35:39 +02:00
|
|
|
BT_DBG("opcode 0x%04x len %u", opcode, buf->len);
|
2015-04-14 15:41:55 +03:00
|
|
|
|
2015-04-28 15:22:17 +03:00
|
|
|
/* Host Number of Completed Packets can ignore the ncmd value
|
|
|
|
* and does not generate any cmd complete/status events.
|
|
|
|
*/
|
|
|
|
if (opcode == BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS) {
|
2015-09-15 17:57:00 +03:00
|
|
|
int err;
|
|
|
|
|
2016-04-20 14:46:48 +03:00
|
|
|
err = bt_send(buf);
|
2015-09-15 17:57:00 +03:00
|
|
|
if (err) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Unable to send to driver (err %d)", err);
|
2015-11-04 21:18:03 +02:00
|
|
|
net_buf_unref(buf);
|
2015-09-15 17:57:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
2015-04-28 15:22:17 +03:00
|
|
|
}
|
|
|
|
|
2016-06-05 17:36:46 +03:00
|
|
|
net_buf_put(&bt_dev.cmd_tx_queue, buf);
|
2015-04-14 15:41:55 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
int bt_hci_cmd_send_sync(uint16_t opcode, struct net_buf *buf,
|
|
|
|
struct net_buf **rsp)
|
2015-04-14 15:44:48 +03:00
|
|
|
{
|
|
|
|
struct nano_sem sync_sem;
|
2015-04-30 12:01:48 +03:00
|
|
|
int err;
|
2015-04-14 15:44:48 +03:00
|
|
|
|
|
|
|
if (!buf) {
|
|
|
|
buf = bt_hci_cmd_create(opcode, 0);
|
2015-05-05 10:50:14 +03:00
|
|
|
if (!buf) {
|
2015-04-14 15:44:48 +03:00
|
|
|
return -ENOBUFS;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-14 15:44:48 +03:00
|
|
|
}
|
|
|
|
|
2016-03-14 12:35:39 +02:00
|
|
|
BT_DBG("opcode 0x%04x len %u", opcode, buf->len);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
|
|
|
nano_sem_init(&sync_sem);
|
2015-10-29 17:05:30 +02:00
|
|
|
cmd(buf)->sync = &sync_sem;
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2016-06-05 17:36:46 +03:00
|
|
|
net_buf_put(&bt_dev.cmd_tx_queue, buf);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-12-18 15:36:34 -05:00
|
|
|
nano_sem_take(&sync_sem, TICKS_UNLIMITED);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-04-30 12:01:48 +03:00
|
|
|
/* Indicate failure if we failed to get the return parameters */
|
2015-10-29 17:05:30 +02:00
|
|
|
if (!cmd(buf)->sync) {
|
2015-04-30 12:01:48 +03:00
|
|
|
err = -EIO;
|
2015-05-05 10:50:14 +03:00
|
|
|
} else {
|
2015-04-30 12:01:48 +03:00
|
|
|
err = 0;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-30 12:01:48 +03:00
|
|
|
|
2015-05-05 10:50:14 +03:00
|
|
|
if (rsp) {
|
2015-10-29 17:05:30 +02:00
|
|
|
*rsp = cmd(buf)->sync;
|
|
|
|
} else if (cmd(buf)->sync) {
|
|
|
|
net_buf_unref(cmd(buf)->sync);
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-30 12:01:48 +03:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(buf);
|
2015-04-30 12:01:48 +03:00
|
|
|
|
|
|
|
return err;
|
2015-04-14 15:44:48 +03:00
|
|
|
}
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
static int bt_hci_stop_scanning(void)
|
|
|
|
{
|
2015-10-28 10:34:15 +02:00
|
|
|
struct net_buf *buf, *rsp;
|
2015-10-01 17:50:19 +02:00
|
|
|
struct bt_hci_cp_le_set_scan_enable *scan_enable;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_SCAN_ENABLE,
|
|
|
|
sizeof(*scan_enable));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
scan_enable = net_buf_add(buf, sizeof(*scan_enable));
|
2015-11-30 13:15:04 +02:00
|
|
|
memset(scan_enable, 0, sizeof(*scan_enable));
|
2015-12-04 13:22:18 +02:00
|
|
|
scan_enable->filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_DISABLE;
|
|
|
|
scan_enable->enable = BT_HCI_LE_SCAN_DISABLE;
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_SCAN_ENABLE, buf, &rsp);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update scan state in case of success (0) status */
|
|
|
|
err = rsp->data[0];
|
|
|
|
if (!err) {
|
|
|
|
atomic_clear_bit(bt_dev.flags, BT_DEV_SCANNING);
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(rsp);
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-10-01 18:21:40 +02:00
|
|
|
static const bt_addr_le_t *find_id_addr(const bt_addr_le_t *addr)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_BLUETOOTH_SMP)
|
|
|
|
struct bt_keys *keys;
|
|
|
|
|
|
|
|
keys = bt_keys_find_irk(addr);
|
|
|
|
if (keys) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("Identity %s matched RPA %s",
|
2015-10-01 18:21:40 +02:00
|
|
|
bt_addr_le_str(&keys->addr), bt_addr_le_str(addr));
|
|
|
|
return &keys->addr;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
2016-02-17 09:43:04 +01:00
|
|
|
static int set_advertise_enable(void)
|
|
|
|
{
|
|
|
|
struct net_buf *buf;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADV_ENABLE, 1);
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_buf_add_u8(buf, BT_HCI_LE_ADV_ENABLE);
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_ADV_ENABLE, buf, NULL);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_set_bit(bt_dev.flags, BT_DEV_ADVERTISING);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int set_advertise_disable(void)
|
|
|
|
{
|
|
|
|
struct net_buf *buf;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADV_ENABLE, 1);
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_buf_add_u8(buf, BT_HCI_LE_ADV_DISABLE);
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_ADV_ENABLE, buf, NULL);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_clear_bit(bt_dev.flags, BT_DEV_ADVERTISING);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-04 12:55:11 +03:00
|
|
|
static int set_random_address(const bt_addr_t *addr)
|
|
|
|
{
|
|
|
|
struct net_buf *buf;
|
2016-04-21 15:39:24 +02:00
|
|
|
int err;
|
2016-04-04 12:55:11 +03:00
|
|
|
|
2016-06-06 05:49:06 +02:00
|
|
|
BT_DBG("%s", bt_addr_str(addr));
|
|
|
|
|
2016-04-04 20:56:45 +03:00
|
|
|
/* Do nothing if we already have the right address */
|
|
|
|
if (!bt_addr_cmp(addr, &bt_dev.random_addr.a)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-04 12:55:11 +03:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_RANDOM_ADDRESS, sizeof(*addr));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(net_buf_add(buf, sizeof(*addr)), addr, sizeof(*addr));
|
|
|
|
|
2016-04-21 15:39:24 +02:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_RANDOM_ADDRESS, buf, NULL);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_addr_copy(&bt_dev.random_addr.a, addr);
|
|
|
|
bt_dev.random_addr.type = BT_ADDR_LE_RANDOM;
|
|
|
|
return 0;
|
2016-04-04 12:55:11 +03:00
|
|
|
}
|
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
2015-10-28 10:34:15 +02:00
|
|
|
static void hci_acl(struct net_buf *buf)
|
2015-04-14 15:41:55 +03:00
|
|
|
{
|
2015-04-14 15:44:48 +03:00
|
|
|
struct bt_hci_acl_hdr *hdr = (void *)buf->data;
|
|
|
|
uint16_t handle, len = sys_le16_to_cpu(hdr->len);
|
2015-04-28 10:39:50 +03:00
|
|
|
struct bt_conn *conn;
|
2015-04-14 15:44:48 +03:00
|
|
|
uint8_t flags;
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("buf %p", buf);
|
2015-05-20 13:14:37 +03:00
|
|
|
|
2015-04-14 15:44:48 +03:00
|
|
|
handle = sys_le16_to_cpu(hdr->handle);
|
2015-11-03 13:42:44 +02:00
|
|
|
flags = bt_acl_flags(handle);
|
2015-10-28 10:20:43 +02:00
|
|
|
|
2015-10-29 17:05:30 +02:00
|
|
|
acl(buf)->handle = bt_acl_handle(handle);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_pull(buf, sizeof(*hdr));
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("handle %u len %u flags %u", acl(buf)->handle, len, flags);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
|
|
|
if (buf->len != len) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("ACL data length mismatch (%u != %u)", buf->len, len);
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(buf);
|
2015-04-14 15:44:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-29 17:05:30 +02:00
|
|
|
conn = bt_conn_lookup_handle(acl(buf)->handle);
|
2015-07-08 11:00:26 +03:00
|
|
|
if (!conn) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Unable to find conn for handle %u", acl(buf)->handle);
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(buf);
|
2015-04-28 10:39:50 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_recv(conn, buf, flags);
|
2015-10-23 12:45:33 +03:00
|
|
|
bt_conn_unref(conn);
|
2015-04-14 15:41:55 +03:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void hci_num_completed_packets(struct net_buf *buf)
|
2015-04-18 11:56:00 +03:00
|
|
|
{
|
|
|
|
struct bt_hci_evt_num_completed_packets *evt = (void *)buf->data;
|
|
|
|
uint16_t i, num_handles = sys_le16_to_cpu(evt->num_handles);
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("num_handles %u", num_handles);
|
2015-04-18 11:56:00 +03:00
|
|
|
|
|
|
|
for (i = 0; i < num_handles; i++) {
|
|
|
|
uint16_t handle, count;
|
2015-09-15 17:19:45 +03:00
|
|
|
struct bt_conn *conn;
|
2015-04-18 11:56:00 +03:00
|
|
|
|
|
|
|
handle = sys_le16_to_cpu(evt->h[i].handle);
|
|
|
|
count = sys_le16_to_cpu(evt->h[i].count);
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("handle %u count %u", handle, count);
|
2015-04-18 11:56:00 +03:00
|
|
|
|
2015-09-15 17:19:45 +03:00
|
|
|
conn = bt_conn_lookup_handle(handle);
|
2015-09-17 11:22:00 +03:00
|
|
|
if (!conn) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("No connection for handle %u", handle);
|
2015-09-17 11:22:00 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->pending_pkts >= count) {
|
|
|
|
conn->pending_pkts -= count;
|
2015-09-15 17:19:45 +03:00
|
|
|
} else {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("completed packets mismatch: %u > %u",
|
|
|
|
count, conn->pending_pkts);
|
2015-09-17 11:22:00 +03:00
|
|
|
conn->pending_pkts = 0;
|
2015-09-15 17:19:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
while (count--) {
|
2015-11-19 12:01:58 +01:00
|
|
|
nano_fiber_sem_give(bt_conn_get_pkts(conn));
|
2015-09-15 17:19:45 +03:00
|
|
|
}
|
2015-11-19 12:01:58 +01:00
|
|
|
|
|
|
|
bt_conn_unref(conn);
|
2015-04-18 11:56:00 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-05 15:32:58 +02:00
|
|
|
static int hci_le_create_conn(const struct bt_conn *conn)
|
2015-06-01 09:22:36 +07:00
|
|
|
{
|
2015-10-28 10:34:15 +02:00
|
|
|
struct net_buf *buf;
|
2015-10-01 17:50:19 +02:00
|
|
|
struct bt_hci_cp_le_create_conn *cp;
|
2015-06-01 09:22:36 +07:00
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CREATE_CONN, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
2015-06-01 09:22:36 +07:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
2015-11-30 13:15:04 +02:00
|
|
|
memset(cp, 0, sizeof(*cp));
|
2015-11-30 13:12:39 +02:00
|
|
|
|
|
|
|
/* Interval == window for continuous scanning */
|
2015-12-04 13:35:55 +02:00
|
|
|
cp->scan_interval = sys_cpu_to_le16(BT_GAP_SCAN_FAST_INTERVAL);
|
2015-11-30 13:12:39 +02:00
|
|
|
cp->scan_window = cp->scan_interval;
|
|
|
|
|
2015-12-05 15:32:58 +02:00
|
|
|
bt_addr_le_copy(&cp->peer_addr, &conn->le.resp_addr);
|
2016-04-02 09:42:08 +03:00
|
|
|
cp->own_addr_type = conn->le.init_addr.type;
|
2015-12-05 15:32:58 +02:00
|
|
|
cp->conn_interval_min = sys_cpu_to_le16(conn->le.interval_min);
|
|
|
|
cp->conn_interval_max = sys_cpu_to_le16(conn->le.interval_max);
|
2015-12-05 21:39:44 +02:00
|
|
|
cp->conn_latency = sys_cpu_to_le16(conn->le.latency);
|
|
|
|
cp->supervision_timeout = sys_cpu_to_le16(conn->le.timeout);
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_CONN, buf, NULL);
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void hci_disconn_complete(struct net_buf *buf)
|
2015-10-01 17:50:19 +02:00
|
|
|
{
|
|
|
|
struct bt_hci_evt_disconn_complete *evt = (void *)buf->data;
|
|
|
|
uint16_t handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status %u handle %u reason %u", evt->status, handle,
|
2015-10-01 17:50:19 +02:00
|
|
|
evt->reason);
|
2015-06-01 09:22:36 +07:00
|
|
|
|
|
|
|
if (evt->status) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_handle(handle);
|
2015-07-08 11:00:26 +03:00
|
|
|
if (!conn) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Unable to look up conn with handle %u", handle);
|
2016-06-01 13:23:50 +02:00
|
|
|
goto advertise;
|
2015-06-01 09:22:36 +07:00
|
|
|
}
|
|
|
|
|
2016-01-14 11:17:32 +02:00
|
|
|
conn->err = evt->reason;
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
/* Check stacks usage (no-ops if not enabled) */
|
|
|
|
stack_analyze("rx stack", rx_fiber_stack, sizeof(rx_fiber_stack));
|
|
|
|
stack_analyze("cmd tx stack", cmd_tx_fiber_stack,
|
|
|
|
sizeof(cmd_tx_fiber_stack));
|
|
|
|
stack_analyze("conn tx stack", conn->stack, sizeof(conn->stack));
|
2015-06-01 09:22:36 +07:00
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
|
|
|
conn->handle = 0;
|
2015-06-01 00:20:14 +07:00
|
|
|
|
2015-12-04 13:02:51 +01:00
|
|
|
if (conn->type != BT_CONN_TYPE_LE) {
|
2016-03-04 14:50:29 +01:00
|
|
|
#if defined(CONFIG_BLUETOOTH_BREDR)
|
|
|
|
/*
|
|
|
|
* If only for one connection session bond was set, clear keys
|
|
|
|
* database row for this connection.
|
|
|
|
*/
|
|
|
|
if (conn->type == BT_CONN_TYPE_BR &&
|
|
|
|
atomic_test_and_clear_bit(conn->flags, BT_CONN_BR_NOBOND)) {
|
|
|
|
bt_keys_clear(conn->keys, BT_KEYS_LINK_KEY);
|
|
|
|
}
|
|
|
|
#endif
|
2015-12-04 13:02:51 +01:00
|
|
|
bt_conn_unref(conn);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
if (atomic_test_bit(conn->flags, BT_CONN_AUTO_CONNECT)) {
|
|
|
|
bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN);
|
2015-12-03 22:51:16 +02:00
|
|
|
bt_le_scan_update(false);
|
2015-07-13 12:43:02 +02:00
|
|
|
}
|
|
|
|
|
2015-10-23 12:45:33 +03:00
|
|
|
bt_conn_unref(conn);
|
2015-07-13 12:39:42 +02:00
|
|
|
|
2016-06-01 13:23:50 +02:00
|
|
|
advertise:
|
2016-02-17 09:43:04 +01:00
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING)) {
|
|
|
|
set_advertise_enable();
|
2015-07-13 12:39:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-27 17:28:59 +03:00
|
|
|
static int hci_le_read_remote_features(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_le_read_remote_features *cp;
|
2015-10-28 10:34:15 +02:00
|
|
|
struct net_buf *buf;
|
2015-07-27 17:28:59 +03:00
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_READ_REMOTE_FEATURES,
|
|
|
|
sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
2015-07-27 17:28:59 +03:00
|
|
|
cp->handle = sys_cpu_to_le16(conn->handle);
|
|
|
|
bt_hci_cmd_send(BT_HCI_OP_LE_READ_REMOTE_FEATURES, buf);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-05-23 16:17:20 +03:00
|
|
|
static void update_conn_param(struct bt_conn *conn)
|
2015-08-10 21:53:45 +02:00
|
|
|
{
|
2016-05-23 16:17:20 +03:00
|
|
|
/*
|
|
|
|
* Core 4.2 Vol 3, Part C, 9.3.12.2
|
|
|
|
* The Peripheral device should not perform a Connection Parameter
|
|
|
|
* Update procedure within 5 s after establishing a connection.
|
|
|
|
*/
|
|
|
|
nano_delayed_work_submit(&conn->le.update_work,
|
|
|
|
conn->role == BT_HCI_ROLE_MASTER ? TICKS_NONE :
|
|
|
|
CONN_UPDATE_TIMEOUT);
|
2015-08-10 21:53:45 +02:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void le_conn_complete(struct net_buf *buf)
|
2015-04-18 18:44:38 +03:00
|
|
|
{
|
|
|
|
struct bt_hci_evt_le_conn_complete *evt = (void *)buf->data;
|
|
|
|
uint16_t handle = sys_le16_to_cpu(evt->handle);
|
2015-10-01 18:21:40 +02:00
|
|
|
const bt_addr_le_t *id_addr;
|
2015-04-28 10:39:50 +03:00
|
|
|
struct bt_conn *conn;
|
2015-07-27 17:28:59 +03:00
|
|
|
int err;
|
2015-04-18 18:44:38 +03:00
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status %u handle %u role %u %s", evt->status, handle,
|
2015-05-25 22:11:28 +03:00
|
|
|
evt->role, bt_addr_le_str(&evt->peer_addr));
|
2015-05-21 20:59:23 +03:00
|
|
|
|
|
|
|
if (evt->status) {
|
2016-06-08 05:56:30 +02:00
|
|
|
/*
|
|
|
|
* if there was an error we are only interested in pending
|
|
|
|
* connection so there is no need to check ID address as
|
|
|
|
* only one connection can be in that state
|
|
|
|
*
|
|
|
|
* Depending on error code address might not be valid anyway.
|
|
|
|
*/
|
|
|
|
conn = bt_conn_lookup_state_le(NULL, BT_CONN_CONNECT);
|
2015-06-30 10:23:09 +03:00
|
|
|
if (!conn) {
|
2015-06-23 14:38:24 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-07-08 11:00:13 +03:00
|
|
|
|
2016-01-14 11:17:32 +02:00
|
|
|
conn->err = evt->status;
|
|
|
|
|
2015-06-23 14:38:24 +02:00
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
|
|
|
|
|
|
|
/* Drop the reference got by lookup call in CONNECT state.
|
|
|
|
* We are now in DISCONNECTED state since no successful LE
|
|
|
|
* link been made.
|
|
|
|
*/
|
2015-10-23 12:45:33 +03:00
|
|
|
bt_conn_unref(conn);
|
2015-06-23 14:38:24 +02:00
|
|
|
|
2015-05-21 20:59:23 +03:00
|
|
|
return;
|
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2016-06-08 05:56:30 +02:00
|
|
|
id_addr = find_id_addr(&evt->peer_addr);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make lookup to check if there's a connection object in
|
|
|
|
* CONNECT state associated with passed peer LE address.
|
|
|
|
*/
|
|
|
|
conn = bt_conn_lookup_state_le(id_addr, BT_CONN_CONNECT);
|
|
|
|
|
2016-02-17 09:43:04 +01:00
|
|
|
if (evt->role == BT_CONN_ROLE_SLAVE) {
|
2016-05-05 12:01:16 +02:00
|
|
|
/*
|
|
|
|
* clear advertising even if we are not able to add connection
|
|
|
|
* object to keep host in sync with controller state
|
|
|
|
*/
|
2016-02-17 09:43:04 +01:00
|
|
|
atomic_clear_bit(bt_dev.flags, BT_DEV_ADVERTISING);
|
|
|
|
|
2016-05-05 12:01:16 +02:00
|
|
|
/* only for slave we may need to add new connection */
|
|
|
|
if (!conn) {
|
|
|
|
conn = bt_conn_add_le(id_addr);
|
|
|
|
}
|
2015-06-23 14:38:24 +02:00
|
|
|
}
|
|
|
|
|
2015-04-28 10:39:50 +03:00
|
|
|
if (!conn) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Unable to add new conn for handle %u", handle);
|
2015-04-28 10:39:50 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-06-23 11:56:50 +02:00
|
|
|
conn->handle = handle;
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_copy(&conn->le.dst, id_addr);
|
2015-12-05 15:32:58 +02:00
|
|
|
conn->le.interval = sys_le16_to_cpu(evt->interval);
|
2015-12-05 21:39:44 +02:00
|
|
|
conn->le.latency = sys_le16_to_cpu(evt->latency);
|
|
|
|
conn->le.timeout = sys_le16_to_cpu(evt->supv_timeout);
|
2015-09-02 10:47:35 +02:00
|
|
|
conn->role = evt->role;
|
2015-06-23 14:38:24 +02:00
|
|
|
|
2016-05-05 12:03:44 +02:00
|
|
|
/*
|
|
|
|
* Use connection address (instead of identity address) as initiator
|
|
|
|
* or responder address. Only slave needs to be updated. For master all
|
|
|
|
* was set during outgoing connection creation.
|
2015-10-01 18:21:40 +02:00
|
|
|
*/
|
2016-05-05 12:03:44 +02:00
|
|
|
if (conn->role == BT_HCI_ROLE_SLAVE) {
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_copy(&conn->le.init_addr, &evt->peer_addr);
|
2016-04-29 11:02:55 +02:00
|
|
|
|
2016-05-02 15:18:28 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_PRIVACY)
|
|
|
|
bt_addr_le_copy(&conn->le.resp_addr, &bt_dev.random_addr);
|
|
|
|
#else
|
|
|
|
bt_addr_le_copy(&conn->le.resp_addr, &bt_dev.id_addr);
|
|
|
|
#endif /* CONFIG_BLUETOOTH_PRIVACY */
|
2015-09-01 17:30:58 +02:00
|
|
|
}
|
|
|
|
|
2015-06-23 11:56:50 +02:00
|
|
|
bt_conn_set_state(conn, BT_CONN_CONNECTED);
|
|
|
|
|
2015-12-15 15:35:05 +01:00
|
|
|
/*
|
|
|
|
* it is possible that connection was disconnected directly from
|
|
|
|
* connected callback so we must check state before doing connection
|
|
|
|
* parameters update
|
|
|
|
*/
|
|
|
|
if (conn->state != BT_CONN_CONNECTED) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2015-07-27 17:28:59 +03:00
|
|
|
if ((evt->role == BT_HCI_ROLE_MASTER) ||
|
2015-11-03 11:19:19 +01:00
|
|
|
(bt_dev.le.features[0] & BT_HCI_LE_SLAVE_FEATURES)) {
|
2015-07-27 17:28:59 +03:00
|
|
|
err = hci_le_read_remote_features(conn);
|
|
|
|
if (!err) {
|
|
|
|
goto done;
|
|
|
|
}
|
2015-06-23 11:56:50 +02:00
|
|
|
}
|
2015-05-21 19:03:17 +03:00
|
|
|
|
2016-02-02 12:48:42 +01:00
|
|
|
update_conn_param(conn);
|
2015-07-27 17:28:59 +03:00
|
|
|
|
|
|
|
done:
|
2015-10-23 12:45:33 +03:00
|
|
|
bt_conn_unref(conn);
|
2015-12-03 22:51:16 +02:00
|
|
|
bt_le_scan_update(false);
|
2015-07-02 11:53:54 +02:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void le_remote_feat_complete(struct net_buf *buf)
|
2015-07-28 13:02:43 +03:00
|
|
|
{
|
|
|
|
struct bt_hci_ev_le_remote_feat_complete *evt = (void *)buf->data;
|
|
|
|
uint16_t handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_handle(handle);
|
|
|
|
if (!conn) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Unable to lookup conn for handle %u", handle);
|
2015-07-28 13:02:43 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!evt->status) {
|
2015-11-03 12:19:01 +01:00
|
|
|
memcpy(conn->le.features, evt->features,
|
|
|
|
sizeof(conn->le.features));
|
2015-07-28 13:02:43 +03:00
|
|
|
}
|
|
|
|
|
2016-02-02 12:48:42 +01:00
|
|
|
update_conn_param(conn);
|
2015-07-27 17:28:59 +03:00
|
|
|
|
2015-10-23 12:45:33 +03:00
|
|
|
bt_conn_unref(conn);
|
2015-07-28 13:02:43 +03:00
|
|
|
}
|
|
|
|
|
2015-08-10 22:23:05 +02:00
|
|
|
static int le_conn_param_neg_reply(uint16_t handle, uint8_t reason)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_le_conn_param_req_neg_reply *cp;
|
2015-10-28 10:34:15 +02:00
|
|
|
struct net_buf *buf;
|
2015-08-10 22:23:05 +02:00
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY,
|
|
|
|
sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
2015-08-10 22:23:05 +02:00
|
|
|
cp->handle = sys_cpu_to_le16(handle);
|
|
|
|
cp->reason = sys_cpu_to_le16(reason);
|
|
|
|
|
|
|
|
return bt_hci_cmd_send(BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int le_conn_param_req_reply(uint16_t handle, uint16_t min, uint16_t max,
|
|
|
|
uint16_t latency, uint16_t timeout)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_le_conn_param_req_reply *cp;
|
2015-10-28 10:34:15 +02:00
|
|
|
struct net_buf *buf;
|
2015-08-10 22:23:05 +02:00
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
2015-11-30 13:15:04 +02:00
|
|
|
memset(cp, 0, sizeof(*cp));
|
2015-08-10 22:23:05 +02:00
|
|
|
|
|
|
|
cp->handle = sys_cpu_to_le16(handle);
|
|
|
|
cp->interval_min = sys_cpu_to_le16(min);
|
|
|
|
cp->interval_max = sys_cpu_to_le16(max);
|
|
|
|
cp->latency = sys_cpu_to_le16(latency);
|
|
|
|
cp->timeout = sys_cpu_to_le16(timeout);
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
return bt_hci_cmd_send(BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY, buf);
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static int le_conn_param_req(struct net_buf *buf)
|
2015-10-01 17:50:19 +02:00
|
|
|
{
|
|
|
|
struct bt_hci_evt_le_conn_param_req *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
uint16_t handle, min, max, latency, timeout;
|
|
|
|
|
|
|
|
handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
min = sys_le16_to_cpu(evt->interval_min);
|
|
|
|
max = sys_le16_to_cpu(evt->interval_max);
|
|
|
|
latency = sys_le16_to_cpu(evt->latency);
|
|
|
|
timeout = sys_le16_to_cpu(evt->timeout);
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_handle(handle);
|
|
|
|
if (!conn) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Unable to lookup conn for handle %u", handle);
|
2015-10-01 17:50:19 +02:00
|
|
|
return le_conn_param_neg_reply(handle,
|
|
|
|
BT_HCI_ERR_UNKNOWN_CONN_ID);
|
|
|
|
}
|
|
|
|
|
2015-10-23 12:45:33 +03:00
|
|
|
bt_conn_unref(conn);
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
if (!bt_le_conn_params_valid(min, max, latency, timeout)) {
|
|
|
|
return le_conn_param_neg_reply(handle,
|
|
|
|
BT_HCI_ERR_INVALID_LL_PARAMS);
|
|
|
|
}
|
|
|
|
|
|
|
|
return le_conn_param_req_reply(handle, min, max, latency, timeout);
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void le_conn_update_complete(struct net_buf *buf)
|
2015-10-01 17:50:19 +02:00
|
|
|
{
|
|
|
|
struct bt_hci_evt_le_conn_update_complete *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
2016-02-02 12:48:42 +01:00
|
|
|
uint16_t handle;
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status %u, handle %u", evt->status, handle);
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
conn = bt_conn_lookup_handle(handle);
|
|
|
|
if (!conn) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Unable to lookup conn for handle %u", handle);
|
2015-10-01 17:50:19 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!evt->status) {
|
2016-02-02 12:48:42 +01:00
|
|
|
conn->le.interval = sys_le16_to_cpu(evt->interval);
|
|
|
|
conn->le.latency = sys_le16_to_cpu(evt->latency);
|
|
|
|
conn->le.timeout = sys_le16_to_cpu(evt->supv_timeout);
|
|
|
|
notify_le_param_updated(conn);
|
2015-10-01 17:50:19 +02:00
|
|
|
}
|
|
|
|
|
2015-10-23 12:45:33 +03:00
|
|
|
bt_conn_unref(conn);
|
2015-10-01 17:50:19 +02:00
|
|
|
}
|
|
|
|
|
2016-05-04 17:18:50 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_PRIVACY)
|
|
|
|
static int le_set_rpa(void)
|
|
|
|
{
|
|
|
|
bt_addr_t rpa;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = bt_smp_create_rpa(bt_dev.irk, &rpa);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return set_random_address(&rpa);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-10-02 10:10:39 +02:00
|
|
|
static void check_pending_conn(const bt_addr_le_t *id_addr,
|
|
|
|
const bt_addr_le_t *addr, uint8_t evtype)
|
2015-10-01 17:50:19 +02:00
|
|
|
{
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
2015-12-03 19:45:46 +02:00
|
|
|
/* No connections are allowed during explicit scanning */
|
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
/* Return if event is not connectable */
|
|
|
|
if (evtype != BT_LE_ADV_IND && evtype != BT_LE_ADV_DIRECT_IND) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-12-07 10:45:41 +02:00
|
|
|
conn = bt_conn_lookup_state_le(id_addr, BT_CONN_CONNECT_SCAN);
|
2015-10-01 17:50:19 +02:00
|
|
|
if (!conn) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bt_hci_stop_scanning()) {
|
2016-05-04 17:13:16 +02:00
|
|
|
goto failed;
|
2015-10-01 17:50:19 +02:00
|
|
|
}
|
|
|
|
|
2016-04-04 12:55:11 +03:00
|
|
|
#if defined(CONFIG_BLUETOOTH_PRIVACY)
|
2016-05-04 17:18:50 +02:00
|
|
|
if (le_set_rpa()) {
|
2016-05-04 17:13:16 +02:00
|
|
|
goto failed;
|
2016-04-04 12:55:11 +03:00
|
|
|
}
|
2016-05-04 17:18:50 +02:00
|
|
|
|
|
|
|
bt_addr_le_copy(&conn->le.init_addr, &bt_dev.random_addr);
|
2016-04-04 12:55:11 +03:00
|
|
|
#else
|
2016-05-09 11:41:14 +02:00
|
|
|
/* If Static Random address is used as Identity address we need to
|
|
|
|
* restore it before creating connection. Otherwise NRPA used for
|
|
|
|
* active scan could be used for connection.
|
|
|
|
*/
|
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_ID_STATIC_RANDOM)) {
|
|
|
|
set_random_address(&bt_dev.id_addr.a);
|
|
|
|
}
|
|
|
|
|
2016-04-02 09:42:08 +03:00
|
|
|
bt_addr_le_copy(&conn->le.init_addr, &bt_dev.id_addr);
|
2016-04-04 12:55:11 +03:00
|
|
|
#endif /* CONFIG_BLUETOOTH_PRIVACY */
|
|
|
|
|
|
|
|
bt_addr_le_copy(&conn->le.resp_addr, addr);
|
2015-12-05 15:32:58 +02:00
|
|
|
|
|
|
|
if (hci_le_create_conn(conn)) {
|
2016-05-04 17:13:16 +02:00
|
|
|
goto failed;
|
2015-10-01 17:50:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_set_state(conn, BT_CONN_CONNECT);
|
2016-05-04 17:13:16 +02:00
|
|
|
bt_conn_unref(conn);
|
|
|
|
return;
|
2015-10-01 17:50:19 +02:00
|
|
|
|
2016-05-04 17:13:16 +02:00
|
|
|
failed:
|
|
|
|
conn->err = BT_HCI_ERR_UNSPECIFIED;
|
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
2015-10-23 12:45:33 +03:00
|
|
|
bt_conn_unref(conn);
|
2016-05-04 17:13:16 +02:00
|
|
|
bt_le_scan_update(false);
|
2015-10-01 17:50:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int set_flow_control(void)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_host_buffer_size *hbs;
|
2015-10-28 10:34:15 +02:00
|
|
|
struct net_buf *buf;
|
2015-10-01 17:50:19 +02:00
|
|
|
int err;
|
|
|
|
|
2016-04-01 08:41:39 +03:00
|
|
|
/* Check if host flow control is actually supported */
|
|
|
|
if (!(bt_dev.supported_commands[10] & 0x20)) {
|
|
|
|
BT_WARN("Controller to host flow control not supported");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_HOST_BUFFER_SIZE,
|
|
|
|
sizeof(*hbs));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
hbs = net_buf_add(buf, sizeof(*hbs));
|
2015-10-01 17:50:19 +02:00
|
|
|
memset(hbs, 0, sizeof(*hbs));
|
2015-11-06 12:19:26 +02:00
|
|
|
hbs->acl_mtu = sys_cpu_to_le16(CONFIG_BLUETOOTH_L2CAP_IN_MTU +
|
|
|
|
sizeof(struct bt_l2cap_hdr));
|
2015-10-29 17:30:44 +02:00
|
|
|
hbs->acl_pkts = sys_cpu_to_le16(CONFIG_BLUETOOTH_ACL_IN_COUNT);
|
2015-10-01 17:50:19 +02:00
|
|
|
|
2015-11-02 16:12:59 +02:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_HOST_BUFFER_SIZE, buf, NULL);
|
2015-10-01 17:50:19 +02:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_SET_CTL_TO_HOST_FLOW, 1);
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2016-02-11 13:49:28 +02:00
|
|
|
net_buf_add_u8(buf, BT_HCI_CTL_TO_HOST_FLOW_ENABLE);
|
2015-10-01 17:50:19 +02:00
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_SET_CTL_TO_HOST_FLOW, buf, NULL);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
|
|
|
|
2016-01-21 09:31:09 +01:00
|
|
|
#if defined(CONFIG_BLUETOOTH_BREDR)
|
2016-04-27 12:39:44 +02:00
|
|
|
static void reset_pairing(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
atomic_clear_bit(conn->flags, BT_CONN_BR_PAIRING);
|
|
|
|
atomic_clear_bit(conn->flags, BT_CONN_BR_PAIRING_INITIATOR);
|
|
|
|
atomic_clear_bit(conn->flags, BT_CONN_BR_LEGACY_SECURE);
|
|
|
|
|
|
|
|
/* Reset required security level to current operational */
|
|
|
|
conn->required_sec_level = conn->sec_level;
|
|
|
|
}
|
|
|
|
|
2016-01-21 09:31:09 +01:00
|
|
|
static int reject_conn(const bt_addr_t *bdaddr, uint8_t reason)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_reject_conn_req *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_REJECT_CONN_REQ, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
bt_addr_copy(&cp->bdaddr, bdaddr);
|
|
|
|
cp->reason = reason;
|
|
|
|
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_REJECT_CONN_REQ, buf, NULL);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int accept_conn(const bt_addr_t *bdaddr)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_accept_conn_req *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_ACCEPT_CONN_REQ, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
bt_addr_copy(&cp->bdaddr, bdaddr);
|
|
|
|
cp->role = BT_HCI_ROLE_SLAVE;
|
|
|
|
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_ACCEPT_CONN_REQ, buf, NULL);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void conn_req(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_conn_request *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
|
|
|
BT_DBG("conn req from %s, type 0x%02x", bt_addr_str(&evt->bdaddr),
|
|
|
|
evt->link_type);
|
|
|
|
|
|
|
|
/* Reject SCO connections until we have support for them */
|
|
|
|
if (evt->link_type != BT_HCI_ACL) {
|
|
|
|
reject_conn(&evt->bdaddr, BT_HCI_ERR_INSUFFICIENT_RESOURCES);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn = bt_conn_add_br(&evt->bdaddr);
|
|
|
|
if (!conn) {
|
|
|
|
reject_conn(&evt->bdaddr, BT_HCI_ERR_INSUFFICIENT_RESOURCES);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
accept_conn(&evt->bdaddr);
|
|
|
|
conn->role = BT_HCI_ROLE_SLAVE;
|
|
|
|
bt_conn_set_state(conn, BT_CONN_CONNECT);
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
}
|
|
|
|
|
2016-01-21 09:42:05 +01:00
|
|
|
static void update_sec_level_br(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
if (!conn->encrypt) {
|
|
|
|
conn->sec_level = BT_SECURITY_LOW;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->keys && (conn->keys->keys & BT_KEYS_LINK_KEY)) {
|
|
|
|
conn->sec_level = BT_SECURITY_MEDIUM;
|
|
|
|
if (atomic_test_bit(&conn->keys->flags,
|
|
|
|
BT_KEYS_AUTHENTICATED)) {
|
|
|
|
conn->sec_level = BT_SECURITY_HIGH;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
BT_WARN("No BR/EDR link key found");
|
|
|
|
conn->sec_level = BT_SECURITY_MEDIUM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->required_sec_level > conn->sec_level) {
|
|
|
|
BT_ERR("Failed to set required security level");
|
|
|
|
bt_conn_disconnect(conn, BT_HCI_ERR_AUTHENTICATION_FAIL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-21 09:31:09 +01:00
|
|
|
static void conn_complete(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_conn_complete *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
2016-06-17 21:27:41 +02:00
|
|
|
struct bt_hci_cp_read_remote_features *cp;
|
2016-01-21 09:31:09 +01:00
|
|
|
uint16_t handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
|
|
|
|
BT_DBG("status 0x%02x, handle %u, type 0x%02x", evt->status, handle,
|
|
|
|
evt->link_type);
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_addr_br(&evt->bdaddr);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Unable to find conn for %s", bt_addr_str(&evt->bdaddr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (evt->status) {
|
|
|
|
conn->err = evt->status;
|
|
|
|
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn->handle = handle;
|
2016-01-21 09:42:05 +01:00
|
|
|
conn->encrypt = evt->encr_enabled;
|
|
|
|
update_sec_level_br(conn);
|
2016-01-21 09:31:09 +01:00
|
|
|
bt_conn_set_state(conn, BT_CONN_CONNECTED);
|
|
|
|
bt_conn_unref(conn);
|
2016-06-17 21:27:41 +02:00
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_READ_REMOTE_FEATURES, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = evt->handle;
|
|
|
|
|
|
|
|
bt_hci_cmd_send_sync(BT_HCI_OP_READ_REMOTE_FEATURES, buf, NULL);
|
2016-01-21 09:31:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pin_code_req(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_pin_code_req *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
|
|
|
BT_DBG("");
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_addr_br(&evt->bdaddr);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Can't find conn for %s", bt_addr_str(&evt->bdaddr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_pin_code_req(conn);
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void link_key_notify(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_ev_link_key_notify *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_addr_br(&evt->bdaddr);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Can't find conn for %s", bt_addr_str(&evt->bdaddr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("%s, link type 0x%02x", bt_addr_str(&evt->bdaddr), evt->key_type);
|
|
|
|
|
|
|
|
if (!conn->keys) {
|
|
|
|
conn->keys = bt_keys_get_link_key(&evt->bdaddr);
|
|
|
|
}
|
|
|
|
if (!conn->keys) {
|
|
|
|
BT_ERR("Can't update keys for %s", bt_addr_str(&evt->bdaddr));
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-22 18:58:56 +01:00
|
|
|
switch (evt->key_type) {
|
|
|
|
case BT_LK_COMBINATION:
|
2016-01-21 09:31:09 +01:00
|
|
|
atomic_set_bit(&conn->keys->flags, BT_KEYS_BR_LEGACY);
|
|
|
|
/*
|
|
|
|
* Setting Combination Link Key as AUTHENTICATED means it was
|
|
|
|
* successfully generated by 16 digits wide PIN code.
|
|
|
|
*/
|
|
|
|
if (atomic_test_and_clear_bit(conn->flags,
|
|
|
|
BT_CONN_BR_LEGACY_SECURE)) {
|
|
|
|
atomic_set_bit(&conn->keys->flags,
|
|
|
|
BT_KEYS_AUTHENTICATED);
|
|
|
|
}
|
2016-03-22 18:58:56 +01:00
|
|
|
memcpy(conn->keys->link_key.val, evt->link_key, 16);
|
|
|
|
break;
|
|
|
|
case BT_LK_UNAUTH_COMBINATION_P192:
|
|
|
|
case BT_LK_AUTH_COMBINATION_P192:
|
|
|
|
if (evt->key_type == BT_LK_AUTH_COMBINATION_P192) {
|
|
|
|
atomic_set_bit(&conn->keys->flags,
|
|
|
|
BT_KEYS_AUTHENTICATED);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Update keys database if authentication bond is required to
|
|
|
|
* be persistent. Mark no-bond link key flag for connection on
|
|
|
|
* the contrary.
|
|
|
|
*/
|
|
|
|
if (bt_conn_ssp_get_auth(conn) > BT_HCI_NO_BONDING_MITM) {
|
|
|
|
memcpy(conn->keys->link_key.val, evt->link_key, 16);
|
|
|
|
} else {
|
|
|
|
atomic_set_bit(conn->flags, BT_CONN_BR_NOBOND);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BT_WARN("Link key type unsupported/unimplemented");
|
|
|
|
break;
|
2016-01-21 09:31:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void link_key_neg_reply(const bt_addr_t *bdaddr)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_link_key_neg_reply *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
BT_DBG("");
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LINK_KEY_NEG_REPLY, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
BT_ERR("Out of command buffers");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
bt_addr_copy(&cp->bdaddr, bdaddr);
|
|
|
|
bt_hci_cmd_send_sync(BT_HCI_OP_LINK_KEY_NEG_REPLY, buf, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void link_key_reply(const bt_addr_t *bdaddr, const uint8_t *lk)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_link_key_reply *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
BT_DBG("");
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LINK_KEY_REPLY, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
BT_ERR("Out of command buffers");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
bt_addr_copy(&cp->bdaddr, bdaddr);
|
|
|
|
memcpy(cp->link_key, lk, 16);
|
|
|
|
bt_hci_cmd_send_sync(BT_HCI_OP_LINK_KEY_REPLY, buf, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void link_key_req(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_link_key_req *evt = (void *)buf->data;
|
2016-03-03 11:15:49 +01:00
|
|
|
struct bt_conn *conn;
|
2016-01-21 09:31:09 +01:00
|
|
|
|
|
|
|
BT_DBG("%s", bt_addr_str(&evt->bdaddr));
|
|
|
|
|
2016-03-03 11:15:49 +01:00
|
|
|
conn = bt_conn_lookup_addr_br(&evt->bdaddr);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Can't find conn for %s", bt_addr_str(&evt->bdaddr));
|
2016-01-21 09:31:09 +01:00
|
|
|
link_key_neg_reply(&evt->bdaddr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-03 11:15:49 +01:00
|
|
|
if (!conn->keys) {
|
|
|
|
conn->keys = bt_keys_find_link_key(&evt->bdaddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!conn->keys) {
|
|
|
|
link_key_neg_reply(&evt->bdaddr);
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-18 14:13:23 +01:00
|
|
|
/*
|
|
|
|
* Enforce regenerate by controller stronger link key since found one
|
|
|
|
* in database not covers requested security level.
|
|
|
|
*/
|
|
|
|
if (!atomic_test_bit(&conn->keys->flags, BT_KEYS_AUTHENTICATED) &&
|
|
|
|
conn->required_sec_level > BT_SECURITY_MEDIUM) {
|
|
|
|
link_key_neg_reply(&evt->bdaddr);
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-03 11:15:49 +01:00
|
|
|
link_key_reply(&evt->bdaddr, conn->keys->link_key.val);
|
|
|
|
bt_conn_unref(conn);
|
2016-01-21 09:31:09 +01:00
|
|
|
}
|
2016-01-29 12:29:11 +01:00
|
|
|
|
2016-03-14 15:19:23 +01:00
|
|
|
static void io_capa_neg_reply(const bt_addr_t *bdaddr, const uint8_t reason)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_io_capability_neg_reply *cp;
|
|
|
|
struct net_buf *resp_buf;
|
|
|
|
|
|
|
|
resp_buf = bt_hci_cmd_create(BT_HCI_OP_IO_CAPABILITY_NEG_REPLY,
|
|
|
|
sizeof(*cp));
|
|
|
|
if (!resp_buf) {
|
|
|
|
BT_ERR("Out of command buffers");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(resp_buf, sizeof(*cp));
|
|
|
|
bt_addr_copy(&cp->bdaddr, bdaddr);
|
|
|
|
cp->reason = reason;
|
|
|
|
bt_hci_cmd_send_sync(BT_HCI_OP_IO_CAPABILITY_NEG_REPLY, resp_buf, NULL);
|
|
|
|
}
|
|
|
|
|
2016-01-29 12:29:11 +01:00
|
|
|
static void io_capa_resp(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_io_capa_resp *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
|
|
|
BT_DBG("remote %s, IOcapa 0x%02x, auth 0x%02x",
|
|
|
|
bt_addr_str(&evt->bdaddr), evt->capability, evt->authentication);
|
|
|
|
|
2016-03-14 15:19:23 +01:00
|
|
|
if (evt->authentication > BT_HCI_GENERAL_BONDING_MITM) {
|
|
|
|
BT_ERR("Invalid remote authentication requirements");
|
|
|
|
io_capa_neg_reply(&evt->bdaddr,
|
|
|
|
BT_HCI_ERR_UNSUPP_FEATURE_PARAMS_VAL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (evt->capability > BT_IO_NO_INPUT_OUTPUT) {
|
|
|
|
BT_ERR("Invalid remote io capability requirements");
|
|
|
|
io_capa_neg_reply(&evt->bdaddr,
|
|
|
|
BT_HCI_ERR_UNSUPP_FEATURE_PARAMS_VAL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-29 12:29:11 +01:00
|
|
|
conn = bt_conn_lookup_addr_br(&evt->bdaddr);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Unable to find conn for %s", bt_addr_str(&evt->bdaddr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn->br.remote_io_capa = evt->capability;
|
|
|
|
conn->br.remote_auth = evt->authentication;
|
2016-01-29 16:12:55 +01:00
|
|
|
atomic_set_bit(conn->flags, BT_CONN_BR_PAIRING);
|
2016-01-29 12:29:11 +01:00
|
|
|
bt_conn_unref(conn);
|
|
|
|
}
|
2016-01-29 13:08:59 +01:00
|
|
|
|
|
|
|
static void io_capa_req(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_io_capa_req *evt = (void *)buf->data;
|
|
|
|
struct net_buf *resp_buf;
|
2016-01-29 16:12:55 +01:00
|
|
|
struct bt_conn *conn;
|
|
|
|
struct bt_hci_cp_io_capability_reply *cp;
|
2016-03-18 14:13:23 +01:00
|
|
|
uint8_t auth;
|
2016-01-29 13:08:59 +01:00
|
|
|
|
|
|
|
BT_DBG("");
|
|
|
|
|
2016-01-29 16:12:55 +01:00
|
|
|
conn = bt_conn_lookup_addr_br(&evt->bdaddr);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Can't find conn for %s", bt_addr_str(&evt->bdaddr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp_buf = bt_hci_cmd_create(BT_HCI_OP_IO_CAPABILITY_REPLY,
|
2016-01-29 13:08:59 +01:00
|
|
|
sizeof(*cp));
|
|
|
|
if (!resp_buf) {
|
2016-01-29 16:12:55 +01:00
|
|
|
BT_ERR("Out of command buffers");
|
|
|
|
bt_conn_unref(conn);
|
2016-01-29 13:08:59 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-18 14:13:23 +01:00
|
|
|
/*
|
|
|
|
* Set authentication requirements when acting as pairing initiator to
|
|
|
|
* 'dedicated bond' with MITM protection set if local IO capa
|
|
|
|
* potentially allows it, and for acceptor, based on local IO capa and
|
|
|
|
* remote's authentication set.
|
|
|
|
*/
|
|
|
|
if (atomic_test_bit(conn->flags, BT_CONN_BR_PAIRING_INITIATOR)) {
|
|
|
|
if (bt_conn_get_io_capa() != BT_IO_NO_INPUT_OUTPUT) {
|
|
|
|
auth = BT_HCI_DEDICATED_BONDING_MITM;
|
|
|
|
} else {
|
|
|
|
auth = BT_HCI_DEDICATED_BONDING;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
auth = bt_conn_ssp_get_auth(conn);
|
|
|
|
}
|
|
|
|
|
2016-01-29 13:08:59 +01:00
|
|
|
cp = net_buf_add(resp_buf, sizeof(*cp));
|
|
|
|
bt_addr_copy(&cp->bdaddr, &evt->bdaddr);
|
2016-01-29 16:12:55 +01:00
|
|
|
cp->capability = bt_conn_get_io_capa();
|
2016-03-18 14:13:23 +01:00
|
|
|
cp->authentication = auth;
|
2016-01-29 16:12:55 +01:00
|
|
|
cp->oob_data = 0;
|
|
|
|
bt_hci_cmd_send_sync(BT_HCI_OP_IO_CAPABILITY_REPLY, resp_buf, NULL);
|
|
|
|
bt_conn_unref(conn);
|
2016-01-29 13:08:59 +01:00
|
|
|
}
|
2016-01-29 13:29:54 +01:00
|
|
|
|
|
|
|
static void ssp_complete(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_ssp_complete *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
|
|
|
BT_DBG("status %u", evt->status);
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_addr_br(&evt->bdaddr);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Can't find conn for %s", bt_addr_str(&evt->bdaddr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (evt->status) {
|
|
|
|
bt_conn_disconnect(conn, BT_HCI_ERR_AUTHENTICATION_FAIL);
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
}
|
2016-02-01 12:41:04 +01:00
|
|
|
|
|
|
|
static void user_confirm_req(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_user_confirm_req *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_addr_br(&evt->bdaddr);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Can't find conn for %s", bt_addr_str(&evt->bdaddr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_ssp_auth(conn, sys_le32_to_cpu(evt->passkey));
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
}
|
2016-02-24 14:47:01 +01:00
|
|
|
|
|
|
|
static void user_passkey_notify(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_user_passkey_notify *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
|
|
|
BT_DBG("");
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_addr_br(&evt->bdaddr);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Can't find conn for %s", bt_addr_str(&evt->bdaddr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_ssp_auth(conn, sys_le32_to_cpu(evt->passkey));
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
}
|
2016-02-24 14:58:03 +01:00
|
|
|
|
|
|
|
static void user_passkey_req(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_user_passkey_req *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_addr_br(&evt->bdaddr);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Can't find conn for %s", bt_addr_str(&evt->bdaddr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_ssp_auth(conn, 0);
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
}
|
2016-03-10 11:58:56 +01:00
|
|
|
|
2016-03-17 18:35:58 +01:00
|
|
|
struct discovery_priv {
|
|
|
|
uint16_t clock_offset;
|
|
|
|
uint8_t pscan_rep_mode;
|
|
|
|
uint8_t resolving;
|
|
|
|
} __packed;
|
|
|
|
|
|
|
|
static int request_name(const bt_addr_t *addr, uint8_t pscan, uint16_t offset)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_remote_name_request *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_REMOTE_NAME_REQUEST, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
|
|
|
|
bt_addr_copy(&cp->bdaddr, addr);
|
|
|
|
cp->pscan_rep_mode = pscan;
|
|
|
|
cp->reserved = 0x00; /* reserver, should be set to 0x00 */
|
|
|
|
cp->clock_offset = offset;
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_REMOTE_NAME_REQUEST, buf, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define EIR_SHORT_NAME 0x08
|
|
|
|
#define EIR_COMPLETE_NAME 0x09
|
|
|
|
|
|
|
|
static bool eir_has_name(const uint8_t *eir)
|
|
|
|
{
|
|
|
|
int len = 240;
|
|
|
|
|
|
|
|
while (len) {
|
|
|
|
if (len < 2) {
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Look for early termination */
|
|
|
|
if (!eir[0]) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if field length is correct */
|
|
|
|
if (eir[0] > len - 1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (eir[1]) {
|
|
|
|
case EIR_SHORT_NAME:
|
|
|
|
case EIR_COMPLETE_NAME:
|
|
|
|
if (eir[0] > 1) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse next AD Structure */
|
|
|
|
len -= eir[0] + 1;
|
|
|
|
eir += eir[0] + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-03-10 12:03:55 +01:00
|
|
|
static void report_discovery_results(void)
|
|
|
|
{
|
2016-03-17 18:35:58 +01:00
|
|
|
bool resolving_names = false;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < discovery_results_count; i++) {
|
|
|
|
struct discovery_priv *priv;
|
|
|
|
|
|
|
|
priv = (struct discovery_priv *)&discovery_results[i].private;
|
|
|
|
|
|
|
|
if (eir_has_name(discovery_results[i].eir)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (request_name(&discovery_results[i].addr,
|
|
|
|
priv->pscan_rep_mode, priv->clock_offset)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
priv->resolving = 1;
|
|
|
|
resolving_names = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (resolving_names) {
|
|
|
|
return;
|
|
|
|
}
|
2016-03-10 12:03:55 +01:00
|
|
|
|
|
|
|
atomic_clear_bit(bt_dev.flags, BT_DEV_INQUIRY);
|
|
|
|
|
|
|
|
discovery_cb(discovery_results, discovery_results_count);
|
|
|
|
|
|
|
|
discovery_cb = NULL;
|
|
|
|
discovery_results = NULL;
|
|
|
|
discovery_results_size = 0;
|
|
|
|
discovery_results_count = 0;
|
|
|
|
}
|
|
|
|
|
2016-03-10 11:58:56 +01:00
|
|
|
static void inquiry_complete(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_inquiry_complete *evt = (void *)buf->data;
|
|
|
|
|
|
|
|
if (evt->status) {
|
|
|
|
BT_ERR("Failed to complete inquiry");
|
|
|
|
}
|
2016-03-10 12:03:55 +01:00
|
|
|
|
|
|
|
report_discovery_results();
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct bt_br_discovery_result *get_result_slot(const bt_addr_t *addr)
|
|
|
|
{
|
|
|
|
size_t i;
|
2016-06-16 10:29:18 +03:00
|
|
|
int err;
|
2016-03-10 12:03:55 +01:00
|
|
|
|
|
|
|
/* check if already present in results */
|
|
|
|
for (i = 0; i < discovery_results_count; i++) {
|
|
|
|
if (!bt_addr_cmp(addr, &discovery_results[i].addr)) {
|
|
|
|
return &discovery_results[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:29:18 +03:00
|
|
|
/* Pick a new slot (if available) */
|
2016-03-10 12:03:55 +01:00
|
|
|
if (discovery_results_count < discovery_results_size) {
|
|
|
|
bt_addr_copy(&discovery_results[discovery_results_count].addr,
|
|
|
|
addr);
|
|
|
|
return &discovery_results[discovery_results_count++];
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:29:18 +03:00
|
|
|
BT_WARN("Got more Inquiry results than requested");
|
|
|
|
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_INQUIRY_CANCEL, NULL, NULL);
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("Failed to cancel discovery (%d)", err);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
report_discovery_results();
|
2016-03-10 12:03:55 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void inquiry_result_with_rssi(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_inquiry_result_with_rssi *evt;
|
|
|
|
uint8_t num_reports = net_buf_pull_u8(buf);
|
|
|
|
|
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_INQUIRY)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("number of results: %u", num_reports);
|
|
|
|
|
|
|
|
evt = (void *)buf->data;
|
|
|
|
while (num_reports--) {
|
|
|
|
struct bt_br_discovery_result *result;
|
2016-03-17 18:35:58 +01:00
|
|
|
struct discovery_priv *priv;
|
2016-03-10 12:03:55 +01:00
|
|
|
|
|
|
|
BT_DBG("%s rssi %d dBm", bt_addr_str(&evt->addr), evt->rssi);
|
|
|
|
|
|
|
|
result = get_result_slot(&evt->addr);
|
|
|
|
if (!result) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-17 18:35:58 +01:00
|
|
|
priv = (struct discovery_priv *)&result->private;
|
|
|
|
priv->pscan_rep_mode = evt->pscan_rep_mode;
|
|
|
|
priv->clock_offset = evt->clock_offset;
|
|
|
|
|
2016-03-10 12:03:55 +01:00
|
|
|
memcpy(result->cod, evt->cod, 3);
|
|
|
|
result->rssi = evt->rssi;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get next report iteration by moving pointer to right offset
|
|
|
|
* in buf according to spec 4.2, Vol 2, Part E, 7.7.33.
|
|
|
|
*/
|
|
|
|
evt = net_buf_pull(buf, sizeof(*evt));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void extended_inquiry_result(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_extended_inquiry_result *evt = (void *)buf->data;
|
|
|
|
struct bt_br_discovery_result *result;
|
2016-03-17 18:35:58 +01:00
|
|
|
struct discovery_priv *priv;
|
2016-03-10 12:03:55 +01:00
|
|
|
|
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_INQUIRY)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("%s rssi %d dBm", bt_addr_str(&evt->addr), evt->rssi);
|
|
|
|
|
|
|
|
result = get_result_slot(&evt->addr);
|
|
|
|
if (!result) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-17 18:35:58 +01:00
|
|
|
priv = (struct discovery_priv *)&result->private;
|
|
|
|
priv->pscan_rep_mode = evt->pscan_rep_mode;
|
|
|
|
priv->clock_offset = evt->clock_offset;
|
|
|
|
|
2016-03-10 12:03:55 +01:00
|
|
|
result->rssi = evt->rssi;
|
|
|
|
memcpy(result->cod, evt->cod, 3);
|
|
|
|
memcpy(result->eir, evt->eir, sizeof(result->eir));
|
2016-03-10 11:58:56 +01:00
|
|
|
}
|
2016-03-17 18:35:58 +01:00
|
|
|
|
2016-06-16 10:55:17 +03:00
|
|
|
static void remote_name_request_complete(struct net_buf *buf)
|
2016-03-17 18:35:58 +01:00
|
|
|
{
|
|
|
|
struct bt_hci_evt_remote_name_req_complete *evt = (void *)buf->data;
|
|
|
|
struct bt_br_discovery_result *result;
|
|
|
|
struct discovery_priv *priv;
|
|
|
|
int eir_len = 240;
|
|
|
|
uint8_t *eir;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
result = get_result_slot(&evt->bdaddr);
|
|
|
|
if (!result) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
priv = (struct discovery_priv *)&result->private;
|
|
|
|
priv->resolving = 0;
|
|
|
|
|
|
|
|
if (evt->status) {
|
|
|
|
goto check_names;
|
|
|
|
}
|
|
|
|
|
|
|
|
eir = result->eir;
|
|
|
|
|
|
|
|
while (eir_len) {
|
|
|
|
if (eir_len < 2) {
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Look for early termination */
|
|
|
|
if (!eir[0]) {
|
|
|
|
size_t name_len;
|
|
|
|
|
|
|
|
eir_len -= 2;
|
|
|
|
|
|
|
|
/* name is null terminated */
|
|
|
|
name_len = strlen(evt->name);
|
|
|
|
|
|
|
|
if (name_len > eir_len) {
|
|
|
|
eir[0] = eir_len + 1;
|
|
|
|
eir[1] = EIR_SHORT_NAME;
|
|
|
|
} else {
|
|
|
|
eir[0] = name_len + 1;
|
|
|
|
eir[1] = EIR_SHORT_NAME;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&eir[2], evt->name, eir[0] - 1);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if field length is correct */
|
|
|
|
if (eir[0] > eir_len - 1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* next EIR Structure */
|
|
|
|
eir_len -= eir[0] + 1;
|
|
|
|
eir += eir[0] + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
check_names:
|
|
|
|
/* if still waiting for names */
|
|
|
|
for (i = 0; i < discovery_results_count; i++) {
|
|
|
|
struct discovery_priv *priv;
|
|
|
|
|
|
|
|
priv = (struct discovery_priv *)&discovery_results[i].private;
|
|
|
|
|
|
|
|
if (priv->resolving) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* all names resolved, report discovery results */
|
|
|
|
atomic_clear_bit(bt_dev.flags, BT_DEV_INQUIRY);
|
|
|
|
|
|
|
|
discovery_cb(discovery_results, discovery_results_count);
|
|
|
|
|
|
|
|
discovery_cb = NULL;
|
|
|
|
discovery_results = NULL;
|
|
|
|
discovery_results_size = 0;
|
|
|
|
discovery_results_count = 0;
|
|
|
|
}
|
2016-03-18 14:13:23 +01:00
|
|
|
|
2016-03-18 14:19:35 +01:00
|
|
|
static void link_encr(const uint16_t handle)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_set_conn_encrypt *encr;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
BT_DBG("");
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_SET_CONN_ENCRYPT, sizeof(*encr));
|
|
|
|
if (!buf) {
|
|
|
|
BT_ERR("Out of command buffers");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
encr = net_buf_add(buf, sizeof(*encr));
|
|
|
|
encr->handle = sys_cpu_to_le16(handle);
|
|
|
|
encr->encrypt = 0x01;
|
|
|
|
|
|
|
|
bt_hci_cmd_send_sync(BT_HCI_OP_SET_CONN_ENCRYPT, buf, NULL);
|
|
|
|
}
|
|
|
|
|
2016-03-18 14:13:23 +01:00
|
|
|
static void auth_complete(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_auth_complete *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
uint16_t handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
|
|
|
|
BT_DBG("status %u, handle %u", evt->status, handle);
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_handle(handle);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Can't find conn for handle %u", handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (evt->status) {
|
2016-04-27 12:39:44 +02:00
|
|
|
reset_pairing(conn);
|
2016-03-18 14:19:35 +01:00
|
|
|
} else {
|
|
|
|
link_encr(handle);
|
2016-03-18 14:13:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
}
|
2016-06-17 21:27:41 +02:00
|
|
|
|
|
|
|
static void read_remote_features_complete(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_remote_features *evt = (void *)buf->data;
|
|
|
|
uint16_t handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
struct bt_hci_cp_read_remote_ext_features *cp;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
|
|
|
BT_DBG("status %u handle %u", evt->status, handle);
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_handle(handle);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Can't find conn for handle %u", handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-20 13:36:40 +03:00
|
|
|
if (evt->status) {
|
|
|
|
goto done;
|
|
|
|
}
|
2016-06-17 21:27:41 +02:00
|
|
|
|
2016-06-20 13:36:40 +03:00
|
|
|
memcpy(conn->br.features[0], evt->features, sizeof(evt->features));
|
2016-06-17 21:27:41 +02:00
|
|
|
|
2016-06-20 13:36:40 +03:00
|
|
|
if (!lmp_ext_feat_capable(conn)) {
|
|
|
|
goto done;
|
|
|
|
}
|
2016-06-17 21:27:41 +02:00
|
|
|
|
2016-06-20 13:36:40 +03:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_READ_REMOTE_EXT_FEATURES,
|
|
|
|
sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
goto done;
|
2016-06-17 21:27:41 +02:00
|
|
|
}
|
2016-06-20 13:36:40 +03:00
|
|
|
|
|
|
|
/* Read remote host features (page 1) */
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = evt->handle;
|
|
|
|
cp->page = 0x01;
|
|
|
|
|
|
|
|
bt_hci_cmd_send_sync(BT_HCI_OP_READ_REMOTE_EXT_FEATURES, buf, NULL);
|
|
|
|
|
2016-06-17 21:27:41 +02:00
|
|
|
done:
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void read_remote_ext_features_complete(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_remote_ext_features *evt = (void *)buf->data;
|
|
|
|
uint16_t handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
|
|
|
BT_DBG("status %u handle %u", evt->status, handle);
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_handle(handle);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Can't find conn for handle %u", handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!evt->status && evt->page == 0x01) {
|
|
|
|
memcpy(conn->br.features[1], evt->features,
|
|
|
|
sizeof(conn->br.features[1]));
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_unref(conn);
|
|
|
|
}
|
|
|
|
|
2016-03-10 11:58:56 +01:00
|
|
|
#endif /* CONFIG_BLUETOOTH_BREDR */
|
2016-01-21 09:31:09 +01:00
|
|
|
|
2016-01-08 11:11:56 +01:00
|
|
|
#if defined(CONFIG_BLUETOOTH_SMP) || defined(CONFIG_BLUETOOTH_BREDR)
|
2015-10-01 17:50:19 +02:00
|
|
|
static void update_sec_level(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
if (!conn->encrypt) {
|
|
|
|
conn->sec_level = BT_SECURITY_LOW;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-04 14:27:14 +01:00
|
|
|
if (conn->keys && atomic_test_bit(&conn->keys->flags,
|
|
|
|
BT_KEYS_AUTHENTICATED)) {
|
2015-11-19 16:50:41 +01:00
|
|
|
if (conn->keys->keys & BT_KEYS_LTK_P256) {
|
|
|
|
conn->sec_level = BT_SECURITY_FIPS;
|
|
|
|
} else {
|
|
|
|
conn->sec_level = BT_SECURITY_HIGH;
|
|
|
|
}
|
2015-10-01 17:50:19 +02:00
|
|
|
} else {
|
|
|
|
conn->sec_level = BT_SECURITY_MEDIUM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->required_sec_level > conn->sec_level) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Failed to set required security level");
|
2015-10-01 17:50:19 +02:00
|
|
|
bt_conn_disconnect(conn, BT_HCI_ERR_AUTHENTICATION_FAIL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void hci_encrypt_change(struct net_buf *buf)
|
2015-10-01 17:50:19 +02:00
|
|
|
{
|
|
|
|
struct bt_hci_evt_encrypt_change *evt = (void *)buf->data;
|
|
|
|
uint16_t handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status %u handle %u encrypt 0x%02x", evt->status, handle,
|
2015-10-01 17:50:19 +02:00
|
|
|
evt->encrypt);
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_handle(handle);
|
|
|
|
if (!conn) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Unable to look up conn with handle %u", handle);
|
2015-10-01 17:50:19 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-13 16:17:42 +02:00
|
|
|
if (evt->status) {
|
|
|
|
/* TODO report error */
|
2016-04-27 12:39:44 +02:00
|
|
|
if (conn->type == BT_CONN_TYPE_LE) {
|
|
|
|
/* reset required security level in case of error */
|
|
|
|
conn->required_sec_level = conn->sec_level;
|
|
|
|
#if defined(CONFIG_BLUETOOTH_BREDR)
|
|
|
|
} else {
|
|
|
|
reset_pairing(conn);
|
|
|
|
#endif /* CONFIG_BLUETOOTH_BREDR */
|
|
|
|
}
|
2015-10-23 12:45:33 +03:00
|
|
|
bt_conn_unref(conn);
|
2015-10-13 16:17:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
conn->encrypt = evt->encrypt;
|
|
|
|
|
2015-11-24 16:11:21 +01:00
|
|
|
/*
|
|
|
|
* we update keys properties only on successful encryption to avoid
|
|
|
|
* losing valid keys if encryption was not successful
|
|
|
|
*
|
|
|
|
* Update keys with last pairing info for proper sec level update.
|
2016-01-13 16:49:07 +01:00
|
|
|
* This is done only for LE transport, for BR/EDR keys are updated on
|
|
|
|
* HCI 'Link Key Notification Event'
|
2015-11-24 16:11:21 +01:00
|
|
|
*/
|
2016-01-13 16:49:07 +01:00
|
|
|
if (conn->encrypt && conn->type == BT_CONN_TYPE_LE) {
|
2015-11-24 16:11:21 +01:00
|
|
|
bt_smp_update_keys(conn);
|
|
|
|
}
|
|
|
|
|
2016-01-21 09:46:51 +01:00
|
|
|
if (conn->type == BT_CONN_TYPE_LE) {
|
|
|
|
update_sec_level(conn);
|
|
|
|
#if defined(CONFIG_BLUETOOTH_BREDR)
|
|
|
|
} else {
|
|
|
|
update_sec_level_br(conn);
|
2016-04-27 12:39:44 +02:00
|
|
|
reset_pairing(conn);
|
2016-01-21 09:46:51 +01:00
|
|
|
#endif /* CONFIG_BLUETOOTH_BREDR */
|
|
|
|
}
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
bt_l2cap_encrypt_change(conn);
|
|
|
|
bt_conn_security_changed(conn);
|
|
|
|
|
2015-10-23 12:45:33 +03:00
|
|
|
bt_conn_unref(conn);
|
2015-10-01 17:50:19 +02:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void hci_encrypt_key_refresh_complete(struct net_buf *buf)
|
2015-10-01 17:50:19 +02:00
|
|
|
{
|
|
|
|
struct bt_hci_evt_encrypt_key_refresh_complete *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
uint16_t handle;
|
|
|
|
|
|
|
|
handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status %u handle %u", evt->status, handle);
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
if (evt->status) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_handle(handle);
|
|
|
|
if (!conn) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Unable to look up conn with handle %u", handle);
|
2015-10-01 17:50:19 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-28 18:09:26 +01:00
|
|
|
/*
|
|
|
|
* Update keys with last pairing info for proper sec level update.
|
2016-01-21 09:55:03 +01:00
|
|
|
* This is done only for LE transport. For BR/EDR transport keys are
|
|
|
|
* updated on HCI 'Link Key Notification Event', therefore update here
|
|
|
|
* only security level based on available keys and encryption state.
|
2016-01-28 18:09:26 +01:00
|
|
|
*/
|
|
|
|
if (conn->type == BT_CONN_TYPE_LE) {
|
|
|
|
bt_smp_update_keys(conn);
|
2016-01-21 09:55:03 +01:00
|
|
|
update_sec_level(conn);
|
|
|
|
#if defined(CONFIG_BLUETOOTH_BREDR)
|
|
|
|
} else {
|
|
|
|
update_sec_level_br(conn);
|
|
|
|
#endif /* CONFIG_BLUETOOTH_BREDR */
|
2016-01-28 18:09:26 +01:00
|
|
|
}
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
bt_l2cap_encrypt_change(conn);
|
2015-10-13 09:25:21 +02:00
|
|
|
bt_conn_security_changed(conn);
|
2015-10-23 12:45:33 +03:00
|
|
|
bt_conn_unref(conn);
|
2015-10-01 17:50:19 +02:00
|
|
|
}
|
2016-01-08 11:11:56 +01:00
|
|
|
#endif /* CONFIG_BLUETOOTH_SMP || CONFIG_BLUETOOTH_BREDR */
|
2015-10-01 17:50:19 +02:00
|
|
|
|
2016-01-08 11:11:56 +01:00
|
|
|
#if defined(CONFIG_BLUETOOTH_SMP)
|
2015-10-28 10:34:15 +02:00
|
|
|
static void le_ltk_request(struct net_buf *buf)
|
2015-10-01 17:50:19 +02:00
|
|
|
{
|
|
|
|
struct bt_hci_evt_le_ltk_request *evt = (void *)buf->data;
|
2015-12-08 17:22:52 +01:00
|
|
|
struct bt_hci_cp_le_ltk_req_neg_reply *cp;
|
2015-10-01 17:50:19 +02:00
|
|
|
struct bt_conn *conn;
|
|
|
|
uint16_t handle;
|
2015-11-24 16:11:21 +01:00
|
|
|
uint8_t tk[16];
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("handle %u", handle);
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
conn = bt_conn_lookup_handle(handle);
|
|
|
|
if (!conn) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Unable to lookup conn for handle %u", handle);
|
2015-10-01 17:50:19 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-11-24 16:11:21 +01:00
|
|
|
/*
|
|
|
|
* if TK is present use it, that means pairing is in progress and
|
|
|
|
* we should use new TK for encryption
|
2015-11-25 08:58:45 +01:00
|
|
|
*
|
|
|
|
* Both legacy STK and LE SC LTK have rand and ediv equal to zero.
|
2015-11-24 16:11:21 +01:00
|
|
|
*/
|
|
|
|
if (evt->rand == 0 && evt->ediv == 0 && bt_smp_get_tk(conn, tk)) {
|
|
|
|
struct bt_hci_cp_le_ltk_req_reply *cp;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_LTK_REQ_REPLY,
|
|
|
|
sizeof(*cp));
|
|
|
|
if (!buf) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Out of command buffers");
|
2015-11-24 16:11:21 +01:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = evt->handle;
|
|
|
|
memcpy(cp->ltk, tk, sizeof(cp->ltk));
|
|
|
|
|
|
|
|
bt_hci_cmd_send(BT_HCI_OP_LE_LTK_REQ_REPLY, buf);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
if (!conn->keys) {
|
2015-11-12 10:17:49 +01:00
|
|
|
conn->keys = bt_keys_find(BT_KEYS_LTK_P256, &conn->le.dst);
|
|
|
|
if (!conn->keys) {
|
|
|
|
conn->keys = bt_keys_find(BT_KEYS_SLAVE_LTK,
|
|
|
|
&conn->le.dst);
|
|
|
|
}
|
2015-10-01 17:50:19 +02:00
|
|
|
}
|
|
|
|
|
2015-11-12 10:17:49 +01:00
|
|
|
if (conn->keys && (conn->keys->keys & BT_KEYS_LTK_P256) &&
|
|
|
|
evt->rand == 0 && evt->ediv == 0) {
|
|
|
|
struct bt_hci_cp_le_ltk_req_reply *cp;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_LTK_REQ_REPLY,
|
|
|
|
sizeof(*cp));
|
|
|
|
if (!buf) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Out of command buffers");
|
2015-11-12 10:17:49 +01:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = evt->handle;
|
|
|
|
|
|
|
|
/* use only enc_size bytes of key for encryption */
|
|
|
|
memcpy(cp->ltk, conn->keys->ltk.val, conn->keys->enc_size);
|
|
|
|
if (conn->keys->enc_size < sizeof(cp->ltk)) {
|
|
|
|
memset(cp->ltk + conn->keys->enc_size, 0,
|
|
|
|
sizeof(cp->ltk) - conn->keys->enc_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_hci_cmd_send(BT_HCI_OP_LE_LTK_REQ_REPLY, buf);
|
2015-12-08 17:22:52 +01:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2015-12-08 16:59:19 +01:00
|
|
|
#if !defined(CONFIG_BLUETOOTH_SMP_SC_ONLY)
|
2015-12-08 17:22:52 +01:00
|
|
|
if (conn->keys && (conn->keys->keys & BT_KEYS_SLAVE_LTK) &&
|
|
|
|
conn->keys->slave_ltk.rand == evt->rand &&
|
|
|
|
conn->keys->slave_ltk.ediv == evt->ediv) {
|
2015-10-01 17:50:19 +02:00
|
|
|
struct bt_hci_cp_le_ltk_req_reply *cp;
|
2015-12-08 17:22:52 +01:00
|
|
|
struct net_buf *buf;
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_LTK_REQ_REPLY,
|
|
|
|
sizeof(*cp));
|
|
|
|
if (!buf) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Out of command buffers");
|
2015-10-01 17:50:19 +02:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
2015-10-01 17:50:19 +02:00
|
|
|
cp->handle = evt->handle;
|
Bluetooth: SMP: Add support for encryption key size reduction
This allows to pair with devices that use reduced encryption key size.
Encryption key size is stored with keys for future use. LTKs are kept
in full form (16 bytes) and are reduced only when used.
As master:
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: Bonding, No MITM, Legacy,
No Keypresses (0x01)
Max encryption key size: 16
Initiator key distribution: EncKey Sign (0x05)
Responder key distribution: EncKey IdKey Sign (0x07)
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
< HCI Command: LE Start Encryption (0x08|0x0019) plen 28
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
Long term key: df3cff52a981d6000000000000000000
As slave:
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 16
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
> HCI Event: LE Meta Event (0x3e) plen 13
LE Long Term Key Request (0x05)
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
< HCI Command: LE Long Term Key Request Reply (0x08|0x001a) plen 18
Handle: 64
Long term key: 701b431a9e17bb000000000000000000
Change-Id: Ibc70aa01c040aff0d39410d273d6880d35aa5ae0
Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
2015-10-07 12:33:45 +02:00
|
|
|
|
|
|
|
/* use only enc_size bytes of key for encryption */
|
|
|
|
memcpy(cp->ltk, conn->keys->slave_ltk.val,
|
|
|
|
conn->keys->enc_size);
|
|
|
|
if (conn->keys->enc_size < sizeof(cp->ltk)) {
|
|
|
|
memset(cp->ltk + conn->keys->enc_size, 0,
|
|
|
|
sizeof(cp->ltk) - conn->keys->enc_size);
|
|
|
|
}
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
bt_hci_cmd_send(BT_HCI_OP_LE_LTK_REQ_REPLY, buf);
|
2015-12-08 17:22:52 +01:00
|
|
|
goto done;
|
|
|
|
}
|
2015-12-08 16:59:19 +01:00
|
|
|
#endif /* !CONFIG_BLUETOOTH_SMP_SC_ONLY */
|
2015-10-01 17:50:19 +02:00
|
|
|
|
2015-12-08 17:22:52 +01:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_LTK_REQ_NEG_REPLY, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
BT_ERR("Out of command buffers");
|
|
|
|
goto done;
|
|
|
|
}
|
2015-10-01 17:50:19 +02:00
|
|
|
|
2015-12-08 17:22:52 +01:00
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = evt->handle;
|
2015-10-01 17:50:19 +02:00
|
|
|
|
2015-12-08 17:22:52 +01:00
|
|
|
bt_hci_cmd_send(BT_HCI_OP_LE_LTK_REQ_NEG_REPLY, buf);
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
done:
|
2015-10-23 12:45:33 +03:00
|
|
|
bt_conn_unref(conn);
|
2015-10-01 17:50:19 +02:00
|
|
|
}
|
2016-06-30 20:05:36 +03:00
|
|
|
#endif /* CONFIG_BLUETOOTH_SMP */
|
2015-10-26 14:51:48 +01:00
|
|
|
|
|
|
|
static void le_pkey_complete(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_le_p256_public_key_complete *evt = (void *)buf->data;
|
2016-06-30 20:05:36 +03:00
|
|
|
struct bt_pub_key_cb *cb;
|
2015-10-26 14:51:48 +01:00
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status: 0x%x", evt->status);
|
2015-10-26 14:51:48 +01:00
|
|
|
|
2016-06-30 20:05:36 +03:00
|
|
|
atomic_clear_bit(bt_dev.flags, BT_DEV_PUB_KEY_BUSY);
|
|
|
|
|
|
|
|
if (!evt->status) {
|
2016-07-03 17:06:49 +03:00
|
|
|
memcpy(pub_key, evt->key, 64);
|
2016-06-30 20:05:36 +03:00
|
|
|
atomic_set_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY);
|
2015-10-26 14:51:48 +01:00
|
|
|
}
|
|
|
|
|
2016-06-30 20:05:36 +03:00
|
|
|
for (cb = pub_key_cb; cb; cb = cb->_next) {
|
|
|
|
cb->func(evt->status ? NULL : evt->key);
|
|
|
|
}
|
2015-10-26 14:51:48 +01:00
|
|
|
}
|
2015-10-28 16:02:17 +01:00
|
|
|
|
|
|
|
static void le_dhkey_complete(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_le_generate_dhkey_complete *evt = (void *)buf->data;
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status: 0x%x", evt->status);
|
2015-10-28 16:02:17 +01:00
|
|
|
|
2016-06-30 20:05:36 +03:00
|
|
|
if (dh_key_cb) {
|
|
|
|
dh_key_cb(evt->status ? NULL : evt->dhkey);
|
|
|
|
dh_key_cb = NULL;
|
2015-10-28 16:02:17 +01:00
|
|
|
}
|
|
|
|
}
|
2015-10-01 17:50:19 +02:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void hci_reset_complete(struct net_buf *buf)
|
2015-10-01 17:50:19 +02:00
|
|
|
{
|
|
|
|
uint8_t status = buf->data[0];
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status %u", status);
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
if (status) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
scan_dev_found_cb = NULL;
|
2016-03-10 11:58:56 +01:00
|
|
|
#if defined(CONFIG_BLUETOOTH_BREDR)
|
|
|
|
discovery_cb = NULL;
|
|
|
|
discovery_results = NULL;
|
|
|
|
discovery_results_size = 0;
|
|
|
|
discovery_results_count = 0;
|
|
|
|
#endif /* CONFIG_BLUETOOTH_BREDR */
|
2016-06-02 14:45:07 +02:00
|
|
|
|
|
|
|
/* we only allow to enable once so this bit must be keep set */
|
|
|
|
atomic_set(bt_dev.flags, BIT(BT_DEV_ENABLE));
|
2015-10-01 17:50:19 +02:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void hci_cmd_done(uint16_t opcode, uint8_t status, struct net_buf *buf)
|
2015-10-01 17:50:19 +02:00
|
|
|
{
|
2015-10-28 10:34:15 +02:00
|
|
|
struct net_buf *sent = bt_dev.sent_cmd;
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
if (!sent) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-29 17:05:30 +02:00
|
|
|
if (cmd(sent)->opcode != opcode) {
|
2015-12-09 16:31:47 +02:00
|
|
|
BT_ERR("Unexpected completion of opcode 0x%04x expected 0x%04x",
|
|
|
|
opcode, cmd(sent)->opcode);
|
2015-10-01 17:50:19 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_dev.sent_cmd = NULL;
|
|
|
|
|
|
|
|
/* If the command was synchronous wake up bt_hci_cmd_send_sync() */
|
2015-10-29 17:05:30 +02:00
|
|
|
if (cmd(sent)->sync) {
|
|
|
|
struct nano_sem *sem = cmd(sent)->sync;
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
if (status) {
|
2015-10-29 17:05:30 +02:00
|
|
|
cmd(sent)->sync = NULL;
|
2015-10-01 17:50:19 +02:00
|
|
|
} else {
|
2015-10-29 17:05:30 +02:00
|
|
|
cmd(sent)->sync = net_buf_ref(buf);
|
2015-10-01 17:50:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
nano_fiber_sem_give(sem);
|
|
|
|
} else {
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(sent);
|
2015-10-01 17:50:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void hci_cmd_complete(struct net_buf *buf)
|
2015-10-01 17:50:19 +02:00
|
|
|
{
|
|
|
|
struct hci_evt_cmd_complete *evt = (void *)buf->data;
|
|
|
|
uint16_t opcode = sys_le16_to_cpu(evt->opcode);
|
2015-12-09 14:13:14 +02:00
|
|
|
uint8_t status;
|
2015-10-01 17:50:19 +02:00
|
|
|
|
2016-03-14 12:35:39 +02:00
|
|
|
BT_DBG("opcode 0x%04x", opcode);
|
2015-10-01 17:50:19 +02:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_pull(buf, sizeof(*evt));
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
/* All command return parameters have a 1-byte status in the
|
|
|
|
* beginning, so we can safely make this generalization.
|
|
|
|
*/
|
2015-12-09 14:13:14 +02:00
|
|
|
status = buf->data[0];
|
2015-10-01 17:50:19 +02:00
|
|
|
|
2015-12-09 14:13:14 +02:00
|
|
|
hci_cmd_done(opcode, status, buf);
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
if (evt->ncmd && !bt_dev.ncmd) {
|
|
|
|
/* Allow next command to be sent */
|
|
|
|
bt_dev.ncmd = 1;
|
|
|
|
nano_fiber_sem_give(&bt_dev.ncmd_sem);
|
|
|
|
}
|
2015-08-10 22:23:05 +02:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void hci_cmd_status(struct net_buf *buf)
|
2015-08-10 22:23:05 +02:00
|
|
|
{
|
2015-10-01 17:50:19 +02:00
|
|
|
struct bt_hci_evt_cmd_status *evt = (void *)buf->data;
|
|
|
|
uint16_t opcode = sys_le16_to_cpu(evt->opcode);
|
2015-08-10 22:23:05 +02:00
|
|
|
|
2016-03-14 12:35:39 +02:00
|
|
|
BT_DBG("opcode 0x%04x", opcode);
|
2015-08-10 22:23:05 +02:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_pull(buf, sizeof(*evt));
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
hci_cmd_done(opcode, evt->status, buf);
|
2015-08-10 22:23:05 +02:00
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
if (evt->ncmd && !bt_dev.ncmd) {
|
|
|
|
/* Allow next command to be sent */
|
|
|
|
bt_dev.ncmd = 1;
|
|
|
|
nano_fiber_sem_give(&bt_dev.ncmd_sem);
|
2015-08-10 22:23:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-13 10:58:26 +03:00
|
|
|
static inline void mynewt_rand_delay(void)
|
|
|
|
{
|
2016-07-06 11:01:44 +02:00
|
|
|
#if defined(CONFIG_BOARD_ARDUINO_101) || defined(CONFIG_BOARD_QUARK_SE_DEVBOARD)
|
2016-06-13 10:58:26 +03:00
|
|
|
/* FIXME: Temporary hack for MyNewt HCI firmware which
|
|
|
|
* crashes if it receives too rapid LE_Rand commands.
|
|
|
|
*/
|
|
|
|
if (sys_execution_context_type_get() == NANO_CTX_FIBER) {
|
|
|
|
fiber_sleep(MSEC(30));
|
|
|
|
} else {
|
|
|
|
task_sleep(MSEC(30));
|
|
|
|
}
|
2016-07-06 11:01:44 +02:00
|
|
|
#endif /* CONFIG_BOARD_ARDUINO_101 || CONFIG_BOARD_QUARK_SE_DEVBOARD */
|
2016-06-13 10:58:26 +03:00
|
|
|
}
|
|
|
|
|
2016-02-08 17:14:58 +01:00
|
|
|
static int prng_reseed(struct tc_hmac_prng_struct *h)
|
|
|
|
{
|
|
|
|
uint8_t seed[32];
|
|
|
|
int64_t extra;
|
|
|
|
int ret, i;
|
|
|
|
|
|
|
|
for (i = 0; i < (sizeof(seed) / 8); i++) {
|
|
|
|
struct bt_hci_rp_le_rand *rp;
|
|
|
|
struct net_buf *rsp;
|
|
|
|
|
2016-06-13 10:58:26 +03:00
|
|
|
/* FIXME: Temporary hack for MyNewt HCI firmware which
|
|
|
|
* crashes if it receives too rapid LE_Rand commands.
|
|
|
|
*/
|
|
|
|
mynewt_rand_delay();
|
|
|
|
|
2016-02-08 17:14:58 +01:00
|
|
|
ret = bt_hci_cmd_send_sync(BT_HCI_OP_LE_RAND, NULL, &rsp);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
rp = (void *)rsp->data;
|
|
|
|
memcpy(&seed[i * 8], rp->rand, 8);
|
|
|
|
|
|
|
|
net_buf_unref(rsp);
|
|
|
|
}
|
|
|
|
|
|
|
|
extra = sys_tick_get();
|
|
|
|
|
|
|
|
ret = tc_hmac_prng_reseed(h, seed, sizeof(seed), (uint8_t *)&extra,
|
|
|
|
sizeof(extra));
|
|
|
|
if (ret == TC_FAIL) {
|
|
|
|
BT_ERR("Failed to re-seed PRNG");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int prng_init(struct tc_hmac_prng_struct *h)
|
|
|
|
{
|
|
|
|
struct bt_hci_rp_le_rand *rp;
|
|
|
|
struct net_buf *rsp;
|
|
|
|
int ret;
|
|
|
|
|
2016-06-13 10:58:26 +03:00
|
|
|
/* FIXME: Temporary hack for MyNewt HCI firmware which
|
|
|
|
* crashes if it receives too rapid LE_Rand commands.
|
|
|
|
*/
|
|
|
|
mynewt_rand_delay();
|
|
|
|
|
2016-02-08 17:14:58 +01:00
|
|
|
ret = bt_hci_cmd_send_sync(BT_HCI_OP_LE_RAND, NULL, &rsp);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
rp = (void *)rsp->data;
|
|
|
|
|
|
|
|
ret = tc_hmac_prng_init(h, rp->rand, sizeof(rp->rand));
|
|
|
|
|
|
|
|
net_buf_unref(rsp);
|
|
|
|
|
|
|
|
if (ret == TC_FAIL) {
|
|
|
|
BT_ERR("Failed to initialize PRNG");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* re-seed is needed after init */
|
|
|
|
return prng_reseed(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_rand(void *buf, size_t len)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = tc_hmac_prng_generate(buf, len, &prng);
|
|
|
|
if (ret == TC_HMAC_PRNG_RESEED_REQ) {
|
|
|
|
ret = prng_reseed(&prng);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = tc_hmac_prng_generate(buf, len, &prng);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == TC_SUCCESS) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EIO;
|
|
|
|
}
|
2015-12-06 09:30:00 +02:00
|
|
|
|
2015-12-06 10:29:11 +02:00
|
|
|
static int le_set_nrpa(void)
|
|
|
|
{
|
2015-12-07 08:00:32 +02:00
|
|
|
bt_addr_t nrpa;
|
2016-04-04 12:55:11 +03:00
|
|
|
int err;
|
|
|
|
|
|
|
|
err = bt_rand(nrpa.val, sizeof(nrpa.val));
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
2015-12-06 10:29:11 +02:00
|
|
|
|
2015-12-07 08:00:32 +02:00
|
|
|
nrpa.val[5] &= 0x3f;
|
|
|
|
|
2016-04-04 12:55:11 +03:00
|
|
|
return set_random_address(&nrpa);
|
|
|
|
}
|
2015-12-06 10:29:11 +02:00
|
|
|
|
2015-12-03 20:17:34 +02:00
|
|
|
static int start_le_scan(uint8_t scan_type, uint16_t interval, uint16_t window,
|
|
|
|
uint8_t filter_dup)
|
2015-08-11 09:13:40 +02:00
|
|
|
{
|
2015-10-28 10:34:15 +02:00
|
|
|
struct net_buf *buf, *rsp;
|
2015-10-01 17:50:19 +02:00
|
|
|
struct bt_hci_cp_le_set_scan_params *set_param;
|
|
|
|
struct bt_hci_cp_le_set_scan_enable *scan_enable;
|
|
|
|
int err;
|
2015-08-11 09:13:40 +02:00
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_SCAN_PARAMS,
|
|
|
|
sizeof(*set_param));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
2015-08-11 09:13:40 +02:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
set_param = net_buf_add(buf, sizeof(*set_param));
|
2015-10-01 17:50:19 +02:00
|
|
|
memset(set_param, 0, sizeof(*set_param));
|
|
|
|
set_param->scan_type = scan_type;
|
2015-08-11 09:13:40 +02:00
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
/* for the rest parameters apply default values according to
|
|
|
|
* spec 4.2, vol2, part E, 7.8.10
|
|
|
|
*/
|
2015-12-03 20:17:34 +02:00
|
|
|
set_param->interval = sys_cpu_to_le16(interval);
|
|
|
|
set_param->window = sys_cpu_to_le16(window);
|
2015-10-01 17:50:19 +02:00
|
|
|
set_param->filter_policy = 0x00;
|
2015-12-07 08:00:32 +02:00
|
|
|
|
|
|
|
if (scan_type == BT_HCI_LE_SCAN_ACTIVE) {
|
|
|
|
err = le_set_nrpa();
|
|
|
|
if (err) {
|
|
|
|
net_buf_unref(buf);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_param->addr_type = BT_ADDR_LE_RANDOM;
|
|
|
|
} else {
|
|
|
|
set_param->addr_type = BT_ADDR_LE_PUBLIC;
|
|
|
|
}
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
bt_hci_cmd_send(BT_HCI_OP_LE_SET_SCAN_PARAMS, buf);
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_SCAN_ENABLE,
|
|
|
|
sizeof(*scan_enable));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
2015-08-11 09:13:40 +02:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
scan_enable = net_buf_add(buf, sizeof(*scan_enable));
|
2015-10-01 17:50:19 +02:00
|
|
|
memset(scan_enable, 0, sizeof(*scan_enable));
|
2015-12-03 20:10:46 +02:00
|
|
|
scan_enable->filter_dup = filter_dup;
|
2015-12-04 13:22:18 +02:00
|
|
|
scan_enable->enable = BT_HCI_LE_SCAN_ENABLE;
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_SCAN_ENABLE, buf, &rsp);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
2015-08-11 09:13:40 +02:00
|
|
|
}
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
/* Update scan state in case of success (0) status */
|
|
|
|
err = rsp->data[0];
|
|
|
|
if (!err) {
|
|
|
|
atomic_set_bit(bt_dev.flags, BT_DEV_SCANNING);
|
|
|
|
}
|
2015-08-11 09:13:40 +02:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(rsp);
|
2015-10-01 17:50:19 +02:00
|
|
|
|
|
|
|
return err;
|
2015-08-11 09:13:40 +02:00
|
|
|
}
|
|
|
|
|
2015-12-03 22:51:16 +02:00
|
|
|
int bt_le_scan_update(bool fast_scan)
|
2015-07-02 11:53:54 +02:00
|
|
|
{
|
2015-12-04 10:55:54 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
|
|
|
uint16_t interval, window;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
|
|
|
|
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) {
|
|
|
|
int err;
|
2015-07-02 11:53:54 +02:00
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
err = bt_hci_stop_scanning();
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
2015-07-02 11:53:54 +02:00
|
|
|
}
|
|
|
|
|
2015-12-04 10:55:54 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
2016-01-28 18:58:55 -05:00
|
|
|
conn = bt_conn_lookup_state_le(NULL, BT_CONN_CONNECT_SCAN);
|
2015-12-04 10:55:54 +02:00
|
|
|
if (!conn) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-07-02 11:53:54 +02:00
|
|
|
|
2015-12-04 10:55:54 +02:00
|
|
|
bt_conn_unref(conn);
|
2015-12-03 22:51:16 +02:00
|
|
|
|
2015-12-04 10:55:54 +02:00
|
|
|
if (fast_scan) {
|
2015-12-04 13:35:55 +02:00
|
|
|
interval = BT_GAP_SCAN_FAST_INTERVAL;
|
|
|
|
window = BT_GAP_SCAN_FAST_WINDOW;
|
2015-12-04 10:55:54 +02:00
|
|
|
} else {
|
2015-12-05 14:33:16 +02:00
|
|
|
interval = BT_GAP_SCAN_SLOW_INTERVAL_1;
|
|
|
|
window = BT_GAP_SCAN_SLOW_WINDOW_1;
|
2015-10-01 17:50:19 +02:00
|
|
|
}
|
2015-04-18 18:44:38 +03:00
|
|
|
|
2015-12-04 10:55:54 +02:00
|
|
|
return start_le_scan(BT_HCI_LE_SCAN_PASSIVE, interval, window, 0x01);
|
|
|
|
#else
|
2015-12-03 20:05:42 +02:00
|
|
|
return 0;
|
2015-12-04 10:55:54 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
2015-10-01 17:50:19 +02:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void le_adv_report(struct net_buf *buf)
|
2015-05-08 20:53:39 +02:00
|
|
|
{
|
2016-02-12 14:57:53 +02:00
|
|
|
uint8_t num_reports = net_buf_pull_u8(buf);
|
2015-05-18 10:32:58 +03:00
|
|
|
struct bt_hci_ev_le_advertising_info *info;
|
2015-05-08 20:53:39 +02:00
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("Adv number of reports %u", num_reports);
|
2015-05-08 20:53:39 +02:00
|
|
|
|
2016-02-12 14:57:53 +02:00
|
|
|
info = (void *)buf->data;
|
2015-05-08 20:53:39 +02:00
|
|
|
while (num_reports--) {
|
|
|
|
int8_t rssi = info->data[info->length];
|
2015-09-09 17:35:39 +02:00
|
|
|
const bt_addr_le_t *addr;
|
2015-10-01 18:21:40 +02:00
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("%s event %u, len %u, rssi %d dBm",
|
|
|
|
bt_addr_le_str(&info->addr),
|
|
|
|
info->evt_type, info->length, rssi);
|
2015-10-01 18:21:40 +02:00
|
|
|
|
|
|
|
addr = find_id_addr(&info->addr);
|
2015-06-02 17:28:00 +02:00
|
|
|
|
|
|
|
if (scan_dev_found_cb) {
|
2015-09-09 17:35:39 +02:00
|
|
|
scan_dev_found_cb(addr, rssi, info->evt_type,
|
2015-06-02 17:28:00 +02:00
|
|
|
info->data, info->length);
|
2015-06-01 10:25:05 +07:00
|
|
|
}
|
|
|
|
|
2015-10-01 18:21:40 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
2015-10-02 10:10:39 +02:00
|
|
|
check_pending_conn(addr, &info->addr, info->evt_type);
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
2015-05-08 20:53:39 +02:00
|
|
|
/* Get next report iteration by moving pointer to right offset
|
|
|
|
* in buf according to spec 4.2, Vol 2, Part E, 7.7.65.2.
|
|
|
|
*/
|
2015-10-28 10:34:15 +02:00
|
|
|
info = net_buf_pull(buf, sizeof(*info) + info->length +
|
|
|
|
sizeof(rssi));
|
2015-05-08 20:53:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void hci_le_meta_event(struct net_buf *buf)
|
2015-04-18 18:37:03 +03:00
|
|
|
{
|
|
|
|
struct bt_hci_evt_le_meta_event *evt = (void *)buf->data;
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_pull(buf, sizeof(*evt));
|
2015-04-18 18:37:03 +03:00
|
|
|
|
|
|
|
switch (evt->subevent) {
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
2015-04-18 18:44:38 +03:00
|
|
|
case BT_HCI_EVT_LE_CONN_COMPLETE:
|
|
|
|
le_conn_complete(buf);
|
|
|
|
break;
|
2015-08-11 09:13:40 +02:00
|
|
|
case BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE:
|
|
|
|
le_conn_update_complete(buf);
|
|
|
|
break;
|
2015-07-28 13:02:43 +03:00
|
|
|
case BT_HCI_EV_LE_REMOTE_FEAT_COMPLETE:
|
|
|
|
le_remote_feat_complete(buf);
|
|
|
|
break;
|
2015-08-10 22:23:05 +02:00
|
|
|
case BT_HCI_EVT_LE_CONN_PARAM_REQ:
|
|
|
|
le_conn_param_req(buf);
|
|
|
|
break;
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
2015-09-09 17:27:16 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_SMP)
|
|
|
|
case BT_HCI_EVT_LE_LTK_REQUEST:
|
|
|
|
le_ltk_request(buf);
|
|
|
|
break;
|
2016-06-30 20:05:36 +03:00
|
|
|
#endif /* CONFIG_BLUETOOTH_SMP */
|
2015-10-26 14:51:48 +01:00
|
|
|
case BT_HCI_EVT_LE_P256_PUBLIC_KEY_COMPLETE:
|
|
|
|
le_pkey_complete(buf);
|
|
|
|
break;
|
2015-10-28 16:02:17 +01:00
|
|
|
case BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE:
|
|
|
|
le_dhkey_complete(buf);
|
|
|
|
break;
|
2015-09-07 18:25:59 +02:00
|
|
|
case BT_HCI_EVT_LE_ADVERTISING_REPORT:
|
|
|
|
le_adv_report(buf);
|
|
|
|
break;
|
2015-04-18 18:37:03 +03:00
|
|
|
default:
|
2016-06-30 13:34:10 +02:00
|
|
|
BT_DBG("Unhandled LE event 0x%02x", evt->subevent);
|
2015-04-18 18:37:03 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void hci_event(struct net_buf *buf)
|
2015-04-14 15:41:55 +03:00
|
|
|
{
|
|
|
|
struct bt_hci_evt_hdr *hdr = (void *)buf->data;
|
|
|
|
|
2016-06-30 13:34:10 +02:00
|
|
|
BT_DBG("event 0x%02x", hdr->evt);
|
2015-04-14 15:41:55 +03:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_pull(buf, sizeof(*hdr));
|
2015-04-14 15:41:55 +03:00
|
|
|
|
|
|
|
switch (hdr->evt) {
|
2015-12-03 12:19:02 +01:00
|
|
|
#if defined(CONFIG_BLUETOOTH_BREDR)
|
|
|
|
case BT_HCI_EVT_CONN_REQUEST:
|
2015-12-16 22:39:08 +01:00
|
|
|
conn_req(buf);
|
2015-12-03 12:19:02 +01:00
|
|
|
break;
|
2015-12-03 17:20:29 +01:00
|
|
|
case BT_HCI_EVT_CONN_COMPLETE:
|
|
|
|
conn_complete(buf);
|
|
|
|
break;
|
2015-12-16 11:08:25 +01:00
|
|
|
case BT_HCI_EVT_PIN_CODE_REQ:
|
|
|
|
pin_code_req(buf);
|
|
|
|
break;
|
2015-12-16 16:35:28 +01:00
|
|
|
case BT_HCI_EVT_LINK_KEY_NOTIFY:
|
|
|
|
link_key_notify(buf);
|
|
|
|
break;
|
2016-01-07 22:55:01 +01:00
|
|
|
case BT_HCI_EVT_LINK_KEY_REQ:
|
|
|
|
link_key_req(buf);
|
|
|
|
break;
|
2016-01-29 12:29:11 +01:00
|
|
|
case BT_HCI_EVT_IO_CAPA_RESP:
|
|
|
|
io_capa_resp(buf);
|
|
|
|
break;
|
2016-01-29 13:08:59 +01:00
|
|
|
case BT_HCI_EVT_IO_CAPA_REQ:
|
|
|
|
io_capa_req(buf);
|
|
|
|
break;
|
2016-01-29 13:29:54 +01:00
|
|
|
case BT_HCI_EVT_SSP_COMPLETE:
|
|
|
|
ssp_complete(buf);
|
|
|
|
break;
|
2016-02-01 12:41:04 +01:00
|
|
|
case BT_HCI_EVT_USER_CONFIRM_REQ:
|
|
|
|
user_confirm_req(buf);
|
|
|
|
break;
|
2016-02-24 14:47:01 +01:00
|
|
|
case BT_HCI_EVT_USER_PASSKEY_NOTIFY:
|
|
|
|
user_passkey_notify(buf);
|
|
|
|
break;
|
2016-02-24 14:58:03 +01:00
|
|
|
case BT_HCI_EVT_USER_PASSKEY_REQ:
|
|
|
|
user_passkey_req(buf);
|
|
|
|
break;
|
2016-03-10 11:58:56 +01:00
|
|
|
case BT_HCI_EVT_INQUIRY_COMPLETE:
|
|
|
|
inquiry_complete(buf);
|
|
|
|
break;
|
2016-03-10 12:03:55 +01:00
|
|
|
case BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI:
|
|
|
|
inquiry_result_with_rssi(buf);
|
|
|
|
break;
|
|
|
|
case BT_HCI_EVT_EXTENDED_INQUIRY_RESULT:
|
|
|
|
extended_inquiry_result(buf);
|
|
|
|
break;
|
2016-03-17 18:35:58 +01:00
|
|
|
case BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE:
|
|
|
|
remote_name_request_complete(buf);
|
|
|
|
break;
|
2016-03-18 14:13:23 +01:00
|
|
|
case BT_HCI_EVT_AUTH_COMPLETE:
|
|
|
|
auth_complete(buf);
|
|
|
|
break;
|
2016-06-17 21:27:41 +02:00
|
|
|
case BT_HCI_EVT_REMOTE_FEATURES:
|
|
|
|
read_remote_features_complete(buf);
|
|
|
|
break;
|
|
|
|
case BT_HCI_EVT_REMOTE_EXT_FEATURES:
|
|
|
|
read_remote_ext_features_complete(buf);
|
|
|
|
break;
|
2015-12-03 12:19:02 +01:00
|
|
|
#endif
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
2015-04-18 18:52:54 +03:00
|
|
|
case BT_HCI_EVT_DISCONN_COMPLETE:
|
|
|
|
hci_disconn_complete(buf);
|
|
|
|
break;
|
2015-09-09 17:27:16 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
2016-01-08 11:11:56 +01:00
|
|
|
#if defined(CONFIG_BLUETOOTH_SMP) || defined(CONFIG_BLUETOOTH_BREDR)
|
2015-05-21 21:00:50 +03:00
|
|
|
case BT_HCI_EVT_ENCRYPT_CHANGE:
|
|
|
|
hci_encrypt_change(buf);
|
|
|
|
break;
|
2015-06-01 09:22:36 +07:00
|
|
|
case BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE:
|
|
|
|
hci_encrypt_key_refresh_complete(buf);
|
|
|
|
break;
|
2016-01-08 11:11:56 +01:00
|
|
|
#endif /* CONFIG_BLUETOOTH_SMP || CONFIG_BLUETOOTH_BREDR */
|
2015-04-18 18:37:03 +03:00
|
|
|
case BT_HCI_EVT_LE_META_EVENT:
|
|
|
|
hci_le_meta_event(buf);
|
|
|
|
break;
|
2015-04-14 15:41:55 +03:00
|
|
|
default:
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_WARN("Unhandled event 0x%02x", hdr->evt);
|
2015-04-14 15:41:55 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(buf);
|
2015-04-14 15:41:55 +03:00
|
|
|
}
|
|
|
|
|
2015-05-23 19:33:51 +03:00
|
|
|
static void hci_cmd_tx_fiber(void)
|
2015-04-14 15:41:55 +03:00
|
|
|
{
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("started");
|
2015-04-14 15:41:55 +03:00
|
|
|
|
|
|
|
while (1) {
|
2015-10-28 10:34:15 +02:00
|
|
|
struct net_buf *buf;
|
2015-09-15 17:57:00 +03:00
|
|
|
int err;
|
2015-04-14 15:41:55 +03:00
|
|
|
|
|
|
|
/* Wait until ncmd > 0 */
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("calling sem_take_wait");
|
2015-12-18 15:36:34 -05:00
|
|
|
nano_fiber_sem_take(&bt_dev.ncmd_sem, TICKS_UNLIMITED);
|
2015-04-14 15:41:55 +03:00
|
|
|
|
|
|
|
/* Get next command - wait if necessary */
|
2016-06-05 17:36:46 +03:00
|
|
|
BT_DBG("calling net_buf_get_timeout");
|
|
|
|
buf = net_buf_get_timeout(&bt_dev.cmd_tx_queue, 0,
|
|
|
|
TICKS_UNLIMITED);
|
2015-07-15 13:53:17 +03:00
|
|
|
bt_dev.ncmd = 0;
|
2015-04-14 15:41:55 +03:00
|
|
|
|
2015-04-28 15:16:03 +03:00
|
|
|
/* Clear out any existing sent command */
|
2015-07-15 13:53:17 +03:00
|
|
|
if (bt_dev.sent_cmd) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Uncleared pending sent_cmd");
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(bt_dev.sent_cmd);
|
2015-07-15 13:53:17 +03:00
|
|
|
bt_dev.sent_cmd = NULL;
|
2015-04-28 15:16:03 +03:00
|
|
|
}
|
|
|
|
|
2015-11-04 21:18:03 +02:00
|
|
|
bt_dev.sent_cmd = net_buf_ref(buf);
|
|
|
|
|
2016-03-14 12:35:39 +02:00
|
|
|
BT_DBG("Sending command 0x%04x (buf %p) to driver",
|
2015-10-29 17:05:30 +02:00
|
|
|
cmd(buf)->opcode, buf);
|
2015-09-15 17:57:00 +03:00
|
|
|
|
2016-04-20 14:46:48 +03:00
|
|
|
err = bt_send(buf);
|
2015-09-15 17:57:00 +03:00
|
|
|
if (err) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Unable to send to driver (err %d)", err);
|
2015-11-03 14:14:57 +02:00
|
|
|
nano_fiber_sem_give(&bt_dev.ncmd_sem);
|
2016-03-14 13:04:09 +02:00
|
|
|
hci_cmd_done(cmd(buf)->opcode, BT_HCI_ERR_UNSPECIFIED,
|
|
|
|
NULL);
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(buf);
|
2015-09-15 17:57:00 +03:00
|
|
|
}
|
2015-04-14 15:41:55 +03:00
|
|
|
}
|
2015-04-14 15:32:32 +03:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void read_local_features_complete(struct net_buf *buf)
|
2015-04-30 13:19:44 +03:00
|
|
|
{
|
|
|
|
struct bt_hci_rp_read_local_features *rp = (void *)buf->data;
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status %u", rp->status);
|
2015-04-30 13:19:44 +03:00
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
memcpy(bt_dev.features, rp->features, sizeof(bt_dev.features));
|
2015-04-30 13:19:44 +03:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void read_local_ver_complete(struct net_buf *buf)
|
2015-04-30 13:19:44 +03:00
|
|
|
{
|
|
|
|
struct bt_hci_rp_read_local_version_info *rp = (void *)buf->data;
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status %u", rp->status);
|
2015-04-30 13:19:44 +03:00
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
bt_dev.hci_version = rp->hci_version;
|
|
|
|
bt_dev.hci_revision = sys_le16_to_cpu(rp->hci_revision);
|
|
|
|
bt_dev.manufacturer = sys_le16_to_cpu(rp->manufacturer);
|
2015-04-30 13:19:44 +03:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void read_bdaddr_complete(struct net_buf *buf)
|
2015-04-30 13:19:44 +03:00
|
|
|
{
|
|
|
|
struct bt_hci_rp_read_bd_addr *rp = (void *)buf->data;
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status %u", rp->status);
|
2015-04-30 13:19:44 +03:00
|
|
|
|
2016-04-04 13:06:55 +03:00
|
|
|
bt_addr_copy(&bt_dev.id_addr.a, &rp->bdaddr);
|
2016-04-02 09:42:08 +03:00
|
|
|
bt_dev.id_addr.type = BT_ADDR_LE_PUBLIC;
|
2015-04-30 13:19:44 +03:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void read_le_features_complete(struct net_buf *buf)
|
2015-04-30 13:19:44 +03:00
|
|
|
{
|
|
|
|
struct bt_hci_rp_le_read_local_features *rp = (void *)buf->data;
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status %u", rp->status);
|
2015-04-30 13:19:44 +03:00
|
|
|
|
2015-11-03 11:19:19 +01:00
|
|
|
memcpy(bt_dev.le.features, rp->features, sizeof(bt_dev.le.features));
|
2015-04-30 13:19:44 +03:00
|
|
|
}
|
|
|
|
|
2015-11-18 08:02:55 +01:00
|
|
|
static void init_sem(struct nano_sem *sem, size_t count)
|
|
|
|
{
|
|
|
|
/* Initialize & prime the semaphore for counting controller-side
|
|
|
|
* available ACL packet buffers.
|
|
|
|
*/
|
|
|
|
nano_sem_init(sem);
|
|
|
|
while (count--) {
|
|
|
|
nano_sem_give(sem);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-11-16 14:57:58 +01:00
|
|
|
#if defined(CONFIG_BLUETOOTH_BREDR)
|
|
|
|
static void read_buffer_size_complete(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_rp_read_buffer_size *rp = (void *)buf->data;
|
2015-11-18 08:59:26 +01:00
|
|
|
uint16_t pkts;
|
2015-11-16 14:57:58 +01:00
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status %u", rp->status);
|
2015-11-16 14:57:58 +01:00
|
|
|
|
|
|
|
bt_dev.br.mtu = sys_le16_to_cpu(rp->acl_max_len);
|
2015-11-18 08:59:26 +01:00
|
|
|
pkts = sys_le16_to_cpu(rp->acl_max_num);
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("ACL BR/EDR buffers: pkts %u mtu %u", pkts, bt_dev.br.mtu);
|
2015-11-18 08:59:26 +01:00
|
|
|
|
|
|
|
init_sem(&bt_dev.br.pkts, pkts);
|
2015-11-16 14:57:58 +01:00
|
|
|
}
|
|
|
|
#else
|
2015-10-28 10:34:15 +02:00
|
|
|
static void read_buffer_size_complete(struct net_buf *buf)
|
2015-04-30 13:19:44 +03:00
|
|
|
{
|
|
|
|
struct bt_hci_rp_read_buffer_size *rp = (void *)buf->data;
|
2015-11-18 08:02:55 +01:00
|
|
|
uint16_t pkts;
|
2015-04-30 13:19:44 +03:00
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status %u", rp->status);
|
2015-04-30 13:19:44 +03:00
|
|
|
|
|
|
|
/* If LE-side has buffers we can ignore the BR/EDR values */
|
2015-11-03 11:19:19 +01:00
|
|
|
if (bt_dev.le.mtu) {
|
2015-04-30 13:19:44 +03:00
|
|
|
return;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-30 13:19:44 +03:00
|
|
|
|
2015-11-03 11:19:19 +01:00
|
|
|
bt_dev.le.mtu = sys_le16_to_cpu(rp->acl_max_len);
|
2015-11-18 08:02:55 +01:00
|
|
|
pkts = sys_le16_to_cpu(rp->acl_max_num);
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("ACL BR/EDR buffers: pkts %u mtu %u", pkts, bt_dev.le.mtu);
|
2015-11-18 08:02:55 +01:00
|
|
|
|
2015-11-23 10:08:46 +01:00
|
|
|
init_sem(&bt_dev.le.pkts, pkts);
|
2015-04-30 13:19:44 +03:00
|
|
|
}
|
2015-11-16 14:57:58 +01:00
|
|
|
#endif
|
2015-04-30 13:19:44 +03:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
static void le_read_buffer_size_complete(struct net_buf *buf)
|
2015-04-30 13:19:44 +03:00
|
|
|
{
|
|
|
|
struct bt_hci_rp_le_read_buffer_size *rp = (void *)buf->data;
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status %u", rp->status);
|
2015-04-30 13:19:44 +03:00
|
|
|
|
2015-11-03 11:19:19 +01:00
|
|
|
bt_dev.le.mtu = sys_le16_to_cpu(rp->le_max_len);
|
2015-11-18 08:02:55 +01:00
|
|
|
|
|
|
|
if (bt_dev.le.mtu) {
|
2015-11-23 10:08:46 +01:00
|
|
|
init_sem(&bt_dev.le.pkts, rp->le_max_num);
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("ACL LE buffers: pkts %u mtu %u", rp->le_max_num,
|
2015-11-18 08:02:55 +01:00
|
|
|
bt_dev.le.mtu);
|
|
|
|
}
|
2015-04-30 13:19:44 +03:00
|
|
|
}
|
|
|
|
|
2015-10-21 16:09:37 +02:00
|
|
|
static void read_supported_commands_complete(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_rp_read_supported_commands *rp = (void *)buf->data;
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("status %u", rp->status);
|
2015-10-21 16:09:37 +02:00
|
|
|
|
|
|
|
memcpy(bt_dev.supported_commands, rp->commands,
|
|
|
|
sizeof(bt_dev.supported_commands));
|
2016-05-24 17:15:03 +02:00
|
|
|
|
|
|
|
#if defined(CONFIG_BLUETOOTH_TINYCRYPT_ECC)
|
|
|
|
/*
|
|
|
|
* Report "LE Read Local P-256 Public Key" and "LE Generate DH Key" as
|
|
|
|
* supported if TinyCrypt ECC is used for emulation.
|
|
|
|
*/
|
|
|
|
bt_dev.supported_commands[34] |= 0x02;
|
|
|
|
bt_dev.supported_commands[34] |= 0x04;
|
|
|
|
#endif /* CONFIG_BLUETOOTH_TINYCRYPT_ECC */
|
2015-10-21 16:09:37 +02:00
|
|
|
}
|
|
|
|
|
2015-10-30 12:46:08 +01:00
|
|
|
static int common_init(void)
|
2015-09-15 14:25:26 +02:00
|
|
|
{
|
2015-10-30 12:46:08 +01:00
|
|
|
struct net_buf *rsp;
|
|
|
|
int err;
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-04-14 15:41:55 +03:00
|
|
|
/* Send HCI_RESET */
|
2016-03-14 13:04:29 +02:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, &rsp);
|
2015-10-30 12:46:08 +01:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
2016-03-14 13:04:29 +02:00
|
|
|
hci_reset_complete(rsp);
|
|
|
|
net_buf_unref(rsp);
|
2015-04-14 15:41:55 +03:00
|
|
|
|
2016-06-08 09:42:28 +02:00
|
|
|
/*
|
|
|
|
* initialize PRNG right after reset so that it is safe to use it later
|
|
|
|
* on in initialization process
|
|
|
|
*/
|
|
|
|
err = prng_init(&prng);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-04-14 15:44:48 +03:00
|
|
|
/* Read Local Supported Features */
|
2015-04-30 13:19:44 +03:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_LOCAL_FEATURES, NULL, &rsp);
|
2015-05-05 10:50:14 +03:00
|
|
|
if (err) {
|
2015-04-30 13:19:44 +03:00
|
|
|
return err;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-30 13:19:44 +03:00
|
|
|
read_local_features_complete(rsp);
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(rsp);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
|
|
|
/* Read Local Version Information */
|
2015-04-30 13:19:44 +03:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_LOCAL_VERSION_INFO, NULL,
|
|
|
|
&rsp);
|
2015-05-05 10:50:14 +03:00
|
|
|
if (err) {
|
2015-04-30 13:19:44 +03:00
|
|
|
return err;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-30 13:19:44 +03:00
|
|
|
read_local_ver_complete(rsp);
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(rsp);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
|
|
|
/* Read Bluetooth Address */
|
2015-04-30 13:19:44 +03:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_BD_ADDR, NULL, &rsp);
|
2015-05-05 10:50:14 +03:00
|
|
|
if (err) {
|
2015-04-30 13:19:44 +03:00
|
|
|
return err;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-30 13:19:44 +03:00
|
|
|
read_bdaddr_complete(rsp);
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(rsp);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2016-04-01 08:37:18 +03:00
|
|
|
/* Read Local Supported Commands */
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_SUPPORTED_COMMANDS, NULL,
|
|
|
|
&rsp);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
read_supported_commands_complete(rsp);
|
|
|
|
net_buf_unref(rsp);
|
|
|
|
|
2015-10-30 12:46:08 +01:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
|
|
|
err = set_flow_control();
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int le_init(void)
|
|
|
|
{
|
2015-11-16 12:19:19 +01:00
|
|
|
struct bt_hci_cp_write_le_host_supp *cp_le;
|
|
|
|
struct bt_hci_cp_le_set_event_mask *cp_mask;
|
|
|
|
struct net_buf *buf;
|
2015-10-30 12:46:08 +01:00
|
|
|
struct net_buf *rsp;
|
|
|
|
int err;
|
|
|
|
|
2015-04-14 15:44:48 +03:00
|
|
|
/* For now we only support LE capable controllers */
|
2015-07-15 13:53:17 +03:00
|
|
|
if (!lmp_le_capable(bt_dev)) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("Non-LE capable controller detected!");
|
2015-04-14 15:44:48 +03:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read Low Energy Supported Features */
|
2015-04-30 13:19:44 +03:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_LOCAL_FEATURES, NULL,
|
|
|
|
&rsp);
|
2015-05-05 10:50:14 +03:00
|
|
|
if (err) {
|
2015-04-30 13:19:44 +03:00
|
|
|
return err;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-30 13:19:44 +03:00
|
|
|
read_le_features_complete(rsp);
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(rsp);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
|
|
|
/* Read LE Buffer Size */
|
2015-04-30 13:19:44 +03:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_BUFFER_SIZE, NULL, &rsp);
|
2015-05-05 10:50:14 +03:00
|
|
|
if (err) {
|
2015-04-30 13:19:44 +03:00
|
|
|
return err;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-30 13:19:44 +03:00
|
|
|
le_read_buffer_size_complete(rsp);
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(rsp);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-10-30 12:46:08 +01:00
|
|
|
if (lmp_bredr_capable(bt_dev)) {
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_WRITE_LE_HOST_SUPP,
|
2015-11-16 12:19:19 +01:00
|
|
|
sizeof(*cp_le));
|
2015-10-30 12:46:08 +01:00
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2015-11-16 12:19:19 +01:00
|
|
|
cp_le = net_buf_add(buf, sizeof(*cp_le));
|
2015-10-30 12:46:08 +01:00
|
|
|
|
|
|
|
/* Excplicitly enable LE for dual-mode controllers */
|
2015-11-16 12:19:19 +01:00
|
|
|
cp_le->le = 0x01;
|
|
|
|
cp_le->simul = 0x00;
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_WRITE_LE_HOST_SUPP, buf,
|
|
|
|
NULL);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
2015-10-30 12:46:08 +01:00
|
|
|
}
|
|
|
|
|
2015-11-16 12:19:19 +01:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_EVENT_MASK, sizeof(*cp_mask));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp_mask = net_buf_add(buf, sizeof(*cp_mask));
|
|
|
|
memset(cp_mask, 0, sizeof(*cp_mask));
|
|
|
|
|
|
|
|
cp_mask->events[0] |= 0x02; /* LE Advertising Report Event */
|
|
|
|
|
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
|
|
|
cp_mask->events[0] |= 0x01; /* LE Connection Complete Event */
|
|
|
|
cp_mask->events[0] |= 0x04; /* LE Connection Update Complete Event */
|
|
|
|
cp_mask->events[0] |= 0x08; /* LE Read Remote Used Features Compl Evt */
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
|
|
|
|
|
|
|
#if defined(CONFIG_BLUETOOTH_SMP)
|
|
|
|
cp_mask->events[0] |= 0x10; /* LE Long Term Key Request Event */
|
2015-10-26 14:51:48 +01:00
|
|
|
|
|
|
|
/*
|
2016-05-24 17:15:03 +02:00
|
|
|
* If "LE Read Local P-256 Public Key" and "LE Generate DH Key" are
|
2015-10-26 14:51:48 +01:00
|
|
|
* supported we need to enable events generated by those commands.
|
|
|
|
*/
|
2016-05-24 17:15:03 +02:00
|
|
|
|
2015-10-26 14:51:48 +01:00
|
|
|
if ((bt_dev.supported_commands[34] & 0x02) &&
|
|
|
|
(bt_dev.supported_commands[34] & 0x04)) {
|
|
|
|
cp_mask->events[0] |= 0x80; /* LE Read Local P-256 PKey Compl */
|
|
|
|
cp_mask->events[1] |= 0x01; /* LE Generate DHKey Compl Event */
|
|
|
|
}
|
2015-11-16 12:19:19 +01:00
|
|
|
#endif /* CONFIG_BLUETOOTH_SMP */
|
|
|
|
|
2015-10-26 14:51:48 +01:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_EVENT_MASK, buf, NULL);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2016-06-08 09:42:28 +02:00
|
|
|
return 0;
|
2015-10-30 12:46:08 +01:00
|
|
|
}
|
|
|
|
|
2015-11-16 14:57:58 +01:00
|
|
|
#if defined(CONFIG_BLUETOOTH_BREDR)
|
|
|
|
static int br_init(void)
|
|
|
|
{
|
2016-02-22 10:55:29 +01:00
|
|
|
struct net_buf *buf;
|
2016-03-10 11:58:56 +01:00
|
|
|
struct bt_hci_cp_write_ssp_mode *ssp_cp;
|
|
|
|
struct bt_hci_cp_write_inquiry_mode *inq_cp;
|
2015-11-16 14:57:58 +01:00
|
|
|
int err;
|
|
|
|
|
|
|
|
/* Get BR/EDR buffer size */
|
2016-02-22 10:55:29 +01:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_BUFFER_SIZE, NULL, &buf);
|
2015-11-16 14:57:58 +01:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2016-02-22 10:55:29 +01:00
|
|
|
read_buffer_size_complete(buf);
|
|
|
|
net_buf_unref(buf);
|
2015-11-16 14:57:58 +01:00
|
|
|
|
2016-01-16 22:29:59 +01:00
|
|
|
/* Set SSP mode */
|
2016-03-10 11:58:56 +01:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_SSP_MODE, sizeof(*ssp_cp));
|
2016-01-16 22:29:59 +01:00
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2016-03-10 11:58:56 +01:00
|
|
|
ssp_cp = net_buf_add(buf, sizeof(*ssp_cp));
|
|
|
|
ssp_cp->mode = 0x01;
|
2016-01-16 22:29:59 +01:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_SSP_MODE, buf, NULL);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2016-03-10 11:58:56 +01:00
|
|
|
/* Enable Inquiry results with RSSI or extended Inquiry */
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_INQUIRY_MODE, sizeof(*inq_cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
inq_cp = net_buf_add(buf, sizeof(*inq_cp));
|
|
|
|
inq_cp->mode = 0x02;
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_INQUIRY_MODE, buf, NULL);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-11-16 14:57:58 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#else
|
2015-10-30 12:46:08 +01:00
|
|
|
static int br_init(void)
|
|
|
|
{
|
|
|
|
struct net_buf *rsp;
|
|
|
|
int err;
|
|
|
|
|
2015-11-03 14:45:59 +01:00
|
|
|
if (bt_dev.le.mtu) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-30 12:46:08 +01:00
|
|
|
/* Use BR/EDR buffer size if LE reports zero buffers */
|
2015-11-03 14:45:59 +01:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_BUFFER_SIZE, NULL, &rsp);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
2015-10-30 12:46:08 +01:00
|
|
|
}
|
|
|
|
|
2015-11-03 14:45:59 +01:00
|
|
|
read_buffer_size_complete(rsp);
|
|
|
|
net_buf_unref(rsp);
|
|
|
|
|
2015-10-30 12:46:08 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2015-11-16 14:57:58 +01:00
|
|
|
#endif
|
2015-10-30 12:46:08 +01:00
|
|
|
|
|
|
|
static int set_event_mask(void)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_set_event_mask *ev;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
2015-05-08 12:49:09 +03:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_SET_EVENT_MASK, sizeof(*ev));
|
2015-05-05 10:50:14 +03:00
|
|
|
if (!buf) {
|
2015-04-14 15:44:48 +03:00
|
|
|
return -ENOBUFS;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
ev = net_buf_add(buf, sizeof(*ev));
|
2015-04-14 15:44:48 +03:00
|
|
|
memset(ev, 0, sizeof(*ev));
|
2015-09-07 18:25:59 +02:00
|
|
|
|
2015-12-03 12:19:02 +01:00
|
|
|
#if defined(CONFIG_BLUETOOTH_BREDR)
|
2016-03-10 11:58:56 +01:00
|
|
|
ev->events[0] |= 0x01; /* Inquiry Complete */
|
2015-12-03 17:20:29 +01:00
|
|
|
ev->events[0] |= 0x04; /* Connection Complete */
|
2015-12-03 12:19:02 +01:00
|
|
|
ev->events[0] |= 0x08; /* Connection Request */
|
2016-03-18 14:13:23 +01:00
|
|
|
ev->events[0] |= 0x20; /* Authentication Complete */
|
2016-03-17 18:35:58 +01:00
|
|
|
ev->events[0] |= 0x40; /* Remote Name Request Complete */
|
2016-06-17 21:27:41 +02:00
|
|
|
ev->events[1] |= 0x04; /* Read Remote Feature Complete */
|
2015-12-16 11:08:25 +01:00
|
|
|
ev->events[2] |= 0x20; /* Pin Code Request */
|
2016-01-07 22:55:01 +01:00
|
|
|
ev->events[2] |= 0x40; /* Link Key Request */
|
2015-12-16 16:35:28 +01:00
|
|
|
ev->events[2] |= 0x80; /* Link Key Notif */
|
2016-03-10 12:03:55 +01:00
|
|
|
ev->events[4] |= 0x02; /* Inquiry Result With RSSI */
|
2016-06-17 21:27:41 +02:00
|
|
|
ev->events[4] |= 0x04; /* Remote Extended Features Complete */
|
2016-03-10 12:03:55 +01:00
|
|
|
ev->events[5] |= 0x40; /* Extended Inquiry Result */
|
2016-01-29 13:08:59 +01:00
|
|
|
ev->events[6] |= 0x01; /* IO Capability Request */
|
2016-01-29 12:29:11 +01:00
|
|
|
ev->events[6] |= 0x02; /* IO Capability Response */
|
2016-02-01 12:41:04 +01:00
|
|
|
ev->events[6] |= 0x04; /* User Confirmation Request */
|
2016-02-24 14:58:03 +01:00
|
|
|
ev->events[6] |= 0x08; /* User Passkey Request */
|
2016-01-29 13:29:54 +01:00
|
|
|
ev->events[6] |= 0x20; /* Simple Pairing Complete */
|
2016-02-24 14:47:01 +01:00
|
|
|
ev->events[7] |= 0x04; /* User Passkey Notification */
|
2016-06-17 21:27:41 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_BREDR */
|
|
|
|
|
2015-04-14 15:44:48 +03:00
|
|
|
ev->events[1] |= 0x20; /* Command Complete */
|
|
|
|
ev->events[1] |= 0x40; /* Command Status */
|
|
|
|
ev->events[1] |= 0x80; /* Hardware Error */
|
2015-10-01 17:50:19 +02:00
|
|
|
ev->events[3] |= 0x02; /* Data Buffer Overflow */
|
|
|
|
ev->events[7] |= 0x20; /* LE Meta-Event */
|
2015-09-07 18:25:59 +02:00
|
|
|
|
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
2015-10-01 17:50:19 +02:00
|
|
|
ev->events[0] |= 0x10; /* Disconnection Complete */
|
|
|
|
ev->events[1] |= 0x08; /* Read Remote Version Information Complete */
|
2015-04-14 15:44:48 +03:00
|
|
|
ev->events[2] |= 0x04; /* Number of Completed Packets */
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
|
|
|
|
2015-09-09 17:27:16 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_SMP)
|
2015-11-03 11:19:19 +01:00
|
|
|
if (bt_dev.le.features[0] & BT_HCI_LE_ENCRYPTION) {
|
2015-04-14 15:44:48 +03:00
|
|
|
ev->events[0] |= 0x80; /* Encryption Change */
|
|
|
|
ev->events[5] |= 0x80; /* Encryption Key Refresh Complete */
|
|
|
|
}
|
2015-09-09 17:27:16 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_SMP */
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-10-30 12:46:08 +01:00
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_SET_EVENT_MASK, buf, NULL);
|
|
|
|
}
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2016-04-02 09:42:22 +03:00
|
|
|
static int set_static_addr(void)
|
|
|
|
{
|
2016-05-09 11:49:41 +02:00
|
|
|
int err;
|
2016-04-02 09:42:22 +03:00
|
|
|
|
2016-04-05 10:14:32 +03:00
|
|
|
if (bt_storage) {
|
2016-05-09 11:49:41 +02:00
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
ret = bt_storage->read(NULL, BT_STORAGE_ID_ADDR,
|
2016-04-05 10:14:32 +03:00
|
|
|
&bt_dev.id_addr, sizeof(bt_dev.id_addr));
|
2016-05-09 11:49:41 +02:00
|
|
|
if (ret == sizeof(bt_dev.id_addr)) {
|
2016-04-02 09:42:22 +03:00
|
|
|
goto set_addr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("Generating new static random address");
|
|
|
|
|
|
|
|
bt_dev.id_addr.type = BT_ADDR_LE_RANDOM;
|
|
|
|
|
2016-04-04 13:06:55 +03:00
|
|
|
err = bt_rand(bt_dev.id_addr.a.val, 6);
|
2016-04-02 09:42:22 +03:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure the address bits indicate static address */
|
2016-04-04 13:06:55 +03:00
|
|
|
bt_dev.id_addr.a.val[5] |= 0xc0;
|
2016-04-02 09:42:22 +03:00
|
|
|
|
2016-04-05 10:14:32 +03:00
|
|
|
if (bt_storage) {
|
2016-05-09 11:49:41 +02:00
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
ret = bt_storage->write(NULL, BT_STORAGE_ID_ADDR,
|
2016-04-05 10:14:32 +03:00
|
|
|
&bt_dev.id_addr,
|
|
|
|
sizeof(bt_dev.id_addr));
|
2016-05-09 11:49:41 +02:00
|
|
|
if (ret != sizeof(bt_dev.id_addr)) {
|
2016-04-02 09:42:22 +03:00
|
|
|
BT_ERR("Unable to store static address");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
BT_WARN("Using temporary static random address");
|
|
|
|
}
|
|
|
|
|
|
|
|
set_addr:
|
|
|
|
if (bt_dev.id_addr.type != BT_ADDR_LE_RANDOM ||
|
2016-04-04 13:06:55 +03:00
|
|
|
(bt_dev.id_addr.a.val[5] & 0xc0) != 0xc0) {
|
2016-04-02 09:42:22 +03:00
|
|
|
BT_ERR("Only static random address supported as identity");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-05-09 11:48:20 +02:00
|
|
|
err = set_random_address(&bt_dev.id_addr.a);
|
2016-05-09 11:41:14 +02:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_set_bit(bt_dev.flags, BT_DEV_ID_STATIC_RANDOM);
|
|
|
|
return 0;
|
2016-04-02 09:42:22 +03:00
|
|
|
}
|
|
|
|
|
2015-10-30 12:46:08 +01:00
|
|
|
static int hci_init(void)
|
|
|
|
{
|
2015-11-18 08:02:55 +01:00
|
|
|
int err;
|
2015-10-30 12:46:08 +01:00
|
|
|
|
|
|
|
err = common_init();
|
2015-05-18 12:04:50 +02:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-10-30 12:46:08 +01:00
|
|
|
err = le_init();
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-11-19 10:45:59 +02:00
|
|
|
if (lmp_bredr_capable(bt_dev)) {
|
|
|
|
err = br_init();
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
} else {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("Non-BR/EDR controller detected! Skipping BR init.");
|
2015-10-30 12:46:08 +01:00
|
|
|
}
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-10-30 12:46:08 +01:00
|
|
|
err = set_event_mask();
|
|
|
|
if (err) {
|
|
|
|
return err;
|
2015-04-14 15:44:48 +03:00
|
|
|
}
|
|
|
|
|
2016-04-02 09:42:22 +03:00
|
|
|
if (!bt_addr_le_cmp(&bt_dev.id_addr, BT_ADDR_LE_ANY)) {
|
|
|
|
BT_DBG("No public address. Trying to set static random.");
|
|
|
|
err = set_static_addr();
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("Unable to set identity address");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("HCI ver %u rev %u, manufacturer %u", bt_dev.hci_version,
|
2015-07-15 13:53:17 +03:00
|
|
|
bt_dev.hci_revision, bt_dev.manufacturer);
|
2015-05-12 14:57:38 +03:00
|
|
|
|
2015-04-14 15:41:55 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-20 14:46:48 +03:00
|
|
|
int bt_send(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
BT_DBG("buf %p len %u type %u", buf, buf->len, bt_buf_get_type(buf));
|
|
|
|
|
2016-04-20 17:54:07 +03:00
|
|
|
bt_monitor_send(bt_monitor_opcode(buf), buf->data, buf->len);
|
|
|
|
|
2016-04-20 14:46:48 +03:00
|
|
|
return bt_dev.drv->send(buf);
|
|
|
|
}
|
|
|
|
|
2015-04-14 15:32:32 +03:00
|
|
|
/* Interface to HCI driver layer */
|
|
|
|
|
2016-04-09 11:29:50 +03:00
|
|
|
int bt_recv(struct net_buf *buf)
|
2015-04-14 15:32:32 +03:00
|
|
|
{
|
2015-05-23 19:58:06 +03:00
|
|
|
struct bt_hci_evt_hdr *hdr;
|
|
|
|
|
2016-05-24 18:01:10 +02:00
|
|
|
#if defined(CONFIG_MICROKERNEL)
|
|
|
|
if (sys_execution_context_type_get() == NANO_CTX_TASK) {
|
|
|
|
return task_offload_to_fiber(bt_recv, buf);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_MICROKERNEL */
|
|
|
|
|
2016-04-20 17:54:07 +03:00
|
|
|
bt_monitor_send(bt_monitor_opcode(buf), buf->data, buf->len);
|
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("buf %p len %u", buf, buf->len);
|
2015-05-23 19:58:06 +03:00
|
|
|
|
2016-04-09 11:29:50 +03:00
|
|
|
if (buf->user_data_size < BT_BUF_USER_DATA_MIN) {
|
|
|
|
BT_ERR("Too small user data size");
|
|
|
|
net_buf_unref(buf);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bt_buf_get_type(buf) == BT_BUF_ACL_IN) {
|
2016-06-05 17:36:46 +03:00
|
|
|
net_buf_put(&bt_dev.rx_queue, buf);
|
2016-04-09 11:29:50 +03:00
|
|
|
return 0;
|
2015-05-23 19:58:06 +03:00
|
|
|
}
|
|
|
|
|
2016-04-09 11:29:50 +03:00
|
|
|
if (bt_buf_get_type(buf) != BT_BUF_EVT) {
|
|
|
|
BT_ERR("Invalid buf type %u", bt_buf_get_type(buf));
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(buf);
|
2016-04-09 11:29:50 +03:00
|
|
|
return -EINVAL;
|
2015-05-23 19:58:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
hdr = (void *)buf->data;
|
2016-04-22 11:36:04 +02:00
|
|
|
|
|
|
|
switch (hdr->evt) {
|
|
|
|
case BT_HCI_EVT_CMD_COMPLETE:
|
|
|
|
net_buf_pull(buf, sizeof(*hdr));
|
|
|
|
hci_cmd_complete(buf);
|
|
|
|
break;
|
|
|
|
case BT_HCI_EVT_CMD_STATUS:
|
|
|
|
net_buf_pull(buf, sizeof(*hdr));
|
|
|
|
hci_cmd_status(buf);
|
|
|
|
break;
|
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
|
|
|
case BT_HCI_EVT_NUM_COMPLETED_PACKETS:
|
|
|
|
net_buf_pull(buf, sizeof(*hdr));
|
|
|
|
hci_num_completed_packets(buf);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
|
|
|
default:
|
2016-06-28 16:48:01 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_HOST_BUFFERS)
|
|
|
|
/*
|
|
|
|
* If buffer used is from priority pool we are running low on
|
|
|
|
* buffers and those needs to be kept for 'critical' events
|
|
|
|
* handled directly from bt_recv().
|
|
|
|
*/
|
|
|
|
if (buf->free == &avail_prio_hci_evt) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_HOST_BUFFERS */
|
|
|
|
|
2016-06-05 17:36:46 +03:00
|
|
|
net_buf_put(&bt_dev.rx_queue, net_buf_ref(buf));
|
2016-04-22 11:36:04 +02:00
|
|
|
break;
|
2015-05-23 19:58:06 +03:00
|
|
|
}
|
|
|
|
|
2016-04-22 11:36:04 +02:00
|
|
|
net_buf_unref(buf);
|
2016-04-09 11:29:50 +03:00
|
|
|
return 0;
|
2015-04-14 15:32:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int bt_driver_register(struct bt_driver *drv)
|
|
|
|
{
|
2015-07-15 13:53:17 +03:00
|
|
|
if (bt_dev.drv) {
|
2015-04-14 15:32:32 +03:00
|
|
|
return -EALREADY;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-14 15:32:32 +03:00
|
|
|
|
2015-10-28 20:24:16 +02:00
|
|
|
if (!drv->open || !drv->send) {
|
2015-04-14 15:32:32 +03:00
|
|
|
return -EINVAL;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-14 15:32:32 +03:00
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
bt_dev.drv = drv;
|
2015-04-14 15:32:32 +03:00
|
|
|
|
2016-04-22 15:13:09 +03:00
|
|
|
BT_DBG("Registered %s", drv->name ? drv->name : "");
|
|
|
|
|
2016-04-22 14:42:59 +03:00
|
|
|
bt_monitor_new_index(BT_MONITOR_TYPE_PRIMARY, drv->bus,
|
2016-04-22 15:13:09 +03:00
|
|
|
BT_ADDR_ANY, drv->name ? drv->name : "bt0");
|
2016-04-20 17:54:07 +03:00
|
|
|
|
2015-04-14 15:32:32 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_driver_unregister(struct bt_driver *drv)
|
|
|
|
{
|
2015-07-15 13:53:17 +03:00
|
|
|
bt_dev.drv = NULL;
|
2015-04-14 15:32:32 +03:00
|
|
|
}
|
|
|
|
|
2016-04-04 12:55:11 +03:00
|
|
|
#if defined(CONFIG_BLUETOOTH_PRIVACY)
|
|
|
|
static int irk_init(void)
|
|
|
|
{
|
|
|
|
ssize_t err;
|
|
|
|
|
2016-04-05 10:14:32 +03:00
|
|
|
if (bt_storage) {
|
|
|
|
err = bt_storage->read(NULL, BT_STORAGE_LOCAL_IRK, &bt_dev.irk,
|
|
|
|
sizeof(bt_dev.irk));
|
2016-04-04 12:55:11 +03:00
|
|
|
if (err == sizeof(bt_dev.irk)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("Generating new IRK");
|
|
|
|
|
|
|
|
err = bt_rand(bt_dev.irk, sizeof(bt_dev.irk));
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2016-04-05 10:14:32 +03:00
|
|
|
if (bt_storage) {
|
|
|
|
err = bt_storage->write(NULL, BT_STORAGE_LOCAL_IRK, bt_dev.irk,
|
|
|
|
sizeof(bt_dev.irk));
|
2016-04-04 12:55:11 +03:00
|
|
|
if (err != sizeof(bt_dev.irk)) {
|
|
|
|
BT_ERR("Unable to store IRK");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
BT_WARN("Using temporary IRK");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_PRIVACY */
|
|
|
|
|
2015-07-28 18:23:19 +03:00
|
|
|
static int bt_init(void)
|
|
|
|
{
|
|
|
|
struct bt_driver *drv = bt_dev.drv;
|
|
|
|
int err;
|
|
|
|
|
2016-05-24 17:15:03 +02:00
|
|
|
bt_hci_ecc_init();
|
|
|
|
|
2015-07-28 18:23:19 +03:00
|
|
|
err = drv->open();
|
|
|
|
if (err) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("HCI driver open failed (%d)", err);
|
2015-07-28 18:23:19 +03:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = hci_init();
|
2016-04-21 15:15:54 +02:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
2015-09-07 18:25:59 +02:00
|
|
|
|
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
2016-04-21 15:15:54 +02:00
|
|
|
err = bt_conn_init();
|
|
|
|
if (err) {
|
|
|
|
return err;
|
2015-07-28 18:23:19 +03:00
|
|
|
}
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
2015-07-28 18:23:19 +03:00
|
|
|
|
2016-04-04 12:55:11 +03:00
|
|
|
#if defined(CONFIG_BLUETOOTH_PRIVACY)
|
2016-04-21 15:15:54 +02:00
|
|
|
err = irk_init();
|
|
|
|
if (err) {
|
|
|
|
return err;
|
2016-04-04 12:55:11 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-04-20 17:54:07 +03:00
|
|
|
bt_monitor_send(BT_MONITOR_OPEN_INDEX, NULL, 0);
|
2016-04-21 15:15:54 +02:00
|
|
|
atomic_set_bit(bt_dev.flags, BT_DEV_READY);
|
|
|
|
bt_le_scan_update(false);
|
2015-12-04 10:33:34 +02:00
|
|
|
|
2016-04-21 15:15:54 +02:00
|
|
|
return 0;
|
2015-07-28 18:23:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void hci_rx_fiber(bt_ready_cb_t ready_cb)
|
2015-07-28 18:20:50 +03:00
|
|
|
{
|
2015-10-28 10:34:15 +02:00
|
|
|
struct net_buf *buf;
|
2015-07-28 18:20:50 +03:00
|
|
|
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("started");
|
2015-07-28 18:20:50 +03:00
|
|
|
|
2015-07-28 18:23:19 +03:00
|
|
|
if (ready_cb) {
|
|
|
|
ready_cb(bt_init());
|
|
|
|
}
|
|
|
|
|
2015-07-28 18:20:50 +03:00
|
|
|
while (1) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_DBG("calling fifo_get_wait");
|
2016-06-05 17:36:46 +03:00
|
|
|
buf = net_buf_get_timeout(&bt_dev.rx_queue, 0, TICKS_UNLIMITED);
|
2015-07-28 18:20:50 +03:00
|
|
|
|
2016-04-09 11:29:50 +03:00
|
|
|
BT_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf),
|
|
|
|
buf->len);
|
2015-07-28 18:20:50 +03:00
|
|
|
|
2016-04-09 11:29:50 +03:00
|
|
|
switch (bt_buf_get_type(buf)) {
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
2016-04-09 11:29:50 +03:00
|
|
|
case BT_BUF_ACL_IN:
|
2015-07-28 18:20:50 +03:00
|
|
|
hci_acl(buf);
|
|
|
|
break;
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
2016-04-09 11:29:50 +03:00
|
|
|
case BT_BUF_EVT:
|
2015-07-28 18:20:50 +03:00
|
|
|
hci_event(buf);
|
|
|
|
break;
|
|
|
|
default:
|
2016-04-09 11:29:50 +03:00
|
|
|
BT_ERR("Unknown buf type %u", bt_buf_get_type(buf));
|
2015-10-28 10:34:15 +02:00
|
|
|
net_buf_unref(buf);
|
2015-07-28 18:20:50 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-06-07 21:28:07 +03:00
|
|
|
/* Make sure we don't hog the CPU if the rx_queue never
|
|
|
|
* gets empty.
|
|
|
|
*/
|
|
|
|
fiber_yield();
|
2015-07-28 18:20:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-28 20:30:04 +03:00
|
|
|
int bt_enable(bt_ready_cb_t cb)
|
2015-04-14 15:41:55 +03:00
|
|
|
{
|
2015-07-28 20:30:04 +03:00
|
|
|
if (!bt_dev.drv) {
|
2015-11-25 14:26:48 +01:00
|
|
|
BT_ERR("No HCI driver registered");
|
2015-07-28 20:30:04 +03:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2016-05-30 14:20:42 +02:00
|
|
|
if (atomic_test_and_set_bit(bt_dev.flags, BT_DEV_ENABLE)) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
2015-10-28 15:14:46 +02:00
|
|
|
/* Initialize the buffer pools */
|
2015-10-29 16:58:18 +02:00
|
|
|
net_buf_pool_init(hci_cmd_pool);
|
2016-04-09 11:29:50 +03:00
|
|
|
#if defined(CONFIG_BLUETOOTH_HOST_BUFFERS)
|
2015-10-29 16:58:18 +02:00
|
|
|
net_buf_pool_init(hci_evt_pool);
|
2016-06-28 16:48:01 +02:00
|
|
|
net_buf_pool_init(hci_evt_prio_pool);
|
2015-10-28 15:14:46 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
|
|
|
net_buf_pool_init(acl_in_pool);
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
2016-04-09 11:29:50 +03:00
|
|
|
#endif /* CONFIG_BLUETOOTH_HOST_BUFFERS */
|
2015-04-14 15:41:55 +03:00
|
|
|
|
2015-07-28 20:30:04 +03:00
|
|
|
nano_sem_init(&bt_dev.ncmd_sem);
|
2016-04-18 11:45:45 +03:00
|
|
|
|
|
|
|
/* Give cmd_sem allowing to send first HCI_Reset cmd, the only
|
|
|
|
* exception is if the controller requests to wait for an
|
|
|
|
* initial Command Complete for NOP.
|
|
|
|
*/
|
|
|
|
#if !defined(CONFIG_BLUETOOTH_WAIT_NOP)
|
|
|
|
bt_dev.ncmd = 1;
|
2015-07-15 13:53:17 +03:00
|
|
|
nano_task_sem_give(&bt_dev.ncmd_sem);
|
2016-04-18 11:45:45 +03:00
|
|
|
#endif /* !CONFIG_BLUETOOTH_WAIT_NOP */
|
2015-04-14 15:41:55 +03:00
|
|
|
|
2015-07-28 20:30:04 +03:00
|
|
|
/* TX fiber */
|
|
|
|
nano_fifo_init(&bt_dev.cmd_tx_queue);
|
2015-05-26 13:03:46 +03:00
|
|
|
fiber_start(cmd_tx_fiber_stack, sizeof(cmd_tx_fiber_stack),
|
2015-05-23 21:00:09 +03:00
|
|
|
(nano_fiber_entry_t)hci_cmd_tx_fiber, 0, 0, 7, 0);
|
2015-04-14 15:41:55 +03:00
|
|
|
|
2015-09-10 11:25:23 +03:00
|
|
|
/* RX fiber */
|
|
|
|
nano_fifo_init(&bt_dev.rx_queue);
|
|
|
|
fiber_start(rx_fiber_stack, sizeof(rx_fiber_stack),
|
|
|
|
(nano_fiber_entry_t)hci_rx_fiber, (int)cb, 0, 7, 0);
|
|
|
|
|
2015-07-28 18:23:19 +03:00
|
|
|
if (!cb) {
|
|
|
|
return bt_init();
|
2015-07-13 11:10:17 +03:00
|
|
|
}
|
2015-05-21 18:53:13 +03:00
|
|
|
|
2015-07-28 18:23:19 +03:00
|
|
|
return 0;
|
2015-04-14 14:38:13 +03:00
|
|
|
}
|
2015-04-17 13:59:34 +03:00
|
|
|
|
2016-04-04 13:38:16 +03:00
|
|
|
bool bt_addr_le_is_bonded(const bt_addr_le_t *addr)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_BLUETOOTH_SMP)
|
|
|
|
struct bt_keys *keys = bt_keys_find_addr(addr);
|
|
|
|
|
|
|
|
/* if there are any keys stored then device is bonded */
|
|
|
|
return keys && keys->keys;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif /* defined(CONFIG_BLUETOOTH_SMP) */
|
|
|
|
}
|
|
|
|
|
2015-12-05 22:47:23 +02:00
|
|
|
static bool valid_adv_param(const struct bt_le_adv_param *param)
|
|
|
|
{
|
2016-05-02 15:18:28 +02:00
|
|
|
if (!(param->options & BT_LE_ADV_OPT_CONNECTABLE)) {
|
2016-03-22 14:34:33 +01:00
|
|
|
/*
|
|
|
|
* BT Core 4.2 [Vol 2, Part E, 7.8.5]
|
|
|
|
* The Advertising_Interval_Min and Advertising_Interval_Max
|
|
|
|
* shall not be set to less than 0x00A0 (100 ms) if the
|
|
|
|
* Advertising_Type is set to ADV_SCAN_IND or ADV_NONCONN_IND.
|
|
|
|
*/
|
|
|
|
if (param->interval_min < 0x00a0) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-12-07 08:11:41 +02:00
|
|
|
}
|
|
|
|
|
2015-12-05 22:47:23 +02:00
|
|
|
if (param->interval_min > param->interval_max ||
|
|
|
|
param->interval_min < 0x0020 || param->interval_max > 0x4000) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-01-14 18:03:08 +02:00
|
|
|
static int set_ad(uint16_t hci_op, const struct bt_data *ad, size_t ad_len)
|
2015-04-17 13:59:34 +03:00
|
|
|
{
|
|
|
|
struct bt_hci_cp_le_set_adv_data *set_data;
|
2016-01-14 18:03:08 +02:00
|
|
|
struct net_buf *buf;
|
|
|
|
int i;
|
2015-12-03 12:18:10 +02:00
|
|
|
|
2016-01-14 18:03:08 +02:00
|
|
|
buf = bt_hci_cmd_create(hci_op, sizeof(*set_data));
|
2015-05-05 10:50:14 +03:00
|
|
|
if (!buf) {
|
2015-04-17 13:59:34 +03:00
|
|
|
return -ENOBUFS;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-17 13:59:34 +03:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
set_data = net_buf_add(buf, sizeof(*set_data));
|
2015-04-17 13:59:34 +03:00
|
|
|
|
|
|
|
memset(set_data, 0, sizeof(*set_data));
|
|
|
|
|
2016-01-13 12:53:54 +02:00
|
|
|
for (i = 0; i < ad_len; i++) {
|
2015-04-30 16:07:09 +03:00
|
|
|
/* Check if ad fit in the remaining buffer */
|
2016-01-13 12:53:54 +02:00
|
|
|
if (set_data->len + ad[i].data_len + 2 > 31) {
|
2016-01-14 18:04:45 +02:00
|
|
|
net_buf_unref(buf);
|
|
|
|
return -EINVAL;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-30 16:07:09 +03:00
|
|
|
|
2016-01-13 12:53:54 +02:00
|
|
|
set_data->data[set_data->len++] = ad[i].data_len + 1;
|
|
|
|
set_data->data[set_data->len++] = ad[i].type;
|
|
|
|
|
|
|
|
memcpy(&set_data->data[set_data->len], ad[i].data,
|
2016-03-21 14:48:40 +01:00
|
|
|
ad[i].data_len);
|
2016-01-13 12:53:54 +02:00
|
|
|
set_data->len += ad[i].data_len;
|
2015-04-30 16:07:09 +03:00
|
|
|
}
|
2015-04-17 13:59:34 +03:00
|
|
|
|
2016-05-09 13:16:58 +03:00
|
|
|
return bt_hci_cmd_send_sync(hci_op, buf, NULL);
|
2016-01-14 18:03:08 +02:00
|
|
|
}
|
2015-04-17 13:59:34 +03:00
|
|
|
|
2016-01-14 18:03:08 +02:00
|
|
|
int bt_le_adv_start(const struct bt_le_adv_param *param,
|
|
|
|
const struct bt_data *ad, size_t ad_len,
|
|
|
|
const struct bt_data *sd, size_t sd_len)
|
|
|
|
{
|
|
|
|
struct net_buf *buf;
|
2016-04-02 09:34:32 +03:00
|
|
|
struct bt_hci_cp_le_set_adv_param *set_param;
|
2016-01-14 18:03:08 +02:00
|
|
|
int err;
|
2015-04-30 16:07:09 +03:00
|
|
|
|
2016-01-14 18:03:08 +02:00
|
|
|
if (!valid_adv_param(param)) {
|
|
|
|
return -EINVAL;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-17 13:59:34 +03:00
|
|
|
|
2016-02-17 09:43:04 +01:00
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING)) {
|
2016-01-14 18:03:08 +02:00
|
|
|
return -EALREADY;
|
|
|
|
}
|
2015-04-17 13:59:34 +03:00
|
|
|
|
2016-02-17 09:43:04 +01:00
|
|
|
err = set_advertise_disable();
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2016-01-14 18:03:08 +02:00
|
|
|
err = set_ad(BT_HCI_OP_LE_SET_ADV_DATA, ad, ad_len);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
2015-04-17 13:59:34 +03:00
|
|
|
|
2016-05-12 10:13:52 +02:00
|
|
|
/*
|
|
|
|
* We need to set SCAN_RSP when enabling advertising type that allows
|
|
|
|
* for Scan Requests.
|
|
|
|
*
|
|
|
|
* If sd was not provided but we enable connectable undirected
|
|
|
|
* advertising sd needs to be cleared from values set by previous calls.
|
|
|
|
* Clearing sd is done by calling set_ad() with NULL data and zero len.
|
|
|
|
* So following condition check is unusual but correct.
|
2016-01-14 18:03:08 +02:00
|
|
|
*/
|
2016-05-02 15:18:28 +02:00
|
|
|
if (sd || (param->options & BT_LE_ADV_OPT_CONNECTABLE)) {
|
2016-01-14 18:03:08 +02:00
|
|
|
err = set_ad(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, sd, sd_len);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-30 16:07:09 +03:00
|
|
|
}
|
2015-04-17 13:59:34 +03:00
|
|
|
|
2016-04-21 15:52:32 +02:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADV_PARAM, sizeof(*set_param));
|
2015-05-05 10:50:14 +03:00
|
|
|
if (!buf) {
|
2015-04-17 13:59:34 +03:00
|
|
|
return -ENOBUFS;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-17 13:59:34 +03:00
|
|
|
|
2015-10-28 10:34:15 +02:00
|
|
|
set_param = net_buf_add(buf, sizeof(*set_param));
|
2015-04-17 13:59:34 +03:00
|
|
|
|
|
|
|
memset(set_param, 0, sizeof(*set_param));
|
2015-12-05 21:50:43 +02:00
|
|
|
set_param->min_interval = sys_cpu_to_le16(param->interval_min);
|
|
|
|
set_param->max_interval = sys_cpu_to_le16(param->interval_max);
|
|
|
|
set_param->channel_map = 0x07;
|
2015-04-17 13:59:34 +03:00
|
|
|
|
2016-05-02 15:18:28 +02:00
|
|
|
if (param->options & BT_LE_ADV_OPT_CONNECTABLE) {
|
|
|
|
#if defined(CONFIG_BLUETOOTH_PRIVACY)
|
|
|
|
err = le_set_rpa();
|
2015-12-07 08:11:41 +02:00
|
|
|
if (err) {
|
|
|
|
net_buf_unref(buf);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_param->own_addr_type = BT_ADDR_LE_RANDOM;
|
2016-05-02 15:18:28 +02:00
|
|
|
#else
|
|
|
|
set_param->own_addr_type = bt_dev.id_addr.type;
|
|
|
|
#endif /* CONFIG_BLUETOOTH_PRIVACY */
|
|
|
|
set_param->type = BT_LE_ADV_IND;
|
|
|
|
} else {
|
2016-04-04 12:55:11 +03:00
|
|
|
#if defined(CONFIG_BLUETOOTH_PRIVACY)
|
2016-06-10 13:49:27 +03:00
|
|
|
err = le_set_rpa();
|
|
|
|
#else
|
2016-05-02 15:18:28 +02:00
|
|
|
err = le_set_nrpa();
|
2016-06-10 13:49:27 +03:00
|
|
|
#endif /* CONFIG_BLUETOOTH_PRIVACY */
|
2016-04-04 12:55:11 +03:00
|
|
|
if (err) {
|
|
|
|
net_buf_unref(buf);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_param->own_addr_type = BT_ADDR_LE_RANDOM;
|
2016-05-02 15:18:28 +02:00
|
|
|
|
|
|
|
if (sd) {
|
|
|
|
set_param->type = BT_LE_ADV_SCAN_IND;
|
|
|
|
} else {
|
|
|
|
set_param->type = BT_LE_ADV_NONCONN_IND;
|
|
|
|
}
|
2015-12-07 08:11:41 +02:00
|
|
|
}
|
|
|
|
|
2016-04-21 15:52:32 +02:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_ADV_PARAM, buf, NULL);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2016-02-17 09:43:04 +01:00
|
|
|
err = set_advertise_enable();
|
2015-07-23 11:35:59 +02:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2016-02-17 09:43:04 +01:00
|
|
|
atomic_set_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING);
|
2015-07-08 12:17:01 +02:00
|
|
|
|
2015-07-23 11:35:59 +02:00
|
|
|
return 0;
|
2015-07-08 12:17:01 +02:00
|
|
|
}
|
|
|
|
|
2015-12-03 10:19:38 +02:00
|
|
|
int bt_le_adv_stop(void)
|
2015-07-08 12:17:01 +02:00
|
|
|
{
|
2015-07-23 11:35:59 +02:00
|
|
|
int err;
|
2015-07-08 12:17:01 +02:00
|
|
|
|
2016-02-17 09:43:04 +01:00
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING)) {
|
2015-07-08 12:17:01 +02:00
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
2016-02-17 09:43:04 +01:00
|
|
|
err = set_advertise_disable();
|
2015-07-23 11:35:59 +02:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2016-02-17 09:43:04 +01:00
|
|
|
atomic_clear_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING);
|
2015-07-23 11:35:59 +02:00
|
|
|
|
|
|
|
return 0;
|
2015-04-17 13:59:34 +03:00
|
|
|
}
|
2015-05-08 10:33:34 +02:00
|
|
|
|
2015-12-03 22:39:11 +02:00
|
|
|
static bool valid_le_scan_param(const struct bt_le_scan_param *param)
|
|
|
|
{
|
|
|
|
if (param->type != BT_HCI_LE_SCAN_PASSIVE &&
|
|
|
|
param->type != BT_HCI_LE_SCAN_ACTIVE) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-12-04 13:23:28 +02:00
|
|
|
if (param->filter_dup != BT_HCI_LE_SCAN_FILTER_DUP_DISABLE &&
|
|
|
|
param->filter_dup != BT_HCI_LE_SCAN_FILTER_DUP_ENABLE) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-12-03 22:39:11 +02:00
|
|
|
if (param->interval < 0x0004 || param->interval > 0x4000) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (param->window < 0x0004 || param->window > 0x4000) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (param->window > param->interval) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-12-03 15:17:10 +02:00
|
|
|
int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb)
|
2015-07-01 18:54:57 +02:00
|
|
|
{
|
2015-12-03 20:05:42 +02:00
|
|
|
int err;
|
|
|
|
|
2015-12-03 22:39:11 +02:00
|
|
|
/* Check that the parameters have valid values */
|
|
|
|
if (!valid_le_scan_param(param)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2015-07-01 18:54:57 +02:00
|
|
|
/* Return if active scan is already enabled */
|
2015-12-03 19:41:42 +02:00
|
|
|
if (atomic_test_and_set_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
|
2015-07-01 18:54:57 +02:00
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
2015-12-03 20:05:42 +02:00
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) {
|
|
|
|
err = bt_hci_stop_scanning();
|
|
|
|
if (err) {
|
|
|
|
atomic_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-03 22:39:11 +02:00
|
|
|
err = start_le_scan(param->type, param->interval, param->window,
|
|
|
|
param->filter_dup);
|
2015-12-03 20:05:42 +02:00
|
|
|
if (err) {
|
|
|
|
atomic_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
scan_dev_found_cb = cb;
|
|
|
|
|
|
|
|
return 0;
|
2015-07-01 18:54:57 +02:00
|
|
|
}
|
|
|
|
|
2015-12-03 10:19:38 +02:00
|
|
|
int bt_le_scan_stop(void)
|
2015-07-01 18:54:57 +02:00
|
|
|
{
|
|
|
|
/* Return if active scanning is already disabled */
|
2015-12-03 19:41:42 +02:00
|
|
|
if (!atomic_test_and_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
|
2015-07-01 18:54:57 +02:00
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
scan_dev_found_cb = NULL;
|
2015-07-06 12:00:04 +02:00
|
|
|
|
2015-12-03 22:51:16 +02:00
|
|
|
return bt_le_scan_update(false);
|
2015-07-01 18:54:57 +02:00
|
|
|
}
|
2015-10-28 14:59:43 +02:00
|
|
|
|
2016-04-09 11:29:50 +03:00
|
|
|
#if defined(CONFIG_BLUETOOTH_HOST_BUFFERS)
|
2016-06-28 16:48:01 +02:00
|
|
|
struct net_buf *bt_buf_get_evt(uint8_t opcode)
|
2015-10-28 14:59:43 +02:00
|
|
|
{
|
2016-04-09 11:29:50 +03:00
|
|
|
struct net_buf *buf;
|
|
|
|
|
2016-06-28 16:48:01 +02:00
|
|
|
switch (opcode) {
|
|
|
|
case BT_HCI_EVT_CMD_COMPLETE:
|
|
|
|
case BT_HCI_EVT_CMD_STATUS:
|
|
|
|
case BT_HCI_EVT_NUM_COMPLETED_PACKETS:
|
|
|
|
buf = net_buf_get(&avail_prio_hci_evt,
|
|
|
|
CONFIG_BLUETOOTH_HCI_RECV_RESERVE);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
buf = net_buf_get(&avail_hci_evt,
|
|
|
|
CONFIG_BLUETOOTH_HCI_RECV_RESERVE);
|
|
|
|
if (!buf && opcode == 0x00) {
|
|
|
|
buf = net_buf_get(&avail_prio_hci_evt,
|
|
|
|
CONFIG_BLUETOOTH_HCI_RECV_RESERVE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-04-09 11:29:50 +03:00
|
|
|
if (buf) {
|
|
|
|
bt_buf_set_type(buf, BT_BUF_EVT);
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf;
|
2015-10-28 14:59:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
struct net_buf *bt_buf_get_acl(void)
|
|
|
|
{
|
2015-10-28 20:39:45 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
2016-04-09 11:29:50 +03:00
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
buf = net_buf_get(&avail_acl_in, CONFIG_BLUETOOTH_HCI_RECV_RESERVE);
|
|
|
|
if (buf) {
|
|
|
|
bt_buf_set_type(buf, BT_BUF_ACL_IN);
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf;
|
2015-10-28 20:39:45 +02:00
|
|
|
#else
|
|
|
|
return NULL;
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
2015-10-28 14:59:43 +02:00
|
|
|
}
|
2016-04-09 11:29:50 +03:00
|
|
|
#endif /* CONFIG_BLUETOOTH_HOST_BUFFERS */
|
2015-11-26 14:47:11 +01:00
|
|
|
|
|
|
|
#if defined(CONFIG_BLUETOOTH_BREDR)
|
2016-06-16 10:29:18 +03:00
|
|
|
static int br_start_inquiry(const struct bt_br_discovery_param *param,
|
|
|
|
size_t num_rsp)
|
2016-03-10 11:58:56 +01:00
|
|
|
{
|
|
|
|
const uint8_t iac[3] = { 0x33, 0x8b, 0x9e };
|
|
|
|
struct bt_hci_op_inquiry *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_INQUIRY, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
|
2016-06-16 10:35:15 +03:00
|
|
|
cp->length = param->length;
|
2016-06-16 10:29:18 +03:00
|
|
|
cp->num_rsp = num_rsp;
|
2016-03-10 11:58:56 +01:00
|
|
|
|
|
|
|
memcpy(cp->lap, iac, 3);
|
2016-06-16 11:28:59 +03:00
|
|
|
if (param->limited) {
|
2016-03-10 11:58:56 +01:00
|
|
|
cp->lap[0] = 0x00;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_INQUIRY, buf, NULL);
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:35:15 +03:00
|
|
|
static bool valid_br_discov_param(const struct bt_br_discovery_param *param,
|
|
|
|
size_t num_results)
|
|
|
|
{
|
|
|
|
if (!num_results || num_results > 255) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!param->length || param->length > 0x30) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-03-10 11:58:56 +01:00
|
|
|
int bt_br_discovery_start(const struct bt_br_discovery_param *param,
|
|
|
|
struct bt_br_discovery_result *results, size_t cnt,
|
|
|
|
bt_br_discovery_cb_t cb)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
BT_DBG("");
|
|
|
|
|
2016-06-16 10:35:15 +03:00
|
|
|
if (!valid_br_discov_param(param, cnt)) {
|
2016-06-16 10:21:15 +03:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-03-10 11:58:56 +01:00
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_INQUIRY)) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:29:18 +03:00
|
|
|
err = br_start_inquiry(param, cnt);
|
2016-03-10 11:58:56 +01:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_set_bit(bt_dev.flags, BT_DEV_INQUIRY);
|
|
|
|
|
|
|
|
memset(results, 0, sizeof(*results) * cnt);
|
|
|
|
|
|
|
|
discovery_cb = cb;
|
|
|
|
discovery_results = results;
|
|
|
|
discovery_results_size = cnt;
|
|
|
|
discovery_results_count = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_br_discovery_stop(void)
|
|
|
|
{
|
|
|
|
int err;
|
2016-03-17 18:35:58 +01:00
|
|
|
int i;
|
2016-03-10 11:58:56 +01:00
|
|
|
|
|
|
|
BT_DBG("");
|
|
|
|
|
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_INQUIRY)) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_INQUIRY_CANCEL, NULL, NULL);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2016-03-17 18:35:58 +01:00
|
|
|
for (i = 0; i < discovery_results_count; i++) {
|
|
|
|
struct discovery_priv *priv;
|
|
|
|
struct bt_hci_cp_remote_name_cancel *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
priv = (struct discovery_priv *)&discovery_results[i].private;
|
|
|
|
|
|
|
|
if (!priv->resolving) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_REMOTE_NAME_CANCEL,
|
|
|
|
sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
bt_addr_copy(&cp->bdaddr, &discovery_results[i].addr);
|
|
|
|
|
|
|
|
bt_hci_cmd_send_sync(BT_HCI_OP_REMOTE_NAME_CANCEL, buf, NULL);
|
|
|
|
}
|
|
|
|
|
2016-03-10 11:58:56 +01:00
|
|
|
atomic_clear_bit(bt_dev.flags, BT_DEV_INQUIRY);
|
|
|
|
|
|
|
|
discovery_cb = NULL;
|
|
|
|
discovery_results = NULL;
|
|
|
|
discovery_results_size = 0;
|
|
|
|
discovery_results_count = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-12-03 10:35:25 +02:00
|
|
|
static int write_scan_enable(uint8_t scan)
|
2015-11-26 14:47:11 +01:00
|
|
|
{
|
|
|
|
struct net_buf *buf;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
BT_DBG("type %u", scan);
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_SCAN_ENABLE, 1);
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2016-02-11 13:49:28 +02:00
|
|
|
net_buf_add_u8(buf, scan);
|
2015-11-26 14:47:11 +01:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_SCAN_ENABLE, buf, NULL);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (scan & BT_BREDR_SCAN_INQUIRY) {
|
|
|
|
atomic_set_bit(bt_dev.flags, BT_DEV_ISCAN);
|
|
|
|
} else {
|
|
|
|
atomic_clear_bit(bt_dev.flags, BT_DEV_ISCAN);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (scan & BT_BREDR_SCAN_PAGE) {
|
|
|
|
atomic_set_bit(bt_dev.flags, BT_DEV_PSCAN);
|
|
|
|
} else {
|
|
|
|
atomic_clear_bit(bt_dev.flags, BT_DEV_PSCAN);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-12-03 10:35:25 +02:00
|
|
|
int bt_br_set_connectable(bool enable)
|
2015-11-26 14:47:11 +01:00
|
|
|
{
|
|
|
|
if (enable) {
|
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_PSCAN)) {
|
|
|
|
return -EALREADY;
|
|
|
|
} else {
|
2015-12-03 10:35:25 +02:00
|
|
|
return write_scan_enable(BT_BREDR_SCAN_PAGE);
|
2015-11-26 14:47:11 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_PSCAN)) {
|
|
|
|
return -EALREADY;
|
|
|
|
} else {
|
2015-12-03 10:35:25 +02:00
|
|
|
return write_scan_enable(BT_BREDR_SCAN_DISABLED);
|
2015-11-26 14:47:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-03 10:35:25 +02:00
|
|
|
int bt_br_set_discoverable(bool enable)
|
2015-11-26 14:47:11 +01:00
|
|
|
{
|
|
|
|
if (enable) {
|
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_ISCAN)) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_PSCAN)) {
|
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
|
2015-12-03 10:35:25 +02:00
|
|
|
return write_scan_enable(BT_BREDR_SCAN_INQUIRY |
|
|
|
|
BT_BREDR_SCAN_PAGE);
|
2015-11-26 14:47:11 +01:00
|
|
|
} else {
|
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_ISCAN)) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
2015-12-03 10:35:25 +02:00
|
|
|
return write_scan_enable(BT_BREDR_SCAN_PAGE);
|
2015-11-26 14:47:11 +01:00
|
|
|
}
|
|
|
|
}
|
2015-12-16 16:07:21 +01:00
|
|
|
#endif /* CONFIG_BLUETOOTH_BREDR */
|
2016-04-01 21:44:38 +03:00
|
|
|
|
2016-05-30 14:05:28 +02:00
|
|
|
void bt_storage_register(const struct bt_storage *storage)
|
2016-04-01 21:44:38 +03:00
|
|
|
{
|
2016-04-05 10:14:32 +03:00
|
|
|
bt_storage = storage;
|
2016-04-01 21:44:38 +03:00
|
|
|
}
|
2016-04-05 10:33:13 +03:00
|
|
|
|
|
|
|
int bt_storage_clear(bt_addr_le_t *addr)
|
|
|
|
{
|
|
|
|
return -ENOSYS;
|
|
|
|
}
|
2016-05-24 17:15:03 +02:00
|
|
|
|
|
|
|
uint16_t bt_hci_get_cmd_opcode(struct net_buf *buf)
|
|
|
|
{
|
|
|
|
return cmd(buf)->opcode;
|
|
|
|
}
|
2016-06-30 20:05:36 +03:00
|
|
|
|
|
|
|
int bt_pub_key_gen(struct bt_pub_key_cb *new_cb)
|
|
|
|
{
|
|
|
|
struct bt_pub_key_cb *cb;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We check for both "LE Read Local P-256 Public Key" and
|
|
|
|
* "LE Generate DH Key" support here since both commands are needed for
|
|
|
|
* ECC support. If "LE Generate DH Key" is not supported then there
|
|
|
|
* is no point in reading local public key.
|
|
|
|
*/
|
|
|
|
if (!(bt_dev.supported_commands[34] & 0x02) ||
|
|
|
|
!(bt_dev.supported_commands[34] & 0x04)) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_cb->_next = pub_key_cb;
|
|
|
|
pub_key_cb = new_cb;
|
|
|
|
|
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_PUB_KEY_BUSY)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_P256_PUBLIC_KEY, NULL, NULL);
|
|
|
|
if (err) {
|
|
|
|
pub_key_cb = NULL;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_set_bit(bt_dev.flags, BT_DEV_PUB_KEY_BUSY);
|
|
|
|
atomic_clear_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY);
|
|
|
|
|
|
|
|
for (cb = pub_key_cb; cb; cb = cb->_next) {
|
|
|
|
if (cb != new_cb) {
|
|
|
|
cb->func(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const uint8_t *bt_pub_key_get(void)
|
|
|
|
{
|
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY)) {
|
|
|
|
return pub_key;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_dh_key_gen(const uint8_t remote_pk[64], bt_dh_key_cb_t cb)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_le_generate_dhkey *cp;
|
|
|
|
struct net_buf *buf;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (dh_key_cb || atomic_test_bit(bt_dev.flags, BT_DEV_PUB_KEY_BUSY)) {
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY)) {
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
dh_key_cb = cb;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_GENERATE_DHKEY, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
dh_key_cb = NULL;
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
memcpy(cp->key, remote_pk, sizeof(cp->key));
|
|
|
|
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_GENERATE_DHKEY, buf, NULL);
|
|
|
|
if (err) {
|
|
|
|
dh_key_cb = NULL;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|