@@ -115,6 +115,18 @@ typedef struct _mp_btstack_active_connection_t {
115
115
uint32_t last_encryption_update ;
116
116
} mp_btstack_active_connection_t ;
117
117
118
+ #endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
119
+
120
+ #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
121
+ // Encryption state tracking to prevent duplicate events
122
+ typedef struct _encryption_state_cache_t {
123
+ btstack_linked_item_t * next ; // Must be first field to match btstack_linked_item.
124
+
125
+ uint16_t conn_handle ;
126
+ bool is_encrypted ;
127
+ uint32_t last_update_ms ;
128
+ } encryption_state_cache_t ;
129
+
118
130
static mp_btstack_active_connection_t * create_active_connection (uint16_t conn_handle ) {
119
131
DEBUG_printf ("create_active_connection: conn_handle=%d\n" , conn_handle );
120
132
mp_btstack_active_connection_t * conn = m_new (mp_btstack_active_connection_t , 1 );
@@ -160,6 +172,60 @@ static void remove_active_connection(uint16_t conn_handle) {
160
172
}
161
173
#endif
162
174
175
+ #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
176
+ // Encryption state management functions
177
+ static encryption_state_cache_t * find_encryption_state (uint16_t conn_handle ) {
178
+ btstack_linked_list_iterator_t it ;
179
+ btstack_linked_list_iterator_init (& it , & MP_STATE_PORT (bluetooth_btstack_root_pointers )-> encryption_states );
180
+ encryption_state_cache_t * state = NULL ;
181
+ while (btstack_linked_list_iterator_has_next (& it )) {
182
+ state = (encryption_state_cache_t * )btstack_linked_list_iterator_next (& it );
183
+ if (state -> conn_handle == conn_handle ) {
184
+ return state ;
185
+ }
186
+ }
187
+ return NULL ;
188
+ }
189
+
190
+ static encryption_state_cache_t * get_or_create_encryption_state (uint16_t conn_handle ) {
191
+ encryption_state_cache_t * state = find_encryption_state (conn_handle );
192
+ if (!state ) {
193
+ state = m_new (encryption_state_cache_t , 1 );
194
+ state -> conn_handle = conn_handle ;
195
+ state -> is_encrypted = false;
196
+ state -> last_update_ms = 0 ;
197
+ btstack_linked_list_add (& MP_STATE_PORT (bluetooth_btstack_root_pointers )-> encryption_states , (btstack_linked_item_t * )state );
198
+ }
199
+ return state ;
200
+ }
201
+
202
+ static void remove_encryption_state (uint16_t conn_handle ) {
203
+ encryption_state_cache_t * state = find_encryption_state (conn_handle );
204
+ if (state ) {
205
+ btstack_linked_list_remove (& MP_STATE_PORT (bluetooth_btstack_root_pointers )-> encryption_states , (btstack_linked_item_t * )state );
206
+ m_del (encryption_state_cache_t , state , 1 );
207
+ }
208
+ }
209
+
210
+ static bool should_forward_encryption_event (uint16_t conn_handle , bool is_encrypted ) {
211
+ encryption_state_cache_t * state = get_or_create_encryption_state (conn_handle );
212
+ uint32_t current_time = mp_hal_ticks_ms ();
213
+
214
+ // Check if state has actually changed
215
+ if (state -> is_encrypted == is_encrypted ) {
216
+ // State hasn't changed - check if enough time has passed to allow duplicate
217
+ if (current_time - state -> last_update_ms < 1000 ) { // 1 second minimum
218
+ return false; // Suppress duplicate event
219
+ }
220
+ }
221
+
222
+ // Update state and timestamp
223
+ state -> is_encrypted = is_encrypted ;
224
+ state -> last_update_ms = current_time ;
225
+ return true; // Forward the event
226
+ }
227
+ #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
228
+
163
229
// This needs to be separate to btstack_packet_handler otherwise we get
164
230
// dual-delivery of the HCI_EVENT_LE_META event.
165
231
static void btstack_packet_handler_att_server (uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) {
@@ -339,8 +405,14 @@ static void btstack_packet_handler_generic(uint8_t packet_type, uint16_t channel
339
405
}
340
406
#endif
341
407
342
- mp_bluetooth_gatts_on_encryption_update (conn_handle ,
343
- encrypted , authenticated , bonded , desc -> sm_actual_encryption_key_size );
408
+ // Use encryption state cache to prevent duplicate events
409
+ if (should_forward_encryption_event (conn_handle , encrypted )) {
410
+ DEBUG_printf (" --> forwarding encryption event: encrypted=%d, authenticated=%d, bonded=%d\n" , encrypted , authenticated , bonded );
411
+ mp_bluetooth_gatts_on_encryption_update (conn_handle ,
412
+ encrypted , authenticated , bonded , desc -> sm_actual_encryption_key_size );
413
+ } else {
414
+ DEBUG_printf (" --> suppressing duplicate encryption event for conn_handle=%d\n" , conn_handle );
415
+ }
344
416
} else if (event_type == SM_EVENT_PASSKEY_DISPLAY_NUMBER ) {
345
417
mp_bluetooth_gap_on_passkey_action (sm_event_passkey_display_number_get_handle (packet ), MP_BLUETOOTH_PASSKEY_ACTION_DISPLAY , sm_event_passkey_display_number_get_passkey (packet ));
346
418
} else if (event_type == SM_EVENT_PASSKEY_INPUT_NUMBER ) {
@@ -365,6 +437,9 @@ static void btstack_packet_handler_generic(uint8_t packet_type, uint16_t channel
365
437
#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
366
438
remove_active_connection (conn_handle );
367
439
#endif
440
+ #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
441
+ remove_encryption_state (conn_handle );
442
+ #endif
368
443
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
369
444
} else if (event_type == GAP_EVENT_ADVERTISING_REPORT ) {
370
445
DEBUG_printf (" --> gap advertising report\n" );
@@ -712,18 +787,7 @@ int mp_bluetooth_init(void) {
712
787
le_device_db_init ();
713
788
sm_init ();
714
789
715
- // Set cryptographically secure ER/IR keys for bonding
716
- #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
717
- // Use port-specific secure key generation
718
- extern void mp_bluetooth_btstack_port_set_er_ir_keys (void );
719
- mp_bluetooth_btstack_port_set_er_ir_keys ();
720
- #else
721
- // Set blank ER/IR keys to suppress BTstack warning when pairing is disabled
722
- sm_key_t dummy_key ;
723
- memset (dummy_key , 0 , sizeof (dummy_key ));
724
- sm_set_er (dummy_key );
725
- sm_set_ir (dummy_key );
726
- #endif
790
+ // BTstack will automatically generate and store ER/IR keys via TLV when pairing is enabled
727
791
728
792
#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
729
793
gatt_client_init ();
0 commit comments