blob: 506a1f9726f625995728ce49a01f71743e4fcac7 [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")) {
111 len = sizeof(bt_dev.id_addr);
112 settings_bytes_from_str(val, &bt_dev.id_addr, &len);
Johan Hedbergae829b22018-06-04 20:56:51 +0200113 if (len != sizeof(bt_dev.id_addr)) {
114 BT_ERR("Invalid length ID address in storage");
115 bt_addr_le_copy(&bt_dev.id_addr, BT_ADDR_LE_ANY);
116 } else {
117 BT_DBG("ID Addr set to %s",
118 bt_addr_le_str(&bt_dev.id_addr));
119 }
120
Johan Hedbergb997a282018-04-26 22:05:26 +0300121 return 0;
122 }
123
Szymon Janc504584a2018-07-31 19:57:08 +0200124#if defined(CONFIG_BT_DEVICE_NAME_DYNAMIC)
Luiz Augusto von Dentz2637c972018-07-09 15:12:04 +0300125 if (!strcmp(argv[0], "name")) {
Luiz Augusto von Dentz13297632018-08-01 10:25:13 +0300126 len = sizeof(bt_dev.name) - 1;
127 settings_bytes_from_str(val, &bt_dev.name, &len);
128 bt_dev.name[len] = '\0';
Luiz Augusto von Dentz2637c972018-07-09 15:12:04 +0300129
130 BT_DBG("Name set to %s", bt_dev.name);
131 return 0;
132 }
Szymon Janc504584a2018-07-31 19:57:08 +0200133#endif
Luiz Augusto von Dentz2637c972018-07-09 15:12:04 +0300134
Johan Hedbergb997a282018-04-26 22:05:26 +0300135#if defined(CONFIG_BT_PRIVACY)
136 if (!strcmp(argv[0], "irk")) {
137 len = sizeof(bt_dev.irk);
138 settings_bytes_from_str(val, bt_dev.irk, &len);
Johan Hedbergae829b22018-06-04 20:56:51 +0200139 if (len != sizeof(bt_dev.irk)) {
140 BT_ERR("Invalid length IRK in storage");
141 memset(bt_dev.irk, 0, sizeof(bt_dev.irk));
142 } else {
143 BT_DBG("IRK set to %s", bt_hex(bt_dev.irk, 16));
144 }
145
Johan Hedbergb997a282018-04-26 22:05:26 +0300146 return 0;
147 }
148#endif /* CONFIG_BT_PRIVACY */
149
150 return 0;
151}
152
153static void generate_static_addr(void)
154{
Johan Hedbergf36ea832018-04-27 20:01:51 +0300155 char buf[BT_SETTINGS_SIZE(sizeof(bt_dev.id_addr))];
Johan Hedbergb997a282018-04-26 22:05:26 +0300156 char *str;
157
158 BT_DBG("Generating new static random address");
159
160 if (bt_addr_le_create_static(&bt_dev.id_addr)) {
161 BT_ERR("Failed to generate static addr");
162 return;
163 }
164
Johan Hedbergd22b7c92018-04-27 10:31:13 +0300165 bt_set_static_addr();
Johan Hedbergb997a282018-04-26 22:05:26 +0300166
167 BT_DBG("New ID Addr: %s", bt_addr_le_str(&bt_dev.id_addr));
168
169 str = settings_str_from_bytes(&bt_dev.id_addr, sizeof(bt_dev.id_addr),
170 buf, sizeof(buf));
171 if (!str) {
172 BT_ERR("Unable to encode ID Addr as value");
173 return;
174 }
175
176 BT_DBG("Saving ID addr as value %s", str);
177 settings_save_one("bt/id", str);
178}
179
180#if defined(CONFIG_BT_PRIVACY)
181static void generate_irk(void)
182{
Johan Hedbergf36ea832018-04-27 20:01:51 +0300183 char buf[BT_SETTINGS_SIZE(sizeof(bt_dev.irk))];
Johan Hedbergb997a282018-04-26 22:05:26 +0300184 char *str;
185
186 BT_DBG("Generating new IRK");
187
188 if (bt_rand(bt_dev.irk, sizeof(bt_dev.irk))) {
189 BT_ERR("Failed to generate IRK");
190 return;
191 }
192
193 BT_DBG("New local IRK: %s", bt_hex(bt_dev.irk, 16));
194
195 str = settings_str_from_bytes(bt_dev.irk, 16, buf, sizeof(buf));
196 if (!str) {
197 BT_ERR("Unable to encode IRK as value");
198 return;
199 }
200
201 BT_DBG("Saving IRK as value %s", str);
202 settings_save_one("bt/irk", str);
203}
204#endif /* CONFIG_BT_PRIVACY */
205
206static int commit(void)
207{
Johan Hedberg470349c2018-04-27 13:24:02 +0300208 const struct bt_settings_handler *h;
209
Johan Hedbergb997a282018-04-26 22:05:26 +0300210 BT_DBG("");
211
212 if (!bt_addr_le_cmp(&bt_dev.id_addr, BT_ADDR_LE_ANY) ||
213 !bt_addr_le_cmp(&bt_dev.id_addr, BT_ADDR_LE_NONE)) {
214 generate_static_addr();
215 }
216
Szymon Janc504584a2018-07-31 19:57:08 +0200217#if defined(CONFIG_BT_DEVICE_NAME_DYNAMIC)
Luiz Augusto von Dentz2637c972018-07-09 15:12:04 +0300218 if (bt_dev.name[0] == '\0') {
219 bt_set_name(CONFIG_BT_DEVICE_NAME);
220 }
221#endif
222
Johan Hedbergb997a282018-04-26 22:05:26 +0300223#if defined(CONFIG_BT_PRIVACY)
224 {
225 u8_t zero[16] = { 0 };
226
227 if (!memcmp(bt_dev.irk, zero, 16)) {
228 generate_irk();
229 }
230 }
231#endif /* CONFIG_BT_PRIVACY */
232
Johan Hedberg470349c2018-04-27 13:24:02 +0300233 for (h = _bt_settings_start; h < _bt_settings_end; h++) {
234 if (h->commit) {
235 h->commit();
236 }
237 }
238
Johan Hedbergb997a282018-04-26 22:05:26 +0300239 bt_dev_show_info();
240
241 return 0;
242}
243
Johan Hedberg470349c2018-04-27 13:24:02 +0300244static int export(int (*func)(const char *name, char *val),
245 enum settings_export_tgt tgt)
246{
247 const struct bt_settings_handler *h;
248
249 if (tgt != SETTINGS_EXPORT_PERSIST) {
250 BT_WARN("Only persist target supported");
251 return -ENOTSUP;
252 }
253
254 for (h = _bt_settings_start; h < _bt_settings_end; h++) {
255 if (h->export) {
256 h->export(func);
257 }
258 }
259
260 return 0;
261}
262
Johan Hedbergb997a282018-04-26 22:05:26 +0300263static struct settings_handler bt_settings = {
264 .name = "bt",
265 .h_set = set,
266 .h_commit = commit,
Johan Hedberg470349c2018-04-27 13:24:02 +0300267 .h_export = export,
Johan Hedbergb997a282018-04-26 22:05:26 +0300268};
269
270int bt_settings_init(void)
271{
272 int err;
273
274 BT_DBG("");
275
276 err = settings_subsys_init();
277 if (err) {
278 BT_ERR("settings_subsys_init failed (err %d)", err);
279 return err;
280 }
281
282 err = settings_register(&bt_settings);
283 if (err) {
284 BT_ERR("settings_register failed (err %d)", err);
285 return err;
286 }
287
288 return 0;
289}