2017-07-25 20:04:16 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2017 Linaro Limited
|
2019-01-24 23:40:23 +01:00
|
|
|
* Copyright (c) 2018-2019 Foundries.io
|
2017-07-25 20:04:16 +02:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2015, Yanzi Networks AB.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of the copyright holder nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Original Authors:
|
|
|
|
* Joakim Eriksson <joakime@sics.se>
|
|
|
|
* Niclas Finne <nfi@sics.se>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Zephyr Contribution by Michael Scott <michael.scott@linaro.org>
|
|
|
|
* - Zephyr code style changes / code cleanup
|
|
|
|
* - Move to Zephyr APIs where possible
|
|
|
|
* - Convert to Zephyr int/uint types
|
|
|
|
* - Remove engine dependency (replace with writer context)
|
|
|
|
* - Add write int64 function
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO:
|
|
|
|
* - Lots of byte-order API clean up
|
|
|
|
* - Var / parameter type cleanup
|
|
|
|
* - Replace magic #'s with defines
|
|
|
|
*/
|
|
|
|
|
2018-09-19 10:22:19 +02:00
|
|
|
#define LOG_MODULE_NAME net_lwm2m_oma_tlv
|
|
|
|
#define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
|
|
|
|
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/logging/log.h>
|
2018-09-19 10:22:19 +02:00
|
|
|
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdint.h>
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/sys/byteorder.h>
|
2017-07-07 20:04:03 +02:00
|
|
|
|
|
|
|
#include "lwm2m_rw_oma_tlv.h"
|
|
|
|
#include "lwm2m_engine.h"
|
2019-01-26 07:36:47 +01:00
|
|
|
#include "lwm2m_rd_client.h"
|
2019-02-08 19:00:00 +01:00
|
|
|
#include "lwm2m_util.h"
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2017-10-11 22:02:31 +02:00
|
|
|
enum {
|
|
|
|
OMA_TLV_TYPE_OBJECT_INSTANCE = 0,
|
|
|
|
OMA_TLV_TYPE_RESOURCE_INSTANCE = 1,
|
|
|
|
OMA_TLV_TYPE_MULTI_RESOURCE = 2,
|
|
|
|
OMA_TLV_TYPE_RESOURCE = 3
|
|
|
|
};
|
|
|
|
|
|
|
|
struct oma_tlv {
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t type;
|
|
|
|
uint16_t id; /* can be 8-bit or 16-bit when serialized */
|
|
|
|
uint32_t length;
|
2017-10-11 22:02:31 +02:00
|
|
|
};
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static uint8_t get_len_type(const struct oma_tlv *tlv)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
|
|
|
if (tlv->length < 8) {
|
|
|
|
return 0;
|
|
|
|
} else if (tlv->length < 0x100) {
|
|
|
|
return 1;
|
|
|
|
} else if (tlv->length < 0x10000) {
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static uint8_t tlv_calc_type(uint8_t flags)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
|
|
|
return flags & WRITER_RESOURCE_INSTANCE ?
|
|
|
|
OMA_TLV_TYPE_RESOURCE_INSTANCE : OMA_TLV_TYPE_RESOURCE;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static uint16_t tlv_calc_id(uint8_t flags, struct lwm2m_obj_path *path)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
|
|
|
return flags & WRITER_RESOURCE_INSTANCE ?
|
|
|
|
path->res_inst_id : path->res_id;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static void tlv_setup(struct oma_tlv *tlv, uint8_t type, uint16_t id,
|
|
|
|
uint32_t buflen)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
|
|
|
if (tlv) {
|
|
|
|
tlv->type = type;
|
|
|
|
tlv->id = id;
|
2017-10-11 21:48:06 +02:00
|
|
|
tlv->length = buflen;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
static int oma_tlv_put_u8(struct lwm2m_output_context *out,
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t value, bool insert)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2019-01-25 23:13:07 +01:00
|
|
|
struct tlv_out_formatter_data *fd;
|
|
|
|
int ret;
|
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
if (insert) {
|
2019-01-25 23:13:07 +01:00
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return -EINVAL;
|
2019-01-25 23:13:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = buf_insert(CPKT_BUF_WRITE(out->out_cpkt),
|
|
|
|
fd->mark_pos, &value, 1);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
2017-10-20 01:27:32 +02:00
|
|
|
}
|
|
|
|
|
2019-01-25 23:13:07 +01:00
|
|
|
fd->mark_pos++;
|
2017-10-20 01:27:32 +02:00
|
|
|
} else {
|
2019-01-25 23:13:07 +01:00
|
|
|
ret = buf_append(CPKT_BUF_WRITE(out->out_cpkt), &value, 1);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
2017-10-20 01:27:32 +02:00
|
|
|
}
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int oma_tlv_put(const struct oma_tlv *tlv,
|
|
|
|
struct lwm2m_output_context *out, uint8_t *value,
|
|
|
|
bool insert)
|
2017-10-20 01:27:32 +02:00
|
|
|
{
|
|
|
|
size_t pos;
|
|
|
|
int ret, i;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t len_type, tmp;
|
2017-10-20 01:27:32 +02:00
|
|
|
|
|
|
|
/* len_type is the same as number of bytes required for length */
|
2017-07-07 20:04:03 +02:00
|
|
|
len_type = get_len_type(tlv);
|
2017-10-20 01:27:32 +02:00
|
|
|
|
|
|
|
/* first type byte in TLV header */
|
|
|
|
tmp = (tlv->type << 6) |
|
|
|
|
(tlv->id > 255 ? (1 << 5) : 0) |
|
|
|
|
(len_type << 3) |
|
2019-03-27 02:57:45 +01:00
|
|
|
(len_type == 0U ? tlv->length : 0);
|
2017-10-20 01:27:32 +02:00
|
|
|
|
|
|
|
ret = oma_tlv_put_u8(out, tmp, insert);
|
|
|
|
if (ret < 0) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return ret;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pos = 1;
|
|
|
|
|
|
|
|
/* The ID */
|
|
|
|
if (tlv->id > 255) {
|
2017-10-20 01:27:32 +02:00
|
|
|
ret = oma_tlv_put_u8(out, (tlv->id >> 8) & 0xff, insert);
|
|
|
|
if (ret < 0) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return ret;
|
2017-10-20 01:27:32 +02:00
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
pos++;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
ret = oma_tlv_put_u8(out, tlv->id & 0xff, insert);
|
|
|
|
if (ret < 0) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return ret;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
pos++;
|
|
|
|
|
|
|
|
for (i = 2; i >= 0; i--) {
|
|
|
|
if (len_type > i) {
|
|
|
|
ret = oma_tlv_put_u8(out,
|
|
|
|
(tlv->length >> (i * 8)) & 0xff,
|
|
|
|
insert);
|
|
|
|
if (ret < 0) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return ret;
|
2017-10-20 01:27:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pos++;
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* finally add the value */
|
2018-08-29 01:57:59 +02:00
|
|
|
if (value != NULL && tlv->length > 0 && !insert) {
|
2021-12-17 16:43:39 +01:00
|
|
|
ret = buf_append(CPKT_BUF_WRITE(out->out_cpkt),
|
|
|
|
value, tlv->length);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
2017-10-20 01:27:32 +02:00
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return pos + tlv->length;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int oma_tlv_get(struct oma_tlv *tlv, struct lwm2m_input_context *in,
|
|
|
|
bool dont_advance)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t len_type;
|
|
|
|
uint8_t len_pos = 1U;
|
2017-07-07 20:04:03 +02:00
|
|
|
size_t tlv_len;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t tmp_offset;
|
|
|
|
uint8_t buf[2];
|
2021-12-17 16:43:39 +01:00
|
|
|
int ret;
|
2017-10-20 01:27:32 +02:00
|
|
|
|
|
|
|
tmp_offset = in->offset;
|
2021-12-17 16:43:39 +01:00
|
|
|
ret = buf_read_u8(&buf[0], CPKT_BUF_READ(in->in_cpkt), &tmp_offset);
|
|
|
|
if (ret < 0) {
|
2017-10-20 01:27:32 +02:00
|
|
|
goto error;
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2017-10-11 21:48:06 +02:00
|
|
|
tlv->type = (buf[0] >> 6) & 3;
|
|
|
|
len_type = (buf[0] >> 3) & 3;
|
2019-03-27 02:57:45 +01:00
|
|
|
len_pos = 1 + (((buf[0] & (1 << 5)) != 0U) ? 2 : 1);
|
2017-10-20 01:27:32 +02:00
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
ret = buf_read_u8(&buf[1], CPKT_BUF_READ(in->in_cpkt), &tmp_offset);
|
|
|
|
if (ret < 0) {
|
|
|
|
goto error;
|
2017-10-20 01:27:32 +02:00
|
|
|
}
|
|
|
|
|
2017-10-11 21:48:06 +02:00
|
|
|
tlv->id = buf[1];
|
2017-07-07 20:04:03 +02:00
|
|
|
|
|
|
|
/* if len_pos > 2 it means that there are more ID to read */
|
|
|
|
if (len_pos > 2) {
|
2021-12-17 16:43:39 +01:00
|
|
|
ret = buf_read_u8(&buf[1], CPKT_BUF_READ(in->in_cpkt),
|
|
|
|
&tmp_offset);
|
|
|
|
if (ret < 0) {
|
2017-10-20 01:27:32 +02:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
tlv->id = (tlv->id << 8) + buf[1];
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2019-03-27 02:57:45 +01:00
|
|
|
if (len_type == 0U) {
|
2017-11-01 18:44:31 +01:00
|
|
|
tlv_len = buf[0] & 7;
|
2017-07-07 20:04:03 +02:00
|
|
|
} else {
|
|
|
|
/* read the length */
|
|
|
|
tlv_len = 0;
|
|
|
|
while (len_type > 0) {
|
2021-12-17 16:43:39 +01:00
|
|
|
ret = buf_read_u8(&buf[1], CPKT_BUF_READ(in->in_cpkt),
|
|
|
|
&tmp_offset);
|
|
|
|
if (ret < 0) {
|
2017-10-20 01:27:32 +02:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
len_pos++;
|
|
|
|
tlv_len = tlv_len << 8 | buf[1];
|
2017-07-07 20:04:03 +02:00
|
|
|
len_type--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* and read out the data??? */
|
|
|
|
tlv->length = tlv_len;
|
2017-10-20 01:27:32 +02:00
|
|
|
|
|
|
|
if (!dont_advance) {
|
|
|
|
in->offset = tmp_offset;
|
|
|
|
}
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
return len_pos + tlv_len;
|
2017-10-20 01:27:32 +02:00
|
|
|
|
|
|
|
error:
|
|
|
|
if (!dont_advance) {
|
|
|
|
in->offset = tmp_offset;
|
|
|
|
}
|
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
return ret;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_begin_tlv(struct lwm2m_output_context *out, uint16_t *mark_pos,
|
|
|
|
uint8_t *writer_flags, int writer_flag)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2018-08-29 00:53:18 +02:00
|
|
|
/* set flags */
|
|
|
|
*writer_flags |= writer_flag;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
|
|
|
/*
|
2017-10-20 01:27:32 +02:00
|
|
|
* store position for inserting TLV when we know the length
|
2017-07-07 20:04:03 +02:00
|
|
|
*/
|
2019-01-25 23:13:07 +01:00
|
|
|
*mark_pos = out->out_cpkt->offset;
|
2018-08-29 00:53:18 +02:00
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
return 0;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_end_tlv(struct lwm2m_output_context *out, uint16_t mark_pos,
|
|
|
|
uint8_t *writer_flags, uint8_t writer_flag, int tlv_type,
|
|
|
|
int tlv_id)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2019-01-25 23:13:07 +01:00
|
|
|
struct tlv_out_formatter_data *fd;
|
2017-10-20 01:27:32 +02:00
|
|
|
struct oma_tlv tlv;
|
2021-12-17 16:43:39 +01:00
|
|
|
int len;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2019-01-25 23:13:07 +01:00
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return -EINVAL;
|
2019-01-25 23:13:07 +01:00
|
|
|
}
|
2018-08-29 23:08:12 +02:00
|
|
|
|
2019-01-25 23:13:07 +01:00
|
|
|
*writer_flags &= ~writer_flag;
|
2017-10-20 01:27:32 +02:00
|
|
|
|
2019-01-25 23:13:07 +01:00
|
|
|
len = out->out_cpkt->offset - mark_pos;
|
2017-10-20 01:27:32 +02:00
|
|
|
|
|
|
|
/* use stored location */
|
2019-01-25 23:13:07 +01:00
|
|
|
fd->mark_pos = mark_pos;
|
2017-10-20 01:27:32 +02:00
|
|
|
|
2018-08-29 00:53:18 +02:00
|
|
|
/* set instance length */
|
|
|
|
tlv_setup(&tlv, tlv_type, tlv_id, len);
|
2017-10-20 01:27:32 +02:00
|
|
|
len = oma_tlv_put(&tlv, out, NULL, true) - tlv.length;
|
|
|
|
|
2020-04-05 18:32:49 +02:00
|
|
|
return len;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_begin_oi(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path)
|
2018-08-29 23:50:07 +02:00
|
|
|
{
|
|
|
|
struct tlv_out_formatter_data *fd;
|
|
|
|
|
2022-03-02 14:58:36 +01:00
|
|
|
/* No need for oi level TLV constructs */
|
|
|
|
if (path->level > LWM2M_PATH_LEVEL_OBJECT) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-08-29 23:50:07 +02:00
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return -EINVAL;
|
2018-08-29 23:50:07 +02:00
|
|
|
}
|
|
|
|
|
2019-01-25 23:13:07 +01:00
|
|
|
return put_begin_tlv(out, &fd->mark_pos_oi, &fd->writer_flags, 0);
|
2018-08-29 23:50:07 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_end_oi(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path)
|
2018-08-29 23:50:07 +02:00
|
|
|
{
|
|
|
|
struct tlv_out_formatter_data *fd;
|
|
|
|
|
2022-03-02 14:58:36 +01:00
|
|
|
if (path->level > LWM2M_PATH_LEVEL_OBJECT) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-08-29 23:50:07 +02:00
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return -EINVAL;
|
2018-08-29 23:50:07 +02:00
|
|
|
}
|
|
|
|
|
2019-01-25 23:13:07 +01:00
|
|
|
return put_end_tlv(out, fd->mark_pos_oi, &fd->writer_flags, 0,
|
2018-08-29 23:50:07 +02:00
|
|
|
OMA_TLV_TYPE_OBJECT_INSTANCE, path->obj_inst_id);
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_begin_ri(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path)
|
2018-08-29 00:53:18 +02:00
|
|
|
{
|
|
|
|
struct tlv_out_formatter_data *fd;
|
|
|
|
|
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return -EINVAL;
|
2018-08-29 00:53:18 +02:00
|
|
|
}
|
|
|
|
|
2019-01-25 23:13:07 +01:00
|
|
|
return put_begin_tlv(out, &fd->mark_pos_ri, &fd->writer_flags,
|
|
|
|
WRITER_RESOURCE_INSTANCE);
|
2018-08-29 00:53:18 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_end_ri(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path)
|
2018-08-29 00:53:18 +02:00
|
|
|
{
|
|
|
|
struct tlv_out_formatter_data *fd;
|
|
|
|
|
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return -EINVAL;
|
2018-08-29 00:53:18 +02:00
|
|
|
}
|
|
|
|
|
2022-02-01 12:44:08 +01:00
|
|
|
/* Skip writing Multiple Resource TLV if path level is 4 */
|
|
|
|
if (IS_ENABLED(CONFIG_LWM2M_VERSION_1_1) &&
|
|
|
|
path->level == LWM2M_PATH_LEVEL_RESOURCE_INST) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-25 23:13:07 +01:00
|
|
|
return put_end_tlv(out, fd->mark_pos_ri, &fd->writer_flags,
|
|
|
|
WRITER_RESOURCE_INSTANCE,
|
2018-08-29 00:53:18 +02:00
|
|
|
OMA_TLV_TYPE_MULTI_RESOURCE, path->res_id);
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_s8(struct lwm2m_output_context *out, struct lwm2m_obj_path *path,
|
|
|
|
int8_t value)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2018-08-29 23:08:12 +02:00
|
|
|
struct tlv_out_formatter_data *fd;
|
2021-12-17 16:43:39 +01:00
|
|
|
int len;
|
2017-07-07 20:04:03 +02:00
|
|
|
struct oma_tlv tlv;
|
|
|
|
|
2018-08-29 23:08:12 +02:00
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return -EINVAL;
|
2018-08-29 23:08:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
tlv_setup(&tlv, tlv_calc_type(fd->writer_flags),
|
|
|
|
tlv_calc_id(fd->writer_flags, path), sizeof(value));
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
len = oma_tlv_put(&tlv, out, (uint8_t *)&value, false);
|
2017-07-07 20:04:03 +02:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_s16(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, int16_t value)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2018-08-29 23:08:12 +02:00
|
|
|
struct tlv_out_formatter_data *fd;
|
2021-12-17 16:43:39 +01:00
|
|
|
int len;
|
2017-07-07 20:04:03 +02:00
|
|
|
struct oma_tlv tlv;
|
2020-05-27 18:26:57 +02:00
|
|
|
int16_t net_value;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2020-10-23 17:05:47 +02:00
|
|
|
if (INT8_MIN <= value && value <= INT8_MAX) {
|
|
|
|
return put_s8(out, path, (int8_t)value);
|
|
|
|
}
|
|
|
|
|
2018-08-29 23:08:12 +02:00
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return -EINVAL;
|
2018-08-29 23:08:12 +02:00
|
|
|
}
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
net_value = sys_cpu_to_be16(value);
|
2018-08-29 23:08:12 +02:00
|
|
|
tlv_setup(&tlv, tlv_calc_type(fd->writer_flags),
|
|
|
|
tlv_calc_id(fd->writer_flags, path), sizeof(net_value));
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
len = oma_tlv_put(&tlv, out, (uint8_t *)&net_value, false);
|
2017-07-07 20:04:03 +02:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_s32(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, int32_t value)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2018-08-29 23:08:12 +02:00
|
|
|
struct tlv_out_formatter_data *fd;
|
2021-12-17 16:43:39 +01:00
|
|
|
int len;
|
2017-07-07 20:04:03 +02:00
|
|
|
struct oma_tlv tlv;
|
2020-05-27 18:26:57 +02:00
|
|
|
int32_t net_value;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2020-10-23 17:05:47 +02:00
|
|
|
if (INT16_MIN <= value && value <= INT16_MAX) {
|
|
|
|
return put_s16(out, path, (int16_t)value);
|
|
|
|
}
|
|
|
|
|
2018-08-29 23:08:12 +02:00
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return -EINVAL;
|
2018-08-29 23:08:12 +02:00
|
|
|
}
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
net_value = sys_cpu_to_be32(value);
|
2018-08-29 23:08:12 +02:00
|
|
|
tlv_setup(&tlv, tlv_calc_type(fd->writer_flags),
|
|
|
|
tlv_calc_id(fd->writer_flags, path), sizeof(net_value));
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
len = oma_tlv_put(&tlv, out, (uint8_t *)&net_value, false);
|
2020-10-23 17:05:47 +02:00
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_s64(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, int64_t value)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2018-08-29 23:08:12 +02:00
|
|
|
struct tlv_out_formatter_data *fd;
|
2021-12-17 16:43:39 +01:00
|
|
|
int len;
|
2017-07-07 20:04:03 +02:00
|
|
|
struct oma_tlv tlv;
|
2020-05-27 18:26:57 +02:00
|
|
|
int64_t net_value;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2020-10-23 17:05:47 +02:00
|
|
|
if (INT32_MIN <= value && value <= INT32_MAX) {
|
|
|
|
return put_s32(out, path, (int32_t)value);
|
|
|
|
}
|
|
|
|
|
2018-08-29 23:08:12 +02:00
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return -EINVAL;
|
2018-08-29 23:08:12 +02:00
|
|
|
}
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
net_value = sys_cpu_to_be64(value);
|
2018-08-29 23:08:12 +02:00
|
|
|
tlv_setup(&tlv, tlv_calc_type(fd->writer_flags),
|
|
|
|
tlv_calc_id(fd->writer_flags, path), sizeof(net_value));
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
len = oma_tlv_put(&tlv, out, (uint8_t *)&net_value, false);
|
2017-07-07 20:04:03 +02:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2022-10-06 12:20:17 +02:00
|
|
|
|
|
|
|
static int put_time(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, time_t value)
|
|
|
|
{
|
|
|
|
return put_s64(out, path, (int64_t)value);
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_string(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, char *buf, size_t buflen)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2018-08-29 23:08:12 +02:00
|
|
|
struct tlv_out_formatter_data *fd;
|
2021-12-17 16:43:39 +01:00
|
|
|
int len;
|
2017-07-07 20:04:03 +02:00
|
|
|
struct oma_tlv tlv;
|
|
|
|
|
2018-08-29 23:08:12 +02:00
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return -EINVAL;
|
2018-08-29 23:08:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
tlv_setup(&tlv, tlv_calc_type(fd->writer_flags),
|
2020-05-27 18:26:57 +02:00
|
|
|
tlv_calc_id(fd->writer_flags, path), (uint32_t)buflen);
|
|
|
|
len = oma_tlv_put(&tlv, out, (uint8_t *)buf, false);
|
2017-07-07 20:04:03 +02:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_float(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, double *value)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2018-08-29 23:08:12 +02:00
|
|
|
struct tlv_out_formatter_data *fd;
|
2021-12-17 16:43:39 +01:00
|
|
|
int len;
|
2017-07-07 20:04:03 +02:00
|
|
|
struct oma_tlv tlv;
|
2019-02-08 19:00:00 +01:00
|
|
|
int ret;
|
2021-07-23 16:38:23 +02:00
|
|
|
uint8_t b64[8];
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2018-08-29 23:08:12 +02:00
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-17 16:43:39 +01:00
|
|
|
return -EINVAL;
|
2018-08-29 23:08:12 +02:00
|
|
|
}
|
|
|
|
|
2021-07-23 16:38:23 +02:00
|
|
|
ret = lwm2m_float_to_b64(value, b64, sizeof(b64));
|
2019-02-08 19:00:00 +01:00
|
|
|
if (ret < 0) {
|
|
|
|
LOG_ERR("float32 conversion error: %d", ret);
|
2021-12-17 16:43:39 +01:00
|
|
|
return ret;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2018-08-29 23:08:12 +02:00
|
|
|
tlv_setup(&tlv, tlv_calc_type(fd->writer_flags),
|
2021-07-23 16:38:23 +02:00
|
|
|
tlv_calc_id(fd->writer_flags, path), sizeof(b64));
|
|
|
|
len = oma_tlv_put(&tlv, out, b64, false);
|
2017-07-07 20:04:03 +02:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_bool(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, bool value)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
int8_t value_s8 = (value != 0 ? 1 : 0);
|
2019-02-13 23:01:38 +01:00
|
|
|
|
|
|
|
return put_s8(out, path, value_s8);
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_opaque(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, char *buf, size_t buflen)
|
2020-03-03 16:49:49 +01:00
|
|
|
{
|
|
|
|
return put_string(out, path, buf, buflen);
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_objlnk(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, struct lwm2m_objlnk *value)
|
2020-05-19 12:37:02 +02:00
|
|
|
{
|
2022-01-04 14:28:59 +01:00
|
|
|
struct tlv_out_formatter_data *fd;
|
|
|
|
struct oma_tlv tlv;
|
|
|
|
int32_t net_value = sys_cpu_to_be32(
|
|
|
|
((value->obj_id) << 16) | value->obj_inst);
|
|
|
|
|
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
tlv_setup(&tlv, tlv_calc_type(fd->writer_flags),
|
|
|
|
tlv_calc_id(fd->writer_flags, path), sizeof(net_value));
|
2020-05-19 12:37:02 +02:00
|
|
|
|
2022-01-04 14:28:59 +01:00
|
|
|
return oma_tlv_put(&tlv, out, (uint8_t *)&net_value, false);
|
2020-05-19 12:37:02 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_number(struct lwm2m_input_context *in, int64_t *value,
|
|
|
|
uint8_t max_len)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
|
|
|
struct oma_tlv tlv;
|
2021-12-17 16:43:39 +01:00
|
|
|
int size;
|
2020-05-27 18:26:57 +02:00
|
|
|
int64_t temp;
|
2021-12-17 16:43:39 +01:00
|
|
|
int ret;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
size = oma_tlv_get(&tlv, in, false);
|
|
|
|
if (size < 0) {
|
|
|
|
return size;
|
|
|
|
}
|
2017-10-20 01:27:32 +02:00
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
if (tlv.length > max_len) {
|
|
|
|
LOG_ERR("invalid length: %u", tlv.length);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2017-10-20 01:27:32 +02:00
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
ret = buf_read((uint8_t *)&temp, tlv.length,
|
|
|
|
CPKT_BUF_READ(in->in_cpkt), &in->offset);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (tlv.length) {
|
|
|
|
case 1:
|
|
|
|
*value = (int8_t)temp;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
*value = sys_cpu_to_be16((int16_t)temp);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
*value = sys_cpu_to_be32((int32_t)temp);
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
*value = sys_cpu_to_be64(temp);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOG_ERR("invalid length: %u", tlv.length);
|
|
|
|
return -EBADMSG;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_s64(struct lwm2m_input_context *in, int64_t *value)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2017-10-20 01:27:32 +02:00
|
|
|
return get_number(in, value, 8);
|
|
|
|
}
|
|
|
|
|
2022-10-06 12:20:17 +02:00
|
|
|
static int get_time(struct lwm2m_input_context *in, time_t *value)
|
|
|
|
{
|
|
|
|
int64_t temp64;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = get_number(in, &temp64, 8);
|
|
|
|
*value = (time_t)temp64;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_s32(struct lwm2m_input_context *in, int32_t *value)
|
2017-10-20 01:27:32 +02:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
int64_t temp;
|
2021-12-17 16:43:39 +01:00
|
|
|
int size;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
size = get_number(in, &temp, 4);
|
2021-12-17 16:43:39 +01:00
|
|
|
if (size < 0) {
|
|
|
|
return size;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
*value = (int32_t)temp;
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_string(struct lwm2m_input_context *in, uint8_t *buf,
|
|
|
|
size_t buflen)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
|
|
|
struct oma_tlv tlv;
|
2021-12-17 16:43:39 +01:00
|
|
|
int size;
|
|
|
|
int ret;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
size = oma_tlv_get(&tlv, in, false);
|
|
|
|
if (size < 0) {
|
|
|
|
return size;
|
|
|
|
}
|
2017-10-20 01:27:32 +02:00
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
if (buflen <= tlv.length) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
ret = buf_read(buf, tlv.length, CPKT_BUF_READ(in->in_cpkt),
|
|
|
|
&in->offset);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
buf[tlv.length] = '\0';
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* convert float to fixpoint */
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_float(struct lwm2m_input_context *in, double *value)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
|
|
|
struct oma_tlv tlv;
|
2021-12-17 16:43:39 +01:00
|
|
|
int size;
|
2021-07-20 16:48:33 +02:00
|
|
|
uint8_t buf[8];
|
2019-02-08 19:00:00 +01:00
|
|
|
int ret;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
size = oma_tlv_get(&tlv, in, false);
|
|
|
|
if (size < 0) {
|
|
|
|
return size;
|
|
|
|
}
|
2019-02-08 19:00:00 +01:00
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
if (tlv.length != 4U && tlv.length != 8U) {
|
|
|
|
LOG_ERR("Invalid float length: %d", tlv.length);
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
2019-02-08 19:00:00 +01:00
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
/* read float in network byte order */
|
|
|
|
ret = buf_read(buf, tlv.length, CPKT_BUF_READ(in->in_cpkt),
|
|
|
|
&in->offset);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2017-10-20 01:27:32 +02:00
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
if (tlv.length == 4U) {
|
|
|
|
ret = lwm2m_b32_to_float(buf, 4, value);
|
|
|
|
} else {
|
|
|
|
ret = lwm2m_b64_to_float(buf, 8, value);
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
if (ret < 0) {
|
|
|
|
LOG_ERR("binary%s conversion error: %d",
|
|
|
|
tlv.length == 4U ? "32" : "64", ret);
|
|
|
|
return ret;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_bool(struct lwm2m_input_context *in, bool *value)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
int64_t temp;
|
2021-12-17 16:43:39 +01:00
|
|
|
int size;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2017-11-01 18:43:32 +01:00
|
|
|
size = get_number(in, &temp, 2);
|
2021-12-17 16:43:39 +01:00
|
|
|
if (size < 0) {
|
|
|
|
return size;
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-17 16:43:39 +01:00
|
|
|
*value = (temp != 0);
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_opaque(struct lwm2m_input_context *in, uint8_t *value,
|
|
|
|
size_t buflen, struct lwm2m_opaque_context *opaque,
|
|
|
|
bool *last_block)
|
2017-10-27 08:32:47 +02:00
|
|
|
{
|
|
|
|
struct oma_tlv tlv;
|
2021-12-17 16:43:39 +01:00
|
|
|
int size;
|
2020-09-16 15:09:30 +02:00
|
|
|
|
|
|
|
/* Get the TLV header only on first read. */
|
|
|
|
if (opaque->remaining == 0) {
|
|
|
|
size = oma_tlv_get(&tlv, in, false);
|
2021-12-17 16:43:39 +01:00
|
|
|
if (size < 0) {
|
|
|
|
return size;
|
|
|
|
}
|
2020-09-16 15:09:30 +02:00
|
|
|
|
|
|
|
opaque->len = tlv.length;
|
|
|
|
opaque->remaining = tlv.length;
|
|
|
|
}
|
2017-10-27 08:32:47 +02:00
|
|
|
|
2020-09-16 15:09:30 +02:00
|
|
|
return lwm2m_engine_get_opaque_more(in, value, buflen,
|
|
|
|
opaque, last_block);
|
2017-10-27 08:32:47 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_objlnk(struct lwm2m_input_context *in,
|
|
|
|
struct lwm2m_objlnk *value)
|
2020-05-19 12:37:02 +02:00
|
|
|
{
|
|
|
|
int32_t value_s32;
|
2021-12-17 16:43:39 +01:00
|
|
|
int size;
|
2020-05-19 12:37:02 +02:00
|
|
|
|
|
|
|
size = get_s32(in, &value_s32);
|
2021-12-17 16:43:39 +01:00
|
|
|
if (size < 0) {
|
|
|
|
return size;
|
|
|
|
}
|
2020-05-19 12:37:02 +02:00
|
|
|
|
|
|
|
value->obj_id = (value_s32 >> 16) & 0xFFFF;
|
2020-07-01 11:42:03 +02:00
|
|
|
value->obj_inst = value_s32 & 0xFFFF;
|
2020-05-19 12:37:02 +02:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
const struct lwm2m_writer oma_tlv_writer = {
|
2018-08-30 17:59:23 +02:00
|
|
|
.put_begin_oi = put_begin_oi,
|
|
|
|
.put_end_oi = put_end_oi,
|
|
|
|
.put_begin_ri = put_begin_ri,
|
|
|
|
.put_end_ri = put_end_ri,
|
|
|
|
.put_s8 = put_s8,
|
|
|
|
.put_s16 = put_s16,
|
|
|
|
.put_s32 = put_s32,
|
|
|
|
.put_s64 = put_s64,
|
|
|
|
.put_string = put_string,
|
2021-07-23 16:38:23 +02:00
|
|
|
.put_float = put_float,
|
2022-10-06 12:20:17 +02:00
|
|
|
.put_time = put_time,
|
2018-08-30 17:59:23 +02:00
|
|
|
.put_bool = put_bool,
|
2020-03-03 16:49:49 +01:00
|
|
|
.put_opaque = put_opaque,
|
2020-05-19 12:37:02 +02:00
|
|
|
.put_objlnk = put_objlnk,
|
2017-07-07 20:04:03 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const struct lwm2m_reader oma_tlv_reader = {
|
2018-08-30 17:59:23 +02:00
|
|
|
.get_s32 = get_s32,
|
|
|
|
.get_s64 = get_s64,
|
|
|
|
.get_string = get_string,
|
2022-10-06 12:20:17 +02:00
|
|
|
.get_time = get_time,
|
2021-07-23 16:38:23 +02:00
|
|
|
.get_float = get_float,
|
2018-08-30 17:59:23 +02:00
|
|
|
.get_bool = get_bool,
|
|
|
|
.get_opaque = get_opaque,
|
2020-05-19 12:37:02 +02:00
|
|
|
.get_objlnk = get_objlnk,
|
2017-07-07 20:04:03 +02:00
|
|
|
};
|
|
|
|
|
2019-07-29 19:08:00 +02:00
|
|
|
int do_read_op_tlv(struct lwm2m_message *msg, int content_format)
|
2018-08-29 22:35:50 +02:00
|
|
|
{
|
2018-08-29 23:08:12 +02:00
|
|
|
struct tlv_out_formatter_data fd;
|
|
|
|
int ret;
|
|
|
|
|
2018-09-12 04:09:03 +02:00
|
|
|
(void)memset(&fd, 0, sizeof(fd));
|
2019-01-24 23:40:23 +01:00
|
|
|
engine_set_out_user_data(&msg->out, &fd);
|
2019-07-29 19:08:00 +02:00
|
|
|
ret = lwm2m_perform_read_op(msg, content_format);
|
2019-01-24 23:40:23 +01:00
|
|
|
engine_clear_out_user_data(&msg->out);
|
2018-08-29 23:08:12 +02:00
|
|
|
return ret;
|
2018-08-29 22:35:50 +02:00
|
|
|
}
|
|
|
|
|
2019-01-24 23:40:23 +01:00
|
|
|
static int do_write_op_tlv_dummy_read(struct lwm2m_message *msg)
|
2018-07-12 19:00:03 +02:00
|
|
|
{
|
|
|
|
struct oma_tlv tlv;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t read_char;
|
2018-07-12 19:00:03 +02:00
|
|
|
|
2019-01-24 23:40:23 +01:00
|
|
|
oma_tlv_get(&tlv, &msg->in, false);
|
2019-01-25 23:13:07 +01:00
|
|
|
while (tlv.length--) {
|
|
|
|
if (buf_read_u8(&read_char, CPKT_BUF_READ(msg->in.in_cpkt),
|
|
|
|
&msg->in.offset) < 0) {
|
|
|
|
break;
|
|
|
|
}
|
2018-07-12 19:00:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-24 23:40:23 +01:00
|
|
|
static int do_write_op_tlv_item(struct lwm2m_message *msg)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
|
|
|
struct lwm2m_engine_obj_inst *obj_inst = NULL;
|
2019-07-29 19:09:00 +02:00
|
|
|
struct lwm2m_engine_res *res = NULL;
|
|
|
|
struct lwm2m_engine_res_inst *res_inst = NULL;
|
2017-07-07 20:04:03 +02:00
|
|
|
struct lwm2m_engine_obj_field *obj_field = NULL;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t created = 0U;
|
2022-02-11 16:03:25 +01:00
|
|
|
int ret;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2019-01-24 23:40:23 +01:00
|
|
|
ret = lwm2m_get_or_create_engine_obj(msg, &obj_inst, &created);
|
2017-07-07 20:04:03 +02:00
|
|
|
if (ret < 0) {
|
2018-07-12 19:00:03 +02:00
|
|
|
goto error;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2022-02-11 16:03:25 +01:00
|
|
|
ret = lwm2m_engine_validate_write_access(msg, obj_inst, &obj_field);
|
|
|
|
if (ret < 0) {
|
2018-07-12 19:00:03 +02:00
|
|
|
goto error;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2022-02-11 16:03:25 +01:00
|
|
|
ret = lwm2m_engine_get_create_res_inst(&msg->path, &res, &res_inst);
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2022-02-11 16:03:25 +01:00
|
|
|
if (ret < 0) {
|
2019-01-26 07:36:47 +01:00
|
|
|
/* if OPTIONAL and BOOTSTRAP-WRITE or CREATE use ENOTSUP */
|
|
|
|
if ((msg->ctx->bootstrap_mode ||
|
|
|
|
msg->operation == LWM2M_OP_CREATE) &&
|
2018-07-12 19:00:03 +02:00
|
|
|
LWM2M_HAS_PERM(obj_field, BIT(LWM2M_FLAG_OPTIONAL))) {
|
|
|
|
ret = -ENOTSUP;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = -ENOENT;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2019-07-29 19:09:00 +02:00
|
|
|
ret = lwm2m_write_handler(obj_inst, res, res_inst, obj_field, msg);
|
2018-07-12 19:00:03 +02:00
|
|
|
if (ret == -EACCES || ret == -ENOENT) {
|
|
|
|
/* if read-only or non-existent data buffer move on */
|
2019-01-24 23:40:23 +01:00
|
|
|
do_write_op_tlv_dummy_read(msg);
|
2018-07-12 19:00:03 +02:00
|
|
|
ret = 0;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2018-07-12 19:00:03 +02:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
error:
|
2019-01-24 23:40:23 +01:00
|
|
|
do_write_op_tlv_dummy_read(msg);
|
2018-07-12 19:00:03 +02:00
|
|
|
return ret;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-05-11 14:38:49 +02:00
|
|
|
static int write_tlv_resource(struct lwm2m_message *msg, struct oma_tlv *tlv)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (msg->in.block_ctx) {
|
2023-04-25 11:55:31 +02:00
|
|
|
msg->in.block_ctx->path.res_id = tlv->id;
|
2021-05-11 14:38:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
msg->path.res_id = tlv->id;
|
|
|
|
msg->path.level = 3U;
|
|
|
|
ret = do_write_op_tlv_item(msg);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ignore errors for CREATE op
|
|
|
|
* for OP_CREATE and BOOTSTRAP WRITE: errors on
|
|
|
|
* optional resources are ignored (ENOTSUP)
|
|
|
|
*/
|
|
|
|
if (ret < 0 &&
|
|
|
|
!((ret == -ENOTSUP) &&
|
|
|
|
(msg->ctx->bootstrap_mode ||
|
|
|
|
msg->operation == LWM2M_OP_CREATE))) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-02-08 08:17:57 +01:00
|
|
|
static int lwm2m_multi_resource_tlv_parse(struct lwm2m_message *msg,
|
|
|
|
struct oma_tlv *multi_resource_tlv)
|
|
|
|
{
|
|
|
|
struct oma_tlv tlv_resource_instance;
|
|
|
|
int len2;
|
|
|
|
int pos = 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (msg->in.block_ctx) {
|
2023-04-25 11:55:31 +02:00
|
|
|
msg->in.block_ctx->path.res_id = multi_resource_tlv->id;
|
2022-02-08 08:17:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (multi_resource_tlv->length == 0U) {
|
|
|
|
/* No data for resource instances, so create only a resource */
|
|
|
|
return write_tlv_resource(msg, multi_resource_tlv);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (pos < multi_resource_tlv->length &&
|
|
|
|
(len2 = oma_tlv_get(&tlv_resource_instance, &msg->in, true))) {
|
|
|
|
if (tlv_resource_instance.type != OMA_TLV_TYPE_RESOURCE_INSTANCE) {
|
|
|
|
LOG_ERR("Multi resource id not supported %u %d", tlv_resource_instance.id,
|
|
|
|
tlv_resource_instance.length);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg->path.res_id = multi_resource_tlv->id;
|
|
|
|
msg->path.res_inst_id = tlv_resource_instance.id;
|
|
|
|
msg->path.level = LWM2M_PATH_LEVEL_RESOURCE_INST;
|
|
|
|
ret = do_write_op_tlv_item(msg);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ignore errors on optional resources when doing
|
|
|
|
* BOOTSTRAP WRITE or CREATE operation.
|
|
|
|
*/
|
|
|
|
if (ret < 0 && !((ret == -ENOTSUP) &&
|
|
|
|
(msg->ctx->bootstrap_mode || msg->operation == LWM2M_OP_CREATE))) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
pos += len2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-29 19:08:00 +02:00
|
|
|
int do_write_op_tlv(struct lwm2m_message *msg)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
|
|
|
struct lwm2m_engine_obj_inst *obj_inst = NULL;
|
2021-12-17 16:43:39 +01:00
|
|
|
int len;
|
2017-07-07 20:04:03 +02:00
|
|
|
struct oma_tlv tlv;
|
2017-10-20 01:27:32 +02:00
|
|
|
int ret;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2021-05-11 14:38:49 +02:00
|
|
|
/* In case of block transfer go directly to the
|
net: lwm2m: Fix opaque data transfer in block mode
When FW update in PUSH mode is used, the firmware is encapsulated in the
TLV as an opaque data, according to the LMWM2M satandard, and then
sliced into blocks and transferred block by block in several
transactions. Therefore, the TLV header is only present in the initial
message.
Current implementation did not handle this case well, reporting errors
on consecutive blocks, therefore making the FW update in PUSH mode
broken.
This commit fixes this issue with following changes:
* The TLV is only assumed to be present in the initial block, while
consecutive blocks will be processed directly into the appropriate
handler,
* 32-bit variables shall be used whenever dealing with the opaque data
length, since the firmware size can easily exceed the 16-bit range,
* Additional information, required for the FW block transfer to work
properly were added to the block context structure,
* The application shall only be notified of the actual data length, and
not the total block size (the total TLV size including header).
Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
2020-06-03 10:48:44 +02:00
|
|
|
* message processing - consecutive blocks will not carry the TLV
|
|
|
|
* header.
|
|
|
|
*/
|
2021-05-11 14:38:49 +02:00
|
|
|
if (msg->in.block_ctx != NULL && msg->in.block_ctx->ctx.current > 0) {
|
2023-04-25 11:55:31 +02:00
|
|
|
msg->path.res_id = msg->in.block_ctx->path.res_id;
|
2021-05-11 14:38:49 +02:00
|
|
|
msg->path.level = 3U;
|
net: lwm2m: Fix opaque data transfer in block mode
When FW update in PUSH mode is used, the firmware is encapsulated in the
TLV as an opaque data, according to the LMWM2M satandard, and then
sliced into blocks and transferred block by block in several
transactions. Therefore, the TLV header is only present in the initial
message.
Current implementation did not handle this case well, reporting errors
on consecutive blocks, therefore making the FW update in PUSH mode
broken.
This commit fixes this issue with following changes:
* The TLV is only assumed to be present in the initial block, while
consecutive blocks will be processed directly into the appropriate
handler,
* 32-bit variables shall be used whenever dealing with the opaque data
length, since the firmware size can easily exceed the 16-bit range,
* Additional information, required for the FW block transfer to work
properly were added to the block context structure,
* The application shall only be notified of the actual data length, and
not the total block size (the total TLV size including header).
Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
2020-06-03 10:48:44 +02:00
|
|
|
ret = do_write_op_tlv_item(msg);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2021-05-11 14:38:49 +02:00
|
|
|
|
|
|
|
return 0;
|
net: lwm2m: Fix opaque data transfer in block mode
When FW update in PUSH mode is used, the firmware is encapsulated in the
TLV as an opaque data, according to the LMWM2M satandard, and then
sliced into blocks and transferred block by block in several
transactions. Therefore, the TLV header is only present in the initial
message.
Current implementation did not handle this case well, reporting errors
on consecutive blocks, therefore making the FW update in PUSH mode
broken.
This commit fixes this issue with following changes:
* The TLV is only assumed to be present in the initial block, while
consecutive blocks will be processed directly into the appropriate
handler,
* 32-bit variables shall be used whenever dealing with the opaque data
length, since the firmware size can easily exceed the 16-bit range,
* Additional information, required for the FW block transfer to work
properly were added to the block context structure,
* The application shall only be notified of the actual data length, and
not the total block size (the total TLV size including header).
Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
2020-06-03 10:48:44 +02:00
|
|
|
}
|
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
while (true) {
|
|
|
|
/*
|
|
|
|
* This initial read of TLV data won't advance frag/offset.
|
|
|
|
* We need tlv.type to determine how to proceed.
|
|
|
|
*/
|
2019-01-24 23:40:23 +01:00
|
|
|
len = oma_tlv_get(&tlv, &msg->in, true);
|
2021-12-17 16:43:39 +01:00
|
|
|
if (len < 0) {
|
2017-10-20 01:27:32 +02:00
|
|
|
break;
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
|
|
|
|
if (tlv.type == OMA_TLV_TYPE_OBJECT_INSTANCE) {
|
|
|
|
struct oma_tlv tlv2;
|
|
|
|
int len2;
|
|
|
|
int pos = 0;
|
|
|
|
|
2019-01-24 23:40:23 +01:00
|
|
|
oma_tlv_get(&tlv, &msg->in, false);
|
|
|
|
msg->path.obj_inst_id = tlv.id;
|
2019-03-27 02:57:45 +01:00
|
|
|
if (tlv.length == 0U) {
|
2017-07-07 20:04:03 +02:00
|
|
|
/* Create only - no data */
|
2019-01-24 23:40:23 +01:00
|
|
|
ret = lwm2m_create_obj_inst(
|
|
|
|
msg->path.obj_id,
|
|
|
|
msg->path.obj_inst_id,
|
|
|
|
&obj_inst);
|
2017-07-07 20:04:03 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2019-01-26 07:36:47 +01:00
|
|
|
|
|
|
|
if (!msg->ctx->bootstrap_mode) {
|
2020-10-28 16:15:27 +01:00
|
|
|
engine_trigger_update(true);
|
2019-01-26 07:36:47 +01:00
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
while (pos < tlv.length &&
|
2019-01-24 23:40:23 +01:00
|
|
|
(len2 = oma_tlv_get(&tlv2, &msg->in, true))) {
|
2022-02-08 08:17:57 +01:00
|
|
|
if (tlv2.type == OMA_TLV_TYPE_RESOURCE) {
|
|
|
|
ret = write_tlv_resource(msg, &tlv2);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
} else if (tlv2.type == OMA_TLV_TYPE_MULTI_RESOURCE) {
|
|
|
|
oma_tlv_get(&tlv2, &msg->in, false);
|
|
|
|
ret = lwm2m_multi_resource_tlv_parse(msg, &tlv2);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Skip Unsupported TLV type */
|
|
|
|
return -ENOTSUP;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pos += len2;
|
|
|
|
}
|
|
|
|
} else if (tlv.type == OMA_TLV_TYPE_RESOURCE) {
|
2022-02-08 08:17:57 +01:00
|
|
|
if (msg->path.level < LWM2M_PATH_LEVEL_OBJECT_INST) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
2021-05-11 14:38:49 +02:00
|
|
|
ret = write_tlv_resource(msg, &tlv);
|
|
|
|
if (ret) {
|
2017-07-07 20:04:03 +02:00
|
|
|
return ret;
|
|
|
|
}
|
2022-02-08 08:17:57 +01:00
|
|
|
} else if (tlv.type == OMA_TLV_TYPE_MULTI_RESOURCE) {
|
|
|
|
if (msg->path.level < LWM2M_PATH_LEVEL_OBJECT_INST) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
oma_tlv_get(&tlv, &msg->in, false);
|
|
|
|
ret = lwm2m_multi_resource_tlv_parse(msg, &tlv);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
2020-07-01 13:52:19 +02:00
|
|
|
} else {
|
|
|
|
return -ENOTSUP;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|