Skip to content

Commit

Permalink
net: lwm2m: Allow CoAP block size to be changed
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
SeppoTakalo authored and nashif committed Apr 12, 2024
1 parent 71437f7 commit 51d80a9
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 33 deletions.
23 changes: 22 additions & 1 deletion include/zephyr/net/coap.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#include <stddef.h>
#include <stdbool.h>
#include <zephyr/net/net_ip.h>

#include <zephyr/sys/math_extras.h>
#include <zephyr/sys/slist.h>

#ifdef __cplusplus
Expand Down Expand Up @@ -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.
*/
Expand Down
42 changes: 16 additions & 26 deletions subsys/net/lib/lwm2m/lwm2m_message_handling.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,32 +103,16 @@ 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

/* block-wise transfer functions */

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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -2649,16 +2635,18 @@ 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) {
LOG_ERR("Failed to parse BLOCK2");
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);
Expand Down Expand Up @@ -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");
}
Expand All @@ -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;
Expand All @@ -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!");
Expand Down
13 changes: 7 additions & 6 deletions tests/net/lib/lwm2m/block_transfer/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand All @@ -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");
}

Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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");
}

Expand Down

0 comments on commit 51d80a9

Please sign in to comment.