Bluetooth: br/edr: store link key
Save link key to settings_subsys, no need to re-pair after restart. Overwrite old pairing records with aging counts. Signed-off-by: ZhongYao Luo <LuoZhongYao@gmail.com>
This commit is contained in:
parent
2bfb128463
commit
ddf5152bb8
|
@ -1088,7 +1088,16 @@ void bt_conn_security_changed(struct bt_conn *conn, enum bt_security_err err)
|
|||
}
|
||||
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
if (!err && conn->sec_level >= BT_SECURITY_L2) {
|
||||
bt_keys_update_usage(conn->id, bt_conn_get_dst(conn));
|
||||
if (conn->type == BT_CONN_TYPE_LE) {
|
||||
bt_keys_update_usage(conn->id, bt_conn_get_dst(conn));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_BREDR)
|
||||
if (conn->type == BT_CONN_TYPE_BR) {
|
||||
bt_keys_link_key_update_usage(&conn->br.dst);
|
||||
}
|
||||
#endif /* CONFIG_BT_BREDR */
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -3055,6 +3055,11 @@ static void link_key_notify(struct net_buf *buf)
|
|||
break;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
|
||||
!atomic_test_bit(conn->flags, BT_CONN_BR_NOBOND)) {
|
||||
bt_keys_link_key_store(conn->br.link_key);
|
||||
}
|
||||
|
||||
bt_conn_unref(conn);
|
||||
}
|
||||
|
||||
|
|
|
@ -102,16 +102,25 @@ enum {
|
|||
|
||||
struct bt_keys_link_key {
|
||||
bt_addr_t addr;
|
||||
uint8_t flags;
|
||||
uint8_t val[16];
|
||||
uint8_t storage_start[0] __aligned(sizeof(void *));
|
||||
uint8_t flags;
|
||||
uint8_t val[16];
|
||||
#if (defined(CONFIG_BT_KEYS_OVERWRITE_OLDEST))
|
||||
uint32_t aging_counter;
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
};
|
||||
#define BT_KEYS_LINK_KEY_STORAGE_LEN (sizeof(struct bt_keys_link_key) - \
|
||||
offsetof(struct bt_keys_link_key, storage_start))
|
||||
|
||||
struct bt_keys_link_key *bt_keys_get_link_key(const bt_addr_t *addr);
|
||||
struct bt_keys_link_key *bt_keys_find_link_key(const bt_addr_t *addr);
|
||||
void bt_keys_link_key_clear(struct bt_keys_link_key *link_key);
|
||||
void bt_keys_link_key_clear_addr(const bt_addr_t *addr);
|
||||
void bt_keys_link_key_store(struct bt_keys_link_key *link_key);
|
||||
|
||||
|
||||
/* This function is used to signal that the key has been used for paring */
|
||||
/* It updates the aging counter and saves it to flash if configuration option */
|
||||
/* BT_KEYS_SAVE_AGING_COUNTER_ON_PAIRING is enabled */
|
||||
void bt_keys_update_usage(uint8_t id, const bt_addr_le_t *addr);
|
||||
void bt_keys_link_key_update_usage(const bt_addr_t *addr);
|
||||
|
|
|
@ -14,16 +14,23 @@
|
|||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/conn.h>
|
||||
#include <bluetooth/hci.h>
|
||||
#include <settings/settings.h>
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_KEYS)
|
||||
#define LOG_MODULE_NAME bt_keys_br
|
||||
#include "common/log.h"
|
||||
|
||||
#include "hci_core.h"
|
||||
#include "settings.h"
|
||||
#include "keys.h"
|
||||
|
||||
static struct bt_keys_link_key key_pool[CONFIG_BT_MAX_PAIRED];
|
||||
|
||||
#if IS_ENABLED(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;
|
||||
|
@ -52,31 +59,67 @@ struct bt_keys_link_key *bt_keys_get_link_key(const bt_addr_t *addr)
|
|||
}
|
||||
|
||||
key = bt_keys_find_link_key(BT_ADDR_ANY);
|
||||
#if IS_ENABLED(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 IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
key->aging_counter = ++aging_counter_val;
|
||||
last_keys_updated = key;
|
||||
#endif
|
||||
BT_DBG("created %p for %s", key, bt_addr_str(addr));
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
BT_DBG("unable to create link key for %s", bt_addr_str(addr));
|
||||
BT_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)
|
||||
{
|
||||
BT_DBG("%s", bt_addr_str(&link_key->addr));
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
char key[BT_SETTINGS_KEY_MAX];
|
||||
bt_addr_le_t le_addr;
|
||||
|
||||
le_addr.type = BT_ADDR_LE_PUBLIC;
|
||||
bt_addr_copy(&le_addr.a, &link_key->addr);
|
||||
bt_settings_encode_key(key, sizeof(key), "link_key",
|
||||
&le_addr, NULL);
|
||||
settings_delete(key);
|
||||
}
|
||||
|
||||
BT_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) {
|
||||
(void)memset(key_pool, 0, sizeof(key_pool));
|
||||
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
|
||||
key = &key_pool[i];
|
||||
bt_keys_link_key_clear(key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -85,3 +128,112 @@ void bt_keys_link_key_clear_addr(const bt_addr_t *addr)
|
|||
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;
|
||||
char key[BT_SETTINGS_KEY_MAX];
|
||||
bt_addr_le_t le_addr;
|
||||
|
||||
le_addr.type = BT_ADDR_LE_PUBLIC;
|
||||
bt_addr_copy(&le_addr.a, &link_key->addr);
|
||||
bt_settings_encode_key(key, sizeof(key), "link_key",
|
||||
&le_addr, NULL);
|
||||
|
||||
err = settings_save_one(key, link_key->storage_start,
|
||||
BT_KEYS_LINK_KEY_STORAGE_LEN);
|
||||
if (err) {
|
||||
BT_ERR("Failed to svae link key (err %d)", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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) {
|
||||
BT_ERR("Insufficient number of arguments");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len = read_cb(cb_arg, val, sizeof(val));
|
||||
if (len < 0) {
|
||||
BT_ERR("Failed to read value (err %zu)", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
BT_DBG("name %s val %s", log_strdup(name),
|
||||
len ? bt_hex(val, sizeof(val)) : "(null)");
|
||||
|
||||
err = bt_settings_decode_key(name, &le_addr);
|
||||
if (err) {
|
||||
BT_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);
|
||||
BT_DBG("Clear keys for %s", bt_addr_le_str(&le_addr));
|
||||
} else {
|
||||
BT_WARN("Unable to find deleted keys for %s",
|
||||
bt_addr_le_str(&le_addr));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(link_key->storage_start, val, len);
|
||||
BT_DBG("Successfully restored link key for %s",
|
||||
bt_addr_le_str(&le_addr));
|
||||
#if IS_ENABLED(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;
|
||||
}
|
||||
|
||||
static int link_key_commit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SETTINGS_STATIC_HANDLER_DEFINE(bt_link_key, "bt/link_key", NULL, link_key_set,
|
||||
link_key_commit, NULL);
|
||||
|
||||
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;
|
||||
|
||||
BT_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
|
||||
|
|
Loading…
Reference in a new issue