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