2015-04-14 14:38:13 +03:00
|
|
|
/* hci_core.c - HCI core Bluetooth handling */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2015 Intel Corporation
|
|
|
|
*
|
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>
|
|
|
|
|
2015-06-16 17:25:37 +03:00
|
|
|
#include <bluetooth/log.h>
|
2015-04-14 14:38:13 +03:00
|
|
|
#include <bluetooth/bluetooth.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>
|
2015-04-14 14:38:13 +03:00
|
|
|
|
2015-04-20 15:11:02 +03:00
|
|
|
#include "hci_core.h"
|
2015-05-30 18:05:26 +07:00
|
|
|
#include "keys.h"
|
2015-06-15 11:05:35 +03:00
|
|
|
#include "conn_internal.h"
|
2015-05-21 18:53:13 +03:00
|
|
|
#include "l2cap.h"
|
2015-09-29 10:45:44 +02:00
|
|
|
#include "stack.h"
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-04-24 12:02:36 +03:00
|
|
|
#if !defined(CONFIG_BLUETOOTH_DEBUG_HCI_CORE)
|
|
|
|
#undef BT_DBG
|
|
|
|
#define BT_DBG(fmt, ...)
|
|
|
|
#endif
|
|
|
|
|
2015-04-28 11:51:28 +03:00
|
|
|
/* How many buffers to use for incoming ACL data */
|
2015-09-16 14:54:20 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
2015-04-28 11:51:28 +03:00
|
|
|
#define ACL_IN_MAX 7
|
|
|
|
#define ACL_OUT_MAX 7
|
2015-09-16 14:54:20 +02:00
|
|
|
#else
|
|
|
|
#define ACL_IN_MAX 0
|
|
|
|
#define ACL_OUT_MAX 0
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
2015-04-28 11:51:28 +03:00
|
|
|
|
2015-04-14 15:32:32 +03:00
|
|
|
/* Stacks for the fibers */
|
2015-05-26 13:20:54 +03:00
|
|
|
static BT_STACK_NOINIT(rx_fiber_stack, 1024);
|
2015-06-03 23:47:06 +07:00
|
|
|
static BT_STACK_NOINIT(rx_prio_fiber_stack, 256);
|
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-05-22 15:45:12 +03:00
|
|
|
#if defined(CONFIG_BLUETOOTH_DEBUG)
|
2015-08-20 11:04:01 -04:00
|
|
|
static nano_thread_id_t rx_prio_fiber_id;
|
2015-05-22 15:45:12 +03:00
|
|
|
#endif
|
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
struct bt_dev bt_dev;
|
2015-04-14 15:32:32 +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
|
|
|
|
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-04-28 14:27:19 +03:00
|
|
|
struct bt_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;
|
|
|
|
struct bt_buf *buf;
|
|
|
|
|
|
|
|
BT_DBG("opcode %x param_len %u\n", opcode, param_len);
|
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
buf = bt_buf_get(BT_CMD, bt_dev.drv->head_reserve);
|
2015-04-14 15:41:55 +03:00
|
|
|
if (!buf) {
|
|
|
|
BT_ERR("Cannot get free buffer\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("buf %p\n", buf);
|
|
|
|
|
2015-04-28 15:18:13 +03:00
|
|
|
buf->hci.opcode = opcode;
|
|
|
|
buf->hci.sync = NULL;
|
2015-04-14 15:41:55 +03:00
|
|
|
|
2015-05-18 10:18:21 +03:00
|
|
|
hdr = bt_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-04-28 14:27:19 +03:00
|
|
|
int bt_hci_cmd_send(uint16_t opcode, struct bt_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
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("opcode %x len %u\n", opcode, buf->len);
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
err = bt_dev.drv->send(buf);
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("Unable to send to driver (err %d)\n", err);
|
|
|
|
}
|
|
|
|
|
2015-04-28 15:22:17 +03:00
|
|
|
bt_buf_put(buf);
|
2015-09-15 17:57:00 +03:00
|
|
|
|
|
|
|
return err;
|
2015-04-28 15:22:17 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
nano_fifo_put(&bt_dev.cmd_tx_queue, buf);
|
2015-04-14 15:41:55 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-08 12:55:03 +03:00
|
|
|
int bt_hci_cmd_send_sync(uint16_t opcode, struct bt_buf *buf,
|
|
|
|
struct bt_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
|
|
|
|
2015-05-22 15:45:12 +03:00
|
|
|
/* This function cannot be called from the rx fiber since it
|
|
|
|
* relies on the very same fiber in processing the cmd_complete
|
|
|
|
* event and giving back the blocking semaphore.
|
|
|
|
*/
|
|
|
|
#if defined(CONFIG_BLUETOOTH_DEBUG)
|
2015-08-20 11:04:01 -04:00
|
|
|
if (sys_thread_self_get() == rx_prio_fiber_id) {
|
2015-05-22 15:45:12 +03:00
|
|
|
BT_ERR("called from invalid context!\n");
|
|
|
|
return -EDEADLK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("opcode %x len %u\n", opcode, buf->len);
|
|
|
|
|
|
|
|
nano_sem_init(&sync_sem);
|
2015-04-28 15:18:13 +03:00
|
|
|
buf->hci.sync = &sync_sem;
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
nano_fifo_put(&bt_dev.cmd_tx_queue, buf);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
|
|
|
nano_sem_take_wait(&sync_sem);
|
|
|
|
|
2015-04-30 12:01:48 +03:00
|
|
|
/* Indicate failure if we failed to get the return parameters */
|
2015-05-05 10:50:14 +03:00
|
|
|
if (!buf->hci.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-04-30 12:01:48 +03:00
|
|
|
*rsp = buf->hci.sync;
|
2015-05-05 10:50:14 +03:00
|
|
|
} else if (buf->hci.sync) {
|
2015-04-30 12:01:48 +03:00
|
|
|
bt_buf_put(buf->hci.sync);
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-30 12:01:48 +03:00
|
|
|
|
|
|
|
bt_buf_put(buf);
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
struct bt_buf *buf, *rsp;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
scan_enable = bt_buf_add(buf, sizeof(*scan_enable));
|
|
|
|
memset(scan_enable, 0x0, sizeof(*scan_enable));
|
|
|
|
scan_enable->filter_dup = 0x00;
|
|
|
|
scan_enable->enable = 0x00;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_buf_put(rsp);
|
|
|
|
|
|
|
|
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) {
|
|
|
|
BT_DBG("Identity %s matched RPA %s\n",
|
|
|
|
bt_addr_le_str(&keys->addr), bt_addr_le_str(addr));
|
|
|
|
return &keys->addr;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
2015-04-14 15:41:55 +03:00
|
|
|
static void hci_acl(struct bt_buf *buf)
|
|
|
|
{
|
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-05-20 13:14:37 +03:00
|
|
|
BT_DBG("buf %p\n", buf);
|
|
|
|
|
2015-04-14 15:44:48 +03:00
|
|
|
handle = sys_le16_to_cpu(hdr->handle);
|
|
|
|
flags = (handle >> 12);
|
2015-04-28 15:20:33 +03:00
|
|
|
buf->acl.handle = bt_acl_handle(handle);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
|
|
|
bt_buf_pull(buf, sizeof(*hdr));
|
|
|
|
|
2015-04-28 15:20:33 +03:00
|
|
|
BT_DBG("handle %u len %u flags %u\n", buf->acl.handle, len, flags);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
|
|
|
if (buf->len != len) {
|
|
|
|
BT_ERR("ACL data length mismatch (%u != %u)\n", buf->len, len);
|
|
|
|
bt_buf_put(buf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-05-27 21:08:39 +03:00
|
|
|
conn = bt_conn_lookup_handle(buf->acl.handle);
|
2015-07-08 11:00:26 +03:00
|
|
|
if (!conn) {
|
2015-04-28 15:20:33 +03:00
|
|
|
BT_ERR("Unable to find conn for handle %u\n", buf->acl.handle);
|
2015-04-28 10:39:50 +03:00
|
|
|
bt_buf_put(buf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_recv(conn, buf, flags);
|
2015-06-17 12:42:54 +03:00
|
|
|
bt_conn_put(conn);
|
2015-04-14 15:41:55 +03:00
|
|
|
}
|
|
|
|
|
2015-04-18 11:56:00 +03:00
|
|
|
static void hci_num_completed_packets(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_num_completed_packets *evt = (void *)buf->data;
|
|
|
|
uint16_t i, num_handles = sys_le16_to_cpu(evt->num_handles);
|
|
|
|
|
|
|
|
BT_DBG("num_handles %u\n", num_handles);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
BT_DBG("handle %u count %u\n", handle, count);
|
|
|
|
|
2015-09-15 17:19:45 +03:00
|
|
|
conn = bt_conn_lookup_handle(handle);
|
2015-09-17 11:22:00 +03:00
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("No connection for handle %u\n", handle);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->pending_pkts >= count) {
|
|
|
|
conn->pending_pkts -= count;
|
2015-09-15 17:19:45 +03:00
|
|
|
} else {
|
2015-09-17 11:22:00 +03:00
|
|
|
BT_ERR("completed packets mismatch: %u > %u\n",
|
|
|
|
count, conn->pending_pkts);
|
|
|
|
conn->pending_pkts = 0;
|
2015-09-15 17:19:45 +03:00
|
|
|
}
|
|
|
|
|
2015-09-17 11:22:00 +03:00
|
|
|
bt_conn_put(conn);
|
|
|
|
|
2015-09-15 17:19:45 +03:00
|
|
|
while (count--) {
|
2015-07-15 13:53:17 +03:00
|
|
|
nano_fiber_sem_give(&bt_dev.le_pkts_sem);
|
2015-09-15 17:19:45 +03:00
|
|
|
}
|
2015-04-18 11:56:00 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
static int hci_le_create_conn(const bt_addr_le_t *addr)
|
2015-06-01 09:22:36 +07:00
|
|
|
{
|
2015-10-01 17:50:19 +02:00
|
|
|
struct bt_buf *buf;
|
|
|
|
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-01 17:50:19 +02:00
|
|
|
cp = bt_buf_add(buf, sizeof(*cp));
|
|
|
|
memset(cp, 0x0, sizeof(*cp));
|
|
|
|
bt_addr_le_copy(&cp->peer_addr, addr);
|
|
|
|
cp->conn_interval_max = sys_cpu_to_le16(0x0028);
|
|
|
|
cp->conn_interval_min = sys_cpu_to_le16(0x0018);
|
|
|
|
cp->scan_interval = sys_cpu_to_le16(0x0060);
|
|
|
|
cp->scan_window = sys_cpu_to_le16(0x0030);
|
|
|
|
cp->supervision_timeout = sys_cpu_to_le16(0x07D0);
|
|
|
|
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_CONN, buf, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hci_disconn_complete(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_disconn_complete *evt = (void *)buf->data;
|
|
|
|
uint16_t handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
|
|
|
BT_DBG("status %u handle %u reason %u\n", evt->status, handle,
|
|
|
|
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-06-01 09:22:36 +07:00
|
|
|
BT_ERR("Unable to look up conn with handle %u\n", handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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 rx stack", rx_prio_fiber_stack,
|
|
|
|
sizeof(rx_prio_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-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);
|
|
|
|
bt_le_scan_update();
|
2015-07-13 12:43:02 +02:00
|
|
|
}
|
|
|
|
|
2015-07-13 12:39:42 +02:00
|
|
|
bt_conn_put(conn);
|
|
|
|
|
2015-07-23 11:35:59 +02:00
|
|
|
if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) {
|
2015-07-13 12:39:42 +02:00
|
|
|
struct bt_buf *buf;
|
2015-07-23 11:35:59 +02:00
|
|
|
uint8_t adv_enable = 0x01;
|
2015-07-13 12:39:42 +02:00
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADV_ENABLE, 1);
|
|
|
|
if (buf) {
|
2015-07-23 11:35:59 +02:00
|
|
|
memcpy(bt_buf_add(buf, 1), &adv_enable, 1);
|
2015-07-13 12:39:42 +02:00
|
|
|
bt_hci_cmd_send(BT_HCI_OP_LE_SET_ADV_ENABLE, buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
struct bt_buf *buf;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_READ_REMOTE_FEATURES,
|
|
|
|
sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = bt_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = sys_cpu_to_le16(conn->handle);
|
|
|
|
bt_hci_cmd_send(BT_HCI_OP_LE_READ_REMOTE_FEATURES, buf);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-10 21:53:45 +02:00
|
|
|
static int update_conn_params(struct bt_conn *conn)
|
|
|
|
{
|
2015-08-26 09:14:45 +02:00
|
|
|
BT_DBG("conn %p features 0x%x\n", conn, conn->le_features[0]);
|
2015-08-10 21:53:45 +02:00
|
|
|
|
|
|
|
/* Check if there's a need to update conn params */
|
|
|
|
if (conn->le_conn_interval >= LE_CONN_MIN_INTERVAL &&
|
|
|
|
conn->le_conn_interval <= LE_CONN_MAX_INTERVAL) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((conn->role == BT_HCI_ROLE_SLAVE) &&
|
|
|
|
!(bt_dev.le_features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC)) {
|
|
|
|
return bt_l2cap_update_conn_param(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((conn->le_features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC) &&
|
|
|
|
(bt_dev.le_features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC)) {
|
|
|
|
return bt_conn_le_conn_update(conn, LE_CONN_MIN_INTERVAL,
|
|
|
|
LE_CONN_MAX_INTERVAL,
|
|
|
|
LE_CONN_LATENCY, LE_CONN_TIMEOUT);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2015-04-18 18:44:38 +03:00
|
|
|
static void le_conn_complete(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
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-09-02 12:35:53 +02:00
|
|
|
bt_addr_le_t src;
|
2015-07-27 17:28:59 +03:00
|
|
|
int err;
|
2015-04-18 18:44:38 +03:00
|
|
|
|
2015-05-25 22:11:28 +03:00
|
|
|
BT_DBG("status %u handle %u role %u %s\n", evt->status, handle,
|
|
|
|
evt->role, bt_addr_le_str(&evt->peer_addr));
|
2015-05-21 20:59:23 +03:00
|
|
|
|
2015-10-01 18:21:40 +02:00
|
|
|
id_addr = find_id_addr(&evt->peer_addr);
|
|
|
|
|
2015-06-23 14:38:24 +02:00
|
|
|
/* Make lookup to check if there's a connection object in CONNECT state
|
|
|
|
* associated with passed peer LE address.
|
|
|
|
*/
|
2015-10-01 18:21:40 +02:00
|
|
|
conn = bt_conn_lookup_state(id_addr, BT_CONN_CONNECT);
|
2015-06-23 14:38:24 +02:00
|
|
|
|
2015-05-21 20:59:23 +03:00
|
|
|
if (evt->status) {
|
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
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
bt_conn_put(conn);
|
|
|
|
|
2015-05-21 20:59:23 +03:00
|
|
|
return;
|
|
|
|
}
|
2015-04-28 10:39:50 +03:00
|
|
|
|
2015-06-23 14:38:24 +02:00
|
|
|
if (!conn) {
|
2015-10-01 18:21:40 +02:00
|
|
|
conn = bt_conn_add(id_addr);
|
2015-06-23 14:38:24 +02:00
|
|
|
}
|
|
|
|
|
2015-04-28 10:39:50 +03:00
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Unable to add new conn for handle %u\n", handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-06-23 11:56:50 +02:00
|
|
|
conn->handle = handle;
|
2015-10-01 18:21:40 +02:00
|
|
|
bt_addr_le_copy(&conn->dst, id_addr);
|
2015-04-28 10:39:50 +03:00
|
|
|
conn->le_conn_interval = sys_le16_to_cpu(evt->interval);
|
2015-09-02 10:47:35 +02:00
|
|
|
conn->role = evt->role;
|
2015-06-23 14:38:24 +02:00
|
|
|
|
2015-09-02 12:35:53 +02:00
|
|
|
src.type = BT_ADDR_LE_PUBLIC;
|
|
|
|
memcpy(src.val, bt_dev.bdaddr.val, sizeof(bt_dev.bdaddr.val));
|
|
|
|
|
2015-10-01 18:21:40 +02:00
|
|
|
/* use connection address (instead of identity address) as initiator
|
|
|
|
* or responder address
|
|
|
|
*/
|
2015-09-01 17:30:58 +02:00
|
|
|
if (conn->role == BT_HCI_ROLE_MASTER) {
|
2015-09-02 12:35:53 +02:00
|
|
|
bt_addr_le_copy(&conn->init_addr, &src);
|
2015-09-01 17:30:58 +02:00
|
|
|
bt_addr_le_copy(&conn->resp_addr, &evt->peer_addr);
|
|
|
|
} else {
|
|
|
|
bt_addr_le_copy(&conn->init_addr, &evt->peer_addr);
|
2015-09-02 12:35:53 +02:00
|
|
|
bt_addr_le_copy(&conn->resp_addr, &src);
|
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-07-27 17:28:59 +03:00
|
|
|
if ((evt->role == BT_HCI_ROLE_MASTER) ||
|
|
|
|
(bt_dev.le_features[0] & BT_HCI_LE_SLAVE_FEATURES)) {
|
|
|
|
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
|
|
|
|
2015-10-05 15:10:59 +02:00
|
|
|
update_conn_params(conn);
|
2015-07-27 17:28:59 +03:00
|
|
|
|
|
|
|
done:
|
2015-07-08 10:55:51 +03:00
|
|
|
bt_conn_put(conn);
|
2015-07-14 14:17:58 +03:00
|
|
|
bt_le_scan_update();
|
2015-07-02 11:53:54 +02:00
|
|
|
}
|
|
|
|
|
2015-07-28 13:02:43 +03:00
|
|
|
static void le_remote_feat_complete(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
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) {
|
|
|
|
BT_ERR("Unable to lookup conn for handle %u\n", handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!evt->status) {
|
|
|
|
memcpy(conn->le_features, evt->features,
|
|
|
|
sizeof(conn->le_features));
|
|
|
|
}
|
|
|
|
|
2015-10-05 15:10:59 +02:00
|
|
|
update_conn_params(conn);
|
2015-07-27 17:28:59 +03:00
|
|
|
|
2015-07-28 13:02:43 +03:00
|
|
|
bt_conn_put(conn);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
struct bt_buf *buf;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY,
|
|
|
|
sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = bt_buf_add(buf, sizeof(*cp));
|
|
|
|
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;
|
|
|
|
struct bt_buf *buf;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = bt_buf_add(buf, sizeof(*cp));
|
|
|
|
memset(cp, 0x0, sizeof(*cp));
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int le_conn_param_req(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
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) {
|
|
|
|
BT_ERR("Unable to lookup conn for handle %u\n", handle);
|
|
|
|
return le_conn_param_neg_reply(handle,
|
|
|
|
BT_HCI_ERR_UNKNOWN_CONN_ID);
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_put(conn);
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void le_conn_update_complete(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_le_conn_update_complete *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
uint16_t handle, interval;
|
|
|
|
|
|
|
|
handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
interval = sys_le16_to_cpu(evt->interval);
|
|
|
|
|
|
|
|
BT_DBG("status %u, handle %u", evt->status, handle);
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_handle(handle);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Unable to lookup conn for handle %u\n", handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!evt->status) {
|
|
|
|
conn->le_conn_interval = interval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO Notify about connection */
|
|
|
|
|
|
|
|
bt_conn_put(conn);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* Return if event is not connectable */
|
|
|
|
if (evtype != BT_LE_ADV_IND && evtype != BT_LE_ADV_DIRECT_IND) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-02 10:10:39 +02:00
|
|
|
conn = bt_conn_lookup_state(id_addr, BT_CONN_CONNECT_SCAN);
|
2015-10-01 17:50:19 +02:00
|
|
|
if (!conn) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bt_hci_stop_scanning()) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hci_le_create_conn(addr)) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_conn_set_state(conn, BT_CONN_CONNECT);
|
|
|
|
|
|
|
|
done:
|
|
|
|
bt_conn_put(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int set_flow_control(void)
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_host_buffer_size *hbs;
|
|
|
|
struct bt_buf *buf;
|
|
|
|
uint8_t *enable;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_HOST_BUFFER_SIZE,
|
|
|
|
sizeof(*hbs));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
hbs = bt_buf_add(buf, sizeof(*hbs));
|
|
|
|
memset(hbs, 0, sizeof(*hbs));
|
|
|
|
hbs->acl_mtu = sys_cpu_to_le16(BT_BUF_MAX_DATA -
|
|
|
|
sizeof(struct bt_hci_acl_hdr) -
|
|
|
|
bt_dev.drv->head_reserve);
|
|
|
|
hbs->acl_pkts = sys_cpu_to_le16(ACL_IN_MAX);
|
|
|
|
|
|
|
|
err = bt_hci_cmd_send(BT_HCI_OP_HOST_BUFFER_SIZE, buf);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_SET_CTL_TO_HOST_FLOW, 1);
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
enable = bt_buf_add(buf, sizeof(*enable));
|
|
|
|
*enable = 0x01;
|
|
|
|
return bt_hci_cmd_send_sync(BT_HCI_OP_SET_CTL_TO_HOST_FLOW, buf, NULL);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
|
|
|
|
|
|
|
#if defined(CONFIG_BLUETOOTH_SMP)
|
|
|
|
static void update_sec_level(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
struct bt_keys *keys;
|
|
|
|
|
|
|
|
if (!conn->encrypt) {
|
|
|
|
conn->sec_level = BT_SECURITY_LOW;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
keys = bt_keys_find_addr(&conn->dst);
|
|
|
|
if (keys && keys->type == BT_KEYS_AUTHENTICATED) {
|
|
|
|
conn->sec_level = BT_SECURITY_HIGH;
|
|
|
|
} else {
|
|
|
|
conn->sec_level = BT_SECURITY_MEDIUM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->required_sec_level > conn->sec_level) {
|
|
|
|
BT_ERR("Failed to set required security level\n");
|
|
|
|
bt_conn_disconnect(conn, BT_HCI_ERR_AUTHENTICATION_FAIL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hci_encrypt_change(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_encrypt_change *evt = (void *)buf->data;
|
|
|
|
uint16_t handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
struct bt_conn *conn;
|
|
|
|
|
|
|
|
BT_DBG("status %u handle %u encrypt 0x%02x\n", evt->status, handle,
|
|
|
|
evt->encrypt);
|
|
|
|
|
|
|
|
if (evt->status) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_handle(handle);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Unable to look up conn with handle %u\n", handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn->encrypt = evt->encrypt;
|
|
|
|
|
|
|
|
update_sec_level(conn);
|
|
|
|
bt_l2cap_encrypt_change(conn);
|
|
|
|
bt_conn_security_changed(conn);
|
|
|
|
|
|
|
|
bt_conn_put(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hci_encrypt_key_refresh_complete(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
|
|
|
BT_DBG("status %u handle %u\n", evt->status, handle);
|
|
|
|
|
|
|
|
if (evt->status) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_handle(handle);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Unable to look up conn with handle %u\n", handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_l2cap_encrypt_change(conn);
|
|
|
|
bt_conn_put(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void le_ltk_request(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_le_ltk_request *evt = (void *)buf->data;
|
|
|
|
struct bt_conn *conn;
|
|
|
|
uint16_t handle;
|
|
|
|
|
|
|
|
handle = sys_le16_to_cpu(evt->handle);
|
|
|
|
|
|
|
|
BT_DBG("handle %u\n", handle);
|
|
|
|
|
|
|
|
conn = bt_conn_lookup_handle(handle);
|
|
|
|
if (!conn) {
|
|
|
|
BT_ERR("Unable to lookup conn for handle %u\n", handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!conn->keys) {
|
|
|
|
conn->keys = bt_keys_find(BT_KEYS_SLAVE_LTK, &conn->dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->keys && (conn->keys->keys & BT_KEYS_SLAVE_LTK) &&
|
|
|
|
conn->keys->slave_ltk.rand == evt->rand &&
|
|
|
|
conn->keys->slave_ltk.ediv == evt->ediv) {
|
|
|
|
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) {
|
|
|
|
BT_ERR("Out of command buffers\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = bt_buf_add(buf, sizeof(*cp));
|
|
|
|
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);
|
|
|
|
} else {
|
|
|
|
struct bt_hci_cp_le_ltk_req_neg_reply *cp;
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_LTK_REQ_NEG_REPLY,
|
|
|
|
sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
BT_ERR("Out of command buffers\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = bt_buf_add(buf, sizeof(*cp));
|
|
|
|
cp->handle = evt->handle;
|
|
|
|
|
|
|
|
bt_hci_cmd_send(BT_HCI_OP_LE_LTK_REQ_NEG_REPLY, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
bt_conn_put(conn);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_SMP */
|
|
|
|
|
|
|
|
static void hci_reset_complete(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
uint8_t status = buf->data[0];
|
|
|
|
|
|
|
|
BT_DBG("status %u\n", status);
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
scan_dev_found_cb = NULL;
|
|
|
|
atomic_set(bt_dev.flags, 0);
|
|
|
|
atomic_set_bit(bt_dev.flags, BT_DEV_SCAN_FILTER_DUP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hci_cmd_done(uint16_t opcode, uint8_t status, struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_buf *sent = bt_dev.sent_cmd;
|
|
|
|
|
|
|
|
if (!sent) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bt_dev.sent_cmd->hci.opcode != opcode) {
|
|
|
|
BT_ERR("Unexpected completion of opcode 0x%04x\n", opcode);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_dev.sent_cmd = NULL;
|
|
|
|
|
|
|
|
/* If the command was synchronous wake up bt_hci_cmd_send_sync() */
|
|
|
|
if (sent->hci.sync) {
|
|
|
|
struct nano_sem *sem = sent->hci.sync;
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
sent->hci.sync = NULL;
|
|
|
|
} else {
|
|
|
|
sent->hci.sync = bt_buf_hold(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
nano_fiber_sem_give(sem);
|
|
|
|
} else {
|
|
|
|
bt_buf_put(sent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hci_cmd_complete(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
struct hci_evt_cmd_complete *evt = (void *)buf->data;
|
|
|
|
uint16_t opcode = sys_le16_to_cpu(evt->opcode);
|
|
|
|
uint8_t *status;
|
|
|
|
|
|
|
|
BT_DBG("opcode %x\n", opcode);
|
|
|
|
|
|
|
|
bt_buf_pull(buf, sizeof(*evt));
|
|
|
|
|
|
|
|
/* All command return parameters have a 1-byte status in the
|
|
|
|
* beginning, so we can safely make this generalization.
|
|
|
|
*/
|
|
|
|
status = buf->data;
|
|
|
|
|
|
|
|
switch (opcode) {
|
|
|
|
case BT_HCI_OP_RESET:
|
|
|
|
hci_reset_complete(buf);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BT_DBG("Unhandled opcode %x\n", opcode);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
hci_cmd_done(opcode, *status, buf);
|
|
|
|
|
|
|
|
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-01 17:50:19 +02:00
|
|
|
static void hci_cmd_status(struct bt_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
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
BT_DBG("opcode %x\n", opcode);
|
2015-08-10 22:23:05 +02:00
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
bt_buf_pull(buf, sizeof(*evt));
|
|
|
|
|
|
|
|
switch (opcode) {
|
|
|
|
default:
|
|
|
|
BT_DBG("Unhandled opcode %x\n", opcode);
|
|
|
|
break;
|
2015-08-10 22:23:05 +02:00
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
static int bt_hci_start_scanning(uint8_t scan_type)
|
2015-08-11 09:13:40 +02:00
|
|
|
{
|
2015-10-01 17:50:19 +02:00
|
|
|
struct bt_buf *buf, *rsp;
|
|
|
|
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-01 17:50:19 +02:00
|
|
|
set_param = bt_buf_add(buf, sizeof(*set_param));
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
set_param->interval = sys_cpu_to_le16(0x0010);
|
|
|
|
set_param->window = sys_cpu_to_le16(0x0010);
|
|
|
|
set_param->filter_policy = 0x00;
|
|
|
|
set_param->addr_type = 0x00;
|
|
|
|
|
|
|
|
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-01 17:50:19 +02:00
|
|
|
scan_enable = bt_buf_add(buf, sizeof(*scan_enable));
|
|
|
|
memset(scan_enable, 0, sizeof(*scan_enable));
|
|
|
|
scan_enable->filter_dup = atomic_test_bit(bt_dev.flags,
|
|
|
|
BT_DEV_SCAN_FILTER_DUP);
|
|
|
|
scan_enable->enable = 0x01;
|
|
|
|
|
|
|
|
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-01 17:50:19 +02:00
|
|
|
bt_buf_put(rsp);
|
|
|
|
|
|
|
|
return err;
|
2015-08-11 09:13:40 +02:00
|
|
|
}
|
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
/* Used to determine whether to start scan and which scan type should be used */
|
|
|
|
int bt_le_scan_update(void)
|
2015-07-02 11:53:54 +02:00
|
|
|
{
|
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
|
|
|
if (scan_dev_found_cb) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-07-09 16:09:47 +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-10-01 17:50:19 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
|
|
|
if (!scan_dev_found_cb) {
|
|
|
|
struct bt_conn *conn;
|
2015-07-02 11:53:54 +02:00
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
conn = bt_conn_lookup_state(BT_ADDR_LE_ANY,
|
|
|
|
BT_CONN_CONNECT_SCAN);
|
|
|
|
if (!conn) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-07-02 11:53:54 +02:00
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
bt_conn_put(conn);
|
2015-07-02 11:53:54 +02:00
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
return bt_hci_start_scanning(BT_LE_SCAN_PASSIVE);
|
|
|
|
}
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
2015-04-18 18:44:38 +03:00
|
|
|
|
2015-10-01 17:50:19 +02:00
|
|
|
return bt_hci_start_scanning(BT_LE_SCAN_ACTIVE);
|
|
|
|
}
|
|
|
|
|
2015-05-08 20:53:39 +02:00
|
|
|
static void le_adv_report(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
uint8_t num_reports = buf->data[0];
|
2015-05-18 10:32:58 +03:00
|
|
|
struct bt_hci_ev_le_advertising_info *info;
|
2015-05-08 20:53:39 +02:00
|
|
|
|
|
|
|
BT_DBG("Adv number of reports %u\n", num_reports);
|
|
|
|
|
2015-05-18 10:32:58 +03:00
|
|
|
info = bt_buf_pull(buf, sizeof(num_reports));
|
|
|
|
|
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-05-25 22:11:28 +03:00
|
|
|
BT_DBG("%s event %u, len %u, rssi %d dBm\n",
|
|
|
|
bt_addr_le_str(&info->addr),
|
2015-05-08 20:53:39 +02:00
|
|
|
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-05-18 10:24:58 +03:00
|
|
|
info = bt_buf_pull(buf, sizeof(*info) + info->length +
|
|
|
|
sizeof(rssi));
|
2015-05-08 20:53:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-18 18:37:03 +03:00
|
|
|
static void hci_le_meta_event(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_le_meta_event *evt = (void *)buf->data;
|
|
|
|
|
|
|
|
bt_buf_pull(buf, sizeof(*evt));
|
|
|
|
|
|
|
|
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;
|
|
|
|
#endif /* CONFIG_BLUETOOTH_SMP */
|
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:
|
|
|
|
BT_DBG("Unhandled LE event %x\n", evt->subevent);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-14 15:41:55 +03:00
|
|
|
static void hci_event(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_evt_hdr *hdr = (void *)buf->data;
|
|
|
|
|
|
|
|
BT_DBG("event %u\n", hdr->evt);
|
|
|
|
|
|
|
|
bt_buf_pull(buf, sizeof(*hdr));
|
|
|
|
|
|
|
|
switch (hdr->evt) {
|
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 */
|
|
|
|
#if defined(CONFIG_BLUETOOTH_SMP)
|
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;
|
2015-09-09 17:27:16 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_SMP */
|
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-05-21 15:58:32 +03:00
|
|
|
BT_WARN("Unhandled event 0x%02x\n", hdr->evt);
|
2015-04-14 15:41:55 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
2015-04-14 15:44:48 +03:00
|
|
|
|
|
|
|
bt_buf_put(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-07-15 13:53:17 +03:00
|
|
|
struct bt_driver *drv = bt_dev.drv;
|
2015-04-14 15:41:55 +03:00
|
|
|
|
2015-05-20 13:14:37 +03:00
|
|
|
BT_DBG("started\n");
|
2015-04-14 15:41:55 +03:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct bt_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-05-20 13:14:37 +03:00
|
|
|
BT_DBG("calling sem_take_wait\n");
|
2015-07-15 13:53:17 +03:00
|
|
|
nano_fiber_sem_take_wait(&bt_dev.ncmd_sem);
|
2015-04-14 15:41:55 +03:00
|
|
|
|
|
|
|
/* Get next command - wait if necessary */
|
2015-05-20 13:14:37 +03:00
|
|
|
BT_DBG("calling fifo_get_wait\n");
|
2015-07-15 13:53:17 +03:00
|
|
|
buf = nano_fifo_get_wait(&bt_dev.cmd_tx_queue);
|
|
|
|
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-04-28 15:16:03 +03:00
|
|
|
BT_ERR("Uncleared pending sent_cmd\n");
|
2015-07-15 13:53:17 +03:00
|
|
|
bt_buf_put(bt_dev.sent_cmd);
|
|
|
|
bt_dev.sent_cmd = NULL;
|
2015-04-28 15:16:03 +03:00
|
|
|
}
|
|
|
|
|
2015-09-15 17:57:00 +03:00
|
|
|
BT_DBG("Sending command %x (buf %p) to driver\n",
|
|
|
|
buf->hci.opcode, buf);
|
|
|
|
|
|
|
|
err = drv->send(buf);
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("Unable to send to driver (err %d)\n", err);
|
|
|
|
bt_buf_put(buf);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
bt_dev.sent_cmd = buf;
|
2015-04-14 15:41:55 +03:00
|
|
|
}
|
2015-04-14 15:32:32 +03:00
|
|
|
}
|
|
|
|
|
2015-06-03 23:47:06 +07:00
|
|
|
static void rx_prio_fiber(void)
|
2015-05-23 19:58:06 +03:00
|
|
|
{
|
|
|
|
struct bt_buf *buf;
|
|
|
|
|
|
|
|
BT_DBG("started\n");
|
|
|
|
|
|
|
|
/* So we can avoid bt_hci_cmd_send_sync deadlocks */
|
|
|
|
#if defined(CONFIG_BLUETOOTH_DEBUG)
|
2015-08-20 11:04:01 -04:00
|
|
|
rx_prio_fiber_id = sys_thread_self_get();
|
2015-05-23 19:58:06 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct bt_hci_evt_hdr *hdr;
|
|
|
|
|
|
|
|
BT_DBG("calling fifo_get_wait\n");
|
2015-07-15 13:53:17 +03:00
|
|
|
buf = nano_fifo_get_wait(&bt_dev.rx_prio_queue);
|
2015-05-23 19:58:06 +03:00
|
|
|
|
|
|
|
BT_DBG("buf %p type %u len %u\n", buf, buf->type, buf->len);
|
|
|
|
|
|
|
|
if (buf->type != BT_EVT) {
|
|
|
|
BT_ERR("Unknown buf type %u\n", buf->type);
|
|
|
|
bt_buf_put(buf);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
hdr = (void *)buf->data;
|
|
|
|
bt_buf_pull(buf, sizeof(*hdr));
|
|
|
|
|
|
|
|
switch (hdr->evt) {
|
|
|
|
case BT_HCI_EVT_CMD_COMPLETE:
|
|
|
|
hci_cmd_complete(buf);
|
|
|
|
break;
|
|
|
|
case BT_HCI_EVT_CMD_STATUS:
|
|
|
|
hci_cmd_status(buf);
|
|
|
|
break;
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
2015-06-03 18:29:03 +07:00
|
|
|
case BT_HCI_EVT_NUM_COMPLETED_PACKETS:
|
|
|
|
hci_num_completed_packets(buf);
|
|
|
|
break;
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
2015-05-23 19:58:06 +03:00
|
|
|
default:
|
|
|
|
BT_ERR("Unknown event 0x%02x\n", hdr->evt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_buf_put(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-30 13:19:44 +03:00
|
|
|
static void read_local_features_complete(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_rp_read_local_features *rp = (void *)buf->data;
|
|
|
|
|
|
|
|
BT_DBG("status %u\n", rp->status);
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
static void read_local_ver_complete(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_rp_read_local_version_info *rp = (void *)buf->data;
|
|
|
|
|
|
|
|
BT_DBG("status %u\n", rp->status);
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
static void read_bdaddr_complete(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_rp_read_bd_addr *rp = (void *)buf->data;
|
|
|
|
|
|
|
|
BT_DBG("status %u\n", rp->status);
|
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
bt_addr_copy(&bt_dev.bdaddr, &rp->bdaddr);
|
2015-04-30 13:19:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void read_le_features_complete(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_rp_le_read_local_features *rp = (void *)buf->data;
|
|
|
|
|
|
|
|
BT_DBG("status %u\n", rp->status);
|
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
memcpy(bt_dev.le_features, rp->features, sizeof(bt_dev.le_features));
|
2015-04-30 13:19:44 +03:00
|
|
|
}
|
|
|
|
|
2015-05-20 08:19:40 +02:00
|
|
|
static void read_buffer_size_complete(struct bt_buf *buf)
|
2015-04-30 13:19:44 +03:00
|
|
|
{
|
|
|
|
struct bt_hci_rp_read_buffer_size *rp = (void *)buf->data;
|
|
|
|
|
|
|
|
BT_DBG("status %u\n", rp->status);
|
|
|
|
|
|
|
|
/* If LE-side has buffers we can ignore the BR/EDR values */
|
2015-07-15 13:53:17 +03: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-07-15 13:53:17 +03:00
|
|
|
bt_dev.le_mtu = sys_le16_to_cpu(rp->acl_max_len);
|
|
|
|
bt_dev.le_pkts = sys_le16_to_cpu(rp->acl_max_num);
|
2015-04-30 13:19:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void le_read_buffer_size_complete(struct bt_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_hci_rp_le_read_buffer_size *rp = (void *)buf->data;
|
|
|
|
|
|
|
|
BT_DBG("status %u\n", rp->status);
|
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
bt_dev.le_mtu = sys_le16_to_cpu(rp->le_max_len);
|
|
|
|
bt_dev.le_pkts = rp->le_max_num;
|
2015-04-30 13:19:44 +03:00
|
|
|
}
|
|
|
|
|
2015-09-15 14:25:26 +02:00
|
|
|
static int hci_init(void)
|
|
|
|
{
|
2015-04-14 15:44:48 +03:00
|
|
|
struct bt_hci_cp_set_event_mask *ev;
|
2015-04-30 13:19:44 +03:00
|
|
|
struct bt_buf *buf, *rsp;
|
2015-05-12 14:57:38 +03:00
|
|
|
int i, err;
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-04-14 15:41:55 +03:00
|
|
|
/* Send HCI_RESET */
|
|
|
|
bt_hci_cmd_send(BT_HCI_OP_RESET, NULL);
|
|
|
|
|
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);
|
|
|
|
bt_buf_put(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);
|
|
|
|
bt_buf_put(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);
|
|
|
|
bt_buf_put(rsp);
|
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-04-14 15:44:48 +03:00
|
|
|
BT_ERR("Non-LE capable controller detected!\n");
|
|
|
|
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);
|
|
|
|
bt_buf_put(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);
|
|
|
|
bt_buf_put(rsp);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
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-05-18 10:18:21 +03:00
|
|
|
ev = bt_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-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-07-15 13:53:17 +03: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-04-30 12:01:48 +03:00
|
|
|
bt_hci_cmd_send_sync(BT_HCI_OP_SET_EVENT_MASK, buf, NULL);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
2015-09-15 14:25:26 +02:00
|
|
|
err = set_flow_control();
|
2015-05-18 12:04:50 +02:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
2015-04-20 12:16:57 +03:00
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
if (lmp_bredr_capable(bt_dev)) {
|
2015-04-14 15:44:48 +03:00
|
|
|
struct bt_hci_cp_write_le_host_supp *cp;
|
|
|
|
|
|
|
|
/* Use BR/EDR buffer size if LE reports zero buffers */
|
2015-07-15 13:53:17 +03:00
|
|
|
if (!bt_dev.le_mtu) {
|
2015-05-20 13:54:46 +03:00
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_BUFFER_SIZE,
|
|
|
|
NULL, &rsp);
|
2015-05-20 08:19:40 +02:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
read_buffer_size_complete(rsp);
|
|
|
|
bt_buf_put(rsp);
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-14 15:44:48 +03:00
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_WRITE_LE_HOST_SUPP,
|
|
|
|
sizeof(*cp));
|
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-05-18 10:18:21 +03:00
|
|
|
cp = bt_buf_add(buf, sizeof*cp);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
|
|
|
/* Excplicitly enable LE for dual-mode controllers */
|
|
|
|
cp->le = 0x01;
|
|
|
|
cp->simul = 0x00;
|
2015-04-30 12:01:48 +03:00
|
|
|
bt_hci_cmd_send_sync(BT_HCI_OP_LE_WRITE_LE_HOST_SUPP, buf,
|
|
|
|
NULL);
|
2015-04-14 15:44:48 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
BT_DBG("HCI ver %u rev %u, manufacturer %u\n", bt_dev.hci_version,
|
|
|
|
bt_dev.hci_revision, bt_dev.manufacturer);
|
|
|
|
BT_DBG("ACL buffers: pkts %u mtu %u\n", bt_dev.le_pkts, bt_dev.le_mtu);
|
2015-04-14 15:44:48 +03:00
|
|
|
|
2015-05-12 14:57:38 +03:00
|
|
|
/* Initialize & prime the semaphore for counting controller-side
|
|
|
|
* available ACL packet buffers.
|
|
|
|
*/
|
2015-07-15 13:53:17 +03:00
|
|
|
nano_sem_init(&bt_dev.le_pkts_sem);
|
|
|
|
for (i = 0; i < bt_dev.le_pkts; i++) {
|
|
|
|
nano_sem_give(&bt_dev.le_pkts_sem);
|
2015-05-13 15:44:14 +03:00
|
|
|
}
|
2015-05-12 14:57:38 +03:00
|
|
|
|
2015-04-14 15:41:55 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-14 15:32:32 +03:00
|
|
|
/* Interface to HCI driver layer */
|
|
|
|
|
|
|
|
void bt_recv(struct bt_buf *buf)
|
|
|
|
{
|
2015-05-23 19:58:06 +03:00
|
|
|
struct bt_hci_evt_hdr *hdr;
|
|
|
|
|
2015-05-20 13:14:37 +03:00
|
|
|
BT_DBG("buf %p len %u\n", buf, buf->len);
|
2015-05-23 19:58:06 +03:00
|
|
|
|
|
|
|
if (buf->type == BT_ACL_IN) {
|
2015-07-15 13:53:17 +03:00
|
|
|
nano_fifo_put(&bt_dev.rx_queue, buf);
|
2015-05-23 19:58:06 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buf->type != BT_EVT) {
|
|
|
|
BT_ERR("Invalid buf type %u\n", buf->type);
|
|
|
|
bt_buf_put(buf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Command Complete/Status events have their own cmd_rx queue,
|
|
|
|
* all other events go through rx queue.
|
|
|
|
*/
|
|
|
|
hdr = (void *)buf->data;
|
|
|
|
if (hdr->evt == BT_HCI_EVT_CMD_COMPLETE ||
|
2015-06-03 18:29:03 +07:00
|
|
|
hdr->evt == BT_HCI_EVT_CMD_STATUS ||
|
|
|
|
hdr->evt == BT_HCI_EVT_NUM_COMPLETED_PACKETS) {
|
2015-07-15 13:53:17 +03:00
|
|
|
nano_fifo_put(&bt_dev.rx_prio_queue, buf);
|
2015-05-23 19:58:06 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-07-15 13:53:17 +03:00
|
|
|
nano_fifo_put(&bt_dev.rx_queue, buf);
|
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-05-05 10:50:14 +03: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
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2015-07-28 18:23:19 +03:00
|
|
|
static int bt_init(void)
|
|
|
|
{
|
|
|
|
struct bt_driver *drv = bt_dev.drv;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = drv->open();
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("HCI driver open failed (%d)\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = hci_init();
|
2015-09-07 18:25:59 +02:00
|
|
|
|
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
|
|
|
if (!err) {
|
|
|
|
err = bt_l2cap_init();
|
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
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
return err;
|
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
|
|
|
{
|
|
|
|
struct bt_buf *buf;
|
|
|
|
|
|
|
|
BT_DBG("started\n");
|
|
|
|
|
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) {
|
|
|
|
BT_DBG("calling fifo_get_wait\n");
|
|
|
|
buf = nano_fifo_get_wait(&bt_dev.rx_queue);
|
|
|
|
|
|
|
|
BT_DBG("buf %p type %u len %u\n", buf, buf->type, buf->len);
|
|
|
|
|
|
|
|
switch (buf->type) {
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
2015-07-28 18:20:50 +03:00
|
|
|
case BT_ACL_IN:
|
|
|
|
hci_acl(buf);
|
|
|
|
break;
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CONN */
|
2015-07-28 18:20:50 +03:00
|
|
|
case BT_EVT:
|
|
|
|
hci_event(buf);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BT_ERR("Unknown buf type %u\n", buf->type);
|
|
|
|
bt_buf_put(buf);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
BT_ERR("No HCI driver registered\n");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_buf_init(ACL_IN_MAX, ACL_OUT_MAX);
|
2015-04-14 15:41:55 +03:00
|
|
|
|
|
|
|
/* Give cmd_sem allowing to send first HCI_Reset cmd */
|
2015-07-15 13:53:17 +03:00
|
|
|
bt_dev.ncmd = 1;
|
2015-07-28 20:30:04 +03:00
|
|
|
nano_sem_init(&bt_dev.ncmd_sem);
|
2015-07-15 13:53:17 +03:00
|
|
|
nano_task_sem_give(&bt_dev.ncmd_sem);
|
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-07-28 20:30:04 +03:00
|
|
|
/* RX prio fiber */
|
2015-07-15 13:53:17 +03:00
|
|
|
nano_fifo_init(&bt_dev.rx_prio_queue);
|
2015-06-03 23:47:06 +07:00
|
|
|
fiber_start(rx_prio_fiber_stack, sizeof(rx_prio_fiber_stack),
|
|
|
|
(nano_fiber_entry_t)rx_prio_fiber, 0, 0, 7, 0);
|
2015-04-14 15:32:32 +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
|
|
|
|
2015-04-30 16:07:09 +03:00
|
|
|
int bt_start_advertising(uint8_t type, const struct bt_eir *ad,
|
|
|
|
const struct bt_eir *sd)
|
2015-04-17 13:59:34 +03:00
|
|
|
{
|
|
|
|
struct bt_buf *buf;
|
|
|
|
struct bt_hci_cp_le_set_adv_data *set_data;
|
|
|
|
struct bt_hci_cp_le_set_adv_data *scan_rsp;
|
|
|
|
struct bt_hci_cp_le_set_adv_parameters *set_param;
|
2015-07-23 11:35:59 +02:00
|
|
|
uint8_t adv_enable;
|
|
|
|
int i, err;
|
2015-04-17 13:59:34 +03:00
|
|
|
|
2015-05-05 10:50:14 +03:00
|
|
|
if (!ad) {
|
2015-04-30 16:07:09 +03:00
|
|
|
goto send_scan_rsp;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-17 13:59:34 +03:00
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADV_DATA, 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-05-18 10:18:21 +03:00
|
|
|
set_data = bt_buf_add(buf, sizeof(*set_data));
|
2015-04-17 13:59:34 +03:00
|
|
|
|
|
|
|
memset(set_data, 0, sizeof(*set_data));
|
|
|
|
|
2015-04-30 16:07:09 +03:00
|
|
|
for (i = 0; ad[i].len; i++) {
|
|
|
|
/* Check if ad fit in the remaining buffer */
|
2015-05-05 10:50:14 +03:00
|
|
|
if (set_data->len + ad[i].len + 1 > 29) {
|
2015-04-30 16:07:09 +03:00
|
|
|
break;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-30 16:07:09 +03:00
|
|
|
|
|
|
|
memcpy(&set_data->data[set_data->len], &ad[i], ad[i].len + 1);
|
|
|
|
set_data->len += ad[i].len + 1;
|
|
|
|
}
|
2015-04-17 13:59:34 +03:00
|
|
|
|
|
|
|
bt_hci_cmd_send(BT_HCI_OP_LE_SET_ADV_DATA, buf);
|
|
|
|
|
2015-04-30 16:07:09 +03:00
|
|
|
send_scan_rsp:
|
2015-05-05 10:50:14 +03:00
|
|
|
if (!sd) {
|
2015-04-30 16:07:09 +03:00
|
|
|
goto send_set_param;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-30 16:07:09 +03:00
|
|
|
|
2015-04-17 13:59:34 +03:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_SCAN_RSP_DATA,
|
|
|
|
sizeof(*scan_rsp));
|
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-05-18 10:18:21 +03:00
|
|
|
scan_rsp = bt_buf_add(buf, sizeof(*scan_rsp));
|
2015-04-17 13:59:34 +03:00
|
|
|
|
|
|
|
memset(scan_rsp, 0, sizeof(*scan_rsp));
|
|
|
|
|
2015-04-30 16:07:09 +03:00
|
|
|
for (i = 0; sd[i].len; i++) {
|
|
|
|
/* Check if ad fit in the remaining buffer */
|
2015-05-05 10:50:14 +03:00
|
|
|
if (scan_rsp->len + sd[i].len + 1 > 29) {
|
2015-04-30 16:07:09 +03:00
|
|
|
break;
|
2015-05-05 10:50:14 +03:00
|
|
|
}
|
2015-04-30 16:07:09 +03:00
|
|
|
|
|
|
|
memcpy(&scan_rsp->data[scan_rsp->len], &sd[i], sd[i].len + 1);
|
|
|
|
scan_rsp->len += sd[i].len + 1;
|
|
|
|
}
|
2015-04-17 13:59:34 +03:00
|
|
|
|
|
|
|
bt_hci_cmd_send(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, buf);
|
|
|
|
|
2015-04-30 16:07:09 +03:00
|
|
|
send_set_param:
|
2015-04-17 13:59:34 +03:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADV_PARAMETERS,
|
|
|
|
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-05-18 10:18:21 +03:00
|
|
|
set_param = bt_buf_add(buf, sizeof(*set_param));
|
2015-04-17 13:59:34 +03:00
|
|
|
|
|
|
|
memset(set_param, 0, sizeof(*set_param));
|
|
|
|
set_param->min_interval = sys_cpu_to_le16(0x0800);
|
|
|
|
set_param->max_interval = sys_cpu_to_le16(0x0800);
|
|
|
|
set_param->type = type;
|
|
|
|
set_param->channel_map = 0x07;
|
|
|
|
|
|
|
|
bt_hci_cmd_send(BT_HCI_OP_LE_SET_ADV_PARAMETERS, buf);
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADV_ENABLE, 1);
|
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-07-23 11:35:59 +02:00
|
|
|
adv_enable = 0x01;
|
|
|
|
memcpy(bt_buf_add(buf, 1), &adv_enable, 1);
|
|
|
|
|
|
|
|
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);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
int bt_stop_advertising(void)
|
|
|
|
{
|
|
|
|
struct bt_buf *buf;
|
2015-07-23 11:35:59 +02:00
|
|
|
uint8_t adv_enable;
|
|
|
|
int err;
|
2015-07-08 12:17:01 +02:00
|
|
|
|
2015-07-23 11:35:59 +02:00
|
|
|
if (!atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) {
|
2015-07-08 12:17:01 +02:00
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADV_ENABLE, 1);
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2015-07-23 11:35:59 +02:00
|
|
|
adv_enable = 0x00;
|
|
|
|
memcpy(bt_buf_add(buf, 1), &adv_enable, 1);
|
2015-04-17 13:59:34 +03:00
|
|
|
|
2015-07-23 11:35:59 +02:00
|
|
|
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;
|
2015-04-17 13:59:34 +03:00
|
|
|
}
|
2015-05-08 10:33:34 +02:00
|
|
|
|
2015-07-23 11:35:59 +02:00
|
|
|
int bt_start_scanning(bt_scan_filter_dup_t filter, bt_le_scan_cb_t cb)
|
2015-07-01 18:54:57 +02:00
|
|
|
{
|
|
|
|
/* Return if active scan is already enabled */
|
|
|
|
if (scan_dev_found_cb) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
scan_dev_found_cb = cb;
|
2015-07-23 11:35:59 +02:00
|
|
|
if (filter == BT_SCAN_FILTER_DUP_DISABLE) {
|
|
|
|
atomic_clear_bit(bt_dev.flags, BT_DEV_SCAN_FILTER_DUP);
|
|
|
|
}
|
2015-07-01 18:54:57 +02:00
|
|
|
|
2015-07-15 13:12:28 +03:00
|
|
|
return bt_le_scan_update();
|
2015-07-01 18:54:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int bt_stop_scanning(void)
|
|
|
|
{
|
|
|
|
/* Return if active scanning is already disabled */
|
|
|
|
if (!scan_dev_found_cb) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
scan_dev_found_cb = NULL;
|
2015-07-23 11:35:59 +02:00
|
|
|
atomic_set_bit(bt_dev.flags, BT_DEV_SCAN_FILTER_DUP);
|
2015-07-06 12:00:04 +02:00
|
|
|
|
2015-07-15 13:12:28 +03:00
|
|
|
return bt_le_scan_update();
|
2015-07-01 18:54:57 +02:00
|
|
|
}
|