From febcf5317b29153b2c78e6f7dbb30cc323c236bc Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 26 Oct 2017 23:45:59 -0700 Subject: [PATCH] net: lwm2m: fix OPAQUE handling in LwM2M engine With the change to support multi-fragement buffers in the LwM2M subsys, the OPAQUE data type was direct write methods were broken. Let's fix OPAQUE handling by using the newly introduced getter methods which can use multiple user callbacks (depending on the size of the user provided buffer). Let's also add public methods for users to set / get OPAQUE data in resources for future use with DTLS key data. Signed-off-by: Michael Scott --- include/net/lwm2m.h | 2 + subsys/net/lib/lwm2m/lwm2m_engine.c | 120 ++++++++++++++++++++-------- 2 files changed, 89 insertions(+), 33 deletions(-) diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index 5c9c1c4d96d..156b7a267f3 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -153,6 +153,7 @@ typedef struct float64_value { int lwm2m_engine_create_obj_inst(char *pathstr); +int lwm2m_engine_set_opaque(char *pathstr, char *data_ptr, u16_t data_len); int lwm2m_engine_set_string(char *path, char *data_ptr); int lwm2m_engine_set_u8(char *path, u8_t value); int lwm2m_engine_set_u16(char *path, u16_t value); @@ -166,6 +167,7 @@ int lwm2m_engine_set_bool(char *path, bool value); int lwm2m_engine_set_float32(char *pathstr, float32_value_t *value); int lwm2m_engine_set_float64(char *pathstr, float64_value_t *value); +int lwm2m_engine_get_opaque(char *pathstr, void *buf, u16_t buflen); int lwm2m_engine_get_string(char *path, void *str, u16_t strlen); u8_t lwm2m_engine_get_u8(char *path); u16_t lwm2m_engine_get_u16(char *path); diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 4d0176c81e2..58d6a26b2f8 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -1225,6 +1225,10 @@ static int lwm2m_engine_set(char *pathstr, void *value, u16_t len) switch (obj_field->data_type) { + case LWM2M_RES_TYPE_OPAQUE: + memcpy((u8_t *)data_ptr, value, len); + break; + case LWM2M_RES_TYPE_STRING: memcpy((u8_t *)data_ptr, value, len); ((u8_t *)data_ptr)[len] = '\0'; @@ -1301,6 +1305,11 @@ static int lwm2m_engine_set(char *pathstr, void *value, u16_t len) return ret; } +int lwm2m_engine_set_opaque(char *pathstr, char *data_ptr, u16_t data_len) +{ + return lwm2m_engine_set(pathstr, data_ptr, data_len); +} + int lwm2m_engine_set_string(char *pathstr, char *data_ptr) { return lwm2m_engine_set(pathstr, data_ptr, strlen(data_ptr)); @@ -1435,6 +1444,11 @@ static int lwm2m_engine_get(char *pathstr, void *buf, u16_t buflen) switch (obj_field->data_type) { case LWM2M_RES_TYPE_OPAQUE: + if (data_len > buflen) { + return -ENOMEM; + } + + memcpy(buf, data_ptr, data_len); break; case LWM2M_RES_TYPE_STRING: @@ -1503,6 +1517,11 @@ static int lwm2m_engine_get(char *pathstr, void *buf, u16_t buflen) return 0; } +int lwm2m_engine_get_opaque(char *pathstr, void *buf, u16_t buflen) +{ + return lwm2m_engine_get(pathstr, buf, buflen); +} + int lwm2m_engine_get_string(char *pathstr, void *buf, u16_t buflen) { return lwm2m_engine_get(pathstr, buf, buflen); @@ -1855,6 +1874,42 @@ size_t lwm2m_engine_get_opaque_more(struct lwm2m_input_context *in, return (size_t)in_len; } +static int lwm2m_write_handler_opaque(struct lwm2m_engine_obj_inst *obj_inst, + struct lwm2m_engine_res_inst *res, + struct lwm2m_input_context *in, + void *data_ptr, size_t data_len, + bool last_block, size_t total_size) +{ + size_t len = 1; + bool last_pkt_block = false, first_read = true; + + while (!last_pkt_block && len > 0) { + if (first_read) { + len = engine_get_opaque(in, (u8_t *)data_ptr, + data_len, &last_pkt_block); + first_read = false; + } else { + len = lwm2m_engine_get_opaque_more(in, (u8_t *)data_ptr, + data_len, + &last_pkt_block); + } + + if (len == 0) { + return -EINVAL; + } + + if (res->post_write_cb) { + /* ignore return value */ + res->post_write_cb(obj_inst->obj_inst_id, + data_ptr, len, + last_pkt_block && last_block, + total_size); + } + } + + return 0; +} + /* This function is exposed for the content format writers */ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, struct lwm2m_engine_res_inst *res, @@ -1883,32 +1938,43 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, data_ptr = res->data_ptr; data_len = res->data_len; - /* setup data_ptr/data_len for OPAQUE when it has none setup */ -/* FIXME: */ -#if 0 - if (obj_field->data_type == LWM2M_RES_TYPE_OPAQUE && - data_ptr == NULL && data_len == 0) { - data_ptr = in->inbuf; - data_len = in->insize; - } -#endif - /* allow user to override data elements via callback */ if (res->pre_write_cb) { data_ptr = res->pre_write_cb(obj_inst->obj_inst_id, &data_len); } + if (res->post_write_cb) { + /* Get block1 option for checking MORE block flag */ + ret = get_option_int(in->in_cpkt, COAP_OPTION_BLOCK1); + if (ret >= 0) { + last_block = !GET_MORE(ret); + + /* Get block_ctx for total_size (might be zero) */ + tkl = coap_header_get_token(in->in_cpkt, token); + if (tkl && !get_block_ctx(token, tkl, &block_ctx)) { + total_size = block_ctx->ctx.total_size; + SYS_LOG_DBG("BLOCK1: total:%zu current:%zu" + " last:%u", + block_ctx->ctx.total_size, + block_ctx->ctx.current, + last_block); + } + } + } + if (data_ptr && data_len > 0) { switch (obj_field->data_type) { - /* do nothing for OPAQUE (probably has a callback) */ -/* FIXME: */ -#if 0 case LWM2M_RES_TYPE_OPAQUE: - data_ptr = in->inbuf; - len = in->insize; + ret = lwm2m_write_handler_opaque(obj_inst, res, in, + data_ptr, data_len, + last_block, + total_size); + if (ret < 0) { + return ret; + } + break; -#endif case LWM2M_RES_TYPE_STRING: engine_get_string(in, (u8_t *)data_ptr, data_len); @@ -1987,20 +2053,8 @@ 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 = get_option_int(in->in_cpkt, COAP_OPTION_BLOCK1); - if (ret >= 0) { - last_block = !GET_MORE(ret); - - /* Get block_ctx for total_size (might be zero) */ - tkl = coap_header_get_token(in->in_cpkt, token); - if (token != NULL && - !get_block_ctx(token, tkl, &block_ctx)) { - total_size = block_ctx->ctx.total_size; - } - } - + if (res->post_write_cb && + obj_field->data_type != LWM2M_RES_TYPE_OPAQUE) { /* ignore return value here */ ret = res->post_write_cb(obj_inst->obj_inst_id, data_ptr, len, last_block, total_size); @@ -2510,9 +2564,6 @@ static int handle_request(struct coap_packet *request, if (block_ctx) { if (block_offset > 0) { msg->code = COAP_RESPONSE_CODE_CONTINUE; - } else { - /* Free context when finished */ - free_block_ctx(block_ctx); } } @@ -2598,6 +2649,9 @@ static int handle_request(struct coap_packet *request, r = -EINVAL; goto error; } + } else { + /* Free context when finished */ + free_block_ctx(block_ctx); } }