From 51d80a9838b3052f9a564d3a8df689b9501597ed Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Wed, 10 Apr 2024 13:44:14 +0300 Subject: [PATCH] net: lwm2m: Allow CoAP block size to be changed Allow changing the CoAP Block-wise transfers block-size for subsequent GET requests. It looks like Leshan switches block size back to its configured value, if it is smaller. So even when we send block N=0 with size of 512, Leshan seem to handle that properly but still asks N=2 with block size 256(if that is configured). Signed-off-by: Seppo Takalo --- include/zephyr/net/coap.h | 23 +++++++++- subsys/net/lib/lwm2m/lwm2m_message_handling.c | 42 +++++++------------ tests/net/lib/lwm2m/block_transfer/src/main.c | 13 +++--- 3 files changed, 45 insertions(+), 33 deletions(-) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index 7f69cc4e9a7..bd47f92106e 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -27,7 +27,7 @@ #include #include #include - +#include #include #ifdef __cplusplus @@ -696,6 +696,27 @@ static inline uint16_t coap_block_size_to_bytes( return (1 << (block_size + 4)); } +/** + * @brief Helper for converting block size in bytes to enumeration. + * + * NOTE: Only valid CoAP block sizes map correctly. + * + * @param bytes CoAP block size in bytes. + * @return enum coap_block_size + */ +static inline enum coap_block_size coap_bytes_to_block_size(uint16_t bytes) +{ + int sz = u32_count_trailing_zeros(bytes) - 4; + + if (sz < COAP_BLOCK_16) { + return COAP_BLOCK_16; + } + if (sz > COAP_BLOCK_1024) { + return COAP_BLOCK_1024; + } + return sz; +} + /** * @brief Represents the current state of a block-wise transaction. */ diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index 75c479640e5..f363ffcb034 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -103,7 +103,8 @@ sys_slist_t *lwm2m_engine_obj_inst_list(void); static int handle_request(struct coap_packet *request, struct lwm2m_message *msg); #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER) -STATIC int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_num); +STATIC int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_num, + enum coap_block_size block_size); struct coap_block_context *lwm2m_output_block_context(void); #endif @@ -111,24 +112,7 @@ struct coap_block_context *lwm2m_output_block_context(void); enum coap_block_size lwm2m_default_block_size(void) { - switch (CONFIG_LWM2M_COAP_BLOCK_SIZE) { - case 16: - return COAP_BLOCK_16; - case 32: - return COAP_BLOCK_32; - case 64: - return COAP_BLOCK_64; - case 128: - return COAP_BLOCK_128; - case 256: - return COAP_BLOCK_256; - case 512: - return COAP_BLOCK_512; - case 1024: - return COAP_BLOCK_1024; - } - - return COAP_BLOCK_256; + return coap_bytes_to_block_size(CONFIG_LWM2M_COAP_BLOCK_SIZE); } void lwm2m_clear_block_contexts(void) @@ -277,11 +261,12 @@ static inline void release_body_encode_buffer(uint8_t **buffer) } } -STATIC int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_num) +STATIC int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_num, + enum coap_block_size block_size) { int ret; uint16_t payload_size; - const uint16_t block_size_bytes = coap_block_size_to_bytes(lwm2m_default_block_size()); + const uint16_t block_size_bytes = coap_block_size_to_bytes(block_size); uint16_t complete_payload_len; const uint8_t *complete_payload = coap_packet_get_payload(&msg->body_encode_buffer, &complete_payload_len); @@ -350,7 +335,7 @@ STATIC int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_nu LOG_ERR("coap packet init error: no output block context available"); return ret; } - ret = coap_block_transfer_init(msg->out.block_ctx, lwm2m_default_block_size(), + ret = coap_block_transfer_init(msg->out.block_ctx, block_size, complete_payload_len); if (ret < 0) { return ret; @@ -362,6 +347,7 @@ STATIC int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_nu } else { /* update block context */ msg->out.block_ctx->current = block_num * block_size_bytes; + msg->out.block_ctx->block_size = block_size; } ret = coap_append_descriptive_block_option(&msg->cpkt, msg->out.block_ctx); @@ -427,7 +413,7 @@ STATIC int prepare_msg_for_send(struct lwm2m_message *msg) (const uint8_t *)&hash, sizeof(hash)); } - ret = build_msg_block_for_send(msg, 0); + ret = build_msg_block_for_send(msg, 0, lwm2m_default_block_size()); if (ret != 0) { return ret; } @@ -2649,6 +2635,7 @@ static void handle_ongoing_block2_tx(struct lwm2m_message *msg, struct coap_pack #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER) int r; uint8_t block; + enum coap_block_size block_size; r = coap_get_block2_option(cpkt, &block); if (r < 0) { @@ -2656,9 +2643,10 @@ static void handle_ongoing_block2_tx(struct lwm2m_message *msg, struct coap_pack return; } + block_size = coap_bytes_to_block_size(r); msg->in.in_cpkt = cpkt; - r = build_msg_block_for_send(msg, block); + r = build_msg_block_for_send(msg, block, block_size); if (r < 0) { clear_ongoing_block2_tx(); LOG_ERR("Unable to build next block of lwm2m message! r=%d", r); @@ -2745,6 +2733,8 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_ return; } + enum coap_block_size block_size = coap_bytes_to_block_size(r); + if (r != CONFIG_LWM2M_COAP_BLOCK_SIZE) { LOG_WRN("Server requests different block size: ignore"); } @@ -2756,7 +2746,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_ } last_block_num = msg->out.block_ctx->current / - coap_block_size_to_bytes(msg->out.block_ctx->block_size); + coap_block_size_to_bytes(block_size); if (last_block_num > block_num) { LOG_INF("Block already sent: ignore"); return; @@ -2765,7 +2755,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_ return; } - r = build_msg_block_for_send(msg, block_num + 1); + r = build_msg_block_for_send(msg, block_num + 1, block_size); if (r < 0) { lwm2m_reset_message(msg, true); LOG_ERR("Unable to build next block of lwm2m message!"); diff --git a/tests/net/lib/lwm2m/block_transfer/src/main.c b/tests/net/lib/lwm2m/block_transfer/src/main.c index 3ec4eb3bed6..1323b5ad10e 100644 --- a/tests/net/lib/lwm2m/block_transfer/src/main.c +++ b/tests/net/lib/lwm2m/block_transfer/src/main.c @@ -11,7 +11,8 @@ /* Declaration of 'private' function */ int prepare_msg_for_send(struct lwm2m_message *msg); -int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_num); +int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_num, + enum coap_block_size block_size); int request_output_block_ctx(struct coap_block_context **ctx); void release_output_block_ctx(struct coap_block_context ** const ctx); @@ -270,7 +271,7 @@ ZTEST_F(net_block_transfer, test_build_blocks_for_send_exactly_2_blocks) "Last byte in payload wrong"); /* block 1 */ - ret = build_msg_block_for_send(msg, 1); + ret = build_msg_block_for_send(msg, 1, COAP_BLOCK_64); zassert_equal(ret, 0, "Could not create second block"); ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1); @@ -285,7 +286,7 @@ ZTEST_F(net_block_transfer, test_build_blocks_for_send_exactly_2_blocks) "Last byte in payload wrong"); /* block 2 doesn't exist */ - ret = build_msg_block_for_send(msg, 2); + ret = build_msg_block_for_send(msg, 2, COAP_BLOCK_64); zassert_equal(ret, -EINVAL, "Could not create second block"); } @@ -346,7 +347,7 @@ ZTEST_F(net_block_transfer, test_build_blocks_for_send_more_than_2_blocks) "Last byte in payload wrong"); /* block 1 */ - ret = build_msg_block_for_send(msg, 1); + ret = build_msg_block_for_send(msg, 1, COAP_BLOCK_64); zassert_equal(ret, 0, "Could not create second block"); ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1); @@ -361,7 +362,7 @@ ZTEST_F(net_block_transfer, test_build_blocks_for_send_more_than_2_blocks) "Last byte in payload wrong"); /* block 2 */ - ret = build_msg_block_for_send(msg, 2); + ret = build_msg_block_for_send(msg, 2, COAP_BLOCK_64); zassert_equal(ret, 0, "Could not create second block"); ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1); @@ -374,7 +375,7 @@ ZTEST_F(net_block_transfer, test_build_blocks_for_send_more_than_2_blocks) zassert_equal(0x80, payload[0], "First (and only) byte in payload wrong"); /* block 3 doesn't exist */ - ret = build_msg_block_for_send(msg, 3); + ret = build_msg_block_for_send(msg, 3, COAP_BLOCK_64); zassert_equal(ret, -EINVAL, "Could not create second block"); }