diff --git a/nimble/host/include/host/ble_store.h b/nimble/host/include/host/ble_store.h index 83b1c4f15f..1db5524629 100644 --- a/nimble/host/include/host/ble_store.h +++ b/nimble/host/include/host/ble_store.h @@ -29,6 +29,7 @@ #include #include "nimble/ble.h" +#include "../../host/src/ble_gatt_priv.h" #ifdef __cplusplus extern "C" { @@ -40,13 +41,16 @@ extern "C" { * @{ */ /** Object type: Our security material. */ -#define BLE_STORE_OBJ_TYPE_OUR_SEC 1 +#define BLE_STORE_OBJ_TYPE_OUR_SEC 1 /** Object type: Peer security material. */ -#define BLE_STORE_OBJ_TYPE_PEER_SEC 2 +#define BLE_STORE_OBJ_TYPE_PEER_SEC 2 /** Object type: Client Characteristic Configuration Descriptor. */ -#define BLE_STORE_OBJ_TYPE_CCCD 3 +#define BLE_STORE_OBJ_TYPE_CCCD 3 + +/** Object type: Peer Client Supported Features. */ +#define BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT 4 /** @} */ @@ -154,6 +158,33 @@ struct ble_store_value_cccd { unsigned value_changed:1; }; +/** + * Used as a key for lookups of stored client supported features of specific + * peer. This struct corresponds to the BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT + * store object type. + */ +struct ble_store_key_cl_sup_feat { + /** + * Key by peer identity address; + * peer_addr=BLE_ADDR_NONE means don't key off peer. + */ + ble_addr_t peer_addr; + + /** Number of results to skip; 0 means retrieve the first match. */ + uint8_t idx; +}; + +/** + * Represents a stored client supported features of specific peer. This struct + * corresponds to the BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT store object type. + */ +struct ble_store_value_cl_sup_feat { + /** The peer address associated with the stored supported features. */ + ble_addr_t peer_addr; + /** Client supported features of a specific peer. */ + uint8_t peer_cl_sup_feat[BLE_GATT_CHR_CLI_SUP_FEAT_SZ]; +}; + /** * Used as a key for store lookups. This union must be accompanied by an * object type code to indicate which field is valid. @@ -163,6 +194,8 @@ union ble_store_key { struct ble_store_key_sec sec; /** Key for Client Characteristic Configuration Descriptor store lookups. */ struct ble_store_key_cccd cccd; + /** Key for Peer Client Supported Features store lookpus. */ + struct ble_store_key_cl_sup_feat feat; }; /** @@ -174,6 +207,8 @@ union ble_store_value { struct ble_store_value_sec sec; /** Stored Client Characteristic Configuration Descriptor. */ struct ble_store_value_cccd cccd; + /** Stored Client Supported Features. */ + struct ble_store_value_cl_sup_feat feat; }; /** Represents an event associated with the BLE Store. */ @@ -556,6 +591,60 @@ int ble_store_write_cccd(const struct ble_store_value_cccd *value); */ int ble_store_delete_cccd(const struct ble_store_key_cccd *key); +/** + * @brief Reads Client Supported Features value from a storage + * + * This function reads client supported features value from a storage based + * on the provied key and stores the retrieved value in the specified output + * structure. + * + * @param key A pointer to a 'ble_store_key_cl_sup_feat' + * struct representing the key to identify + * Client Supported Features value to be read. + * @param out_value A pointer to a 'ble_store_value_cl_sup_feat' + * struct to store the Client Supported + * Features value read from a storage + * + * @return 0 if the Client Supported Features values was + * successfully read and stored in the + * 'out_value' structure; + * Non-zero on error + */ +int ble_store_read_peer_cl_sup_feat(const struct ble_store_key_cl_sup_feat *key, + struct ble_store_value_cl_sup_feat *out_value); + +/** + * @brief Writes a Client Supported Features value to a storage. + * + * This function writes a Client Supported Features value to a storage based on + * the provided value + * + * @param value A pointer to a 'ble_store_value_cl_sup_feat' + * structure representing the Client Supported + * Features value to be written to a storage. + * + * @return 0 if the value was successfully written to + * a storage; + * Non-zero on error. + */ +int ble_store_write_peer_cl_sup_feat(const struct ble_store_value_cl_sup_feat *value); + +/** + * @brief Deletes a Client Supported Features value from a storage. + * + * This function deletes a Client Supported Features value from a storage based + * on the provided key. + * + * @param key A pointer to a 'ble_store_key_cl_sup_feat' + * structure identifying the Client Supported + * Features value to be deleted from + * a storage. + * + * @return 0 if the Client Supported Features value was + * successfully written to a storage; + * Non-zero on error. + */ +int ble_store_delete_peer_cl_sup_feat(const struct ble_store_key_cl_sup_feat *key); /** * @brief Generates a storage key for a security material entry from its value. @@ -587,6 +676,24 @@ void ble_store_key_from_value_sec(struct ble_store_key_sec *out_key, void ble_store_key_from_value_cccd(struct ble_store_key_cccd *out_key, const struct ble_store_value_cccd *value); +/** + * @brief Generates a storage key for a Client Supported Features entry from + * its value + * + * This function generates a storage key for a Client Supported Features value + * entry based on the provided value. + * + * @param out_key A pointer to a 'ble_store_key_cl_sup_feat' + * structure where the generated key will be + * stored. + * @param value A pointer to a 'ble_store_value_cl_sup_feat' + * structure containing the Client Supported + * Features value from which the key will be + * generated. + */ +void ble_store_key_from_value_peer_cl_sup_feat( + struct ble_store_key_cl_sup_feat *out_key, + const struct ble_store_value_cl_sup_feat *value); /** * @brief Generates a storage key from a value based on the object type. diff --git a/nimble/host/src/ble_gatts.c b/nimble/host/src/ble_gatts.c index 6c3ae19de9..578a2be32d 100644 --- a/nimble/host/src/ble_gatts.c +++ b/nimble/host/src/ble_gatts.c @@ -1612,6 +1612,8 @@ int ble_gatts_peer_cl_sup_feat_get(uint16_t conn_handle, uint8_t *out_supported_feat, uint8_t len) { struct ble_hs_conn *conn; + struct ble_store_key_cl_sup_feat feat_key; + struct ble_store_value_cl_sup_feat feat_val; int rc = 0; if (out_supported_feat == NULL) { @@ -1629,8 +1631,15 @@ ble_gatts_peer_cl_sup_feat_get(uint16_t conn_handle, uint8_t *out_supported_feat len = BLE_GATT_CHR_CLI_SUP_FEAT_SZ; } - memcpy(out_supported_feat, conn->bhc_gatt_svr.peer_cl_sup_feat, - sizeof(uint8_t) * len); + if (conn->bhc_sec_state.bonded) { + feat_key.peer_addr = conn->bhc_peer_addr; + feat_key.idx = 0; + ble_store_read_peer_cl_sup_feat(&feat_key, &feat_val); + memcpy(out_supported_feat, feat_val.peer_cl_sup_feat, sizeof(uint8_t) * len); + } else { + memcpy(out_supported_feat, conn->bhc_gatt_svr.peer_cl_sup_feat, + sizeof(uint8_t) * len); + } done: ble_hs_unlock(); @@ -1641,6 +1650,9 @@ int ble_gatts_peer_cl_sup_feat_update(uint16_t conn_handle, struct os_mbuf *om) { struct ble_hs_conn *conn; + struct ble_store_value_cl_sup_feat store_feat; + struct ble_store_key_cl_sup_feat feat_key; + struct ble_store_value_cl_sup_feat feat_val; uint8_t feat[BLE_GATT_CHR_CLI_SUP_FEAT_SZ] = {}; uint16_t len; int rc = 0; @@ -1686,6 +1698,32 @@ ble_gatts_peer_cl_sup_feat_update(uint16_t conn_handle, struct os_mbuf *om) memcpy(conn->bhc_gatt_svr.peer_cl_sup_feat, feat, BLE_GATT_CHR_CLI_SUP_FEAT_SZ); + if (conn->bhc_sec_state.bonded) { + feat_key.peer_addr = conn->bhc_peer_addr; + rc = ble_store_read_peer_cl_sup_feat(&feat_key, &feat_val); + if (rc == BLE_HS_ENOENT) { + /* Assume the values were not stored yet */ + store_feat.peer_addr = conn->bhc_peer_addr; + memcpy(store_feat.peer_cl_sup_feat, feat, BLE_GATT_CHR_CLI_SUP_FEAT_SZ); + if (ble_store_write_peer_cl_sup_feat(&store_feat)) { + /* XXX: Should error get reported? */ + } + rc = 0; + goto done; + } + if (rc == 0) { + /* Found cl_sup_feat for this peer, check for disabling already + * enabled features */ + for (i = 0; i < BLE_GATT_CHR_CLI_SUP_FEAT_SZ; i++) { + if ((feat_val.peer_cl_sup_feat[i] & feat[i]) != + feat_val.peer_cl_sup_feat[i]) { + rc = BLE_ATT_ERR_VALUE_NOT_ALLOWED; + goto done; + } + } + } + } + done: ble_hs_unlock(); return rc; diff --git a/nimble/host/src/ble_store.c b/nimble/host/src/ble_store.c index 79b2f7b95e..e0070ad2b1 100644 --- a/nimble/host/src/ble_store.c +++ b/nimble/host/src/ble_store.c @@ -249,6 +249,42 @@ ble_store_write_peer_sec(const struct ble_store_value_sec *value_sec) return 0; } +int +ble_store_read_peer_cl_sup_feat(const struct ble_store_key_cl_sup_feat *key, + struct ble_store_value_cl_sup_feat *out_value) +{ + union ble_store_value *store_value; + union ble_store_key *store_key; + int rc; + + store_key = (void *)key; + store_value = (void *)out_value; + rc = ble_store_read(BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT, store_key, store_value); + return rc; +} + +int +ble_store_write_peer_cl_sup_feat(const struct ble_store_value_cl_sup_feat *value) +{ + union ble_store_value *store_value; + int rc; + + store_value = (void *)value; + rc = ble_store_write(BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT, store_value); + return rc; +} + +int +ble_store_delete_peer_cl_sup_feat(const struct ble_store_key_cl_sup_feat *key) +{ + union ble_store_key *store_key; + int rc; + + store_key = (void *)key; + rc = ble_store_delete(BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT, store_key); + return rc; +} + int ble_store_read_cccd(const struct ble_store_key_cccd *key, struct ble_store_value_cccd *out_value) @@ -302,6 +338,14 @@ ble_store_key_from_value_sec(struct ble_store_key_sec *out_key, out_key->idx = 0; } +void +ble_store_key_from_value_peer_cl_sup_feat(struct ble_store_key_cl_sup_feat *out_key, + const struct ble_store_value_cl_sup_feat *value) +{ + out_key->peer_addr = value->peer_addr; + out_key->idx = 0; +} + void ble_store_key_from_value(int obj_type, union ble_store_key *out_key, @@ -317,6 +361,9 @@ ble_store_key_from_value(int obj_type, ble_store_key_from_value_cccd(&out_key->cccd, &value->cccd); break; + case BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT: + ble_store_key_from_value_peer_cl_sup_feat(&out_key->feat, &value->feat); + default: BLE_HS_DBG_ASSERT(0); break; @@ -346,6 +393,10 @@ ble_store_iterate(int obj_type, key.cccd.peer_addr = *BLE_ADDR_ANY; pidx = &key.cccd.idx; break; + case BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT: + key.feat.peer_addr = *BLE_ADDR_ANY; + pidx = &key.feat.idx; + break; default: BLE_HS_DBG_ASSERT(0); return BLE_HS_EINVAL; @@ -390,6 +441,7 @@ ble_store_clear(void) BLE_STORE_OBJ_TYPE_OUR_SEC, BLE_STORE_OBJ_TYPE_PEER_SEC, BLE_STORE_OBJ_TYPE_CCCD, + BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT, }; union ble_store_key key; int obj_type; diff --git a/nimble/host/src/ble_store_util.c b/nimble/host/src/ble_store_util.c index 6dcbca25a1..7c04868331 100644 --- a/nimble/host/src/ble_store_util.c +++ b/nimble/host/src/ble_store_util.c @@ -109,6 +109,14 @@ ble_store_util_delete_peer(const ble_addr_t *peer_id_addr) return rc; } + memset(&key, 0, sizeof key); + key.feat.peer_addr = *peer_id_addr; + + rc = ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT, &key); + if (rc != 0) { + return rc; + } + return 0; } @@ -192,6 +200,7 @@ ble_store_util_status_rr(struct ble_store_status_event *event, void *arg) switch (event->overflow.obj_type) { case BLE_STORE_OBJ_TYPE_OUR_SEC: case BLE_STORE_OBJ_TYPE_PEER_SEC: + case BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT: return ble_gap_unpair_oldest_peer(); case BLE_STORE_OBJ_TYPE_CCCD: /* Try unpairing oldest peer except current peer */ diff --git a/nimble/host/store/config/src/ble_store_config.c b/nimble/host/store/config/src/ble_store_config.c index 741c73a5f5..80cd8ac20d 100644 --- a/nimble/host/store/config/src/ble_store_config.c +++ b/nimble/host/store/config/src/ble_store_config.c @@ -47,6 +47,12 @@ struct ble_store_value_cccd int ble_store_config_num_cccds; +#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS) +struct ble_store_value_cl_sup_feat ble_store_config_feats[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; +#endif + +int ble_store_config_num_feats; + /***************************************************************************** * $sec * *****************************************************************************/ @@ -447,6 +453,120 @@ ble_store_config_write_cccd(const struct ble_store_value_cccd *value_cccd) #endif } +/***************************************************************************** + * $cl_sup_feat * + *****************************************************************************/ + +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) +static int +ble_store_config_find_cl_sup_feat(const struct ble_store_key_cl_sup_feat *key) +{ + struct ble_store_value_cl_sup_feat *feat; + int skipped; + int i; + + skipped = 0; + for (i = 0; i < ble_store_config_num_feats; i++) { + feat = ble_store_config_feats + i; + + if (ble_addr_cmp(&key->peer_addr, BLE_ADDR_ANY)) { + if (ble_addr_cmp(&feat->peer_addr, &key->peer_addr)) { + continue; + } + } + + if (key->idx > skipped) { + skipped++; + continue; + } + + return i; + } + return -1; +} +#endif + +static int +ble_store_config_delete_cl_sup_feat(const struct ble_store_key_cl_sup_feat *key_feat) +{ +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) + int idx; + int rc; + + idx = ble_store_config_find_cl_sup_feat(key_feat); + if (idx < 0) { + return BLE_HS_ENOENT; + } + + assert(ble_store_config_num_feats < ARRAY_SIZE(ble_store_config_feats)); + rc = ble_store_config_delete_obj(ble_store_config_feats, + sizeof *ble_store_config_feats, idx, + &ble_store_config_num_feats); + if (rc != 0) { + return rc; + } + + rc = ble_store_config_persist_feats(); + if (rc != 0) { + return rc; + } + return 0; +#else + return BLE_HS_ENOENT; +#endif +} + +static int +ble_store_config_read_cl_sup_feat(const struct ble_store_key_cl_sup_feat *key_feat, + struct ble_store_value_cl_sup_feat *value_feat) +{ +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) + int idx; + + idx = ble_store_config_find_cl_sup_feat(key_feat); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + *value_feat = ble_store_config_feats[idx]; + return 0; +#else + return BLE_HS_ENOENT; +#endif +} + +static int +ble_store_config_write_cl_sup(const struct ble_store_value_cl_sup_feat *value_feat) +{ +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) + struct ble_store_key_cl_sup_feat key_feat; + int idx; + int rc; + + ble_store_key_from_value_peer_cl_sup_feat(&key_feat, value_feat); + idx = ble_store_config_find_cl_sup_feat(&key_feat); + if (idx == -1) { + if (ble_store_config_num_feats >= MYNEWT_VAL(BLE_STORE_MAX_BONDS)) { + return BLE_HS_ESTORE_CAP; + } + + idx = ble_store_config_num_feats; + ble_store_config_num_feats++; + } + + ble_store_config_feats[idx] = *value_feat; + + rc = ble_store_config_persist_feats(); + if (rc != 0) { + return rc; + } + + return 0; +#else + return BLE_HS_ENOENT; +#endif +} + /***************************************************************************** * $api * *****************************************************************************/ @@ -489,6 +609,10 @@ ble_store_config_read(int obj_type, const union ble_store_key *key, rc = ble_store_config_read_cccd(&key->cccd, &value->cccd); return rc; + case BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT: + rc = ble_store_config_read_cl_sup_feat(&key->feat, &value->feat); + return rc; + default: return BLE_HS_ENOTSUP; } @@ -518,6 +642,10 @@ ble_store_config_write(int obj_type, const union ble_store_value *val) rc = ble_store_config_write_cccd(&val->cccd); return rc; + case BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT: + rc = ble_store_config_write_cl_sup(&val->feat); + return rc; + default: return BLE_HS_ENOTSUP; } @@ -541,6 +669,10 @@ ble_store_config_delete(int obj_type, const union ble_store_key *key) rc = ble_store_config_delete_cccd(&key->cccd); return rc; + case BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT: + rc = ble_store_config_delete_cl_sup_feat(&key->feat); + return rc; + default: return BLE_HS_ENOTSUP; } @@ -560,6 +692,7 @@ ble_store_config_init(void) ble_store_config_num_our_secs = 0; ble_store_config_num_peer_secs = 0; ble_store_config_num_cccds = 0; + ble_store_config_num_feats = 0; ble_store_config_conf_init(); } diff --git a/nimble/host/store/config/src/ble_store_config_conf.c b/nimble/host/store/config/src/ble_store_config_conf.c index e74127ae93..43c4a00fb6 100644 --- a/nimble/host/store/config/src/ble_store_config_conf.c +++ b/nimble/host/store/config/src/ble_store_config_conf.c @@ -57,6 +57,12 @@ static struct conf_handler ble_store_config_conf_handler = { #define BLE_STORE_CONFIG_CCCD_SET_ENCODE_SZ \ (MYNEWT_VAL(BLE_STORE_MAX_CCCDS) * BLE_STORE_CONFIG_CCCD_ENCODE_SZ + 1) +#define BLE_STORE_CONFIG_CL_SUP_FEAT_ENCODE_SZ \ + BASE64_ENCODE_SIZE(sizeof(struct ble_store_value_cl_sup_feat)) + +#define BLE_STORE_CONFIG_CL_SUP_FEAT_SET_ENCODE_SZ \ + (MYNEWT_VAL(BLE_STORE_MAX_BONDS) * BLE_STORE_CONFIG_CL_SUP_FEAT_ENCODE_SZ + 1) + static void ble_store_config_serialize_arr(const void *arr, int obj_sz, int num_objs, char *out_buf, int buf_sz) @@ -113,6 +119,11 @@ ble_store_config_conf_set(int argc, char **argv, char *val) sizeof *ble_store_config_cccds, &ble_store_config_num_cccds); return rc; + } else if (strcmp(argv[0], "feat") == 0) { + rc = ble_store_config_deserialize_arr(val, ble_store_config_feats, + sizeof *ble_store_config_feats, + &ble_store_config_num_feats); + return rc; } } return OS_ENOENT; @@ -125,6 +136,7 @@ ble_store_config_conf_export(void (*func)(char *name, char *val), union { char sec[BLE_STORE_CONFIG_SEC_SET_ENCODE_SZ]; char cccd[BLE_STORE_CONFIG_CCCD_SET_ENCODE_SZ]; + char feat[BLE_STORE_CONFIG_CL_SUP_FEAT_SET_ENCODE_SZ]; } buf; ble_store_config_serialize_arr(ble_store_config_our_secs, @@ -148,6 +160,11 @@ ble_store_config_conf_export(void (*func)(char *name, char *val), sizeof buf.cccd); func("ble_hs/cccd", buf.cccd); + ble_store_config_serialize_arr( + ble_store_config_feats, sizeof *ble_store_config_feats, + ble_store_config_num_feats, buf.feat, sizeof buf.feat); + func("ble_hs/feat", buf.feat); + return 0; } @@ -218,6 +235,23 @@ ble_store_config_persist_cccds(void) return 0; } +int +ble_store_config_persist_feats(void) +{ + char buf[BLE_STORE_CONFIG_CL_SUP_FEAT_SET_ENCODE_SZ]; + int rc; + + ble_store_config_serialize_arr(ble_store_config_feats, + sizeof *ble_store_config_feats, + ble_store_config_num_feats, buf, sizeof buf); + rc = conf_save_one("ble_hs/feat", buf); + if (rc != 0) { + return BLE_HS_ESTORE_FAIL; + } + + return 0; +} + void ble_store_config_conf_init(void) { diff --git a/nimble/host/store/config/src/ble_store_config_priv.h b/nimble/host/store/config/src/ble_store_config_priv.h index bae90e9765..d86d039f11 100644 --- a/nimble/host/store/config/src/ble_store_config_priv.h +++ b/nimble/host/store/config/src/ble_store_config_priv.h @@ -36,11 +36,15 @@ extern struct ble_store_value_cccd ble_store_config_cccds[MYNEWT_VAL(BLE_STORE_MAX_CCCDS)]; extern int ble_store_config_num_cccds; +extern struct ble_store_value_cl_sup_feat ble_store_config_feats[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; +extern int ble_store_config_num_feats; + #if MYNEWT_VAL(BLE_STORE_CONFIG_PERSIST) int ble_store_config_persist_our_secs(void); int ble_store_config_persist_peer_secs(void); int ble_store_config_persist_cccds(void); +int ble_store_config_persist_feats(void); void ble_store_config_conf_init(void); #else @@ -48,6 +52,11 @@ void ble_store_config_conf_init(void); static inline int ble_store_config_persist_our_secs(void) { return 0; } static inline int ble_store_config_persist_peer_secs(void) { return 0; } static inline int ble_store_config_persist_cccds(void) { return 0; } +static inline int +ble_store_config_persist_feats(void) +{ + return 0; +} static inline void ble_store_config_conf_init(void) { } #endif /* MYNEWT_VAL(BLE_STORE_CONFIG_PERSIST) */ diff --git a/nimble/host/store/ram/src/ble_store_ram.c b/nimble/host/store/ram/src/ble_store_ram.c index 9359f6d399..f16461a003 100644 --- a/nimble/host/store/ram/src/ble_store_ram.c +++ b/nimble/host/store/ram/src/ble_store_ram.c @@ -24,8 +24,8 @@ */ /* This package has been deprecated and you should - * use the store/config package. For a RAM-only BLE store, - * use store/config and set BLE_STORE_CONFIG_PERSIST to 0. + * use the store/ram package. For a RAM-only BLE store, + * use store/ram and set BLE_STORE_ram_PERSIST to 0. */ #include @@ -57,6 +57,12 @@ static struct ble_store_value_cccd static int ble_store_ram_num_cccds; +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) +static struct ble_store_value_cl_sup_feat ble_store_ram_feats[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; +#endif + +static int ble_store_ram_num_feats; + /***************************************************************************** * $sec * *****************************************************************************/ @@ -426,6 +432,107 @@ ble_store_ram_write_cccd(const struct ble_store_value_cccd *value_cccd) } +/***************************************************************************** + * $cl_sup_feat * + *****************************************************************************/ + +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) +static int +ble_store_ram_find_cl_sup_feat(const struct ble_store_key_cl_sup_feat *key) +{ + struct ble_store_value_cl_sup_feat *feat; + int skipped; + int i; + + skipped = 0; + for (i = 0; i < ble_store_ram_num_feats; i++) { + feat = ble_store_ram_feats + i; + + if (ble_addr_cmp(&key->peer_addr, BLE_ADDR_ANY)) { + if (ble_addr_cmp(&feat->peer_addr, &key->peer_addr)) { + continue; + } + } + + if (key->idx > skipped) { + skipped++; + continue; + } + + return i; + } + return -1; +} +#endif + +static int +ble_store_ram_delete_cl_sup_feat(const struct ble_store_key_cl_sup_feat *key_feat) +{ +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) + int idx; + int rc; + + idx = ble_store_ram_find_cl_sup_feat(key_feat); + if (idx < 0) { + return BLE_HS_ENOENT; + } + + rc = ble_store_ram_delete_obj(ble_store_ram_feats, sizeof *ble_store_ram_feats, + idx, &ble_store_ram_num_feats); + if (rc != 0) { + return rc; + } + + return 0; +#else + return BLE_HS_ENOENT; +#endif +} + +static int +ble_store_ram_read_cl_sup_feat(const struct ble_store_key_cl_sup_feat *key_feat, + struct ble_store_value_cl_sup_feat *value_feat) +{ +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) + int idx; + + idx = ble_store_ram_find_cl_sup_feat(key_feat); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + *value_feat = ble_store_ram_feats[idx]; + return 0; +#else + return BLE_HS_ENOENT; +#endif +} + +static int +ble_store_ram_write_cl_sup(const struct ble_store_value_cl_sup_feat *value_feat) +{ +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) + struct ble_store_key_cl_sup_feat key_feat; + int idx; + + ble_store_key_from_value_peer_cl_sup_feat(&key_feat, value_feat); + idx = ble_store_ram_find_cl_sup_feat(&key_feat); + if (idx == -1) { + if (ble_store_ram_num_feats >= MYNEWT_VAL(BLE_STORE_MAX_BONDS)) { + return BLE_HS_ESTORE_CAP; + } + + idx = ble_store_ram_num_feats; + ble_store_ram_num_feats++; + } + + ble_store_ram_feats[idx] = *value_feat; + return 0; +#else + return BLE_HS_ENOENT; +#endif +} + /***************************************************************************** * $api * *****************************************************************************/ @@ -468,6 +575,9 @@ ble_store_ram_read(int obj_type, const union ble_store_key *key, rc = ble_store_ram_read_cccd(&key->cccd, &value->cccd); return rc; + case BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT: + rc = ble_store_ram_read_cl_sup_feat(&key->feat, &value->feat); + default: return BLE_HS_ENOTSUP; } @@ -497,6 +607,10 @@ ble_store_ram_write(int obj_type, const union ble_store_value *val) rc = ble_store_ram_write_cccd(&val->cccd); return rc; + case BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT: + rc = ble_store_ram_write_cl_sup(&val->feat); + return rc; + default: return BLE_HS_ENOTSUP; } @@ -520,6 +634,10 @@ ble_store_ram_delete(int obj_type, const union ble_store_key *key) rc = ble_store_ram_delete_cccd(&key->cccd); return rc; + case BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT: + rc = ble_store_ram_delete_cl_sup_feat(&key->feat); + return rc; + default: return BLE_HS_ENOTSUP; } @@ -539,4 +657,5 @@ ble_store_ram_init(void) ble_store_ram_num_our_secs = 0; ble_store_ram_num_peer_secs = 0; ble_store_ram_num_cccds = 0; + ble_store_ram_num_feats = 0; } diff --git a/nimble/host/test/src/ble_store_test.c b/nimble/host/test/src/ble_store_test.c index 75d3a490f8..9939bc2e0f 100644 --- a/nimble/host/test/src/ble_store_test.c +++ b/nimble/host/test/src/ble_store_test.c @@ -45,6 +45,11 @@ ble_store_test_util_verify_peer_deleted(const ble_addr_t *addr) rc = ble_store_read(BLE_STORE_OBJ_TYPE_CCCD, &key, &value); TEST_ASSERT(rc == BLE_HS_ENOENT); + memset(&key, 0, sizeof key); + key.feat.peer_addr = *addr; + rc = ble_store_read(BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT, &key, &value); + TEST_ASSERT(rc == BLE_HS_ENOENT); + rc = ble_store_util_bonded_peers(addrs, &num_addrs, sizeof addrs / sizeof addrs[0]); TEST_ASSERT_FATAL(rc == 0); @@ -198,6 +203,16 @@ TEST_CASE_SELF(ble_store_test_delete_peer) .chr_val_handle = 5, }, }; + struct ble_store_value_cl_sup_feat feats[2] = { + { + .peer_addr = secs[0].peer_addr, + .peer_cl_sup_feat[0] = 0, + }, + { + .peer_addr = secs[1].peer_addr, + .peer_cl_sup_feat[0] = 0, + }, + }; union ble_store_value value; union ble_store_key key; int count; @@ -218,6 +233,11 @@ TEST_CASE_SELF(ble_store_test_delete_peer) TEST_ASSERT_FATAL(rc == 0); } + for (i = 0; i < sizeof feats / sizeof feats[0]; i++) { + rc = ble_store_write_peer_cl_sup_feat(feats + i); + TEST_ASSERT_FATAL(rc == 0); + } + /* Delete first peer. */ rc = ble_store_util_delete_peer(&secs[0].peer_addr); TEST_ASSERT_FATAL(rc == 0); @@ -254,6 +274,16 @@ TEST_CASE_SELF(ble_store_test_delete_peer) TEST_ASSERT_FATAL(rc == 0); TEST_ASSERT(memcmp(&value.cccd, cccds + 2, sizeof value.cccd) == 0); + ble_store_key_from_value_peer_cl_sup_feat(&key.feat, feats + 1); + + rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT, &count); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(count == 1); + + rc = ble_store_read_peer_cl_sup_feat(&key.feat, &value.feat); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(memcmp(&value.feat, feats + 1, sizeof value.feat) == 0); + /* Delete second peer. */ rc = ble_store_util_delete_peer(&secs[1].peer_addr); TEST_ASSERT_FATAL(rc == 0); @@ -294,6 +324,16 @@ TEST_CASE_SELF(ble_store_test_count) .chr_val_handle = 8, }, }; + struct ble_store_value_cl_sup_feat feats[2] = { + { + .peer_addr = secs[0].peer_addr, + .peer_cl_sup_feat[0] = 0, + }, + { + .peer_addr = secs[1].peer_addr, + .peer_cl_sup_feat[0] = 0, + }, + }; int count; int rc; int i; @@ -314,6 +354,10 @@ TEST_CASE_SELF(ble_store_test_count) TEST_ASSERT_FATAL(rc == 0); TEST_ASSERT(count == 0); + rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT, &count); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(count == 0); + /* Write some test data. */ for (i = 0; i < 3; i++) { @@ -328,6 +372,10 @@ TEST_CASE_SELF(ble_store_test_count) rc = ble_store_write_cccd(cccds + i); TEST_ASSERT_FATAL(rc == 0); } + for (i = 0; i < 1; i++) { + rc = ble_store_write_peer_cl_sup_feat(feats + i); + TEST_ASSERT_FATAL(rc == 0); + } /*** Verify counts after populating store. */ rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_OUR_SEC, &count); @@ -342,6 +390,10 @@ TEST_CASE_SELF(ble_store_test_count) TEST_ASSERT_FATAL(rc == 0); TEST_ASSERT(count == 1); + rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT, &count); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(count == 1); + ble_hs_test_util_assert_mbufs_freed(NULL); } @@ -383,6 +435,16 @@ TEST_CASE_SELF(ble_store_test_clear) .chr_val_handle = 5, }, }; + struct ble_store_value_cl_sup_feat feats[2] = { + { + .peer_addr = secs[0].peer_addr, + .peer_cl_sup_feat[0] = 0, + }, + { + .peer_addr = secs[1].peer_addr, + .peer_cl_sup_feat[0] = 0, + }, + }; int rc; int i; @@ -400,6 +462,11 @@ TEST_CASE_SELF(ble_store_test_clear) TEST_ASSERT_FATAL(rc == 0); } + for (i = 0; i < sizeof feats / sizeof feats[0]; i++) { + rc = ble_store_write_peer_cl_sup_feat(feats + i); + TEST_ASSERT_FATAL(rc == 0); + } + /* Sanity check. */ TEST_ASSERT_FATAL( ble_store_test_util_count(BLE_STORE_OBJ_TYPE_OUR_SEC) == 2); @@ -407,6 +474,8 @@ TEST_CASE_SELF(ble_store_test_clear) ble_store_test_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC) == 2); TEST_ASSERT_FATAL( ble_store_test_util_count(BLE_STORE_OBJ_TYPE_CCCD) == 3); + TEST_ASSERT_FATAL( + ble_store_test_util_count(BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT) == 2); /* Ensure store is empty after clear gets called. */ rc = ble_store_clear(); @@ -414,6 +483,7 @@ TEST_CASE_SELF(ble_store_test_clear) TEST_ASSERT(ble_store_test_util_count(BLE_STORE_OBJ_TYPE_OUR_SEC) == 0); TEST_ASSERT(ble_store_test_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC) == 0); TEST_ASSERT(ble_store_test_util_count(BLE_STORE_OBJ_TYPE_CCCD) == 0); + TEST_ASSERT(ble_store_test_util_count(BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT) == 0); /* Ensure second clear succeeds with no effect. */ rc = ble_store_clear(); @@ -421,6 +491,7 @@ TEST_CASE_SELF(ble_store_test_clear) TEST_ASSERT(ble_store_test_util_count(BLE_STORE_OBJ_TYPE_OUR_SEC) == 0); TEST_ASSERT(ble_store_test_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC) == 0); TEST_ASSERT(ble_store_test_util_count(BLE_STORE_OBJ_TYPE_CCCD) == 0); + TEST_ASSERT(ble_store_test_util_count(BLE_STORE_OBJ_TYPE_PEER_CL_SUP_FEAT) == 0); ble_hs_test_util_assert_mbufs_freed(NULL); }