1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <errno.h>
9 #include <sys/types.h>
10 #include <zephyr/sys/util.h>
11 
12 #include <zephyr/bluetooth/hci.h>
13 
14 #include <zephyr/settings/settings.h>
15 #include <common/bt_settings_commit.h>
16 #include <zephyr/bluetooth/mesh.h>
17 
18 #include "host/hci_core.h"
19 #include "mesh.h"
20 #include "subnet.h"
21 #include "app_keys.h"
22 #include "net.h"
23 #include "cdb.h"
24 #include "crypto.h"
25 #include "rpl.h"
26 #include "transport.h"
27 #include "heartbeat.h"
28 #include "access.h"
29 #include "proxy.h"
30 #include "pb_gatt_srv.h"
31 #include "settings.h"
32 #include "cfg.h"
33 #include "brg_cfg.h"
34 #include "solicitation.h"
35 #include "va.h"
36 
37 #define LOG_LEVEL CONFIG_BT_MESH_SETTINGS_LOG_LEVEL
38 #include <zephyr/logging/log.h>
39 LOG_MODULE_REGISTER(bt_mesh_settings);
40 
41 #ifdef CONFIG_BT_MESH_RPL_STORE_TIMEOUT
42 #define RPL_STORE_TIMEOUT CONFIG_BT_MESH_RPL_STORE_TIMEOUT
43 #else
44 #define RPL_STORE_TIMEOUT (-1)
45 #endif
46 
47 #ifdef CONFIG_BT_MESH_SETTINGS_WORKQ_PRIO
48 #define SETTINGS_WORKQ_PRIO CONFIG_BT_MESH_SETTINGS_WORKQ_PRIO
49 #else
50 #define SETTINGS_WORKQ_PRIO 1
51 #endif
52 
53 #ifdef CONFIG_BT_MESH_SETTINGS_WORKQ_STACK_SIZE
54 #define SETTINGS_WORKQ_STACK_SIZE CONFIG_BT_MESH_SETTINGS_WORKQ_STACK_SIZE
55 #else
56 #define SETTINGS_WORKQ_STACK_SIZE 0
57 #endif
58 
59 static struct k_work_q settings_work_q;
60 static K_THREAD_STACK_DEFINE(settings_work_stack, SETTINGS_WORKQ_STACK_SIZE);
61 
62 static struct k_work_delayable pending_store;
63 static ATOMIC_DEFINE(pending_flags, BT_MESH_SETTINGS_FLAG_COUNT);
64 
bt_mesh_settings_set(settings_read_cb read_cb,void * cb_arg,void * out,size_t read_len)65 int bt_mesh_settings_set(settings_read_cb read_cb, void *cb_arg,
66 			 void *out, size_t read_len)
67 {
68 	ssize_t len;
69 
70 	len = read_cb(cb_arg, out, read_len);
71 	if (len < 0) {
72 		LOG_ERR("Failed to read value (err %zd)", len);
73 		return len;
74 	}
75 
76 	LOG_HEXDUMP_DBG(out, len, "val");
77 
78 	if (len != read_len) {
79 		LOG_ERR("Unexpected value length (%zd != %zu)", len, read_len);
80 		return -EINVAL;
81 	}
82 
83 	return 0;
84 }
85 
mesh_commit(void)86 static int mesh_commit(void)
87 {
88 	if (!atomic_test_bit(bt_mesh.flags, BT_MESH_INIT)) {
89 		return 0;
90 	}
91 
92 	if (!atomic_test_bit(bt_dev.flags, BT_DEV_ENABLE)) {
93 		/* The Bluetooth Mesh settings loader calls bt_mesh_start() immediately
94 		 * after loading the settings. This is not intended to work before
95 		 * bt_enable(). The doc on @ref bt_enable requires the "bt/" settings
96 		 * tree to be loaded after @ref bt_enable is completed, so this handler
97 		 * will be called again later.
98 		 */
99 		return 0;
100 	}
101 
102 	if (!bt_mesh_subnet_next(NULL)) {
103 		/* Nothing to do since we're not yet provisioned */
104 		return 0;
105 	}
106 
107 	if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) {
108 		(void)bt_mesh_pb_gatt_srv_disable();
109 	}
110 
111 	bt_mesh_net_settings_commit();
112 	bt_mesh_model_settings_commit();
113 
114 	atomic_set_bit(bt_mesh.flags, BT_MESH_VALID);
115 
116 	bt_mesh_start();
117 
118 	return 0;
119 }
120 
121 SETTINGS_STATIC_HANDLER_DEFINE_WITH_CPRIO(bt_mesh, "bt/mesh", NULL, NULL, mesh_commit, NULL,
122 					  BT_SETTINGS_CPRIO_2);
123 
124 /* Pending flags that use K_NO_WAIT as the storage timeout */
125 #define NO_WAIT_PENDING_BITS (BIT(BT_MESH_SETTINGS_NET_PENDING) |           \
126 			      BIT(BT_MESH_SETTINGS_IV_PENDING)  |           \
127 			      BIT(BT_MESH_SETTINGS_SEQ_PENDING) |           \
128 			      BIT(BT_MESH_SETTINGS_CDB_PENDING))
129 
130 /* Pending flags that use CONFIG_BT_MESH_STORE_TIMEOUT */
131 #define GENERIC_PENDING_BITS                                                                       \
132 	(BIT(BT_MESH_SETTINGS_NET_KEYS_PENDING) | BIT(BT_MESH_SETTINGS_APP_KEYS_PENDING) |         \
133 	 BIT(BT_MESH_SETTINGS_HB_PUB_PENDING) | BIT(BT_MESH_SETTINGS_CFG_PENDING) |                \
134 	 BIT(BT_MESH_SETTINGS_MOD_PENDING) | BIT(BT_MESH_SETTINGS_VA_PENDING) |                    \
135 	 BIT(BT_MESH_SETTINGS_SSEQ_PENDING) | BIT(BT_MESH_SETTINGS_COMP_PENDING) |                 \
136 	 BIT(BT_MESH_SETTINGS_DEV_KEY_CAND_PENDING) | BIT(BT_MESH_SETTINGS_BRG_PENDING))
137 
bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag)138 void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag)
139 {
140 	uint32_t timeout_ms, remaining_ms;
141 
142 	atomic_set_bit(pending_flags, flag);
143 
144 	if (atomic_get(pending_flags) & NO_WAIT_PENDING_BITS) {
145 		timeout_ms = 0;
146 	} else if (IS_ENABLED(CONFIG_BT_MESH_RPL_STORAGE_MODE_SETTINGS) && RPL_STORE_TIMEOUT >= 0 &&
147 		   (atomic_test_bit(pending_flags, BT_MESH_SETTINGS_RPL_PENDING) ||
148 		     atomic_test_bit(pending_flags, BT_MESH_SETTINGS_SRPL_PENDING)) &&
149 		   !(atomic_get(pending_flags) & GENERIC_PENDING_BITS)) {
150 		timeout_ms = RPL_STORE_TIMEOUT * MSEC_PER_SEC;
151 	} else {
152 		timeout_ms = CONFIG_BT_MESH_STORE_TIMEOUT * MSEC_PER_SEC;
153 	}
154 
155 	remaining_ms = k_ticks_to_ms_floor32(k_work_delayable_remaining_get(&pending_store));
156 	LOG_DBG("Waiting %u ms vs rem %u ms", timeout_ms, remaining_ms);
157 
158 	/* If the new deadline is sooner, override any existing
159 	 * deadline; otherwise schedule without changing any existing
160 	 * deadline.
161 	 */
162 	if (timeout_ms < remaining_ms) {
163 		if (IS_ENABLED(CONFIG_BT_MESH_SETTINGS_WORKQ)) {
164 			k_work_reschedule_for_queue(&settings_work_q, &pending_store,
165 						    K_MSEC(timeout_ms));
166 		} else {
167 			k_work_reschedule(&pending_store, K_MSEC(timeout_ms));
168 		}
169 	} else {
170 		if (IS_ENABLED(CONFIG_BT_MESH_SETTINGS_WORKQ)) {
171 			k_work_schedule_for_queue(&settings_work_q, &pending_store,
172 						  K_MSEC(timeout_ms));
173 		} else {
174 			k_work_schedule(&pending_store, K_MSEC(timeout_ms));
175 		}
176 	}
177 }
178 
bt_mesh_settings_store_cancel(enum bt_mesh_settings_flag flag)179 void bt_mesh_settings_store_cancel(enum bt_mesh_settings_flag flag)
180 {
181 	atomic_clear_bit(pending_flags, flag);
182 }
183 
store_pending(struct k_work * work)184 static void store_pending(struct k_work *work)
185 {
186 	LOG_DBG("");
187 
188 	static const struct {
189 		void (*handler)(void);
190 	} handlers[BT_MESH_SETTINGS_FLAG_COUNT] = {
191 		[BT_MESH_SETTINGS_RPL_PENDING]      = { bt_mesh_rpl_pending_store_all_nodes },
192 		[BT_MESH_SETTINGS_NET_KEYS_PENDING] = { bt_mesh_subnet_pending_store },
193 		[BT_MESH_SETTINGS_APP_KEYS_PENDING] = { bt_mesh_app_key_pending_store },
194 		[BT_MESH_SETTINGS_NET_PENDING]	    = { bt_mesh_net_pending_net_store },
195 		[BT_MESH_SETTINGS_IV_PENDING]	    = { bt_mesh_net_pending_iv_store },
196 		[BT_MESH_SETTINGS_SEQ_PENDING]	    = { bt_mesh_net_pending_seq_store },
197 		[BT_MESH_SETTINGS_DEV_KEY_CAND_PENDING] = {
198 			bt_mesh_net_pending_dev_key_cand_store },
199 		[BT_MESH_SETTINGS_HB_PUB_PENDING]   = { bt_mesh_hb_pub_pending_store },
200 		[BT_MESH_SETTINGS_CFG_PENDING]	    = { bt_mesh_cfg_pending_store },
201 		[BT_MESH_SETTINGS_COMP_PENDING]	    = { bt_mesh_comp_data_pending_clear },
202 		[BT_MESH_SETTINGS_MOD_PENDING]	    = { bt_mesh_model_pending_store },
203 		[BT_MESH_SETTINGS_VA_PENDING]	    = { bt_mesh_va_pending_store },
204 		[BT_MESH_SETTINGS_CDB_PENDING]	    = {
205 			IS_ENABLED(CONFIG_BT_MESH_CDB) ?
206 				bt_mesh_cdb_pending_store : NULL },
207 		[BT_MESH_SETTINGS_SRPL_PENDING]     = {
208 			IS_ENABLED(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) ?
209 				bt_mesh_srpl_pending_store : NULL },
210 		[BT_MESH_SETTINGS_SSEQ_PENDING]     = {
211 			IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) ?
212 				bt_mesh_sseq_pending_store : NULL },
213 		[BT_MESH_SETTINGS_BRG_PENDING]      = {
214 			IS_ENABLED(CONFIG_BT_MESH_BRG_CFG_SRV) ?
215 				bt_mesh_brg_cfg_pending_store : NULL },
216 	};
217 
218 	for (int i = 0; i < ARRAY_SIZE(handlers); i++) {
219 		if (!handlers[i].handler) {
220 			continue;
221 		}
222 
223 		if (atomic_test_and_clear_bit(pending_flags, i)) {
224 			handlers[i].handler();
225 		}
226 	}
227 }
228 
bt_mesh_settings_init(void)229 void bt_mesh_settings_init(void)
230 {
231 	if (IS_ENABLED(CONFIG_BT_MESH_SETTINGS_WORKQ)) {
232 		k_work_queue_start(&settings_work_q, settings_work_stack,
233 				   K_THREAD_STACK_SIZEOF(settings_work_stack),
234 				   K_PRIO_COOP(SETTINGS_WORKQ_PRIO), NULL);
235 		k_thread_name_set(&settings_work_q.thread, "BT Mesh settings workq");
236 	}
237 
238 	k_work_init_delayable(&pending_store, store_pending);
239 }
240 
bt_mesh_settings_store_pending(void)241 void bt_mesh_settings_store_pending(void)
242 {
243 	(void)k_work_cancel_delayable(&pending_store);
244 
245 	store_pending(&pending_store.work);
246 }
247