Skip to content

Commit 59ff3cf

Browse files
committed
extmod/zephyr_ble: Add bond key persistence via Python secret callbacks.
Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
1 parent 3f975fa commit 59ff3cf

3 files changed

Lines changed: 186 additions & 27 deletions

File tree

extmod/zephyr_ble/hal/zephyr_ble_settings.c

Lines changed: 165 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,206 @@
11
/*
2-
* Zephyr BLE Settings Stubs
3-
* Stub implementations for settings storage functions (disabled in Phase 1)
2+
* Zephyr BLE Settings
3+
*
4+
* Routes bond key storage through MicroPython's _IRQ_GET_SECRET / _IRQ_SET_SECRET
5+
* Python callback interface (same as NimBLE). Other settings types (CCC, CF, hash)
6+
* remain as no-op stubs.
7+
*
8+
* CONFIG_BT_SETTINGS is defined to 0 in zephyr_ble_config.h. Because keys.c uses
9+
* `#if defined(CONFIG_BT_SETTINGS)` (not IS_ENABLED), bt_keys_store() and
10+
* bt_keys_clear() call our typed wrappers. The IS_ENABLED paths (bt_settings_init,
11+
* etc.) remain disabled.
412
*/
513

14+
#include <string.h>
15+
#include <errno.h>
16+
617
#include <zephyr/bluetooth/bluetooth.h>
718
#include <zephyr/bluetooth/conn.h>
819
#include "../../lib/zephyr/subsys/bluetooth/host/conn_internal.h"
20+
#include "../../lib/zephyr/subsys/bluetooth/host/keys.h"
21+
22+
#include "py/mpconfig.h"
23+
#include "py/runtime.h"
24+
25+
#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
26+
#include "extmod/modbluetooth.h"
27+
#endif
28+
29+
#include "extmod/zephyr_ble/hal/zephyr_ble_settings.h"
30+
31+
#if ZEPHYR_BLE_DEBUG
32+
#define DEBUG_printf(...) mp_printf(&mp_plat_print, "BLE: " __VA_ARGS__)
33+
#else
34+
#define DEBUG_printf(...) do {} while (0)
35+
#endif
36+
37+
// Set to 1 to stub out bond key storage for isolation testing (Step 3)
38+
#ifndef ZEPHYR_BLE_SETTINGS_NOOP
39+
#define ZEPHYR_BLE_SETTINGS_NOOP 0
40+
#endif
41+
42+
// ---- Bond key storage (active when pairing/bonding enabled) ----
43+
44+
#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
45+
46+
int bt_settings_store_keys(uint8_t id, const bt_addr_le_t *addr,
47+
const void *value, size_t val_len) {
48+
#if ZEPHYR_BLE_SETTINGS_NOOP
49+
DEBUG_printf("<<< bt_settings_store_keys: NO-OP stub (isolation test)\n");
50+
return 0;
51+
#endif
52+
53+
// Build self-contained value blob: addr(7) + id(1) + keys_data(N)
54+
uint8_t buf[sizeof(bt_addr_le_t) + 1 + BT_KEYS_STORAGE_LEN];
55+
size_t total = sizeof(bt_addr_le_t) + 1 + val_len;
56+
if (total > sizeof(buf)) {
57+
DEBUG_printf("<<< bt_settings_store_keys: EINVAL total=%d > buf=%d\n",
58+
(int)total, (int)sizeof(buf));
59+
return -EINVAL;
60+
}
61+
memcpy(buf, addr, sizeof(bt_addr_le_t));
62+
buf[sizeof(bt_addr_le_t)] = id;
63+
memcpy(buf + sizeof(bt_addr_le_t) + 1, value, val_len);
64+
65+
bool result = mp_bluetooth_gap_on_set_secret(
66+
MP_BLUETOOTH_ZEPHYR_SECRET_KEYS,
67+
(const uint8_t *)addr, sizeof(bt_addr_le_t),
68+
buf, total);
69+
DEBUG_printf("<<< bt_settings_store_keys: set_secret returned %d\n", result);
70+
71+
if (!result) {
72+
return -EIO;
73+
}
74+
return 0;
75+
}
76+
77+
int bt_settings_delete_keys(uint8_t id, const bt_addr_le_t *addr) {
78+
DEBUG_printf(">>> bt_settings_delete_keys: addr=%02x:%02x:%02x:%02x:%02x:%02x id=%d\n",
79+
addr->a.val[5], addr->a.val[4], addr->a.val[3],
80+
addr->a.val[2], addr->a.val[1], addr->a.val[0], id);
81+
82+
#if ZEPHYR_BLE_SETTINGS_NOOP
83+
DEBUG_printf("<<< bt_settings_delete_keys: NO-OP stub (isolation test)\n");
84+
return 0;
85+
#endif
86+
87+
// Note: id is not included in the lookup key (only addr is used).
88+
// MicroPython only uses BT_ID_DEFAULT (0), so this is fine.
89+
// Multi-identity support would require including id in the key.
90+
(void)id;
91+
bool result = mp_bluetooth_gap_on_set_secret(
92+
MP_BLUETOOTH_ZEPHYR_SECRET_KEYS,
93+
(const uint8_t *)addr, sizeof(bt_addr_le_t),
94+
NULL, 0);
95+
DEBUG_printf("<<< bt_settings_delete_keys: set_secret returned %d\n", result);
96+
97+
if (!result) {
98+
return -EIO;
99+
}
100+
return 0;
101+
}
102+
103+
void mp_bluetooth_zephyr_load_keys(void) {
104+
#if ZEPHYR_BLE_SETTINGS_NOOP
105+
return;
106+
#endif
107+
108+
const uint8_t *value;
109+
size_t value_len;
110+
int loaded = 0;
111+
112+
for (uint8_t idx = 0; idx < CONFIG_BT_MAX_PAIRED; idx++) {
113+
if (!mp_bluetooth_gap_on_get_secret(
114+
MP_BLUETOOTH_ZEPHYR_SECRET_KEYS, idx,
115+
NULL, 0, // NULL key = enumerate by index
116+
&value, &value_len)) {
117+
break; // No more entries
118+
}
119+
120+
size_t min_len = sizeof(bt_addr_le_t) + 1;
121+
if (value_len < min_len) {
122+
continue; // Corrupted entry, skip
123+
}
9124

10-
// Stub: Store CCC (Client Characteristic Configuration) to settings
11-
int bt_settings_store_ccc(uint8_t id, const bt_addr_le_t *peer) {
125+
// Parse self-contained blob: addr(7) + id(1) + keys_data(N)
126+
const bt_addr_le_t *addr = (const bt_addr_le_t *)value;
127+
uint8_t id = value[sizeof(bt_addr_le_t)];
128+
const void *keys_data = value + sizeof(bt_addr_le_t) + 1;
129+
size_t keys_data_len = value_len - min_len;
130+
131+
// Allocate key slot and populate from stored data
132+
struct bt_keys *keys = bt_keys_get_addr(id, addr);
133+
if (keys && keys_data_len <= BT_KEYS_STORAGE_LEN) {
134+
memcpy(keys->storage_start, keys_data, keys_data_len);
135+
loaded++;
136+
}
137+
}
138+
}
139+
140+
#else // !MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
141+
142+
// No-op stubs when pairing/bonding is disabled
143+
int bt_settings_store_keys(uint8_t id, const bt_addr_le_t *addr,
144+
const void *value, size_t val_len) {
12145
(void)id;
13-
(void)peer;
14-
// Phase 1: RAM-only, no persistent storage
146+
(void)addr;
147+
(void)value;
148+
(void)val_len;
15149
return 0;
16150
}
17151

18-
// Stub: Store CF (Client Features) to settings
19-
int bt_settings_store_cf(uint8_t id, const bt_addr_le_t *peer) {
152+
int bt_settings_delete_keys(uint8_t id, const bt_addr_le_t *addr) {
20153
(void)id;
21-
(void)peer;
22-
// Phase 1: RAM-only, no persistent storage
154+
(void)addr;
23155
return 0;
24156
}
25157

26-
// Stub: Store database hash to settings
27-
int bt_settings_store_hash(void) {
28-
// Phase 1: RAM-only, no persistent storage
158+
#endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
159+
160+
// ---- Remaining stubs (no-op, correct signatures) ----
161+
162+
int bt_settings_store_ccc(uint8_t id, const bt_addr_le_t *addr,
163+
const void *value, size_t val_len) {
164+
(void)id;
165+
(void)addr;
166+
(void)value;
167+
(void)val_len;
29168
return 0;
30169
}
31170

32-
// Stub: Store bonding keys to settings
33-
int bt_settings_store_keys(const bt_addr_le_t *peer, uint8_t id) {
34-
(void)peer;
171+
int bt_settings_store_cf(uint8_t id, const bt_addr_le_t *addr,
172+
const void *value, size_t val_len) {
35173
(void)id;
36-
// Phase 1: RAM-only, no persistent key storage
174+
(void)addr;
175+
(void)value;
176+
(void)val_len;
177+
return 0;
178+
}
179+
180+
int bt_settings_store_hash(const void *value, size_t val_len) {
181+
(void)value;
182+
(void)val_len;
37183
return 0;
38184
}
39185

40-
// Stub: Decode settings key
41186
int bt_settings_decode_key(const char *key, bt_addr_le_t *addr) {
42187
(void)key;
43188
(void)addr;
44-
// Phase 1: No settings support
45-
return -1; // Error - key not found
189+
return -1;
46190
}
47191

48-
// Stub: Get next component of settings name
49192
int settings_name_next(const char *name, const char **next) {
50193
(void)name;
51194
(void)next;
52-
// Phase 1: No settings support
53-
return 0; // No more components
195+
return 0;
54196
}
55197

56-
// Stub: Delete CCC settings
57198
int bt_settings_delete_ccc(uint8_t id, const bt_addr_le_t *addr) {
58199
(void)id;
59200
(void)addr;
60201
return 0;
61202
}
62203

63-
// Stub: Delete CF settings
64204
int bt_settings_delete_cf(uint8_t id, const bt_addr_le_t *addr) {
65205
(void)id;
66206
(void)addr;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Zephyr BLE Settings — bond key storage via Python secret callbacks.
3+
*/
4+
5+
#ifndef MICROPY_INCLUDED_EXTMOD_ZEPHYR_BLE_HAL_SETTINGS_H
6+
#define MICROPY_INCLUDED_EXTMOD_ZEPHYR_BLE_HAL_SETTINGS_H
7+
8+
// Zephyr-specific secret type codes passed to _IRQ_GET_SECRET / _IRQ_SET_SECRET.
9+
// Type values are stack-specific (see modbluetooth.h) — these overlap with NimBLE's
10+
// type codes but the two stacks are never mixed in the same build.
11+
#define MP_BLUETOOTH_ZEPHYR_SECRET_KEYS 1 // Pairing/bonding keys
12+
13+
#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
14+
// Load stored bond keys from Python secret callbacks into Zephyr's key_pool[].
15+
// Called from mp_bluetooth_init() after bt_enable() succeeds.
16+
void mp_bluetooth_zephyr_load_keys(void);
17+
#endif
18+
19+
#endif // MICROPY_INCLUDED_EXTMOD_ZEPHYR_BLE_HAL_SETTINGS_H

extmod/zephyr_ble/zephyr_ble_config.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -973,8 +973,8 @@ int lll_csrand_get(void *buf, size_t len); // Controller crypto stub
973973
#define CONFIG_BT_CTLR_ADV_DATA_BUF_MAX 1 // Double-buffered advertising data
974974

975975
// --- LLCP Context Buffers ---
976-
#define CONFIG_BT_CTLR_LLCP_LOCAL_PROC_CTX_BUF_NUM 2
977-
#define CONFIG_BT_CTLR_LLCP_REMOTE_PROC_CTX_BUF_NUM 1
976+
#define CONFIG_BT_CTLR_LLCP_LOCAL_PROC_CTX_BUF_NUM 4
977+
#define CONFIG_BT_CTLR_LLCP_REMOTE_PROC_CTX_BUF_NUM 2
978978

979979
// --- Connection Scheduling ---
980980
#define CONFIG_BT_CTLR_CENTRAL_SPACING 625 // Min spacing between central events (us)

0 commit comments

Comments
 (0)