diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 8f76f2bcef9..047775475e8 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -141,8 +141,11 @@ static int sock_nfds; struct block_context { struct coap_block_context ctx; int64_t timestamp; + uint32_t remaining_len; uint8_t token[8]; uint8_t tkl; + uint8_t opaque_header_len; + bool last_block : 1; }; static struct block_context block1_contexts[NUM_BLOCK1_CONTEXT]; @@ -272,6 +275,9 @@ init_block_ctx(const uint8_t *token, uint8_t tkl, struct block_context **ctx) memcpy((*ctx)->token, token, tkl); coap_block_transfer_init(&(*ctx)->ctx, lwm2m_default_block_size(), 0); (*ctx)->timestamp = timestamp; + (*ctx)->remaining_len = 0; + (*ctx)->opaque_header_len = 0; + (*ctx)->last_block = false; return 0; } @@ -2209,14 +2215,20 @@ static int lwm2m_read_handler(struct lwm2m_engine_obj_inst *obj_inst, size_t lwm2m_engine_get_opaque_more(struct lwm2m_input_context *in, uint8_t *buf, size_t buflen, bool *last_block) { - uint16_t in_len = in->opaque_len; + uint32_t in_len = in->opaque_len; + uint16_t remaining = in->in_cpkt->max_len - in->offset; if (in_len > buflen) { in_len = buflen; } + if (in_len > remaining) { + in_len = remaining; + } + in->opaque_len -= in_len; - if (in->opaque_len == 0U) { + remaining -= in_len; + if (in->opaque_len == 0U || remaining == 0) { *last_block = true; } @@ -2234,14 +2246,23 @@ static int lwm2m_write_handler_opaque(struct lwm2m_engine_obj_inst *obj_inst, struct lwm2m_engine_res_inst *res_inst, struct lwm2m_input_context *in, void *data_ptr, size_t data_len, - bool last_block, size_t total_size) + struct block_context *block_ctx) { size_t len = 1; bool last_pkt_block = false, first_read = true; + int block_num = 0; int ret = 0; + size_t total_size = 0; + bool last_block = true; + + if (block_ctx != NULL) { + block_num = block_ctx->ctx.current / + coap_block_size_to_bytes(block_ctx->ctx.block_size); + last_block = block_ctx->last_block; + } while (!last_pkt_block && len > 0) { - if (first_read) { + if (first_read && block_num == 0) { len = engine_get_opaque(in, (uint8_t *)data_ptr, data_len, &last_pkt_block); if (len == 0) { @@ -2249,24 +2270,49 @@ static int lwm2m_write_handler_opaque(struct lwm2m_engine_obj_inst *obj_inst, return 0; } + if (block_ctx != NULL) { + block_ctx->remaining_len = in->opaque_len; + /* engine_get_opaque returns only the actual + * data length, not the header length, so we + * need to calculate it. + */ + block_ctx->opaque_header_len = + block_ctx->ctx.total_size - + (block_ctx->remaining_len + len); + } + first_read = false; } else { + if (block_ctx != NULL) { + in->opaque_len = block_ctx->remaining_len; + } + len = lwm2m_engine_get_opaque_more(in, (uint8_t *)data_ptr, data_len, &last_pkt_block); + + if (block_ctx != NULL) { + block_ctx->remaining_len = in->opaque_len; + } } if (len == 0) { return -EINVAL; } + if (block_ctx != NULL) { + /* We shall only report the actual total data length, + * excluding the header size (if any). + */ + total_size = block_ctx->ctx.total_size - + block_ctx->opaque_header_len; + } + if (res->post_write_cb) { - ret = res->post_write_cb(obj_inst->obj_inst_id, - res->res_id, - res_inst->res_inst_id, - data_ptr, len, - last_pkt_block && last_block, - total_size); + ret = res->post_write_cb( + obj_inst->obj_inst_id, res->res_id, + res_inst->res_inst_id, data_ptr, len, + last_pkt_block && last_block, total_size); if (ret < 0) { return ret; } @@ -2318,8 +2364,6 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, /* Get block1 option for checking MORE block flag */ ret = coap_get_option_int(msg->in.in_cpkt, COAP_OPTION_BLOCK1); if (ret >= 0) { - last_block = !GET_MORE(ret); - /* Get block_ctx for total_size (might be zero) */ tkl = coap_header_get_token(msg->in.in_cpkt, token); if (tkl && !get_block_ctx(token, tkl, &block_ctx)) { @@ -2328,7 +2372,7 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, " last:%u", block_ctx->ctx.total_size, block_ctx->ctx.current, - last_block); + block_ctx->last_block); } } } @@ -2340,8 +2384,7 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, ret = lwm2m_write_handler_opaque(obj_inst, res, res_inst, &msg->in, data_ptr, data_len, - last_block, - total_size); + block_ctx); if (ret < 0) { return ret; } @@ -3498,6 +3541,8 @@ static int handle_request(struct coap_packet *request, goto error; } + block_ctx->last_block = last_block; + /* Handle blockwise 1 (Part 1): Set response code */ if (!last_block) { msg->code = COAP_RESPONSE_CODE_CONTINUE; diff --git a/subsys/net/lib/lwm2m/lwm2m_object.h b/subsys/net/lib/lwm2m/lwm2m_object.h index 723f64ca0ab..444fd6deec9 100644 --- a/subsys/net/lib/lwm2m/lwm2m_object.h +++ b/subsys/net/lib/lwm2m/lwm2m_object.h @@ -379,7 +379,7 @@ struct lwm2m_input_context { uint16_t offset; /* length of incoming opaque */ - uint16_t opaque_len; + size_t opaque_len; /* private output data */ void *user_data; diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c index 66380965382..18fbe74bb04 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c +++ b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c @@ -919,6 +919,17 @@ int do_write_op_tlv(struct lwm2m_message *msg) struct oma_tlv tlv; int ret; + /* In case of Firmware object Package resource go directly to the + * message processing - consecutive blocks will not carry the TLV + * header. + */ + if (msg->path.obj_id == 5 && msg->path.res_id == 0) { + ret = do_write_op_tlv_item(msg); + if (ret < 0) { + return ret; + } + } + while (true) { /* * This initial read of TLV data won't advance frag/offset.