Skip to content

Commit bf45055

Browse files
jilu-otcarlescufi
authored andcommitted
Bluetooth: host: Save CCC data on pairing complete
Fixes issue #39989. Save CCC data on pairing complete by replacing private addresses for the just bonded device with its public address in CCC attributes' CFG arrays. This is then followed by calls to bt_gatt_store_ccc and bt_gatt_store_cf for the just bonded device. Signed-off-by: Jim Benjamin Luther <[email protected]>
1 parent ec0d878 commit bf45055

File tree

1 file changed

+109
-45
lines changed

1 file changed

+109
-45
lines changed

subsys/bluetooth/host/gatt.c

Lines changed: 109 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,103 @@ static ssize_t sf_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
868868
#endif /* CONFIG_BT_EATT */
869869
#endif /* CONFIG_BT_GATT_CACHING */
870870

871+
static int bt_gatt_store_cf(struct bt_conn *conn)
872+
{
873+
#if defined(CONFIG_BT_GATT_CACHING)
874+
struct gatt_cf_cfg *cfg;
875+
char key[BT_SETTINGS_KEY_MAX];
876+
char *str;
877+
size_t len;
878+
int err;
879+
880+
cfg = find_cf_cfg(conn);
881+
if (!cfg) {
882+
/* No cfg found, just clear it */
883+
BT_DBG("No config for CF");
884+
str = NULL;
885+
len = 0;
886+
} else {
887+
str = (char *)cfg->data;
888+
len = sizeof(cfg->data);
889+
890+
if (conn->id) {
891+
char id_str[4];
892+
893+
u8_to_dec(id_str, sizeof(id_str), conn->id);
894+
bt_settings_encode_key(key, sizeof(key), "cf",
895+
&conn->le.dst, id_str);
896+
}
897+
}
898+
899+
if (!cfg || !conn->id) {
900+
bt_settings_encode_key(key, sizeof(key), "cf",
901+
&conn->le.dst, NULL);
902+
}
903+
904+
err = settings_save_one(key, str, len);
905+
if (err) {
906+
BT_ERR("Failed to store Client Features (err %d)", err);
907+
return err;
908+
}
909+
910+
BT_DBG("Stored CF for %s (%s)", bt_addr_le_str(&conn->le.dst), log_strdup(key));
911+
#endif /* CONFIG_BT_GATT_CACHING */
912+
return 0;
913+
914+
}
915+
916+
#if defined(CONFIG_BT_SETTINGS) && defined(CONFIG_BT_SMP) && defined(CONFIG_BT_GATT_CLIENT)
917+
/** Struct used to store both the id and the random address of a device when replacing
918+
* random addresses in the ccc attribute's cfg array with the device's id address after
919+
* pairing complete.
920+
*/
921+
struct addr_match {
922+
const bt_addr_le_t *private_addr;
923+
const bt_addr_le_t *id_addr;
924+
};
925+
926+
static uint8_t convert_to_id_on_match(const struct bt_gatt_attr *attr,
927+
uint16_t handle, void *user_data)
928+
{
929+
struct _bt_gatt_ccc *ccc;
930+
struct addr_match *match = user_data;
931+
932+
/* Check if attribute is a CCC */
933+
if (attr->write != bt_gatt_attr_write_ccc) {
934+
return BT_GATT_ITER_CONTINUE;
935+
}
936+
937+
ccc = attr->user_data;
938+
939+
/* Copy the device's id address to the config's address if the config's address is the
940+
* same as the device's private address
941+
*/
942+
for (size_t i = 0; i < ARRAY_SIZE(ccc->cfg); i++) {
943+
if (bt_addr_le_cmp(&ccc->cfg[i].peer, match->private_addr) == 0) {
944+
bt_addr_le_copy(&ccc->cfg[i].peer, match->id_addr);
945+
}
946+
}
947+
948+
return BT_GATT_ITER_CONTINUE;
949+
}
950+
951+
static void bt_gatt_identity_resolved(struct bt_conn *conn, const bt_addr_le_t *private_addr,
952+
const bt_addr_le_t *id_addr)
953+
{
954+
/* Update the ccc cfg addresses */
955+
struct addr_match user_data = {
956+
.private_addr = private_addr,
957+
.id_addr = id_addr
958+
};
959+
960+
bt_gatt_foreach_attr(0x0001, 0xffff, convert_to_id_on_match, &user_data);
961+
962+
/* Store the ccc and cf data */
963+
bt_gatt_store_ccc(conn->id, &(conn->le.dst));
964+
bt_gatt_store_cf(conn);
965+
}
966+
#endif /* CONFIG_BT_SETTINGS && CONFIG_BT_SMP && CONFIG_BT_GATT_CLIENT */
967+
871968
BT_GATT_SERVICE_DEFINE(_1_gatt_svc,
872969
BT_GATT_PRIMARY_SERVICE(BT_UUID_GATT),
873970
#if defined(CONFIG_BT_GATT_SERVICE_CHANGED)
@@ -4991,6 +5088,18 @@ void bt_gatt_connected(struct bt_conn *conn)
49915088

49925089
#if defined(CONFIG_BT_GATT_CLIENT)
49935090
add_subscriptions(conn);
5091+
5092+
#if defined(CONFIG_BT_SETTINGS) && defined(CONFIG_BT_SMP)
5093+
static struct bt_conn_cb gatt_conn_cb = {
5094+
.identity_resolved = bt_gatt_identity_resolved,
5095+
};
5096+
5097+
/* Register the gatt module for connection callbacks so it can be
5098+
* notified when pairing has completed. This is used to enable CCC and
5099+
* CF storage on pairing complete.
5100+
*/
5101+
bt_conn_cb_register(&gatt_conn_cb);
5102+
#endif /* CONFIG_BT_SETTINGS && CONFIG_BT_SMP */
49945103
#endif /* CONFIG_BT_GATT_CLIENT */
49955104
}
49965105

@@ -5061,51 +5170,6 @@ bool bt_gatt_change_aware(struct bt_conn *conn, bool req)
50615170
#endif
50625171
}
50635172

5064-
static int bt_gatt_store_cf(struct bt_conn *conn)
5065-
{
5066-
#if defined(CONFIG_BT_GATT_CACHING)
5067-
struct gatt_cf_cfg *cfg;
5068-
char key[BT_SETTINGS_KEY_MAX];
5069-
char *str;
5070-
size_t len;
5071-
int err;
5072-
5073-
cfg = find_cf_cfg(conn);
5074-
if (!cfg) {
5075-
/* No cfg found, just clear it */
5076-
BT_DBG("No config for CF");
5077-
str = NULL;
5078-
len = 0;
5079-
} else {
5080-
str = (char *)cfg->data;
5081-
len = sizeof(cfg->data);
5082-
5083-
if (conn->id) {
5084-
char id_str[4];
5085-
5086-
u8_to_dec(id_str, sizeof(id_str), conn->id);
5087-
bt_settings_encode_key(key, sizeof(key), "cf",
5088-
&conn->le.dst, id_str);
5089-
}
5090-
}
5091-
5092-
if (!cfg || !conn->id) {
5093-
bt_settings_encode_key(key, sizeof(key), "cf",
5094-
&conn->le.dst, NULL);
5095-
}
5096-
5097-
err = settings_save_one(key, str, len);
5098-
if (err) {
5099-
BT_ERR("Failed to store Client Features (err %d)", err);
5100-
return err;
5101-
}
5102-
5103-
BT_DBG("Stored CF for %s (%s)", bt_addr_le_str(&conn->le.dst), log_strdup(key));
5104-
#endif /* CONFIG_BT_GATT_CACHING */
5105-
return 0;
5106-
5107-
}
5108-
51095173
static struct gatt_cf_cfg *find_cf_cfg_by_addr(uint8_t id,
51105174
const bt_addr_le_t *addr)
51115175
{

0 commit comments

Comments
 (0)