@@ -229,6 +229,7 @@ enum {
229229
230230#if defined(CONFIG_BT_GATT_CACHING )
231231 DB_HASH_VALID , /* Database hash needs to be calculated */
232+ DB_HASH_LOAD , /* Database hash loaded from settings. */
232233#endif
233234 /* Total number of flags - must be at the end of the enum */
234235 SC_NUM_FLAGS ,
@@ -248,6 +249,9 @@ static struct gatt_sc {
248249#if defined(CONFIG_BT_GATT_CACHING )
249250static struct db_hash {
250251 uint8_t hash [16 ];
252+ #if defined(CONFIG_BT_SETTINGS )
253+ uint8_t stored_hash [16 ];
254+ #endif
251255 struct k_work_delayable work ;
252256 struct k_work_sync sync ;
253257} db_hash ;
@@ -719,8 +723,44 @@ static void db_hash_gen(bool store)
719723 atomic_set_bit (gatt_sc .flags , DB_HASH_VALID );
720724}
721725
726+ #if defined(CONFIG_BT_SETTINGS )
727+ static void sc_indicate (uint16_t start , uint16_t end );
728+ #endif
729+
722730static void db_hash_process (struct k_work * work )
723731{
732+ #if defined(CONFIG_BT_SETTINGS )
733+ if (atomic_test_and_clear_bit (gatt_sc .flags , DB_HASH_LOAD )) {
734+ if (!atomic_test_bit (gatt_sc .flags , DB_HASH_VALID )) {
735+ db_hash_gen (false);
736+ }
737+
738+ /* Check if hash matches then skip SC update */
739+ if (!memcmp (db_hash .stored_hash , db_hash .hash ,
740+ sizeof (db_hash .stored_hash ))) {
741+ BT_DBG ("Database Hash matches" );
742+ k_work_cancel_delayable (& gatt_sc .work );
743+ atomic_clear_bit (gatt_sc .flags , SC_RANGE_CHANGED );
744+ return ;
745+ }
746+
747+ BT_HEXDUMP_DBG (db_hash .hash , sizeof (db_hash .hash ),
748+ "New Hash: " );
749+
750+ /* GATT database has been modified since last boot, likely due
751+ * to a firmware update or a dynamic service that was not
752+ * re-registered on boot.
753+ * Indicate Service Changed to all bonded devices for the full
754+ * database range to invalidate client-side cache and force
755+ * discovery on reconnect.
756+ */
757+ sc_indicate (0x0001 , 0xffff );
758+
759+ /* Hash did not match, overwrite with current hash */
760+ db_hash_store ();
761+ return ;
762+ }
763+ #endif /* defined(CONFIG_BT_SETTINGS) */
724764 db_hash_gen (true);
725765}
726766
@@ -5147,58 +5187,30 @@ static int cf_set(const char *name, size_t len_rd, settings_read_cb read_cb,
51475187
51485188SETTINGS_STATIC_HANDLER_DEFINE (bt_cf , "bt/cf" , NULL , cf_set , NULL , NULL );
51495189
5150- static uint8_t stored_hash [16 ];
5151-
51525190static int db_hash_set (const char * name , size_t len_rd ,
51535191 settings_read_cb read_cb , void * cb_arg )
51545192{
51555193 ssize_t len ;
51565194
5157- len = read_cb (cb_arg , stored_hash , sizeof (stored_hash ));
5195+ len = read_cb (cb_arg , db_hash . stored_hash , sizeof (db_hash . stored_hash ));
51585196 if (len < 0 ) {
51595197 BT_ERR ("Failed to decode value (err %zd)" , len );
51605198 return len ;
51615199 }
51625200
5163- BT_HEXDUMP_DBG (stored_hash , sizeof (stored_hash ), "Stored Hash: " );
5201+ BT_HEXDUMP_DBG (db_hash .stored_hash , sizeof (db_hash .stored_hash ),
5202+ "Stored Hash: " );
51645203
51655204 return 0 ;
51665205}
51675206
51685207static int db_hash_commit (void )
51695208{
5170-
5171- k_sched_lock ();
5172-
5173- /* Stop work and generate the hash */
5174- (void )k_work_cancel_delayable_sync (& db_hash .work , & db_hash .sync );
5175- if (!atomic_test_bit (gatt_sc .flags , DB_HASH_VALID )) {
5176- db_hash_gen (false);
5177- }
5178-
5179- k_sched_unlock ();
5180-
5181- /* Check if hash matches then skip SC update */
5182- if (!memcmp (stored_hash , db_hash .hash , sizeof (stored_hash ))) {
5183- BT_DBG ("Database Hash matches" );
5184- k_work_cancel_delayable (& gatt_sc .work );
5185- atomic_clear_bit (gatt_sc .flags , SC_RANGE_CHANGED );
5186- return 0 ;
5187- }
5188-
5189- BT_HEXDUMP_DBG (db_hash .hash , sizeof (db_hash .hash ), "New Hash: " );
5190-
5191- /**
5192- * GATT database has been modified since last boot, likely due to
5193- * a firmware update or a dynamic service that was not re-registered on
5194- * boot. Indicate Service Changed to all bonded devices for the full
5195- * database range to invalidate client-side cache and force discovery on
5196- * reconnect.
5209+ atomic_set_bit (gatt_sc .flags , DB_HASH_LOAD );
5210+ /* Reschedule work to calculate and compare against the Hash value
5211+ * loaded from flash.
51975212 */
5198- sc_indicate (0x0001 , 0xffff );
5199-
5200- /* Hash did not match overwrite with current hash */
5201- db_hash_store ();
5213+ k_work_reschedule (& db_hash .work , K_NO_WAIT );
52025214
52035215 return 0 ;
52045216}
0 commit comments