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