|
1 | 1 | /* |
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. |
4 | 12 | */ |
5 | 13 |
|
| 14 | +#include <string.h> |
| 15 | +#include <errno.h> |
| 16 | + |
6 | 17 | #include <zephyr/bluetooth/bluetooth.h> |
7 | 18 | #include <zephyr/bluetooth/conn.h> |
8 | 19 | #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 | + } |
9 | 124 |
|
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) { |
12 | 145 | (void)id; |
13 | | - (void)peer; |
14 | | - // Phase 1: RAM-only, no persistent storage |
| 146 | + (void)addr; |
| 147 | + (void)value; |
| 148 | + (void)val_len; |
15 | 149 | return 0; |
16 | 150 | } |
17 | 151 |
|
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) { |
20 | 153 | (void)id; |
21 | | - (void)peer; |
22 | | - // Phase 1: RAM-only, no persistent storage |
| 154 | + (void)addr; |
23 | 155 | return 0; |
24 | 156 | } |
25 | 157 |
|
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; |
29 | 168 | return 0; |
30 | 169 | } |
31 | 170 |
|
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) { |
35 | 173 | (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; |
37 | 183 | return 0; |
38 | 184 | } |
39 | 185 |
|
40 | | -// Stub: Decode settings key |
41 | 186 | int bt_settings_decode_key(const char *key, bt_addr_le_t *addr) { |
42 | 187 | (void)key; |
43 | 188 | (void)addr; |
44 | | - // Phase 1: No settings support |
45 | | - return -1; // Error - key not found |
| 189 | + return -1; |
46 | 190 | } |
47 | 191 |
|
48 | | -// Stub: Get next component of settings name |
49 | 192 | int settings_name_next(const char *name, const char **next) { |
50 | 193 | (void)name; |
51 | 194 | (void)next; |
52 | | - // Phase 1: No settings support |
53 | | - return 0; // No more components |
| 195 | + return 0; |
54 | 196 | } |
55 | 197 |
|
56 | | -// Stub: Delete CCC settings |
57 | 198 | int bt_settings_delete_ccc(uint8_t id, const bt_addr_le_t *addr) { |
58 | 199 | (void)id; |
59 | 200 | (void)addr; |
60 | 201 | return 0; |
61 | 202 | } |
62 | 203 |
|
63 | | -// Stub: Delete CF settings |
64 | 204 | int bt_settings_delete_cf(uint8_t id, const bt_addr_le_t *addr) { |
65 | 205 | (void)id; |
66 | 206 | (void)addr; |
|
0 commit comments