From 31e5ec79b88081fab0b8540e825328558f1c8e6b Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 17 Feb 2021 15:47:28 +0100 Subject: [PATCH] net: lwm2m: Add data validation callback Add a data validation callback to the resource structure, which can be registered by an application. It allows to verify the data before actually modifying the resource data. If the callback is registered for a resource, the data is decoded into a temporary buffer first, and only copied into the actual resource buffer if the validation is successfull. If no validation is required (and thus no callback registered) the resource value is decoded directly into the resource buffer, as it used to be. Signed-off-by: Robert Lubos --- include/net/lwm2m.h | 30 ++++ subsys/net/lib/lwm2m/Kconfig | 10 ++ subsys/net/lib/lwm2m/ipso_buzzer.c | 2 +- subsys/net/lib/lwm2m/ipso_generic_sensor.c | 2 +- subsys/net/lib/lwm2m/ipso_humidity_sensor.c | 2 +- subsys/net/lib/lwm2m/ipso_light_control.c | 2 +- subsys/net/lib/lwm2m/ipso_onoff_switch.c | 6 +- subsys/net/lib/lwm2m/ipso_pressure_sensor.c | 2 +- subsys/net/lib/lwm2m/ipso_push_button.c | 2 +- subsys/net/lib/lwm2m/ipso_temp_sensor.c | 2 +- subsys/net/lib/lwm2m/ipso_timer.c | 8 +- subsys/net/lib/lwm2m/lwm2m_engine.c | 153 ++++++++++++++++---- subsys/net/lib/lwm2m/lwm2m_obj_device.c | 2 +- subsys/net/lib/lwm2m/lwm2m_obj_firmware.c | 4 +- subsys/net/lib/lwm2m/lwm2m_obj_server.c | 2 +- subsys/net/lib/lwm2m/lwm2m_object.h | 22 +-- 16 files changed, 192 insertions(+), 59 deletions(-) diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index 4b282ab0d5f..66a6e747578 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -124,6 +124,12 @@ struct lwm2m_ctx { * callback in case of socket errors on receive. */ lwm2m_socket_fault_cb_t fault_cb; + + /** Validation buffer. Used as a temporary buffer to decode the resource + * value before validation. On successful validation, its content is + * copied into the actual resource buffer. + */ + uint8_t validate_buf[CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE]; }; @@ -159,6 +165,7 @@ typedef void *(*lwm2m_engine_get_data_cb_t)(uint16_t obj_inst_id, * objects. * * A function of this type can be registered via: + * lwm2m_engine_register_validate_callback() * lwm2m_engine_register_post_write_callback() * * @param[in] obj_inst_id Object instance ID generating the callback. @@ -746,6 +753,29 @@ int lwm2m_engine_register_read_callback(char *pathstr, int lwm2m_engine_register_pre_write_callback(char *pathstr, lwm2m_engine_get_data_cb_t cb); +/** + * @brief Set resource (instance) validation callback + * + * This callback is triggered before setting the value of a resource to the + * resource data buffer. + * + * The callback allows an LwM2M client or object to validate the data before + * writing and notify an error if the data should be discarded for any reason + * (by returning a negative error code). + * + * @note All resources that have a validation callback registered are initially + * decoded into a temporary validation buffer. Make sure that + * ``CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE`` is large enough to + * store each of the validated resources (individually). + * + * @param[in] pathstr LwM2M path string "obj/obj-inst/res(/res-inst)" + * @param[in] cb Validate resource data callback + * + * @return 0 for success or negative in case of error. + */ +int lwm2m_engine_register_validate_callback(char *pathstr, + lwm2m_engine_set_data_cb_t cb); + /** * @brief Set resource (instance) post-write callback * diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 147cf011f77..47c4a9278d2 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -56,6 +56,16 @@ config LWM2M_ENGINE_MESSAGE_HEADER_SIZE help Extra room allocated to handle CoAP header data +config LWM2M_ENGINE_VALIDATION_BUFFER_SIZE + int "Size of the validation buffer for the incoming data" + default 64 + help + LwM2M will use the validation buffer during the write operation, to + decode the resource value before validating it (applies for resources + for which validation callback has been registered). Set this value to + the maximum expected size of the resources that need to be validated + (and thus have validation callback registered). + config LWM2M_ENGINE_MAX_PENDING int "LWM2M engine max. pending objects" default 5 diff --git a/subsys/net/lib/lwm2m/ipso_buzzer.c b/subsys/net/lib/lwm2m/ipso_buzzer.c index 21ab78f997e..8f9e74b1fdb 100644 --- a/subsys/net/lib/lwm2m/ipso_buzzer.c +++ b/subsys/net/lib/lwm2m/ipso_buzzer.c @@ -216,7 +216,7 @@ static struct lwm2m_engine_obj_inst *buzzer_create(uint16_t obj_inst_id) res_inst[avail], j, 1, false, true, &buzzer_data[avail].onoff, sizeof(buzzer_data[avail].onoff), - NULL, NULL, onoff_post_write_cb, NULL); + NULL, NULL, NULL, onoff_post_write_cb, NULL); INIT_OBJ_RES_DATA(BUZZER_LEVEL_ID, res[avail], i, res_inst[avail], j, &buzzer_data[avail].level, sizeof(buzzer_data[avail].level)); diff --git a/subsys/net/lib/lwm2m/ipso_generic_sensor.c b/subsys/net/lib/lwm2m/ipso_generic_sensor.c index 311f009c4ad..359d4bc40b9 100644 --- a/subsys/net/lib/lwm2m/ipso_generic_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_generic_sensor.c @@ -207,7 +207,7 @@ static struct lwm2m_engine_obj_inst *generic_sensor_create(uint16_t obj_inst_id) /* initialize instance resource data */ INIT_OBJ_RES(SENSOR_VALUE_RID, res[index], i, res_inst[index], j, 1, false, true, &sensor_value[index], sizeof(*sensor_value), - NULL, NULL, sensor_value_write_cb, NULL); + NULL, NULL, NULL, sensor_value_write_cb, NULL); INIT_OBJ_RES_DATA(SENSOR_UNITS_RID, res[index], i, res_inst[index], j, units[index], UNIT_STR_MAX_SIZE); INIT_OBJ_RES_DATA(MIN_MEASURED_VALUE_RID, res[index], i, diff --git a/subsys/net/lib/lwm2m/ipso_humidity_sensor.c b/subsys/net/lib/lwm2m/ipso_humidity_sensor.c index b39a2a31d31..1bec5c1d274 100644 --- a/subsys/net/lib/lwm2m/ipso_humidity_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_humidity_sensor.c @@ -190,7 +190,7 @@ humidity_sensor_create(uint16_t obj_inst_id) /* initialize instance resource data */ INIT_OBJ_RES(SENSOR_VALUE_RID, res[index], i, res_inst[index], j, 1, false, true, &sensor_value[index], sizeof(*sensor_value), - NULL, NULL, sensor_value_write_cb, NULL); + NULL, NULL, NULL, sensor_value_write_cb, NULL); INIT_OBJ_RES_DATA(SENSOR_UNITS_RID, res[index], i, res_inst[index], j, units[index], UNIT_STR_MAX_SIZE); INIT_OBJ_RES_DATA(MIN_MEASURED_VALUE_RID, res[index], i, diff --git a/subsys/net/lib/lwm2m/ipso_light_control.c b/subsys/net/lib/lwm2m/ipso_light_control.c index a75006177a8..79ce2bdf308 100644 --- a/subsys/net/lib/lwm2m/ipso_light_control.c +++ b/subsys/net/lib/lwm2m/ipso_light_control.c @@ -173,7 +173,7 @@ static struct lwm2m_engine_obj_inst *light_control_create(uint16_t obj_inst_id) INIT_OBJ_RES(LIGHT_ON_TIME_ID, res[avail], i, res_inst[avail], j, 1, false, true, &on_time_value[avail], sizeof(*on_time_value), - on_time_read_cb, NULL, on_time_post_write_cb, NULL); + on_time_read_cb, NULL, NULL, on_time_post_write_cb, NULL); INIT_OBJ_RES_DATA(LIGHT_CUMULATIVE_ACTIVE_POWER_ID, res[avail], i, res_inst[avail], j, &cumulative_active_value[avail], diff --git a/subsys/net/lib/lwm2m/ipso_onoff_switch.c b/subsys/net/lib/lwm2m/ipso_onoff_switch.c index 9d85e8055f1..4889f0fe8c9 100644 --- a/subsys/net/lib/lwm2m/ipso_onoff_switch.c +++ b/subsys/net/lib/lwm2m/ipso_onoff_switch.c @@ -214,17 +214,17 @@ static struct lwm2m_engine_obj_inst *switch_create(uint16_t obj_inst_id) res_inst[avail], j, 1, false, true, &switch_data[avail].state, sizeof(switch_data[avail].state), - NULL, NULL, state_post_write_cb, NULL); + NULL, NULL, NULL, state_post_write_cb, NULL); INIT_OBJ_RES_DATA(SWITCH_DIGITAL_INPUT_COUNTER_ID, res[avail], i, res_inst[avail], j, &switch_data[avail].counter, sizeof(switch_data[avail].counter)); INIT_OBJ_RES_OPT(SWITCH_ON_TIME_ID, res[avail], i, res_inst[avail], j, 1, false, true, - on_time_read_cb, NULL, time_post_write_cb, NULL); + on_time_read_cb, NULL, NULL, time_post_write_cb, NULL); INIT_OBJ_RES_OPT(SWITCH_OFF_TIME_ID, res[avail], i, res_inst[avail], j, 1, false, true, - off_time_read_cb, NULL, time_post_write_cb, NULL); + off_time_read_cb, NULL, NULL, time_post_write_cb, NULL); INIT_OBJ_RES_OPTDATA(SWITCH_APPLICATION_TYPE_ID, res[avail], i, res_inst[avail], j); #if ADD_TIMESTAMPS diff --git a/subsys/net/lib/lwm2m/ipso_pressure_sensor.c b/subsys/net/lib/lwm2m/ipso_pressure_sensor.c index ed1f7e2cc17..1c5ca10e990 100644 --- a/subsys/net/lib/lwm2m/ipso_pressure_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_pressure_sensor.c @@ -190,7 +190,7 @@ pressure_sensor_create(uint16_t obj_inst_id) /* initialize instance resource data */ INIT_OBJ_RES(SENSOR_VALUE_RID, res[index], i, res_inst[index], j, 1, false, true, &sensor_value[index], sizeof(*sensor_value), - NULL, NULL, sensor_value_write_cb, NULL); + NULL, NULL, NULL, sensor_value_write_cb, NULL); INIT_OBJ_RES_DATA(SENSOR_UNITS_RID, res[index], i, res_inst[index], j, units[index], UNIT_STR_MAX_SIZE); INIT_OBJ_RES_DATA(MIN_MEASURED_VALUE_RID, res[index], i, diff --git a/subsys/net/lib/lwm2m/ipso_push_button.c b/subsys/net/lib/lwm2m/ipso_push_button.c index 9ad883fcfac..52a2dcd8942 100644 --- a/subsys/net/lib/lwm2m/ipso_push_button.c +++ b/subsys/net/lib/lwm2m/ipso_push_button.c @@ -146,7 +146,7 @@ static struct lwm2m_engine_obj_inst *button_create(uint16_t obj_inst_id) res_inst[avail], j, 1, false, true, &button_data[avail].state, sizeof(button_data[avail].state), - NULL, NULL, state_post_write_cb, NULL); + NULL, NULL, NULL, state_post_write_cb, NULL); INIT_OBJ_RES_DATA(BUTTON_DIGITAL_INPUT_COUNTER_ID, res[avail], i, res_inst[avail], j, &button_data[avail].counter, diff --git a/subsys/net/lib/lwm2m/ipso_temp_sensor.c b/subsys/net/lib/lwm2m/ipso_temp_sensor.c index 11e50805642..3d5ee5be843 100644 --- a/subsys/net/lib/lwm2m/ipso_temp_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_temp_sensor.c @@ -205,7 +205,7 @@ static struct lwm2m_engine_obj_inst *temp_sensor_create(uint16_t obj_inst_id) INIT_OBJ_RES(TEMP_SENSOR_VALUE_ID, res[index], i, res_inst[index], j, 1, false, true, &sensor_value[index], sizeof(*sensor_value), - NULL, NULL, sensor_value_write_cb, NULL); + NULL, NULL, NULL, sensor_value_write_cb, NULL); INIT_OBJ_RES_DATA(TEMP_UNITS_ID, res[index], i, res_inst[index], j, units[index], TEMP_STRING_SHORT); INIT_OBJ_RES_DATA(TEMP_MIN_MEASURED_VALUE_ID, res[index], i, diff --git a/subsys/net/lib/lwm2m/ipso_timer.c b/subsys/net/lib/lwm2m/ipso_timer.c index c3cb0c45d3c..407369c9b2b 100644 --- a/subsys/net/lib/lwm2m/ipso_timer.c +++ b/subsys/net/lib/lwm2m/ipso_timer.c @@ -344,7 +344,7 @@ static struct lwm2m_engine_obj_inst *timer_create(uint16_t obj_inst_id) res_inst[avail], j, 1, false, true, &timer_data[avail].remaining_time, sizeof(timer_data[avail].remaining_time), - remaining_time_read_cb, NULL, NULL, NULL); + remaining_time_read_cb, NULL, NULL, NULL, NULL); INIT_OBJ_RES_DATA(TIMER_MINIMUM_OFF_TIME_ID, res[avail], i, res_inst[avail], j, &timer_data[avail].min_off_time, sizeof(timer_data[avail].min_off_time)); @@ -354,12 +354,12 @@ static struct lwm2m_engine_obj_inst *timer_create(uint16_t obj_inst_id) res_inst[avail], j, 1, false, true, &timer_data[avail].enabled, sizeof(timer_data[avail].enabled), - NULL, NULL, enabled_post_write_cb, NULL); + NULL, NULL, NULL, enabled_post_write_cb, NULL); INIT_OBJ_RES(TIMER_CUMULATIVE_TIME_ID, res[avail], i, res_inst[avail], j, 1, false, true, &timer_data[avail].cumulative_time, sizeof(timer_data[avail].cumulative_time), - cumulative_time_read_cb, NULL, + cumulative_time_read_cb, NULL, NULL, cumulative_time_post_write_cb, NULL); INIT_OBJ_RES_DATA(TIMER_DIGITAL_STATE_ID, res[avail], i, res_inst[avail], j, &timer_data[avail].active, @@ -368,7 +368,7 @@ static struct lwm2m_engine_obj_inst *timer_create(uint16_t obj_inst_id) res_inst[avail], j, 1, false, true, &timer_data[avail].trigger_counter, sizeof(timer_data[avail].trigger_counter), - NULL, NULL, trigger_counter_post_write_cb, NULL); + NULL, NULL, NULL, trigger_counter_post_write_cb, NULL); INIT_OBJ_RES_DATA(TIMER_MODE_ID, res[avail], i, res_inst[avail], j, &timer_data[avail].timer_mode, sizeof(timer_data[avail].timer_mode)); diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 2727cee6613..9879793caaf 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -1500,6 +1500,15 @@ static int lwm2m_engine_set(char *pathstr, void *value, uint16_t len) changed = true; } + if (res->validate_cb) { + ret = res->validate_cb(obj_inst->obj_inst_id, res->res_id, + res_inst->res_inst_id, value, + len, false, 0); + if (ret < 0) { + return -EINVAL; + } + } + switch (obj_field->data_type) { case LWM2M_RES_TYPE_OPAQUE: @@ -2103,6 +2112,21 @@ int lwm2m_engine_register_pre_write_callback(char *pathstr, return 0; } +int lwm2m_engine_register_validate_callback(char *pathstr, + lwm2m_engine_set_data_cb_t cb) +{ + int ret; + struct lwm2m_engine_res *res = NULL; + + ret = lwm2m_engine_get_resource(pathstr, &res); + if (ret < 0) { + return ret; + } + + res->validate_cb = cb; + return 0; +} + int lwm2m_engine_register_post_write_callback(char *pathstr, lwm2m_engine_set_data_cb_t cb) { @@ -2350,7 +2374,7 @@ size_t lwm2m_engine_get_opaque_more(struct lwm2m_input_context *in, static int lwm2m_write_handler_opaque(struct lwm2m_engine_obj_inst *obj_inst, struct lwm2m_engine_res *res, struct lwm2m_engine_res_inst *res_inst, - struct lwm2m_input_context *in, + struct lwm2m_message *msg, void *data_ptr, size_t data_len) { size_t len = 1; @@ -2358,22 +2382,51 @@ static int lwm2m_write_handler_opaque(struct lwm2m_engine_obj_inst *obj_inst, int ret = 0; bool last_block = true; struct lwm2m_opaque_context opaque_ctx = { 0 }; + void *write_buf; + size_t write_buf_len; - if (in->block_ctx != NULL) { - last_block = in->block_ctx->last_block; + if (msg->in.block_ctx != NULL) { + last_block = msg->in.block_ctx->last_block; /* Restore the opaque context from the block context, if used. */ - opaque_ctx = in->block_ctx->opaque; + opaque_ctx = msg->in.block_ctx->opaque; + } + + /* In case validation callback is present, write data to the temporary + * buffer first, for validation. Otherwise, write to the data buffer + * directly. + */ + if (res->validate_cb) { + write_buf = msg->ctx->validate_buf; + write_buf_len = sizeof(msg->ctx->validate_buf); + } else { + write_buf = data_ptr; + write_buf_len = data_len; } while (!last_pkt_block && len > 0) { - len = engine_get_opaque(in, (uint8_t *)data_ptr, - data_len, &opaque_ctx, &last_pkt_block); + len = engine_get_opaque(&msg->in, write_buf, + MIN(data_len, write_buf_len), + &opaque_ctx, &last_pkt_block); if (len == 0) { /* ignore empty content and continue */ return 0; } + + if (res->validate_cb) { + ret = res->validate_cb( + obj_inst->obj_inst_id, res->res_id, + res_inst->res_inst_id, write_buf, len, + last_pkt_block && last_block, opaque_ctx.len); + if (ret < 0) { + /* -EEXIST will generate Bad Request LWM2M response. */ + return -EEXIST; + } + + memcpy(data_ptr, write_buf, len); + } + if (res->post_write_cb) { ret = res->post_write_cb( obj_inst->obj_inst_id, res->res_id, @@ -2385,8 +2438,8 @@ static int lwm2m_write_handler_opaque(struct lwm2m_engine_obj_inst *obj_inst, } } - if (in->block_ctx != NULL) { - in->block_ctx->opaque = opaque_ctx; + if (msg->in.block_ctx != NULL) { + msg->in.block_ctx->opaque = opaque_ctx; } return opaque_ctx.len; @@ -2407,6 +2460,8 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, int32_t temp32 = 0; int ret = 0; bool last_block = true; + void *write_buf; + size_t write_buf_len; if (!obj_inst || !res || !res_inst || !obj_field || !msg) { return -EINVAL; @@ -2427,7 +2482,7 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, &data_len); } - if (res->post_write_cb) { + if (res->post_write_cb || res->validate_cb) { if (msg->in.block_ctx != NULL) { /* Get block_ctx for total_size (might be zero) */ total_size = msg->in.block_ctx->ctx.total_size; @@ -2439,12 +2494,24 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, } } + /* In case validation callback is present, write data to the temporary + * buffer first, for validation. Otherwise, write to the data buffer + * directly. + */ + if (res->validate_cb) { + write_buf = msg->ctx->validate_buf; + write_buf_len = sizeof(msg->ctx->validate_buf); + } else { + write_buf = data_ptr; + write_buf_len = data_len; + } + if (data_ptr && data_len > 0) { switch (obj_field->data_type) { case LWM2M_RES_TYPE_OPAQUE: ret = lwm2m_write_handler_opaque(obj_inst, res, - res_inst, &msg->in, + res_inst, msg, data_ptr, data_len); if (ret < 0) { return ret; @@ -2454,77 +2521,77 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, break; case LWM2M_RES_TYPE_STRING: - engine_get_string(&msg->in, (uint8_t *)data_ptr, data_len); - len = strlen((char *)data_ptr); + engine_get_string(&msg->in, write_buf, write_buf_len); + len = strlen((char *)write_buf); break; case LWM2M_RES_TYPE_U64: engine_get_s64(&msg->in, &temp64); - *(uint64_t *)data_ptr = temp64; + *(uint64_t *)write_buf = temp64; len = 8; break; case LWM2M_RES_TYPE_U32: case LWM2M_RES_TYPE_TIME: engine_get_s32(&msg->in, &temp32); - *(uint32_t *)data_ptr = temp32; + *(uint32_t *)write_buf = temp32; len = 4; break; case LWM2M_RES_TYPE_U16: engine_get_s32(&msg->in, &temp32); - *(uint16_t *)data_ptr = temp32; + *(uint16_t *)write_buf = temp32; len = 2; break; case LWM2M_RES_TYPE_U8: engine_get_s32(&msg->in, &temp32); - *(uint8_t *)data_ptr = temp32; + *(uint8_t *)write_buf = temp32; len = 1; break; case LWM2M_RES_TYPE_S64: - engine_get_s64(&msg->in, (int64_t *)data_ptr); + engine_get_s64(&msg->in, (int64_t *)write_buf); len = 8; break; case LWM2M_RES_TYPE_S32: - engine_get_s32(&msg->in, (int32_t *)data_ptr); + engine_get_s32(&msg->in, (int32_t *)write_buf); len = 4; break; case LWM2M_RES_TYPE_S16: engine_get_s32(&msg->in, &temp32); - *(int16_t *)data_ptr = temp32; + *(int16_t *)write_buf = temp32; len = 2; break; case LWM2M_RES_TYPE_S8: engine_get_s32(&msg->in, &temp32); - *(int8_t *)data_ptr = temp32; + *(int8_t *)write_buf = temp32; len = 1; break; case LWM2M_RES_TYPE_BOOL: - engine_get_bool(&msg->in, (bool *)data_ptr); + engine_get_bool(&msg->in, (bool *)write_buf); len = 1; break; case LWM2M_RES_TYPE_FLOAT32: engine_get_float32fix(&msg->in, - (float32_value_t *)data_ptr); + (float32_value_t *)write_buf); len = sizeof(float32_value_t); break; case LWM2M_RES_TYPE_FLOAT64: engine_get_float64fix(&msg->in, - (float64_value_t *)data_ptr); + (float64_value_t *)write_buf); len = sizeof(float64_value_t); break; case LWM2M_RES_TYPE_OBJLNK: engine_get_objlnk(&msg->in, - (struct lwm2m_objlnk *)data_ptr); + (struct lwm2m_objlnk *)write_buf); len = sizeof(struct lwm2m_objlnk); break; @@ -2538,16 +2605,40 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, return -ENOENT; } - res_inst->data_len = len; + if (obj_field->data_type != LWM2M_RES_TYPE_OPAQUE) { + if (res->validate_cb) { + ret = res->validate_cb( + obj_inst->obj_inst_id, res->res_id, + res_inst->res_inst_id, write_buf, len, + last_block, total_size); + if (ret < 0) { + /* -EEXIST will generate Bad Request LWM2M response. */ + return -EEXIST; + } - if (res->post_write_cb && - obj_field->data_type != LWM2M_RES_TYPE_OPAQUE) { - ret = res->post_write_cb(obj_inst->obj_inst_id, - res->res_id, res_inst->res_inst_id, - data_ptr, len, - last_block, total_size); + if (len > data_len) { + LOG_ERR("Received data won't fit into provided " + "bufffer"); + return -ENOMEM; + } + + if (obj_field->data_type == LWM2M_RES_TYPE_STRING) { + strncpy(data_ptr, write_buf, data_len); + } else { + memcpy(data_ptr, write_buf, len); + } + } + + if (res->post_write_cb) { + ret = res->post_write_cb( + obj_inst->obj_inst_id, res->res_id, + res_inst->res_inst_id, data_ptr, len, + last_block, total_size); + } } + res_inst->data_len = len; + NOTIFY_OBSERVER_PATH(&msg->path); return ret; diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_device.c b/subsys/net/lib/lwm2m/lwm2m_obj_device.c index c1aa3772eb6..f3b45aabf07 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_device.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_device.c @@ -229,7 +229,7 @@ static struct lwm2m_engine_obj_inst *device_create(uint16_t obj_inst_id) reset_error_list_cb); INIT_OBJ_RES_OPT(DEVICE_CURRENT_TIME_ID, res, i, res_inst, j, 1, false, true, current_time_read_cb, current_time_pre_write_cb, - current_time_post_write_cb, NULL); + NULL, current_time_post_write_cb, NULL); INIT_OBJ_RES_OPTDATA(DEVICE_UTC_OFFSET_ID, res, i, res_inst, j); INIT_OBJ_RES_OPTDATA(DEVICE_TIMEZONE_ID, res, i, res_inst, j); INIT_OBJ_RES_DATA(DEVICE_SUPPORTED_BINDING_MODES_ID, res, i, diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c index 0e9cf19c09e..aec3f92e48f 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c @@ -320,10 +320,10 @@ static struct lwm2m_engine_obj_inst *firmware_create(uint16_t obj_inst_id) /* initialize instance resource data */ INIT_OBJ_RES_OPT(FIRMWARE_PACKAGE_ID, res, i, res_inst, j, 1, false, - true, NULL, NULL, package_write_cb, NULL); + true, NULL, NULL, NULL, package_write_cb, NULL); INIT_OBJ_RES(FIRMWARE_PACKAGE_URI_ID, res, i, res_inst, j, 1, false, true, package_uri, PACKAGE_URI_LEN, - NULL, NULL, package_uri_write_cb, NULL); + NULL, NULL, NULL, package_uri_write_cb, NULL); INIT_OBJ_RES_EXECUTE(FIRMWARE_UPDATE_ID, res, i, firmware_update_cb); INIT_OBJ_RES_DATA(FIRMWARE_STATE_ID, res, i, res_inst, j, &update_state, sizeof(update_state)); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_server.c b/subsys/net/lib/lwm2m/lwm2m_obj_server.c index 89c0917f261..8dc891ab687 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_server.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_server.c @@ -213,7 +213,7 @@ static struct lwm2m_engine_obj_inst *server_create(uint16_t obj_inst_id) &server_id[index], sizeof(*server_id)); INIT_OBJ_RES(SERVER_LIFETIME_ID, res[index], i, res_inst[index], j, 1U, false, true, &lifetime[index], sizeof(*lifetime), - NULL, NULL, lifetime_write_cb, NULL); + NULL, NULL, NULL, lifetime_write_cb, NULL); INIT_OBJ_RES_DATA(SERVER_DEFAULT_MIN_PERIOD_ID, res[index], i, res_inst[index], j, &default_min_period[index], diff --git a/subsys/net/lib/lwm2m/lwm2m_object.h b/subsys/net/lib/lwm2m/lwm2m_object.h index 70aeb78156d..da51cfc23b8 100644 --- a/subsys/net/lib/lwm2m/lwm2m_object.h +++ b/subsys/net/lib/lwm2m/lwm2m_object.h @@ -198,13 +198,14 @@ struct lwm2m_engine_obj { /* Resource macros */ #define _INIT_OBJ_RES(_id, _r_ptr, _r_idx, _ri_ptr, _ri_count, _multi_ri, \ - _r_cb, _pre_w_cb, _post_w_cb, _ex_cb) \ + _r_cb, _pre_w_cb, _val_cb, _post_w_cb, _ex_cb) \ _r_ptr[_r_idx].res_id = _id; \ _r_ptr[_r_idx].res_instances = _ri_ptr; \ _r_ptr[_r_idx].res_inst_count = _ri_count; \ _r_ptr[_r_idx].multi_res_inst = _multi_ri; \ _r_ptr[_r_idx].read_cb = _r_cb; \ _r_ptr[_r_idx].pre_write_cb = _pre_w_cb; \ + _r_ptr[_r_idx].validate_cb = _val_cb; \ _r_ptr[_r_idx].post_write_cb = _post_w_cb; \ _r_ptr[_r_idx].execute_cb = _ex_cb @@ -253,11 +254,11 @@ struct lwm2m_engine_obj { #define INIT_OBJ_RES(_id, _r_ptr, _r_idx, \ _ri_ptr, _ri_idx, _ri_count, _multi_ri, _ri_create, \ _data_ptr, _data_len, \ - _r_cb, _pre_w_cb, _post_w_cb, _ex_cb) \ + _r_cb, _pre_w_cb, _val_cb, _post_w_cb, _ex_cb) \ do { \ _INIT_OBJ_RES(_id, _r_ptr, _r_idx, \ (_ri_ptr + _ri_idx), _ri_count, _multi_ri, \ - _r_cb, _pre_w_cb, _post_w_cb, _ex_cb); \ + _r_cb, _pre_w_cb, _val_cb, _post_w_cb, _ex_cb); \ _INIT_OBJ_RES_INST(_ri_ptr, _ri_idx, _ri_count, _ri_create, \ _data_ptr, _data_len); \ ++_r_idx; \ @@ -266,11 +267,11 @@ struct lwm2m_engine_obj { #define INIT_OBJ_RES_OPT(_id, _r_ptr, _r_idx, \ _ri_ptr, _ri_idx, _ri_count, _multi_ri, _ri_create, \ - _r_cb, _pre_w_cb, _post_w_cb, _ex_cb) \ + _r_cb, _pre_w_cb, _val_cb, _post_w_cb, _ex_cb) \ do { \ _INIT_OBJ_RES(_id, _r_ptr, _r_idx, \ (_ri_ptr + _ri_idx), _ri_count, _multi_ri, \ - _r_cb, _pre_w_cb, _post_w_cb, _ex_cb); \ + _r_cb, _pre_w_cb, _val_cb, _post_w_cb, _ex_cb); \ _INIT_OBJ_RES_INST_OPT(_ri_ptr, _ri_idx, _ri_count, _ri_create); \ ++_r_idx; \ } while (false) @@ -280,27 +281,27 @@ struct lwm2m_engine_obj { _data_ptr, _data_len) \ INIT_OBJ_RES(_id, _r_ptr, _r_idx, \ _ri_ptr, _ri_idx, _ri_count, true, _ri_create, \ - _data_ptr, _data_len, NULL, NULL, NULL, NULL) + _data_ptr, _data_len, NULL, NULL, NULL, NULL, NULL) #define INIT_OBJ_RES_MULTI_OPTDATA(_id, _r_ptr, _r_idx, \ _ri_ptr, _ri_idx, _ri_count, _ri_create) \ INIT_OBJ_RES_OPT(_id, _r_ptr, _r_idx, \ _ri_ptr, _ri_idx, _ri_count, true, _ri_create, \ - NULL, NULL, NULL, NULL) + NULL, NULL, NULL, NULL, NULL) #define INIT_OBJ_RES_DATA(_id, _r_ptr, _r_idx, _ri_ptr, _ri_idx, \ _data_ptr, _data_len) \ INIT_OBJ_RES(_id, _r_ptr, _r_idx, _ri_ptr, _ri_idx, 1U, false, true, \ - _data_ptr, _data_len, NULL, NULL, NULL, NULL) + _data_ptr, _data_len, NULL, NULL, NULL, NULL, NULL) #define INIT_OBJ_RES_OPTDATA(_id, _r_ptr, _r_idx, _ri_ptr, _ri_idx) \ INIT_OBJ_RES_OPT(_id, _r_ptr, _r_idx, _ri_ptr, _ri_idx, 1U, false, \ - true, NULL, NULL, NULL, NULL) + true, NULL, NULL, NULL, NULL, NULL) #define INIT_OBJ_RES_EXECUTE(_id, _r_ptr, _r_idx, _ex_cb) \ do { \ _INIT_OBJ_RES(_id, _r_ptr, _r_idx, NULL, 0, false, \ - NULL, NULL, NULL, _ex_cb); \ + NULL, NULL, NULL, NULL, _ex_cb); \ ++_r_idx; \ } while (false) @@ -336,6 +337,7 @@ struct lwm2m_engine_res_inst { struct lwm2m_engine_res { lwm2m_engine_get_data_cb_t read_cb; lwm2m_engine_get_data_cb_t pre_write_cb; + lwm2m_engine_set_data_cb_t validate_cb; lwm2m_engine_set_data_cb_t post_write_cb; lwm2m_engine_execute_cb_t execute_cb;