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 <michael.scott@linaro.org>
This commit is contained in:
Michael Scott 2017-10-26 23:45:59 -07:00 committed by Jukka Rissanen
commit febcf5317b
2 changed files with 89 additions and 33 deletions

View file

@ -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);

View file

@ -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);
}
}