In current implementation, the bonding information of classic is queried by calling the function `bt_foreach_bond()`. And the bonding information of classic is deleted by calling `bt_unpair()`. There are two issues if the LE and classic are bonded at same time for dual mode peer device. Issue 1, for the function `bt_foreach_bond()`, there are two bonding information will be found. But there is no way to find which bonding information belongs to LE or classic. Issue 2, For the function `bt_unpair()`, all bonding information will be deleted if the passed address is the public address. But there is no way to delete the bonding information of LE or classic. Remove the calling of function `bt_foreach_bond_br()` from the function `bt_foreach_bond()`. And rename it to `bt_br_foreach_bond()`, and public it as an API to query the bonding information of classic. Remove the calling of function `bt_keys_link_key_clear_addr()` from the function `bt_unpair()`. Add an API `bt_br_unpair()` to delete the bonding information of classic. Add a `br_bond_deleted` to structure `bt_conn_auth_info_cb` for classic. The callback will be triggered if the bonding information has been deleted by the function `bt_br_unpair()`. Add a `clear` shell command for classic to delete the bonding information. Signed-off-by: Lyle Zhu <lyle.zhu@nxp.com>
247 lines
5.4 KiB
C
247 lines
5.4 KiB
C
/* keys_br.c - Bluetooth BR/EDR key handling */
|
|
|
|
/*
|
|
* Copyright (c) 2015-2016 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/kernel.h>
|
|
#include <string.h>
|
|
#include <zephyr/sys/atomic.h>
|
|
#include <zephyr/sys/util.h>
|
|
|
|
#include <zephyr/bluetooth/bluetooth.h>
|
|
#include <zephyr/bluetooth/conn.h>
|
|
#include <zephyr/bluetooth/hci.h>
|
|
#include <zephyr/settings/settings.h>
|
|
|
|
#include "common/bt_str.h"
|
|
|
|
#include "host/hci_core.h"
|
|
#include "host/settings.h"
|
|
#include "host/keys.h"
|
|
|
|
#define LOG_LEVEL CONFIG_BT_KEYS_LOG_LEVEL
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(bt_keys_br);
|
|
|
|
static struct bt_keys_link_key key_pool[CONFIG_BT_MAX_PAIRED];
|
|
|
|
#if defined(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
|
static uint32_t aging_counter_val;
|
|
static struct bt_keys_link_key *last_keys_updated;
|
|
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
|
|
|
struct bt_keys_link_key *bt_keys_find_link_key(const bt_addr_t *addr)
|
|
{
|
|
struct bt_keys_link_key *key;
|
|
int i;
|
|
|
|
LOG_DBG("%s", bt_addr_str(addr));
|
|
|
|
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
|
|
key = &key_pool[i];
|
|
|
|
if (bt_addr_eq(&key->addr, addr)) {
|
|
return key;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct bt_keys_link_key *bt_keys_get_link_key(const bt_addr_t *addr)
|
|
{
|
|
struct bt_keys_link_key *key;
|
|
|
|
key = bt_keys_find_link_key(addr);
|
|
if (key) {
|
|
return key;
|
|
}
|
|
|
|
key = bt_keys_find_link_key(BT_ADDR_ANY);
|
|
#if defined(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
|
if (!key) {
|
|
int i;
|
|
|
|
key = &key_pool[0];
|
|
for (i = 1; i < ARRAY_SIZE(key_pool); i++) {
|
|
struct bt_keys_link_key *current = &key_pool[i];
|
|
|
|
if (current->aging_counter < key->aging_counter) {
|
|
key = current;
|
|
}
|
|
}
|
|
|
|
if (key) {
|
|
bt_keys_link_key_clear(key);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (key) {
|
|
bt_addr_copy(&key->addr, addr);
|
|
#if defined(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
|
key->aging_counter = ++aging_counter_val;
|
|
last_keys_updated = key;
|
|
#endif
|
|
LOG_DBG("created %p for %s", key, bt_addr_str(addr));
|
|
return key;
|
|
}
|
|
|
|
LOG_DBG("unable to create keys for %s", bt_addr_str(addr));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void bt_keys_link_key_clear(struct bt_keys_link_key *link_key)
|
|
{
|
|
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
bt_addr_le_t le_addr;
|
|
|
|
le_addr.type = BT_ADDR_LE_PUBLIC;
|
|
bt_addr_copy(&le_addr.a, &link_key->addr);
|
|
|
|
bt_settings_delete_link_key(&le_addr);
|
|
}
|
|
|
|
LOG_DBG("%s", bt_addr_str(&link_key->addr));
|
|
(void)memset(link_key, 0, sizeof(*link_key));
|
|
}
|
|
|
|
void bt_keys_link_key_clear_addr(const bt_addr_t *addr)
|
|
{
|
|
int i;
|
|
struct bt_keys_link_key *key;
|
|
|
|
if (!addr) {
|
|
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
|
|
key = &key_pool[i];
|
|
bt_keys_link_key_clear(key);
|
|
}
|
|
return;
|
|
}
|
|
|
|
key = bt_keys_find_link_key(addr);
|
|
if (key) {
|
|
bt_keys_link_key_clear(key);
|
|
}
|
|
}
|
|
|
|
void bt_keys_link_key_store(struct bt_keys_link_key *link_key)
|
|
{
|
|
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
int err;
|
|
bt_addr_le_t le_addr;
|
|
|
|
le_addr.type = BT_ADDR_LE_PUBLIC;
|
|
bt_addr_copy(&le_addr.a, &link_key->addr);
|
|
|
|
err = bt_settings_store_link_key(&le_addr, link_key->storage_start,
|
|
BT_KEYS_LINK_KEY_STORAGE_LEN);
|
|
if (err) {
|
|
LOG_ERR("Failed to save link key (err %d)", err);
|
|
}
|
|
}
|
|
}
|
|
|
|
void bt_br_foreach_bond(void (*func)(const struct bt_br_bond_info *info, void *user_data),
|
|
void *user_data)
|
|
{
|
|
__ASSERT_NO_MSG(func != NULL);
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(key_pool); i++) {
|
|
const struct bt_keys_link_key *key = &key_pool[i];
|
|
|
|
if (!bt_addr_eq(&key->addr, BT_ADDR_ANY)) {
|
|
struct bt_br_bond_info info;
|
|
|
|
bt_addr_copy(&info.addr, &key->addr);
|
|
func(&info, user_data);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_BT_SETTINGS)
|
|
|
|
static int link_key_set(const char *name, size_t len_rd,
|
|
settings_read_cb read_cb, void *cb_arg)
|
|
{
|
|
int err;
|
|
ssize_t len;
|
|
bt_addr_le_t le_addr;
|
|
struct bt_keys_link_key *link_key;
|
|
char val[BT_KEYS_LINK_KEY_STORAGE_LEN];
|
|
|
|
if (!name) {
|
|
LOG_ERR("Insufficient number of arguments");
|
|
return -EINVAL;
|
|
}
|
|
|
|
len = read_cb(cb_arg, val, sizeof(val));
|
|
if (len < 0) {
|
|
LOG_ERR("Failed to read value (err %zu)", len);
|
|
return -EINVAL;
|
|
}
|
|
|
|
LOG_DBG("name %s val %s", name, len ? bt_hex(val, sizeof(val)) : "(null)");
|
|
|
|
err = bt_settings_decode_key(name, &le_addr);
|
|
if (err) {
|
|
LOG_ERR("Unable to decode address %s", name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
link_key = bt_keys_get_link_key(&le_addr.a);
|
|
if (len != BT_KEYS_LINK_KEY_STORAGE_LEN) {
|
|
if (link_key) {
|
|
bt_keys_link_key_clear(link_key);
|
|
LOG_DBG("Clear keys for %s", bt_addr_le_str(&le_addr));
|
|
} else {
|
|
LOG_WRN("Unable to find deleted keys for %s", bt_addr_le_str(&le_addr));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
memcpy(link_key->storage_start, val, len);
|
|
LOG_DBG("Successfully restored link key for %s", bt_addr_le_str(&le_addr));
|
|
#if defined(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
|
if (aging_counter_val < link_key->aging_counter) {
|
|
aging_counter_val = link_key->aging_counter;
|
|
}
|
|
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
|
|
|
return 0;
|
|
}
|
|
|
|
SETTINGS_STATIC_HANDLER_DEFINE(bt_link_key, "bt/link_key", NULL, link_key_set,
|
|
NULL, NULL);
|
|
|
|
#if defined(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
|
void bt_keys_link_key_update_usage(const bt_addr_t *addr)
|
|
{
|
|
struct bt_keys_link_key *link_key = bt_keys_find_link_key(addr);
|
|
|
|
if (!link_key) {
|
|
return;
|
|
}
|
|
|
|
if (last_keys_updated == link_key) {
|
|
return;
|
|
}
|
|
|
|
link_key->aging_counter = ++aging_counter_val;
|
|
last_keys_updated = link_key;
|
|
|
|
LOG_DBG("Aging counter for %s is set to %u", bt_addr_str(addr), link_key->aging_counter);
|
|
|
|
if (IS_ENABLED(CONFIG_BT_KEYS_SAVE_AGING_COUNTER_ON_PAIRING)) {
|
|
bt_keys_link_key_store(link_key);
|
|
}
|
|
}
|
|
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
|
|
|
#endif /* defined(CONFIG_BT_SETTINGS) */
|