[FL-2809] Rework BLE key storage (#2154)
* bt: disconnect first on profile change * bt keys: rework bt keys * saved struct: add payload size getter to API * bt: rework bt with new key storage API * bt: add keys storage operation to bt API * hid: save bt keys on sd card * bt: add unit tests for key storage * bt: working profile switch * bt: cleanup * bt hid: change keys storage path Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
@@ -117,6 +117,8 @@ Bt* bt_alloc() {
|
||||
if(!bt_settings_load(&bt->bt_settings)) {
|
||||
bt_settings_save(&bt->bt_settings);
|
||||
}
|
||||
// Keys storage
|
||||
bt->keys_storage = bt_keys_storage_alloc(BT_KEYS_STORAGE_PATH);
|
||||
// Alloc queue
|
||||
bt->message_queue = furi_message_queue_alloc(8, sizeof(BtMessage));
|
||||
|
||||
@@ -285,8 +287,10 @@ static bool bt_on_gap_event_callback(GapEvent event, void* context) {
|
||||
static void bt_on_key_storage_change_callback(uint8_t* addr, uint16_t size, void* context) {
|
||||
furi_assert(context);
|
||||
Bt* bt = context;
|
||||
FURI_LOG_I(TAG, "Changed addr start: %p, size changed: %d", addr, size);
|
||||
BtMessage message = {.type = BtMessageTypeKeysStorageUpdated};
|
||||
BtMessage message = {
|
||||
.type = BtMessageTypeKeysStorageUpdated,
|
||||
.data.key_storage_data.start_address = addr,
|
||||
.data.key_storage_data.size = size};
|
||||
furi_check(
|
||||
furi_message_queue_put(bt->message_queue, &message, FuriWaitForever) == FuriStatusOk);
|
||||
}
|
||||
@@ -331,6 +335,8 @@ static void bt_change_profile(Bt* bt, BtMessage* message) {
|
||||
furi_profile = FuriHalBtProfileSerial;
|
||||
}
|
||||
|
||||
bt_keys_storage_load(bt->keys_storage);
|
||||
|
||||
if(furi_hal_bt_change_app(furi_profile, bt_on_gap_event_callback, bt)) {
|
||||
FURI_LOG_I(TAG, "Bt App started");
|
||||
if(bt->bt_settings.enabled) {
|
||||
@@ -358,6 +364,7 @@ static void bt_change_profile(Bt* bt, BtMessage* message) {
|
||||
|
||||
static void bt_close_connection(Bt* bt) {
|
||||
bt_close_rpc_connection(bt);
|
||||
furi_hal_bt_stop_advertising();
|
||||
furi_event_flag_set(bt->api_event, BT_API_UNLOCK_EVENT);
|
||||
}
|
||||
|
||||
@@ -372,8 +379,8 @@ int32_t bt_srv(void* p) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read keys
|
||||
if(!bt_keys_storage_load(bt)) {
|
||||
// Load keys
|
||||
if(!bt_keys_storage_load(bt->keys_storage)) {
|
||||
FURI_LOG_W(TAG, "Failed to load bonding keys");
|
||||
}
|
||||
|
||||
@@ -418,13 +425,16 @@ int32_t bt_srv(void* p) {
|
||||
// Display PIN code
|
||||
bt_pin_code_show(bt, message.data.pin_code);
|
||||
} else if(message.type == BtMessageTypeKeysStorageUpdated) {
|
||||
bt_keys_storage_save(bt);
|
||||
bt_keys_storage_update(
|
||||
bt->keys_storage,
|
||||
message.data.key_storage_data.start_address,
|
||||
message.data.key_storage_data.size);
|
||||
} else if(message.type == BtMessageTypeSetProfile) {
|
||||
bt_change_profile(bt, &message);
|
||||
} else if(message.type == BtMessageTypeDisconnect) {
|
||||
bt_close_connection(bt);
|
||||
} else if(message.type == BtMessageTypeForgetBondedDevices) {
|
||||
bt_keys_storage_delete(bt);
|
||||
bt_keys_storage_delete(bt->keys_storage);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@@ -56,6 +56,19 @@ void bt_set_status_changed_callback(Bt* bt, BtStatusChangedCallback callback, vo
|
||||
*/
|
||||
void bt_forget_bonded_devices(Bt* bt);
|
||||
|
||||
/** Set keys storage file path
|
||||
*
|
||||
* @param bt Bt instance
|
||||
* @param keys_storage_path Path to file with saved keys
|
||||
*/
|
||||
void bt_keys_storage_set_storage_path(Bt* bt, const char* keys_storage_path);
|
||||
|
||||
/** Set default keys storage file path
|
||||
*
|
||||
* @param bt Bt instance
|
||||
*/
|
||||
void bt_keys_storage_set_default_path(Bt* bt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -39,3 +39,18 @@ void bt_forget_bonded_devices(Bt* bt) {
|
||||
furi_check(
|
||||
furi_message_queue_put(bt->message_queue, &message, FuriWaitForever) == FuriStatusOk);
|
||||
}
|
||||
|
||||
void bt_keys_storage_set_storage_path(Bt* bt, const char* keys_storage_path) {
|
||||
furi_assert(bt);
|
||||
furi_assert(bt->keys_storage);
|
||||
furi_assert(keys_storage_path);
|
||||
|
||||
bt_keys_storage_set_file_path(bt->keys_storage, keys_storage_path);
|
||||
}
|
||||
|
||||
void bt_keys_storage_set_default_path(Bt* bt) {
|
||||
furi_assert(bt);
|
||||
furi_assert(bt->keys_storage);
|
||||
|
||||
bt_keys_storage_set_file_path(bt->keys_storage, BT_KEYS_STORAGE_PATH);
|
||||
}
|
||||
|
@@ -13,8 +13,14 @@
|
||||
#include <power/power_service/power.h>
|
||||
#include <rpc/rpc.h>
|
||||
#include <notification/notification.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
#include <bt/bt_settings.h>
|
||||
#include <bt/bt_service/bt_keys_storage.h>
|
||||
|
||||
#include "bt_keys_filename.h"
|
||||
|
||||
#define BT_KEYS_STORAGE_PATH INT_PATH(BT_KEYS_STORAGE_FILE_NAME)
|
||||
|
||||
#define BT_API_UNLOCK_EVENT (1UL << 0)
|
||||
|
||||
@@ -29,10 +35,16 @@ typedef enum {
|
||||
BtMessageTypeForgetBondedDevices,
|
||||
} BtMessageType;
|
||||
|
||||
typedef struct {
|
||||
uint8_t* start_address;
|
||||
uint16_t size;
|
||||
} BtKeyStorageUpdateData;
|
||||
|
||||
typedef union {
|
||||
uint32_t pin_code;
|
||||
uint8_t battery_level;
|
||||
BtProfile profile;
|
||||
BtKeyStorageUpdateData key_storage_data;
|
||||
} BtMessageData;
|
||||
|
||||
typedef struct {
|
||||
@@ -46,6 +58,7 @@ struct Bt {
|
||||
uint16_t bt_keys_size;
|
||||
uint16_t max_packet_size;
|
||||
BtSettings bt_settings;
|
||||
BtKeysStorage* keys_storage;
|
||||
BtStatus status;
|
||||
BtProfile profile;
|
||||
FuriMessageQueue* message_queue;
|
||||
|
@@ -1,49 +1,24 @@
|
||||
#include "bt_keys_storage.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal_bt.h>
|
||||
#include <lib/toolbox/saved_struct.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
#define BT_KEYS_STORAGE_PATH INT_PATH(BT_KEYS_STORAGE_FILE_NAME)
|
||||
#define BT_KEYS_STORAGE_VERSION (0)
|
||||
#define BT_KEYS_STORAGE_MAGIC (0x18)
|
||||
|
||||
bool bt_keys_storage_load(Bt* bt) {
|
||||
furi_assert(bt);
|
||||
bool file_loaded = false;
|
||||
#define TAG "BtKeyStorage"
|
||||
|
||||
furi_hal_bt_get_key_storage_buff(&bt->bt_keys_addr_start, &bt->bt_keys_size);
|
||||
furi_hal_bt_nvm_sram_sem_acquire();
|
||||
file_loaded = saved_struct_load(
|
||||
BT_KEYS_STORAGE_PATH,
|
||||
bt->bt_keys_addr_start,
|
||||
bt->bt_keys_size,
|
||||
BT_KEYS_STORAGE_MAGIC,
|
||||
BT_KEYS_STORAGE_VERSION);
|
||||
furi_hal_bt_nvm_sram_sem_release();
|
||||
struct BtKeysStorage {
|
||||
uint8_t* nvm_sram_buff;
|
||||
uint16_t nvm_sram_buff_size;
|
||||
FuriString* file_path;
|
||||
};
|
||||
|
||||
return file_loaded;
|
||||
}
|
||||
bool bt_keys_storage_delete(BtKeysStorage* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool bt_keys_storage_save(Bt* bt) {
|
||||
furi_assert(bt);
|
||||
furi_assert(bt->bt_keys_addr_start);
|
||||
bool file_saved = false;
|
||||
|
||||
furi_hal_bt_nvm_sram_sem_acquire();
|
||||
file_saved = saved_struct_save(
|
||||
BT_KEYS_STORAGE_PATH,
|
||||
bt->bt_keys_addr_start,
|
||||
bt->bt_keys_size,
|
||||
BT_KEYS_STORAGE_MAGIC,
|
||||
BT_KEYS_STORAGE_VERSION);
|
||||
furi_hal_bt_nvm_sram_sem_release();
|
||||
|
||||
return file_saved;
|
||||
}
|
||||
|
||||
bool bt_keys_storage_delete(Bt* bt) {
|
||||
furi_assert(bt);
|
||||
bool delete_succeed = false;
|
||||
bool bt_is_active = furi_hal_bt_is_active();
|
||||
|
||||
@@ -55,3 +30,117 @@ bool bt_keys_storage_delete(Bt* bt) {
|
||||
|
||||
return delete_succeed;
|
||||
}
|
||||
|
||||
BtKeysStorage* bt_keys_storage_alloc(const char* keys_storage_path) {
|
||||
furi_assert(keys_storage_path);
|
||||
|
||||
BtKeysStorage* instance = malloc(sizeof(BtKeysStorage));
|
||||
// Set default nvm ram parameters
|
||||
furi_hal_bt_get_key_storage_buff(&instance->nvm_sram_buff, &instance->nvm_sram_buff_size);
|
||||
// Set key storage file
|
||||
instance->file_path = furi_string_alloc();
|
||||
furi_string_set_str(instance->file_path, keys_storage_path);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void bt_keys_storage_free(BtKeysStorage* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
furi_string_free(instance->file_path);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void bt_keys_storage_set_file_path(BtKeysStorage* instance, const char* path) {
|
||||
furi_assert(instance);
|
||||
furi_assert(path);
|
||||
|
||||
furi_string_set_str(instance->file_path, path);
|
||||
}
|
||||
|
||||
void bt_keys_storage_set_ram_params(BtKeysStorage* instance, uint8_t* buff, uint16_t size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(buff);
|
||||
|
||||
instance->nvm_sram_buff = buff;
|
||||
instance->nvm_sram_buff_size = size;
|
||||
}
|
||||
|
||||
bool bt_keys_storage_load(BtKeysStorage* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool loaded = false;
|
||||
do {
|
||||
// Get payload size
|
||||
size_t payload_size = 0;
|
||||
if(!saved_struct_get_payload_size(
|
||||
furi_string_get_cstr(instance->file_path),
|
||||
BT_KEYS_STORAGE_MAGIC,
|
||||
BT_KEYS_STORAGE_VERSION,
|
||||
&payload_size)) {
|
||||
FURI_LOG_E(TAG, "Failed to read payload size");
|
||||
break;
|
||||
}
|
||||
|
||||
if(payload_size > instance->nvm_sram_buff_size) {
|
||||
FURI_LOG_E(TAG, "Saved data doesn't fit ram buffer");
|
||||
break;
|
||||
}
|
||||
|
||||
// Load saved data to ram
|
||||
furi_hal_bt_nvm_sram_sem_acquire();
|
||||
bool data_loaded = saved_struct_load(
|
||||
furi_string_get_cstr(instance->file_path),
|
||||
instance->nvm_sram_buff,
|
||||
payload_size,
|
||||
BT_KEYS_STORAGE_MAGIC,
|
||||
BT_KEYS_STORAGE_VERSION);
|
||||
furi_hal_bt_nvm_sram_sem_release();
|
||||
if(!data_loaded) {
|
||||
FURI_LOG_E(TAG, "Failed to load struct");
|
||||
break;
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
} while(false);
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
bool bt_keys_storage_update(BtKeysStorage* instance, uint8_t* start_addr, uint32_t size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(start_addr);
|
||||
|
||||
bool updated = false;
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"Base address: %p. Start update address: %p. Size changed: %ld",
|
||||
(void*)instance->nvm_sram_buff,
|
||||
start_addr,
|
||||
size);
|
||||
|
||||
do {
|
||||
size_t new_size = start_addr - instance->nvm_sram_buff + size;
|
||||
if(new_size > instance->nvm_sram_buff_size) {
|
||||
FURI_LOG_E(TAG, "NVM RAM buffer overflow");
|
||||
break;
|
||||
}
|
||||
|
||||
furi_hal_bt_nvm_sram_sem_acquire();
|
||||
bool data_updated = saved_struct_save(
|
||||
furi_string_get_cstr(instance->file_path),
|
||||
instance->nvm_sram_buff,
|
||||
new_size,
|
||||
BT_KEYS_STORAGE_MAGIC,
|
||||
BT_KEYS_STORAGE_VERSION);
|
||||
furi_hal_bt_nvm_sram_sem_release();
|
||||
if(!data_updated) {
|
||||
FURI_LOG_E(TAG, "Failed to update key storage");
|
||||
break;
|
||||
}
|
||||
updated = true;
|
||||
} while(false);
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
@@ -1,10 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "bt_i.h"
|
||||
#include "bt_keys_filename.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
bool bt_keys_storage_load(Bt* bt);
|
||||
typedef struct BtKeysStorage BtKeysStorage;
|
||||
|
||||
bool bt_keys_storage_save(Bt* bt);
|
||||
BtKeysStorage* bt_keys_storage_alloc(const char* keys_storage_path);
|
||||
|
||||
bool bt_keys_storage_delete(Bt* bt);
|
||||
void bt_keys_storage_free(BtKeysStorage* instance);
|
||||
|
||||
void bt_keys_storage_set_file_path(BtKeysStorage* instance, const char* path);
|
||||
|
||||
void bt_keys_storage_set_ram_params(BtKeysStorage* instance, uint8_t* buff, uint16_t size);
|
||||
|
||||
bool bt_keys_storage_load(BtKeysStorage* instance);
|
||||
|
||||
bool bt_keys_storage_update(BtKeysStorage* instance, uint8_t* start_addr, uint32_t size);
|
||||
|
||||
bool bt_keys_storage_delete(BtKeysStorage* instance);
|
||||
|
Reference in New Issue
Block a user