Skip to content

Commit f62a40b

Browse files
Michał Narajowskicarlescufi
authored andcommitted
Bluetooth: Fix callback handling in ECC Public Key generation
Commit d6c34c4 changed the behavior slightly but didn't update the documentation. The callback will now be reset to NULL once the key is generated. Calling bt_pub_key_gen() multiple times before the key is finished would result in creation of an infinite loop. This could happen when an application calls mesh_init() and mesh_reset() in quick succession. Clarify the behavior of the API in the documentation. Also passing a NULL argument would result in an undefined behavior, so add a check to match the behavior described in documentation. Signed-off-by: Michał Narajowski <michal.narajowski@codecoup.pl>
1 parent 865c818 commit f62a40b

File tree

2 files changed

+37
-13
lines changed

2 files changed

+37
-13
lines changed

subsys/bluetooth/host/ecc.c

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#include "common/log.h"
1818

1919
static uint8_t pub_key[64];
20-
static struct bt_pub_key_cb *pub_key_cb;
20+
static sys_slist_t pub_key_cb_slist;
2121
static bt_dh_key_cb_t dh_key_cb;
2222

2323
static const uint8_t debug_public_key[64] = {
@@ -40,6 +40,7 @@ bool bt_pub_key_is_debug(uint8_t *pub_key)
4040

4141
int bt_pub_key_gen(struct bt_pub_key_cb *new_cb)
4242
{
43+
struct bt_pub_key_cb *cb;
4344
int err;
4445

4546
/*
@@ -64,8 +65,18 @@ int bt_pub_key_gen(struct bt_pub_key_cb *new_cb)
6465
}
6566
}
6667

67-
new_cb->_next = pub_key_cb;
68-
pub_key_cb = new_cb;
68+
if (!new_cb) {
69+
return -EINVAL;
70+
}
71+
72+
SYS_SLIST_FOR_EACH_CONTAINER(&pub_key_cb_slist, cb, node) {
73+
if (cb == new_cb) {
74+
BT_WARN("Callback already registered");
75+
return -EALREADY;
76+
}
77+
}
78+
79+
sys_slist_prepend(&pub_key_cb_slist, &new_cb->node);
6980

7081
if (atomic_test_and_set_bit(bt_dev.flags, BT_DEV_PUB_KEY_BUSY)) {
7182
return 0;
@@ -75,9 +86,17 @@ int bt_pub_key_gen(struct bt_pub_key_cb *new_cb)
7586

7687
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_P256_PUBLIC_KEY, NULL, NULL);
7788
if (err) {
89+
7890
BT_ERR("Sending LE P256 Public Key command failed");
7991
atomic_clear_bit(bt_dev.flags, BT_DEV_PUB_KEY_BUSY);
80-
pub_key_cb = NULL;
92+
93+
SYS_SLIST_FOR_EACH_CONTAINER(&pub_key_cb_slist, cb, node) {
94+
if (cb->func) {
95+
cb->func(NULL);
96+
}
97+
}
98+
99+
sys_slist_init(&pub_key_cb_slist);
81100
return err;
82101
}
83102

@@ -180,11 +199,13 @@ void bt_hci_evt_le_pkey_complete(struct net_buf *buf)
180199
atomic_set_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY);
181200
}
182201

183-
for (cb = pub_key_cb; cb; cb = cb->_next) {
184-
cb->func(evt->status ? NULL : pub_key);
202+
SYS_SLIST_FOR_EACH_CONTAINER(&pub_key_cb_slist, cb, node) {
203+
if (cb->func) {
204+
cb->func(evt->status ? NULL : pub_key);
205+
}
185206
}
186207

187-
pub_key_cb = NULL;
208+
sys_slist_init(&pub_key_cb_slist);
188209
}
189210

190211
void bt_hci_evt_le_dhkey_complete(struct net_buf *buf)

subsys/bluetooth/host/ecc.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ struct bt_pub_key_cb {
1818
*/
1919
void (*func)(const uint8_t key[64]);
2020

21-
struct bt_pub_key_cb *_next;
21+
/* Internal */
22+
sys_snode_t node;
2223
};
2324

2425
/* @brief Check if public key is equal to the debug public key.
@@ -34,12 +35,14 @@ bool bt_pub_key_is_debug(uint8_t *pub_key);
3435

3536
/* @brief Generate a new Public Key.
3637
*
37-
* Generate a new ECC Public Key. The callback will persist even after the
38-
* key has been generated, and will be used to notify of new generation
39-
* processes (NULL as key).
38+
* Generate a new ECC Public Key. Provided cb must persists until callback
39+
* is called. Callee adds the callback structure to a linked list. Registering
40+
* multiple callbacks requires multiple calls to bt_pub_key_gen() and separate
41+
* callback structures. This method cannot be called directly from result
42+
* callback. After calling all the registered callbacks the linked list
43+
* is cleared.
4044
*
41-
* @param cb Callback to notify the new key, or NULL to request an update
42-
* without registering any new callback.
45+
* @param cb Callback to notify the new key.
4346
*
4447
* @return Zero on success or negative error code otherwise
4548
*/

0 commit comments

Comments
 (0)