Skip to content

Commit 69ca589

Browse files
rluboscarlescufi
authored andcommitted
net: lwm2m: Fix opaque data transfer in block mode
When FW update in PUSH mode is used, the firmware is encapsulated in the TLV as an opaque data, according to the LMWM2M satandard, and then sliced into blocks and transferred block by block in several transactions. Therefore, the TLV header is only present in the initial message. Current implementation did not handle this case well, reporting errors on consecutive blocks, therefore making the FW update in PUSH mode broken. This commit fixes this issue with following changes: * The TLV is only assumed to be present in the initial block, while consecutive blocks will be processed directly into the appropriate handler, * 32-bit variables shall be used whenever dealing with the opaque data length, since the firmware size can easily exceed the 16-bit range, * Additional information, required for the FW block transfer to work properly were added to the block context structure, * The application shall only be notified of the actual data length, and not the total block size (the total TLV size including header). Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
1 parent daf303e commit 69ca589

File tree

3 files changed

+72
-16
lines changed

3 files changed

+72
-16
lines changed

subsys/net/lib/lwm2m/lwm2m_engine.c

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,11 @@ static int sock_nfds;
141141
struct block_context {
142142
struct coap_block_context ctx;
143143
int64_t timestamp;
144+
uint32_t remaining_len;
144145
uint8_t token[8];
145146
uint8_t tkl;
147+
uint8_t opaque_header_len;
148+
bool last_block : 1;
146149
};
147150

148151
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)
272275
memcpy((*ctx)->token, token, tkl);
273276
coap_block_transfer_init(&(*ctx)->ctx, lwm2m_default_block_size(), 0);
274277
(*ctx)->timestamp = timestamp;
278+
(*ctx)->remaining_len = 0;
279+
(*ctx)->opaque_header_len = 0;
280+
(*ctx)->last_block = false;
275281

276282
return 0;
277283
}
@@ -2209,14 +2215,20 @@ static int lwm2m_read_handler(struct lwm2m_engine_obj_inst *obj_inst,
22092215
size_t lwm2m_engine_get_opaque_more(struct lwm2m_input_context *in,
22102216
uint8_t *buf, size_t buflen, bool *last_block)
22112217
{
2212-
uint16_t in_len = in->opaque_len;
2218+
uint32_t in_len = in->opaque_len;
2219+
uint16_t remaining = in->in_cpkt->max_len - in->offset;
22132220

22142221
if (in_len > buflen) {
22152222
in_len = buflen;
22162223
}
22172224

2225+
if (in_len > remaining) {
2226+
in_len = remaining;
2227+
}
2228+
22182229
in->opaque_len -= in_len;
2219-
if (in->opaque_len == 0U) {
2230+
remaining -= in_len;
2231+
if (in->opaque_len == 0U || remaining == 0) {
22202232
*last_block = true;
22212233
}
22222234

@@ -2234,39 +2246,73 @@ static int lwm2m_write_handler_opaque(struct lwm2m_engine_obj_inst *obj_inst,
22342246
struct lwm2m_engine_res_inst *res_inst,
22352247
struct lwm2m_input_context *in,
22362248
void *data_ptr, size_t data_len,
2237-
bool last_block, size_t total_size)
2249+
struct block_context *block_ctx)
22382250
{
22392251
size_t len = 1;
22402252
bool last_pkt_block = false, first_read = true;
2253+
int block_num = 0;
22412254
int ret = 0;
2255+
size_t total_size = 0;
2256+
bool last_block = true;
2257+
2258+
if (block_ctx != NULL) {
2259+
block_num = block_ctx->ctx.current /
2260+
coap_block_size_to_bytes(block_ctx->ctx.block_size);
2261+
last_block = block_ctx->last_block;
2262+
}
22422263

22432264
while (!last_pkt_block && len > 0) {
2244-
if (first_read) {
2265+
if (first_read && block_num == 0) {
22452266
len = engine_get_opaque(in, (uint8_t *)data_ptr,
22462267
data_len, &last_pkt_block);
22472268
if (len == 0) {
22482269
/* ignore empty content and continue */
22492270
return 0;
22502271
}
22512272

2273+
if (block_ctx != NULL) {
2274+
block_ctx->remaining_len = in->opaque_len;
2275+
/* engine_get_opaque returns only the actual
2276+
* data length, not the header length, so we
2277+
* need to calculate it.
2278+
*/
2279+
block_ctx->opaque_header_len =
2280+
block_ctx->ctx.total_size -
2281+
(block_ctx->remaining_len + len);
2282+
}
2283+
22522284
first_read = false;
22532285
} else {
2286+
if (block_ctx != NULL) {
2287+
in->opaque_len = block_ctx->remaining_len;
2288+
}
2289+
22542290
len = lwm2m_engine_get_opaque_more(in, (uint8_t *)data_ptr,
22552291
data_len,
22562292
&last_pkt_block);
2293+
2294+
if (block_ctx != NULL) {
2295+
block_ctx->remaining_len = in->opaque_len;
2296+
}
22572297
}
22582298

22592299
if (len == 0) {
22602300
return -EINVAL;
22612301
}
22622302

2303+
if (block_ctx != NULL) {
2304+
/* We shall only report the actual total data length,
2305+
* excluding the header size (if any).
2306+
*/
2307+
total_size = block_ctx->ctx.total_size -
2308+
block_ctx->opaque_header_len;
2309+
}
2310+
22632311
if (res->post_write_cb) {
2264-
ret = res->post_write_cb(obj_inst->obj_inst_id,
2265-
res->res_id,
2266-
res_inst->res_inst_id,
2267-
data_ptr, len,
2268-
last_pkt_block && last_block,
2269-
total_size);
2312+
ret = res->post_write_cb(
2313+
obj_inst->obj_inst_id, res->res_id,
2314+
res_inst->res_inst_id, data_ptr, len,
2315+
last_pkt_block && last_block, total_size);
22702316
if (ret < 0) {
22712317
return ret;
22722318
}
@@ -2318,8 +2364,6 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst,
23182364
/* Get block1 option for checking MORE block flag */
23192365
ret = coap_get_option_int(msg->in.in_cpkt, COAP_OPTION_BLOCK1);
23202366
if (ret >= 0) {
2321-
last_block = !GET_MORE(ret);
2322-
23232367
/* Get block_ctx for total_size (might be zero) */
23242368
tkl = coap_header_get_token(msg->in.in_cpkt, token);
23252369
if (tkl && !get_block_ctx(token, tkl, &block_ctx)) {
@@ -2328,7 +2372,7 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst,
23282372
" last:%u",
23292373
block_ctx->ctx.total_size,
23302374
block_ctx->ctx.current,
2331-
last_block);
2375+
block_ctx->last_block);
23322376
}
23332377
}
23342378
}
@@ -2340,8 +2384,7 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst,
23402384
ret = lwm2m_write_handler_opaque(obj_inst, res,
23412385
res_inst, &msg->in,
23422386
data_ptr, data_len,
2343-
last_block,
2344-
total_size);
2387+
block_ctx);
23452388
if (ret < 0) {
23462389
return ret;
23472390
}
@@ -3498,6 +3541,8 @@ static int handle_request(struct coap_packet *request,
34983541
goto error;
34993542
}
35003543

3544+
block_ctx->last_block = last_block;
3545+
35013546
/* Handle blockwise 1 (Part 1): Set response code */
35023547
if (!last_block) {
35033548
msg->code = COAP_RESPONSE_CODE_CONTINUE;

subsys/net/lib/lwm2m/lwm2m_object.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ struct lwm2m_input_context {
379379
uint16_t offset;
380380

381381
/* length of incoming opaque */
382-
uint16_t opaque_len;
382+
size_t opaque_len;
383383

384384
/* private output data */
385385
void *user_data;

subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,17 @@ int do_write_op_tlv(struct lwm2m_message *msg)
919919
struct oma_tlv tlv;
920920
int ret;
921921

922+
/* In case of Firmware object Package resource go directly to the
923+
* message processing - consecutive blocks will not carry the TLV
924+
* header.
925+
*/
926+
if (msg->path.obj_id == 5 && msg->path.res_id == 0) {
927+
ret = do_write_op_tlv_item(msg);
928+
if (ret < 0) {
929+
return ret;
930+
}
931+
}
932+
922933
while (true) {
923934
/*
924935
* This initial read of TLV data won't advance frag/offset.

0 commit comments

Comments
 (0)