blob: 5a34d07b79f551b6d35ce88455ed62eb14cc2339 [file] [log] [blame]
Johan Hedbergb997a282018-04-26 22:05:26 +03001/*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#include <errno.h>
8
9#include <zephyr.h>
10#include <settings/settings.h>
11
12#include <bluetooth/bluetooth.h>
13#include <bluetooth/conn.h>
14
15#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_SETTINGS)
16#include "common/log.h"
17
18#include "hci_core.h"
19#include "settings.h"
20
Johan Hedberg470349c2018-04-27 13:24:02 +030021/* Linker-defined symbols bound to the bt_settings_handler structs */
22extern const struct bt_settings_handler _bt_settings_start[];
23extern const struct bt_settings_handler _bt_settings_end[];
24
Johan Hedbergf36ea832018-04-27 20:01:51 +030025void bt_settings_encode_key(char *path, size_t path_size, const char *subsys,
26 bt_addr_le_t *addr, const char *key)
27{
28 if (key) {
29 snprintk(path, path_size,
30 "bt/%s/%02x%02x%02x%02x%02x%02x%u/%s", subsys,
31 addr->a.val[5], addr->a.val[4], addr->a.val[3],
32 addr->a.val[2], addr->a.val[1], addr->a.val[0],
33 addr->type, key);
34 } else {
35 snprintk(path, path_size,
36 "bt/%s/%02x%02x%02x%02x%02x%02x%u", subsys,
37 addr->a.val[5], addr->a.val[4], addr->a.val[3],
38 addr->a.val[2], addr->a.val[1], addr->a.val[0],
39 addr->type);
40 }
41
42 BT_DBG("Encoded path %s", path);
43}
44
45int bt_settings_decode_key(char *key, bt_addr_le_t *addr)
46{
47 bool high;
48 int i;
49
50 if (strlen(key) != 13) {
51 return -EINVAL;
52 }
53
54 if (key[12] == '0') {
55 addr->type = BT_ADDR_LE_PUBLIC;
56 } else if (key[12] == '1') {
57 addr->type = BT_ADDR_LE_RANDOM;
58 } else {
59 return -EINVAL;
60 }
61
62 for (i = 5, high = true; i >= 0; key++) {
63 u8_t nibble;
64
65 if (*key >= '0' && *key <= '9') {
66 nibble = *key - '0';
67 } else if (*key >= 'a' && *key <= 'f') {
68 nibble = *key - 'a' + 10;
69 } else {
70 return -EINVAL;
71 }
72
73 if (high) {
74 addr->a.val[i] = nibble << 4;
75 high = false;
76 } else {
77 addr->a.val[i] |= nibble;
78 high = true;
79 i--;
80 }
81 }
82
83 BT_DBG("Decoded %s as %s", key, bt_addr_le_str(addr));
84
85 return 0;
86}
87
Johan Hedbergb997a282018-04-26 22:05:26 +030088static int set(int argc, char **argv, char *val)
89{
90 int len;
91
Johan Hedbergf36ea832018-04-27 20:01:51 +030092 BT_DBG("argc %d argv[0] %s argv[1] %s val %s", argc, argv[0],
93 argc > 1 ? argv[1] : "(null)", val ? val : "(null)");
Johan Hedbergb997a282018-04-26 22:05:26 +030094
Johan Hedberg470349c2018-04-27 13:24:02 +030095 if (argc > 1) {
96 const struct bt_settings_handler *h;
97
98 for (h = _bt_settings_start; h < _bt_settings_end; h++) {
99 if (!strcmp(argv[0], h->name)) {
100 argc--;
101 argv++;
102
103 return h->set(argc, argv, val);
104 }
105 }
106
Johan Hedbergb997a282018-04-26 22:05:26 +0300107 return -ENOENT;
108 }
109
110 if (!strcmp(argv[0], "id")) {
Johan Hedberge70c5562018-07-16 14:39:06 +0300111 /* Any previously provided identities supersede flash */
112 if (atomic_test_bit(bt_dev.flags, BT_DEV_PRESET_ID)) {
113 BT_WARN("Ignoring identities stored in flash");
114 return 0;
115 }
116
Johan Hedbergb997a282018-04-26 22:05:26 +0300117 len = sizeof(bt_dev.id_addr);
118 settings_bytes_from_str(val, &bt_dev.id_addr, &len);
Johan Hedberg5708f1e2018-07-04 12:58:10 +0300119 if (len < sizeof(bt_dev.id_addr[0])) {
Johan Hedbergae829b22018-06-04 20:56:51 +0200120 BT_ERR("Invalid length ID address in storage");
Johan Hedberg5708f1e2018-07-04 12:58:10 +0300121 memset(bt_dev.id_addr, 0, sizeof(bt_dev.id_addr));
122 bt_dev.id_count = 0;
Johan Hedbergae829b22018-06-04 20:56:51 +0200123 } else {
Johan Hedberg5708f1e2018-07-04 12:58:10 +0300124 int i;
125
126 bt_dev.id_count = len / sizeof(bt_dev.id_addr[0]);
127 for (i = 0; i < bt_dev.id_count; i++) {
128 BT_DBG("ID Addr %d %s", i,
129 bt_addr_le_str(&bt_dev.id_addr[i]));
130 }
Johan Hedbergae829b22018-06-04 20:56:51 +0200131 }
132
Johan Hedbergb997a282018-04-26 22:05:26 +0300133 return 0;
134 }
135
Szymon Janc504584a2018-07-31 19:57:08 +0200136#if defined(CONFIG_BT_DEVICE_NAME_DYNAMIC)
Luiz Augusto von Dentz2637c972018-07-09 15:12:04 +0300137 if (!strcmp(argv[0], "name")) {
Luiz Augusto von Dentz13297632018-08-01 10:25:13 +0300138 len = sizeof(bt_dev.name) - 1;
139 settings_bytes_from_str(val, &bt_dev.name, &len);
140 bt_dev.name[len] = '\0';
Luiz Augusto von Dentz2637c972018-07-09 15:12:04 +0300141
142 BT_DBG("Name set to %s", bt_dev.name);
143 return 0;
144 }
Szymon Janc504584a2018-07-31 19:57:08 +0200145#endif
Luiz Augusto von Dentz2637c972018-07-09 15:12:04 +0300146
Johan Hedbergb997a282018-04-26 22:05:26 +0300147#if defined(CONFIG_BT_PRIVACY)
148 if (!strcmp(argv[0], "irk")) {
149 len = sizeof(bt_dev.irk);
150 settings_bytes_from_str(val, bt_dev.irk, &len);
Johan Hedberg5708f1e2018-07-04 12:58:10 +0300151 if (len < sizeof(bt_dev.irk[0])) {
Johan Hedbergae829b22018-06-04 20:56:51 +0200152 BT_ERR("Invalid length IRK in storage");
153 memset(bt_dev.irk, 0, sizeof(bt_dev.irk));
154 } else {
Johan Hedberg5708f1e2018-07-04 12:58:10 +0300155 BT_DBG("IRK set to %s", bt_hex(bt_dev.irk[0], 16));
Johan Hedbergae829b22018-06-04 20:56:51 +0200156 }
157
Johan Hedbergb997a282018-04-26 22:05:26 +0300158 return 0;
159 }
160#endif /* CONFIG_BT_PRIVACY */
161
162 return 0;
163}
164
Johan Hedberge70c5562018-07-16 14:39:06 +0300165#if defined(CONFIG_BT_PRIVACY)
166#define ID_SIZE_MAX sizeof(bt_dev.irk)
167#else
168#define ID_SIZE_MAX sizeof(bt_dev.id_addr)
169#endif
170
171#define ID_DATA_LEN(array) (bt_dev.id_count * sizeof(array[0]))
172
173static void save_id(struct k_work *work)
Johan Hedbergb997a282018-04-26 22:05:26 +0300174{
Johan Hedberge70c5562018-07-16 14:39:06 +0300175 char buf[BT_SETTINGS_SIZE(ID_SIZE_MAX)];
Johan Hedbergb997a282018-04-26 22:05:26 +0300176 char *str;
177
Johan Hedberge70c5562018-07-16 14:39:06 +0300178 str = settings_str_from_bytes(&bt_dev.id_addr,
179 ID_DATA_LEN(bt_dev.id_addr),
Johan Hedbergb997a282018-04-26 22:05:26 +0300180 buf, sizeof(buf));
181 if (!str) {
182 BT_ERR("Unable to encode ID Addr as value");
183 return;
184 }
185
186 BT_DBG("Saving ID addr as value %s", str);
187 settings_save_one("bt/id", str);
Johan Hedbergb997a282018-04-26 22:05:26 +0300188
189#if defined(CONFIG_BT_PRIVACY)
Johan Hedberge70c5562018-07-16 14:39:06 +0300190 str = settings_str_from_bytes(bt_dev.irk, ID_DATA_LEN(bt_dev.irk),
191 buf, sizeof(buf));
Johan Hedbergb997a282018-04-26 22:05:26 +0300192 if (!str) {
193 BT_ERR("Unable to encode IRK as value");
194 return;
195 }
196
197 BT_DBG("Saving IRK as value %s", str);
198 settings_save_one("bt/irk", str);
Johan Hedberge70c5562018-07-16 14:39:06 +0300199#endif
Johan Hedbergb997a282018-04-26 22:05:26 +0300200}
Johan Hedberge70c5562018-07-16 14:39:06 +0300201
202K_WORK_DEFINE(save_id_work, save_id);
203
204void bt_settings_save_id(void)
205{
206 k_work_submit(&save_id_work);
207}
Johan Hedbergb997a282018-04-26 22:05:26 +0300208
209static int commit(void)
210{
Johan Hedberg470349c2018-04-27 13:24:02 +0300211 const struct bt_settings_handler *h;
212
Johan Hedbergb997a282018-04-26 22:05:26 +0300213 BT_DBG("");
214
Szymon Janc504584a2018-07-31 19:57:08 +0200215#if defined(CONFIG_BT_DEVICE_NAME_DYNAMIC)
Luiz Augusto von Dentz2637c972018-07-09 15:12:04 +0300216 if (bt_dev.name[0] == '\0') {
217 bt_set_name(CONFIG_BT_DEVICE_NAME);
218 }
219#endif
Johan Hedberge70c5562018-07-16 14:39:06 +0300220 if (!bt_dev.id_count) {
221 int err;
Luiz Augusto von Dentz2637c972018-07-09 15:12:04 +0300222
Johan Hedberge70c5562018-07-16 14:39:06 +0300223 err = bt_setup_id_addr();
224 if (err) {
225 BT_ERR("Unable to setup an identity address");
226 return err;
Johan Hedbergb997a282018-04-26 22:05:26 +0300227 }
228 }
Johan Hedbergb997a282018-04-26 22:05:26 +0300229
Johan Hedberg470349c2018-04-27 13:24:02 +0300230 for (h = _bt_settings_start; h < _bt_settings_end; h++) {
231 if (h->commit) {
232 h->commit();
233 }
234 }
235
Johan Hedbergb997a282018-04-26 22:05:26 +0300236 bt_dev_show_info();
237
238 return 0;
239}
240
Johan Hedberg470349c2018-04-27 13:24:02 +0300241static int export(int (*func)(const char *name, char *val),
242 enum settings_export_tgt tgt)
243{
244 const struct bt_settings_handler *h;
245
246 if (tgt != SETTINGS_EXPORT_PERSIST) {
247 BT_WARN("Only persist target supported");
248 return -ENOTSUP;
249 }
250
251 for (h = _bt_settings_start; h < _bt_settings_end; h++) {
252 if (h->export) {
253 h->export(func);
254 }
255 }
256
257 return 0;
258}
259
Johan Hedbergb997a282018-04-26 22:05:26 +0300260static struct settings_handler bt_settings = {
261 .name = "bt",
262 .h_set = set,
263 .h_commit = commit,
Johan Hedberg470349c2018-04-27 13:24:02 +0300264 .h_export = export,
Johan Hedbergb997a282018-04-26 22:05:26 +0300265};
266
267int bt_settings_init(void)
268{
269 int err;
270
271 BT_DBG("");
272
273 err = settings_subsys_init();
274 if (err) {
275 BT_ERR("settings_subsys_init failed (err %d)", err);
276 return err;
277 }
278
279 err = settings_register(&bt_settings);
280 if (err) {
281 BT_ERR("settings_register failed (err %d)", err);
282 return err;
283 }
284
285 return 0;
286}