Skip to content

Commit 7bd44ad

Browse files
PavelVPVcvinayak
authored andcommitted
[nrf fromlist] Bluetooth: Mesh: Keep sending Partial Block Report message
When the BLOB server is in Pull mode and all chunks were received for the current block, and the current block is the last block, then according to section 5.2.4 of MshMBTv1.0 the server should stop sending BLOB Partial Block Report messages if it determines that the client knows that the transfer is complete: ``` While the Pull BLOB State Machine is in the All Chunks Received state, the Pull BLOB State Machine continues to send the BLOB Partial Block Report messages until one of the following happens: • The Receive BLOB Timeout timer expires. • If the current block is not the last block, then the client starts a new block, in which case a new Pull BLOB State Machine is instantiated. • If the current block is the last block, then the server determines that the client knows the transfer is complete. For example, a higher-layer model may indicate that the client considers the transfer complete. ``` We currently don't have any OOB mean (for example, API) to determine whether the client knows that the transfer is complete. We also need to keep in mind that the Partial Block Report message can get lost so one transmission may not be enough. The client could immediately send BLOB Transfer Get message to get the transfer status, but this goes against its state machine defined in section 6.2.4.2, where a Block transmission completes when a BLOB Partial Block Report message is received with an empty list of requested chunks (table 6.4, figure 6.1). Because of this, we need to keep sending Partial Block Report messages. We can keep sending them at least until Block Report timer expires. If the client sends BLOB Transfer Get message, then it finished with sending the block and we can change the phase and finish the transfer. Upstream PR: zephyrproject-rtos/zephyr#63904 Signed-off-by: Pavel Vasilyev <[email protected]>
1 parent 83bc101 commit 7bd44ad

File tree

1 file changed

+56
-14
lines changed

1 file changed

+56
-14
lines changed

subsys/bluetooth/mesh/blob_srv.c

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,37 @@ static void resume(struct bt_mesh_blob_srv *srv)
251251
reset_timer(srv);
252252
}
253253

254+
static void end(struct bt_mesh_blob_srv *srv)
255+
{
256+
phase_set(srv, BT_MESH_BLOB_XFER_PHASE_COMPLETE);
257+
k_work_cancel_delayable(&srv->rx_timeout);
258+
k_work_cancel_delayable(&srv->pull.report);
259+
io_close(srv);
260+
erase_state(srv);
261+
262+
if (srv->cb && srv->cb->end) {
263+
srv->cb->end(srv, srv->state.xfer.id, true);
264+
}
265+
}
266+
267+
static bool all_blocks_received(struct bt_mesh_blob_srv *srv)
268+
{
269+
for (int i = 0; i < ARRAY_SIZE(srv->state.blocks); ++i) {
270+
if (srv->state.blocks[i]) {
271+
return false;
272+
}
273+
}
274+
275+
return true;
276+
}
277+
278+
static bool pull_mode_xfer_complete(struct bt_mesh_blob_srv *srv)
279+
{
280+
return srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL &&
281+
srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK &&
282+
all_blocks_received(srv);
283+
}
284+
254285
static void timeout(struct k_work *work)
255286
{
256287
struct bt_mesh_blob_srv *srv =
@@ -260,6 +291,8 @@ static void timeout(struct k_work *work)
260291

261292
if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) {
262293
cancel(srv);
294+
} else if (pull_mode_xfer_complete(srv)) {
295+
end(srv);
263296
} else {
264297
suspend(srv);
265298
}
@@ -388,6 +421,15 @@ static int handle_xfer_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ct
388421
struct bt_mesh_blob_srv *srv = mod->user_data;
389422

390423
LOG_DBG("");
424+
425+
if (pull_mode_xfer_complete(srv)) {
426+
/* The client requested transfer. If we are in Pull mode and all blocks were
427+
* received, we should change the Transfer state here to Complete so that the client
428+
* receives the correct state.
429+
*/
430+
end(srv);
431+
}
432+
391433
xfer_status_rsp(srv, ctx, BT_MESH_BLOB_SUCCESS);
392434

393435
return 0;
@@ -685,7 +727,7 @@ static int handle_chunk(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
685727
struct bt_mesh_blob_chunk chunk;
686728
size_t expected_size = 0;
687729
uint16_t idx;
688-
int i, err;
730+
int err;
689731

690732
idx = net_buf_simple_pull_le16(buf);
691733
chunk.size = buf->len;
@@ -745,26 +787,26 @@ static int handle_chunk(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
745787

746788
atomic_clear_bit(srv->state.blocks, srv->block.number);
747789

748-
for (i = 0; i < ARRAY_SIZE(srv->state.blocks); ++i) {
749-
if (!srv->state.blocks[i]) {
750-
continue;
751-
}
752-
790+
if (!all_blocks_received(srv)) {
753791
phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK);
754792
store_state(srv);
755793
return 0;
756794
}
757795

758-
phase_set(srv, BT_MESH_BLOB_XFER_PHASE_COMPLETE);
759-
k_work_cancel_delayable(&srv->rx_timeout);
760-
k_work_cancel_delayable(&srv->pull.report);
761-
io_close(srv);
762-
erase_state(srv);
763-
764-
if (srv->cb && srv->cb->end) {
765-
srv->cb->end(srv, srv->state.xfer.id, true);
796+
if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) {
797+
/* By spec (section 5.2.4), the BLOB Server stops sending BLOB Partial Block Report
798+
* messages "If the current block is the last block, then the server determines that
799+
* the client knows the transfer is complete. For example, a higher-layer model may
800+
* indicate that the client considers the transfer complete."
801+
*
802+
* We don't have any way for higher-layer model to indicate that the transfer is
803+
* complete. Therefore we need to keep sending Partial Block Report messages until
804+
* the client sends BLOB Transfer Get message or the Block Timer expires.
805+
*/
806+
return 0;
766807
}
767808

809+
end(srv);
768810
return 0;
769811
}
770812

0 commit comments

Comments
 (0)