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 <seppo.takalo@nordicsemi.no>
This commit is contained in:
Seppo Takalo 2024-04-10 13:44:14 +03:00 committed by Anas Nashif
commit 51d80a9838
3 changed files with 45 additions and 33 deletions

View file

@ -27,7 +27,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include <zephyr/net/net_ip.h> #include <zephyr/net/net_ip.h>
#include <zephyr/sys/math_extras.h>
#include <zephyr/sys/slist.h> #include <zephyr/sys/slist.h>
#ifdef __cplusplus #ifdef __cplusplus
@ -696,6 +696,27 @@ static inline uint16_t coap_block_size_to_bytes(
return (1 << (block_size + 4)); 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. * @brief Represents the current state of a block-wise transaction.
*/ */

View file

@ -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); static int handle_request(struct coap_packet *request, struct lwm2m_message *msg);
#if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER) #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); struct coap_block_context *lwm2m_output_block_context(void);
#endif #endif
@ -111,24 +112,7 @@ struct coap_block_context *lwm2m_output_block_context(void);
enum coap_block_size lwm2m_default_block_size(void) enum coap_block_size lwm2m_default_block_size(void)
{ {
switch (CONFIG_LWM2M_COAP_BLOCK_SIZE) { return coap_bytes_to_block_size(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;
} }
void lwm2m_clear_block_contexts(void) 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; int ret;
uint16_t payload_size; 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; uint16_t complete_payload_len;
const uint8_t *complete_payload = const uint8_t *complete_payload =
coap_packet_get_payload(&msg->body_encode_buffer, &complete_payload_len); 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"); LOG_ERR("coap packet init error: no output block context available");
return ret; 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); complete_payload_len);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
@ -362,6 +347,7 @@ STATIC int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_nu
} else { } else {
/* update block context */ /* update block context */
msg->out.block_ctx->current = block_num * block_size_bytes; 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); 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)); (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) { if (ret != 0) {
return ret; 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) #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER)
int r; int r;
uint8_t block; uint8_t block;
enum coap_block_size block_size;
r = coap_get_block2_option(cpkt, &block); r = coap_get_block2_option(cpkt, &block);
if (r < 0) { if (r < 0) {
@ -2656,9 +2643,10 @@ static void handle_ongoing_block2_tx(struct lwm2m_message *msg, struct coap_pack
return; return;
} }
block_size = coap_bytes_to_block_size(r);
msg->in.in_cpkt = cpkt; 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) { if (r < 0) {
clear_ongoing_block2_tx(); clear_ongoing_block2_tx();
LOG_ERR("Unable to build next block of lwm2m message! r=%d", r); 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; return;
} }
enum coap_block_size block_size = coap_bytes_to_block_size(r);
if (r != CONFIG_LWM2M_COAP_BLOCK_SIZE) { if (r != CONFIG_LWM2M_COAP_BLOCK_SIZE) {
LOG_WRN("Server requests different block size: ignore"); 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 / 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) { if (last_block_num > block_num) {
LOG_INF("Block already sent: ignore"); LOG_INF("Block already sent: ignore");
return; return;
@ -2765,7 +2755,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_
return; 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) { if (r < 0) {
lwm2m_reset_message(msg, true); lwm2m_reset_message(msg, true);
LOG_ERR("Unable to build next block of lwm2m message!"); LOG_ERR("Unable to build next block of lwm2m message!");

View file

@ -11,7 +11,8 @@
/* Declaration of 'private' function */ /* Declaration of 'private' function */
int prepare_msg_for_send(struct lwm2m_message *msg); 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); int request_output_block_ctx(struct coap_block_context **ctx);
void release_output_block_ctx(struct coap_block_context ** const 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"); "Last byte in payload wrong");
/* block 1 */ /* 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"); zassert_equal(ret, 0, "Could not create second block");
ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1); 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"); "Last byte in payload wrong");
/* block 2 doesn't exist */ /* 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"); 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"); "Last byte in payload wrong");
/* block 1 */ /* 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"); zassert_equal(ret, 0, "Could not create second block");
ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1); 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"); "Last byte in payload wrong");
/* block 2 */ /* 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"); zassert_equal(ret, 0, "Could not create second block");
ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1); 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"); zassert_equal(0x80, payload[0], "First (and only) byte in payload wrong");
/* block 3 doesn't exist */ /* 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"); zassert_equal(ret, -EINVAL, "Could not create second block");
} }