net: lwm2m: Fix FOTA block transfer with opaque content-format

This commit fixes PUSH FOTA when opaque content-format is used.

This consists of the following fixes:
 * Moved `struct block_context` to a private header, so that it can be a
   part of `struct lwm2m_input_context`. This allows content decoders to
   make use of the block context data.
 * Removed faulty `get_length_left` function from the plain text
   decoder, and replace it with coap_packet_get_payload() to obtain the
   actual payload size.
 * Introduce `struct lwm2m_opaque_context` as a part of block context,
   which allows to keep track of opaque data download progress.
 * Simplify `lwm2m_write_handler_opaque()` function. It will now only
   make calls to `engine_get_opaque` - it's the decoder responsibility
   to update the opaque context according to it's content format (for
   instance TLV decoder should only update it with the actual opaque
   data size, not the whole TLV).

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
Robert Lubos 2020-09-16 15:09:30 +02:00 committed by Carles Cufí
commit 12e1fd653d
6 changed files with 125 additions and 116 deletions

View file

@ -138,18 +138,7 @@ static int sock_nfds;
/* TODO: figure out what's correct value */
#define TIMEOUT_BLOCKWISE_TRANSFER_MS (MSEC_PER_SEC * 30)
struct block_context {
struct coap_block_context ctx;
int64_t timestamp;
uint32_t remaining_len;
uint32_t expected;
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];
static struct lwm2m_block_context block1_contexts[NUM_BLOCK1_CONTEXT];
/* write-attribute related definitons */
static const char * const LWM2M_ATTR_STR[] = { "pmin", "pmax",
@ -243,8 +232,8 @@ enum coap_block_size lwm2m_default_block_size(void)
return COAP_BLOCK_256;
}
static int
init_block_ctx(const uint8_t *token, uint8_t tkl, struct block_context **ctx)
static int init_block_ctx(const uint8_t *token, uint8_t tkl,
struct lwm2m_block_context **ctx)
{
int i;
int64_t timestamp;
@ -276,16 +265,15 @@ 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)->expected = 0;
(*ctx)->last_block = false;
memset(&(*ctx)->opaque, 0, sizeof((*ctx)->opaque));
return 0;
}
static int
get_block_ctx(const uint8_t *token, uint8_t tkl, struct block_context **ctx)
static int get_block_ctx(const uint8_t *token, uint8_t tkl,
struct lwm2m_block_context **ctx)
{
int i;
@ -308,7 +296,7 @@ get_block_ctx(const uint8_t *token, uint8_t tkl, struct block_context **ctx)
return 0;
}
static void free_block_ctx(struct block_context *ctx)
static void free_block_ctx(struct lwm2m_block_context *ctx)
{
if (ctx == NULL) {
return;
@ -2213,9 +2201,11 @@ 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)
uint8_t *buf, size_t buflen,
struct lwm2m_opaque_context *opaque,
bool *last_block)
{
uint32_t in_len = in->opaque_len;
uint32_t in_len = opaque->remaining;
uint16_t remaining = in->in_cpkt->max_len - in->offset;
if (in_len > buflen) {
@ -2226,9 +2216,9 @@ size_t lwm2m_engine_get_opaque_more(struct lwm2m_input_context *in,
in_len = remaining;
}
in->opaque_len -= in_len;
opaque->remaining -= in_len;
remaining -= in_len;
if (in->opaque_len == 0U || remaining == 0) {
if (opaque->remaining == 0U || remaining == 0) {
*last_block = true;
}
@ -2245,80 +2235,44 @@ static int lwm2m_write_handler_opaque(struct lwm2m_engine_obj_inst *obj_inst,
struct lwm2m_engine_res *res,
struct lwm2m_engine_res_inst *res_inst,
struct lwm2m_input_context *in,
void *data_ptr, size_t data_len,
struct block_context *block_ctx)
void *data_ptr, size_t data_len)
{
size_t len = 1;
bool last_pkt_block = false, first_read = true;
int block_num = 0;
bool last_pkt_block = false;
int ret = 0;
size_t total_size = 0;
bool last_block = true;
struct lwm2m_opaque_context opaque_ctx = { 0 };
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;
if (in->block_ctx != NULL) {
last_block = in->block_ctx->last_block;
/* Restore the opaque context from the block context, if used.
*/
opaque_ctx = in->block_ctx->opaque;
}
while (!last_pkt_block && len > 0) {
if (first_read && block_num == 0) {
len = engine_get_opaque(in, (uint8_t *)data_ptr,
data_len, &last_pkt_block);
if (len == 0) {
/* ignore empty content and continue */
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;
}
}
len = engine_get_opaque(in, (uint8_t *)data_ptr,
data_len, &opaque_ctx, &last_pkt_block);
if (len == 0) {
return -EINVAL;
/* ignore empty content and continue */
return 0;
}
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);
last_pkt_block && last_block, opaque_ctx.len);
if (ret < 0) {
return ret;
}
}
}
if (in->block_ctx != NULL) {
in->block_ctx->opaque = opaque_ctx;
}
return ret;
}
@ -2329,7 +2283,6 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst,
struct lwm2m_engine_obj_field *obj_field,
struct lwm2m_message *msg)
{
struct block_context *block_ctx = NULL;
void *data_ptr = NULL;
size_t data_len = 0;
size_t len = 0;
@ -2337,8 +2290,6 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst,
int64_t temp64 = 0;
int32_t temp32 = 0;
int ret = 0;
uint8_t token[8];
uint8_t tkl = 0U;
bool last_block = true;
if (!obj_inst || !res || !res_inst || !obj_field || !msg) {
@ -2361,19 +2312,14 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst,
}
if (res->post_write_cb) {
/* Get block1 option for checking MORE block flag */
ret = coap_get_option_int(msg->in.in_cpkt, COAP_OPTION_BLOCK1);
if (ret >= 0) {
if (msg->in.block_ctx != NULL) {
/* 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)) {
total_size = block_ctx->ctx.total_size;
LOG_DBG("BLOCK1: total:%zu current:%zu"
" last:%u",
block_ctx->ctx.total_size,
block_ctx->ctx.current,
block_ctx->last_block);
}
total_size = msg->in.block_ctx->ctx.total_size;
LOG_DBG("BLOCK1: total:%zu current:%zu"
" last:%u",
msg->in.block_ctx->ctx.total_size,
msg->in.block_ctx->ctx.current,
msg->in.block_ctx->last_block);
}
}
@ -2383,8 +2329,7 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst,
case LWM2M_RES_TYPE_OPAQUE:
ret = lwm2m_write_handler_opaque(obj_inst, res,
res_inst, &msg->in,
data_ptr, data_len,
block_ctx);
data_ptr, data_len);
if (ret < 0) {
return ret;
}
@ -3330,7 +3275,7 @@ static int handle_request(struct coap_packet *request,
int observe = -1; /* default to -1, 0 = ENABLE, 1 = DISABLE */
bool well_known = false;
int block_opt, block_num;
struct block_context *block_ctx = NULL;
struct lwm2m_block_context *block_ctx = NULL;
enum coap_block_size block_size;
uint16_t payload_len = 0U;
bool last_block = false;
@ -3543,6 +3488,8 @@ static int handle_request(struct coap_packet *request,
goto error;
}
msg->in.block_ctx = block_ctx;
if (block_num < block_ctx->expected) {
LOG_WRN("Block already handled %d, expected %d",
block_num, block_ctx->expected);
@ -4518,8 +4465,7 @@ static int lwm2m_engine_init(const struct device *dev)
{
int ret = 0;
(void)memset(block1_contexts, 0,
sizeof(struct block_context) * NUM_BLOCK1_CONTEXT);
(void)memset(block1_contexts, 0, sizeof(block1_contexts));
/* start sock receive thread */
k_thread_create(&engine_thread_data,