mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-03 04:51:56 +00:00
The API name space for Bluetooth is bt_* and BT_* so it makes sense to align the Kconfig name space with this. The additional benefit is that this also makes the names shorter. It is also in line with what Linux uses for Bluetooth Kconfig entries. Some Bluetooth-related Networking Kconfig defines are renamed as well in order to be consistent, such as NET_L2_BLUETOOTH. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
230 lines
4.3 KiB
C
230 lines
4.3 KiB
C
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <misc/printk.h>
|
|
|
|
#include <zephyr.h>
|
|
#include <init.h>
|
|
#include <fs.h>
|
|
|
|
#include <bluetooth/bluetooth.h>
|
|
#include <bluetooth/storage.h>
|
|
|
|
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE)
|
|
#include "common/log.h"
|
|
|
|
#define STORAGE_ROOT "/bt"
|
|
|
|
/* Required file name length for full storage support. If the maximum
|
|
* file name length supported by the chosen file system is less than
|
|
* this value, then only local keys are supported (/bt/abcd).
|
|
*/
|
|
#define STORAGE_FILE_NAME_LEN 13
|
|
|
|
#if MAX_FILE_NAME >= STORAGE_FILE_NAME_LEN
|
|
/* /bt/aabbccddeeff0/abcd */
|
|
#define STORAGE_PATH_MAX 23
|
|
#else
|
|
/* /bt/abcd */
|
|
#define STORAGE_PATH_MAX 9
|
|
#endif
|
|
|
|
enum storage_access {
|
|
STORAGE_READ,
|
|
STORAGE_WRITE
|
|
};
|
|
|
|
static int storage_open(const bt_addr_le_t *addr, u16_t key,
|
|
enum storage_access access, fs_file_t *file)
|
|
{
|
|
char path[STORAGE_PATH_MAX];
|
|
|
|
if (addr) {
|
|
#if MAX_FILE_NAME >= STORAGE_FILE_NAME_LEN
|
|
int len;
|
|
|
|
len = snprintk(path, sizeof(path),
|
|
STORAGE_ROOT "/%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%u",
|
|
addr->a.val[5], addr->a.val[4], addr->a.val[3],
|
|
addr->a.val[2], addr->a.val[1], addr->a.val[0],
|
|
addr->type);
|
|
|
|
/* Create the subdirectory if necessary */
|
|
if (access == STORAGE_WRITE) {
|
|
struct fs_dirent entry;
|
|
int err;
|
|
|
|
err = fs_stat(path, &entry);
|
|
if (err) {
|
|
err = fs_mkdir(path);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
}
|
|
}
|
|
|
|
snprintk(path + len, sizeof(path) - len, "/%04x", key);
|
|
#else
|
|
return -ENAMETOOLONG;
|
|
#endif
|
|
} else {
|
|
snprintk(path, sizeof(path), STORAGE_ROOT "/%04x", key);
|
|
}
|
|
|
|
return fs_open(file, path);
|
|
}
|
|
|
|
static ssize_t storage_read(const bt_addr_le_t *addr, u16_t key, void *data,
|
|
size_t length)
|
|
{
|
|
fs_file_t file;
|
|
ssize_t ret;
|
|
|
|
ret = storage_open(addr, key, STORAGE_READ, &file);
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
|
|
ret = fs_read(&file, data, length);
|
|
fs_close(&file);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t storage_write(const bt_addr_le_t *addr, u16_t key,
|
|
const void *data, size_t length)
|
|
{
|
|
fs_file_t file;
|
|
ssize_t ret;
|
|
|
|
ret = storage_open(addr, key, STORAGE_WRITE, &file);
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
|
|
ret = fs_write(&file, data, length);
|
|
fs_close(&file);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int unlink_recursive(char path[STORAGE_PATH_MAX])
|
|
{
|
|
size_t path_len;
|
|
fs_dir_t dir;
|
|
int err;
|
|
|
|
err = fs_opendir(&dir, path);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
|
|
/* We calculate this up-front so we can keep reusing the same
|
|
* buffer for the path when recursing.
|
|
*/
|
|
path_len = strlen(path);
|
|
|
|
while (1) {
|
|
struct fs_dirent entry;
|
|
|
|
err = fs_readdir(&dir, &entry);
|
|
if (err) {
|
|
break;
|
|
}
|
|
|
|
if (entry.name[0] == '\0') {
|
|
break;
|
|
}
|
|
|
|
snprintk(path + path_len, STORAGE_PATH_MAX - path_len, "/%s",
|
|
entry.name);
|
|
|
|
if (entry.type == FS_DIR_ENTRY_DIR) {
|
|
err = unlink_recursive(path);
|
|
} else {
|
|
err = fs_unlink(path);
|
|
}
|
|
|
|
if (err) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
fs_closedir(&dir);
|
|
|
|
/* Return to the original value */
|
|
path[path_len] = '\0';
|
|
|
|
fs_unlink(path);
|
|
|
|
return err;
|
|
}
|
|
|
|
static int storage_clear(const bt_addr_le_t *addr)
|
|
{
|
|
char path[STORAGE_PATH_MAX];
|
|
int err;
|
|
|
|
if (addr) {
|
|
#if MAX_FILE_NAME >= STORAGE_FILE_NAME_LEN
|
|
snprintk(path, STORAGE_PATH_MAX,
|
|
STORAGE_ROOT "/%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%u",
|
|
addr->a.val[5], addr->a.val[4], addr->a.val[3],
|
|
addr->a.val[2], addr->a.val[1], addr->a.val[0],
|
|
addr->type);
|
|
|
|
return unlink_recursive(path);
|
|
#else
|
|
return -ENAMETOOLONG;
|
|
#endif
|
|
}
|
|
|
|
/* unlink_recursive() uses the given path as a buffer for
|
|
* constructing sub-paths, so we can't give it a string literal
|
|
* such as STORAGE_ROOT directly.
|
|
*/
|
|
strcpy(path, STORAGE_ROOT);
|
|
|
|
err = unlink_recursive(path);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
|
|
return fs_mkdir(STORAGE_ROOT);
|
|
}
|
|
|
|
static int storage_init(struct device *unused)
|
|
{
|
|
static const struct bt_storage storage = {
|
|
.read = storage_read,
|
|
.write = storage_write,
|
|
.clear = storage_clear
|
|
};
|
|
struct fs_dirent entry;
|
|
int err;
|
|
|
|
err = fs_stat(STORAGE_ROOT, &entry);
|
|
if (err) {
|
|
BT_WARN("%s doesn't seem to exist (err %d). Creating it.",
|
|
STORAGE_ROOT, err);
|
|
|
|
err = fs_mkdir(STORAGE_ROOT);
|
|
if (err) {
|
|
BT_ERR("Unable to create %s (err %d)",
|
|
STORAGE_ROOT, err);
|
|
return err;
|
|
}
|
|
}
|
|
|
|
bt_storage_register(&storage);
|
|
|
|
return 0;
|
|
}
|
|
|
|
SYS_INIT(storage_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|