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