1 /*
2  * Copyright (c) 2020 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/bluetooth/mesh.h>
8 #include "dfu.h"
9 #include "blob.h"
10 #include "access.h"
11 
12 #define LOG_LEVEL CONFIG_BT_MESH_DFU_LOG_LEVEL
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(bt_mesh_dfu_srv);
15 
16 #define UPDATE_IDX_NONE 0xff
17 
18 BUILD_ASSERT((DFU_UPDATE_START_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_DFU_OP_UPDATE_START) +
19 	      BT_MESH_MIC_SHORT) <= BT_MESH_RX_SDU_MAX,
20 	     "The Firmware Update Start message does not fit into the maximum incoming SDU size.");
21 
22 BUILD_ASSERT((DFU_UPDATE_INFO_STATUS_MSG_MINLEN +
23 	      BT_MESH_MODEL_OP_LEN(BT_MESH_DFU_OP_UPDATE_INFO_STATUS) + BT_MESH_MIC_SHORT)
24 	     <= BT_MESH_TX_SDU_MAX,
25 	     "The Firmware Update Info Status message does not fit into the maximum outgoing SDU "
26 	     "size.");
27 
store_state(struct bt_mesh_dfu_srv * srv)28 static void store_state(struct bt_mesh_dfu_srv *srv)
29 {
30 	bt_mesh_model_data_store(srv->mod, false, NULL, &srv->update,
31 				 sizeof(srv->update));
32 }
33 
erase_state(struct bt_mesh_dfu_srv * srv)34 static void erase_state(struct bt_mesh_dfu_srv *srv)
35 {
36 	bt_mesh_model_data_store(srv->mod, false, NULL, NULL, 0);
37 }
38 
xfer_failed(struct bt_mesh_dfu_srv * srv)39 static void xfer_failed(struct bt_mesh_dfu_srv *srv)
40 {
41 	if (!bt_mesh_dfu_srv_is_busy(srv) ||
42 	    srv->update.idx >= srv->img_count) {
43 		return;
44 	}
45 
46 	erase_state(srv);
47 
48 	if (srv->cb->end) {
49 		srv->cb->end(srv, &srv->imgs[srv->update.idx], false);
50 	}
51 }
52 
metadata_check(struct bt_mesh_dfu_srv * srv,uint8_t idx,struct net_buf_simple * buf,enum bt_mesh_dfu_effect * effect)53 static enum bt_mesh_dfu_status metadata_check(struct bt_mesh_dfu_srv *srv,
54 					      uint8_t idx,
55 					      struct net_buf_simple *buf,
56 					      enum bt_mesh_dfu_effect *effect)
57 {
58 	*effect = BT_MESH_DFU_EFFECT_NONE;
59 
60 	if (idx >= srv->img_count) {
61 		return BT_MESH_DFU_ERR_FW_IDX;
62 	}
63 
64 	if (!srv->cb->check) {
65 		return BT_MESH_DFU_SUCCESS;
66 	}
67 
68 	if (srv->cb->check(srv, &srv->imgs[idx], buf, effect)) {
69 		*effect = BT_MESH_DFU_EFFECT_NONE;
70 		return BT_MESH_DFU_ERR_METADATA;
71 	}
72 
73 	return BT_MESH_DFU_SUCCESS;
74 }
75 
apply_rsp_sent(int err,void * cb_params)76 static void apply_rsp_sent(int err, void *cb_params)
77 {
78 	struct bt_mesh_dfu_srv *srv = cb_params;
79 
80 	if (err) {
81 		LOG_WRN("Apply response failed, wait for retry");
82 		return;
83 	}
84 
85 	LOG_DBG("");
86 
87 	if (!srv->cb->apply || srv->update.idx == UPDATE_IDX_NONE) {
88 		srv->update.phase = BT_MESH_DFU_PHASE_IDLE;
89 		store_state(srv);
90 		return;
91 	}
92 
93 	err = srv->cb->apply(srv, &srv->imgs[srv->update.idx]);
94 	if (err) {
95 		srv->update.phase = BT_MESH_DFU_PHASE_IDLE;
96 	}
97 
98 	store_state(srv);
99 }
100 
apply_rsp_sending(uint16_t duration,int err,void * cb_params)101 static void apply_rsp_sending(uint16_t duration, int err, void *cb_params)
102 {
103 	if (err) {
104 		apply_rsp_sent(err, cb_params);
105 	}
106 }
107 
verify(struct bt_mesh_dfu_srv * srv)108 static void verify(struct bt_mesh_dfu_srv *srv)
109 {
110 	srv->update.phase = BT_MESH_DFU_PHASE_VERIFY;
111 
112 	if (srv->update.idx >= srv->img_count) {
113 		bt_mesh_dfu_srv_rejected(srv);
114 		return;
115 	}
116 
117 	if (!srv->cb->end) {
118 		bt_mesh_dfu_srv_verified(srv);
119 		return;
120 	}
121 
122 	srv->cb->end(srv, &srv->imgs[srv->update.idx], true);
123 	if (srv->update.phase == BT_MESH_DFU_PHASE_VERIFY) {
124 		store_state(srv);
125 	}
126 }
127 
handle_info_get(struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)128 static int handle_info_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
129 			   struct net_buf_simple *buf)
130 {
131 	struct bt_mesh_dfu_srv *srv = mod->user_data;
132 	uint8_t idx, limit;
133 
134 	if (srv->update.phase == BT_MESH_DFU_PHASE_APPLYING) {
135 		LOG_INF("Still applying, not responding");
136 		return -EBUSY;
137 	}
138 
139 	idx = net_buf_simple_pull_u8(buf);
140 	limit = net_buf_simple_pull_u8(buf);
141 
142 	LOG_DBG("from %u (limit: %u)", idx, limit);
143 
144 	NET_BUF_SIMPLE_DEFINE(rsp, BT_MESH_TX_SDU_MAX);
145 	bt_mesh_model_msg_init(&rsp, BT_MESH_DFU_OP_UPDATE_INFO_STATUS);
146 	net_buf_simple_add_u8(&rsp, srv->img_count);
147 	net_buf_simple_add_u8(&rsp, idx);
148 
149 	for (; idx < srv->img_count && limit > 0; ++idx) {
150 		uint32_t entry_len;
151 
152 		if (!srv->imgs[idx].fwid) {
153 			continue;
154 		}
155 
156 		entry_len = 2 + srv->imgs[idx].fwid_len;
157 		if (srv->imgs[idx].uri) {
158 			entry_len += strlen(srv->imgs[idx].uri);
159 		}
160 
161 		if (net_buf_simple_tailroom(&rsp) + BT_MESH_MIC_SHORT < entry_len) {
162 			break;
163 		}
164 
165 		net_buf_simple_add_u8(&rsp, srv->imgs[idx].fwid_len);
166 		net_buf_simple_add_mem(&rsp, srv->imgs[idx].fwid,
167 				       srv->imgs[idx].fwid_len);
168 
169 		if (srv->imgs[idx].uri) {
170 			size_t len = strlen(srv->imgs[idx].uri);
171 
172 			net_buf_simple_add_u8(&rsp, len);
173 			net_buf_simple_add_mem(&rsp, srv->imgs[idx].uri, len);
174 		} else {
175 			net_buf_simple_add_u8(&rsp, 0);
176 		}
177 
178 		limit--;
179 	}
180 
181 	if (srv->update.phase != BT_MESH_DFU_PHASE_IDLE) {
182 		ctx->send_ttl = srv->update.ttl;
183 	}
184 
185 	bt_mesh_model_send(mod, ctx, &rsp, NULL, NULL);
186 
187 	return 0;
188 }
189 
handle_metadata_check(struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)190 static int handle_metadata_check(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
191 				 struct net_buf_simple *buf)
192 {
193 	struct bt_mesh_dfu_srv *srv = mod->user_data;
194 	enum bt_mesh_dfu_status status;
195 	enum bt_mesh_dfu_effect effect;
196 	uint8_t idx;
197 
198 	BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFU_OP_UPDATE_METADATA_STATUS, 2);
199 	bt_mesh_model_msg_init(&rsp, BT_MESH_DFU_OP_UPDATE_METADATA_STATUS);
200 
201 	idx = net_buf_simple_pull_u8(buf);
202 	status = metadata_check(srv, idx, buf, &effect);
203 
204 	LOG_DBG("%u", idx);
205 
206 	net_buf_simple_add_u8(&rsp, (status & BIT_MASK(3)) | (effect << 3));
207 	net_buf_simple_add_u8(&rsp, idx);
208 
209 	if (srv->update.phase != BT_MESH_DFU_PHASE_IDLE) {
210 		ctx->send_ttl = srv->update.ttl;
211 	}
212 
213 	bt_mesh_model_send(mod, ctx, &rsp, NULL, NULL);
214 
215 	return 0;
216 }
217 
update_status_rsp(struct bt_mesh_dfu_srv * srv,struct bt_mesh_msg_ctx * ctx,enum bt_mesh_dfu_status status,const struct bt_mesh_send_cb * send_cb)218 static void update_status_rsp(struct bt_mesh_dfu_srv *srv,
219 			      struct bt_mesh_msg_ctx *ctx,
220 			      enum bt_mesh_dfu_status status,
221 			      const struct bt_mesh_send_cb *send_cb)
222 {
223 	BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_STATUS, 14);
224 	bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_STATUS);
225 
226 	net_buf_simple_add_u8(&buf, ((status & BIT_MASK(3)) |
227 				     (srv->update.phase << 5)));
228 
229 	if (srv->update.phase != BT_MESH_DFU_PHASE_IDLE) {
230 		net_buf_simple_add_u8(&buf, srv->update.ttl);
231 		net_buf_simple_add_u8(&buf, srv->update.effect);
232 		net_buf_simple_add_le16(&buf, srv->update.timeout_base);
233 		net_buf_simple_add_le64(&buf, srv->blob.state.xfer.id);
234 		net_buf_simple_add_u8(&buf, srv->update.idx);
235 
236 		ctx->send_ttl = srv->update.ttl;
237 	}
238 
239 	bt_mesh_model_send(srv->mod, ctx, &buf, send_cb, srv);
240 }
241 
handle_get(struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)242 static int handle_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
243 		      struct net_buf_simple *buf)
244 {
245 	struct bt_mesh_dfu_srv *srv = mod->user_data;
246 
247 	LOG_DBG("");
248 
249 	update_status_rsp(srv, ctx, BT_MESH_DFU_SUCCESS, NULL);
250 
251 	return 0;
252 }
253 
is_active_update(struct bt_mesh_dfu_srv * srv,uint8_t idx,uint16_t timeout_base,const uint64_t * blob_id,uint8_t ttl,uint16_t meta_checksum)254 static inline bool is_active_update(struct bt_mesh_dfu_srv *srv, uint8_t idx,
255 				    uint16_t timeout_base,
256 				    const uint64_t *blob_id, uint8_t ttl,
257 				    uint16_t meta_checksum)
258 {
259 	return (srv->update.idx != idx || srv->blob.state.xfer.id != *blob_id ||
260 		srv->update.ttl != ttl ||
261 		srv->update.timeout_base != timeout_base ||
262 		srv->update.meta != meta_checksum);
263 }
264 
handle_start(struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)265 static int handle_start(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
266 			struct net_buf_simple *buf)
267 {
268 	struct bt_mesh_dfu_srv *srv = mod->user_data;
269 	const struct bt_mesh_blob_io *io;
270 	uint16_t timeout_base, meta_checksum;
271 	enum bt_mesh_dfu_status status;
272 	uint8_t ttl, idx;
273 	uint64_t blob_id;
274 	int err;
275 	struct net_buf_simple_state buf_state;
276 
277 	ttl = net_buf_simple_pull_u8(buf);
278 	timeout_base = net_buf_simple_pull_le16(buf);
279 	blob_id = net_buf_simple_pull_le64(buf);
280 	idx = net_buf_simple_pull_u8(buf);
281 	meta_checksum = dfu_metadata_checksum(buf);
282 
283 	LOG_DBG("%u ttl: %u extra time: %u", idx, ttl, timeout_base);
284 
285 	if ((!buf->len || meta_checksum == srv->update.meta) &&
286 	    srv->update.phase == BT_MESH_DFU_PHASE_TRANSFER_ERR &&
287 	    srv->update.ttl == ttl &&
288 	    srv->update.timeout_base == timeout_base &&
289 	    srv->update.idx == idx &&
290 	    srv->blob.state.xfer.id == blob_id) {
291 		srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ACTIVE;
292 		status = BT_MESH_DFU_SUCCESS;
293 		store_state(srv);
294 		/* blob srv will resume the transfer. */
295 		LOG_DBG("Resuming transfer");
296 		goto rsp;
297 	}
298 
299 	if (bt_mesh_dfu_srv_is_busy(srv)) {
300 		if (is_active_update(srv, idx, timeout_base, &blob_id, ttl,
301 				     meta_checksum)) {
302 			status = BT_MESH_DFU_ERR_WRONG_PHASE;
303 		} else {
304 			status = BT_MESH_DFU_SUCCESS;
305 		}
306 
307 		srv->update.ttl = ttl;
308 		srv->blob.state.xfer.id = blob_id;
309 		LOG_WRN("Busy. Phase: %u", srv->update.phase);
310 		goto rsp;
311 	}
312 
313 	net_buf_simple_save(buf, &buf_state);
314 	status = metadata_check(srv, idx, buf,
315 				(enum bt_mesh_dfu_effect *)&srv->update.effect);
316 	net_buf_simple_restore(buf, &buf_state);
317 	if (status != BT_MESH_DFU_SUCCESS) {
318 		goto rsp;
319 	}
320 
321 	srv->update.ttl = ttl;
322 	srv->update.timeout_base = timeout_base;
323 	srv->update.meta = meta_checksum;
324 
325 	io = NULL;
326 	err = srv->cb->start(srv, &srv->imgs[idx], buf, &io);
327 	if (err == -EALREADY || (!err && bt_mesh_has_addr(ctx->addr))) {
328 		/* This image has already been received or this is a
329 		 * self-update. Skip the transfer phase and proceed to
330 		 * verifying update.
331 		 */
332 		status = BT_MESH_DFU_SUCCESS;
333 		srv->update.idx = idx;
334 		srv->blob.state.xfer.id = blob_id;
335 		srv->update.phase = BT_MESH_DFU_PHASE_VERIFY;
336 		update_status_rsp(srv, ctx, status, NULL);
337 		verify(srv);
338 		return 0;
339 	}
340 
341 	if (err == -ENOMEM) {
342 		status = BT_MESH_DFU_ERR_RESOURCES;
343 		goto rsp;
344 	}
345 
346 	if (err == -EBUSY) {
347 		status = BT_MESH_DFU_ERR_TEMPORARILY_UNAVAILABLE;
348 		goto rsp;
349 	}
350 
351 	if (err || !io || !io->wr) {
352 		status = BT_MESH_DFU_ERR_INTERNAL;
353 		goto rsp;
354 	}
355 
356 	err = bt_mesh_blob_srv_recv(&srv->blob, blob_id, io,
357 				    ttl, timeout_base);
358 	if (err) {
359 		status = BT_MESH_DFU_ERR_BLOB_XFER_BUSY;
360 		goto rsp;
361 	}
362 
363 	srv->update.idx = idx;
364 	srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ACTIVE;
365 	status = BT_MESH_DFU_SUCCESS;
366 	store_state(srv);
367 
368 rsp:
369 	update_status_rsp(srv, ctx, status, NULL);
370 
371 	return 0;
372 }
373 
handle_cancel(struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)374 static int handle_cancel(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
375 			 struct net_buf_simple *buf)
376 {
377 	struct bt_mesh_dfu_srv *srv = mod->user_data;
378 
379 	if (srv->update.idx == UPDATE_IDX_NONE) {
380 		goto rsp;
381 	}
382 
383 	LOG_DBG("");
384 
385 	bt_mesh_blob_srv_cancel(&srv->blob);
386 	srv->update.phase = BT_MESH_DFU_PHASE_IDLE;
387 	xfer_failed(srv);
388 
389 rsp:
390 	update_status_rsp(srv, ctx, BT_MESH_DFU_SUCCESS, NULL);
391 
392 	return 0;
393 }
394 
handle_apply(struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)395 static int handle_apply(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
396 			struct net_buf_simple *buf)
397 {
398 	struct bt_mesh_dfu_srv *srv = mod->user_data;
399 	static const struct bt_mesh_send_cb send_cb = {
400 		.start = apply_rsp_sending,
401 		.end = apply_rsp_sent,
402 	};
403 
404 	LOG_DBG("");
405 
406 	if (srv->update.phase == BT_MESH_DFU_PHASE_APPLYING) {
407 		update_status_rsp(srv, ctx, BT_MESH_DFU_SUCCESS, NULL);
408 		return 0;
409 	}
410 
411 	if (srv->update.phase != BT_MESH_DFU_PHASE_VERIFY_OK) {
412 		LOG_WRN("Apply: Invalid phase %u", srv->update.phase);
413 		update_status_rsp(srv, ctx, BT_MESH_DFU_ERR_WRONG_PHASE, NULL);
414 		return 0;
415 	}
416 
417 	/* Postponing the apply callback until the response has been sent, in
418 	 * case it triggers a reboot:
419 	 */
420 	srv->update.phase = BT_MESH_DFU_PHASE_APPLYING;
421 	store_state(srv);
422 
423 	update_status_rsp(srv, ctx, BT_MESH_DFU_SUCCESS, &send_cb);
424 
425 	return 0;
426 }
427 
428 const struct bt_mesh_model_op _bt_mesh_dfu_srv_op[] = {
429 	{ BT_MESH_DFU_OP_UPDATE_INFO_GET, BT_MESH_LEN_EXACT(2), handle_info_get },
430 	{ BT_MESH_DFU_OP_UPDATE_METADATA_CHECK, BT_MESH_LEN_MIN(1), handle_metadata_check },
431 	{ BT_MESH_DFU_OP_UPDATE_GET, BT_MESH_LEN_EXACT(0), handle_get },
432 	{ BT_MESH_DFU_OP_UPDATE_START, BT_MESH_LEN_MIN(12), handle_start },
433 	{ BT_MESH_DFU_OP_UPDATE_CANCEL, BT_MESH_LEN_EXACT(0), handle_cancel },
434 	{ BT_MESH_DFU_OP_UPDATE_APPLY, BT_MESH_LEN_EXACT(0), handle_apply },
435 	BT_MESH_MODEL_OP_END,
436 };
437 
dfu_srv_init(struct bt_mesh_model * mod)438 static int dfu_srv_init(struct bt_mesh_model *mod)
439 {
440 	struct bt_mesh_dfu_srv *srv = mod->user_data;
441 
442 	srv->mod = mod;
443 	srv->update.idx = UPDATE_IDX_NONE;
444 
445 	if (!srv->cb || !srv->cb->start || !srv->imgs || srv->img_count == 0 ||
446 	    srv->img_count == UPDATE_IDX_NONE) {
447 		LOG_ERR("Invalid DFU Server initialization");
448 		return -EINVAL;
449 	}
450 
451 	if (IS_ENABLED(CONFIG_BT_MESH_MODEL_EXTENSIONS)) {
452 		bt_mesh_model_extend(mod, srv->blob.mod);
453 	}
454 
455 	return 0;
456 }
457 
dfu_srv_settings_set(struct bt_mesh_model * mod,const char * name,size_t len_rd,settings_read_cb read_cb,void * cb_arg)458 static int dfu_srv_settings_set(struct bt_mesh_model *mod, const char *name,
459 				size_t len_rd, settings_read_cb read_cb,
460 				void *cb_arg)
461 {
462 	struct bt_mesh_dfu_srv *srv = mod->user_data;
463 	ssize_t len;
464 
465 	if (len_rd < sizeof(srv->update)) {
466 		return -EINVAL;
467 	}
468 
469 	len = read_cb(cb_arg, &srv->update, sizeof(srv->update));
470 	if (len < 0) {
471 		return len;
472 	}
473 
474 	LOG_DBG("Recovered transfer (phase: %u, idx: %u)", srv->update.phase,
475 		srv->update.idx);
476 	if (srv->update.phase == BT_MESH_DFU_PHASE_TRANSFER_ACTIVE) {
477 		LOG_DBG("Settings recovered mid-transfer, setting transfer error");
478 		srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ERR;
479 	} else if (srv->update.phase == BT_MESH_DFU_PHASE_VERIFY_OK) {
480 		LOG_DBG("Settings recovered before application, setting verification fail");
481 		srv->update.phase = BT_MESH_DFU_PHASE_VERIFY_FAIL;
482 	}
483 
484 	return 0;
485 }
486 
dfu_srv_reset(struct bt_mesh_model * mod)487 static void dfu_srv_reset(struct bt_mesh_model *mod)
488 {
489 	struct bt_mesh_dfu_srv *srv = mod->user_data;
490 
491 	srv->update.phase = BT_MESH_DFU_PHASE_IDLE;
492 	erase_state(srv);
493 }
494 
495 const struct bt_mesh_model_cb _bt_mesh_dfu_srv_cb = {
496 	.init = dfu_srv_init,
497 	.settings_set = dfu_srv_settings_set,
498 	.reset = dfu_srv_reset,
499 };
500 
blob_suspended(struct bt_mesh_blob_srv * b)501 static void blob_suspended(struct bt_mesh_blob_srv *b)
502 {
503 	struct bt_mesh_dfu_srv *srv = CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob);
504 
505 	srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ERR;
506 	store_state(srv);
507 }
508 
blob_end(struct bt_mesh_blob_srv * b,uint64_t id,bool success)509 static void blob_end(struct bt_mesh_blob_srv *b, uint64_t id, bool success)
510 {
511 	struct bt_mesh_dfu_srv *srv =
512 		CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob);
513 
514 	LOG_DBG("success: %u", success);
515 
516 	if (!success) {
517 		srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ERR;
518 		xfer_failed(srv);
519 		return;
520 	}
521 
522 	verify(srv);
523 }
524 
blob_recover(struct bt_mesh_blob_srv * b,struct bt_mesh_blob_xfer * xfer,const struct bt_mesh_blob_io ** io)525 static int blob_recover(struct bt_mesh_blob_srv *b,
526 			struct bt_mesh_blob_xfer *xfer,
527 			const struct bt_mesh_blob_io **io)
528 {
529 	struct bt_mesh_dfu_srv *srv =
530 		CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob);
531 
532 	if (!srv->cb->recover ||
533 	    srv->update.phase != BT_MESH_DFU_PHASE_TRANSFER_ERR ||
534 	    srv->update.idx >= srv->img_count) {
535 		return -ENOTSUP;
536 	}
537 
538 	return srv->cb->recover(srv, &srv->imgs[srv->update.idx], io);
539 }
540 
541 const struct bt_mesh_blob_srv_cb _bt_mesh_dfu_srv_blob_cb = {
542 	.suspended = blob_suspended,
543 	.end = blob_end,
544 	.recover = blob_recover,
545 };
546 
bt_mesh_dfu_srv_verified(struct bt_mesh_dfu_srv * srv)547 void bt_mesh_dfu_srv_verified(struct bt_mesh_dfu_srv *srv)
548 {
549 	if (srv->update.phase != BT_MESH_DFU_PHASE_VERIFY) {
550 		LOG_WRN("Wrong state");
551 		return;
552 	}
553 
554 	LOG_DBG("");
555 
556 	srv->update.phase = BT_MESH_DFU_PHASE_VERIFY_OK;
557 	store_state(srv);
558 }
559 
bt_mesh_dfu_srv_rejected(struct bt_mesh_dfu_srv * srv)560 void bt_mesh_dfu_srv_rejected(struct bt_mesh_dfu_srv *srv)
561 {
562 	if (srv->update.phase != BT_MESH_DFU_PHASE_VERIFY) {
563 		LOG_WRN("Wrong state");
564 		return;
565 	}
566 
567 	LOG_DBG("");
568 
569 	srv->update.phase = BT_MESH_DFU_PHASE_VERIFY_FAIL;
570 	store_state(srv);
571 }
572 
bt_mesh_dfu_srv_cancel(struct bt_mesh_dfu_srv * srv)573 void bt_mesh_dfu_srv_cancel(struct bt_mesh_dfu_srv *srv)
574 {
575 	if (srv->update.phase == BT_MESH_DFU_PHASE_IDLE) {
576 		LOG_WRN("Wrong state");
577 		return;
578 	}
579 
580 	(void)bt_mesh_blob_srv_cancel(&srv->blob);
581 }
582 
bt_mesh_dfu_srv_applied(struct bt_mesh_dfu_srv * srv)583 void bt_mesh_dfu_srv_applied(struct bt_mesh_dfu_srv *srv)
584 {
585 	if (srv->update.phase != BT_MESH_DFU_PHASE_APPLYING) {
586 		LOG_WRN("Wrong state");
587 		return;
588 	}
589 
590 	LOG_DBG("");
591 
592 	srv->update.phase = BT_MESH_DFU_PHASE_IDLE;
593 	store_state(srv);
594 }
595 
bt_mesh_dfu_srv_is_busy(const struct bt_mesh_dfu_srv * srv)596 bool bt_mesh_dfu_srv_is_busy(const struct bt_mesh_dfu_srv *srv)
597 {
598 	return srv->update.phase != BT_MESH_DFU_PHASE_IDLE &&
599 	       srv->update.phase != BT_MESH_DFU_PHASE_TRANSFER_ERR &&
600 	       srv->update.phase != BT_MESH_DFU_PHASE_VERIFY_FAIL;
601 }
602 
bt_mesh_dfu_srv_progress(const struct bt_mesh_dfu_srv * srv)603 uint8_t bt_mesh_dfu_srv_progress(const struct bt_mesh_dfu_srv *srv)
604 {
605 	if (!bt_mesh_dfu_srv_is_busy(srv)) {
606 		return 0U;
607 	}
608 
609 	if (srv->update.phase == BT_MESH_DFU_PHASE_TRANSFER_ACTIVE) {
610 		return bt_mesh_blob_srv_progress(&srv->blob);
611 	}
612 
613 	return 100U;
614 }
615