181 lines
3.9 KiB
C
181 lines
3.9 KiB
C
/*
|
|
* Copyright (c) 2022 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/bluetooth/mesh.h>
|
|
|
|
#include "foundation.h"
|
|
#include "msg.h"
|
|
|
|
#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(bt_mesh_sol_pdu_rpl_cli);
|
|
|
|
static struct bt_mesh_sol_pdu_rpl_cli *cli;
|
|
|
|
static int32_t msg_timeout;
|
|
|
|
struct sol_rpl_param {
|
|
uint16_t *start;
|
|
uint8_t *len;
|
|
};
|
|
|
|
static int handle_status(const struct bt_mesh_model *mod,
|
|
struct bt_mesh_msg_ctx *ctx,
|
|
struct net_buf_simple *buf)
|
|
{
|
|
struct sol_rpl_param *param;
|
|
uint16_t primary, range;
|
|
uint8_t len = 0;
|
|
|
|
LOG_DBG("");
|
|
|
|
if (buf->len > 3) {
|
|
return -EMSGSIZE;
|
|
}
|
|
|
|
range = net_buf_simple_pull_le16(buf);
|
|
primary = range >> 1;
|
|
if (primary == 0) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (range & BIT(0)) {
|
|
if (buf->len == 0) {
|
|
return -EMSGSIZE;
|
|
}
|
|
|
|
len = net_buf_simple_pull_u8(buf);
|
|
|
|
if (len < 2) {
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
LOG_DBG("SRPL clear status received: range start: %u, range len: %u",
|
|
primary, len);
|
|
|
|
if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_SOL_PDU_RPL_ITEM_STATUS,
|
|
ctx->addr, (void **)¶m)) {
|
|
if (param->start) {
|
|
*param->start = primary;
|
|
}
|
|
|
|
if (param->len) {
|
|
*param->len = len;
|
|
}
|
|
|
|
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
|
}
|
|
|
|
if (cli->srpl_status) {
|
|
cli->srpl_status(cli, ctx->addr, primary, len);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void sol_pdu_rpl_clear_pdu_create(uint16_t range_start, uint8_t range_len,
|
|
struct net_buf_simple *msg)
|
|
{
|
|
uint16_t range;
|
|
|
|
range = range_start << 1 | (range_len >= 2 ? 1U : 0);
|
|
net_buf_simple_add_le16(msg, range);
|
|
if (range_len >= 2) {
|
|
net_buf_simple_add_u8(msg, range_len);
|
|
}
|
|
}
|
|
|
|
int bt_mesh_sol_pdu_rpl_clear(struct bt_mesh_msg_ctx *ctx, uint16_t range_start,
|
|
uint8_t range_len, uint16_t *start_rsp, uint8_t *len_rsp)
|
|
{
|
|
struct sol_rpl_param param = {
|
|
.start = start_rsp,
|
|
.len = len_rsp,
|
|
};
|
|
|
|
const struct bt_mesh_msg_rsp_ctx rsp = {
|
|
.ack = &cli->ack_ctx,
|
|
.op = OP_SOL_PDU_RPL_ITEM_STATUS,
|
|
.user_data = ¶m,
|
|
.timeout = msg_timeout,
|
|
};
|
|
|
|
if (range_len == 1) {
|
|
LOG_ERR("Invalid range length");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((range_start + (range_len > 1 ? range_len : 0)) > 0x8000 || range_start == 0) {
|
|
LOG_ERR("Range outside unicast address range");
|
|
return -EINVAL;
|
|
}
|
|
|
|
BT_MESH_MODEL_BUF_DEFINE(msg, OP_SOL_PDU_RPL_ITEM_CLEAR,
|
|
range_len >= 2 ? 3 : 2);
|
|
|
|
bt_mesh_model_msg_init(&msg, OP_SOL_PDU_RPL_ITEM_CLEAR);
|
|
|
|
sol_pdu_rpl_clear_pdu_create(range_start, range_len, &msg);
|
|
|
|
return bt_mesh_msg_ackd_send(cli->model, ctx, &msg,
|
|
(start_rsp && len_rsp) ? &rsp : NULL);
|
|
}
|
|
|
|
int bt_mesh_sol_pdu_rpl_clear_unack(struct bt_mesh_msg_ctx *ctx, uint16_t range_start,
|
|
uint8_t range_len)
|
|
{
|
|
if (range_len == 1) {
|
|
LOG_ERR("Invalid range length");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((range_start + (range_len > 1 ? range_len : 0)) > 0x8000 || range_start == 0) {
|
|
LOG_ERR("Range outside unicast address range");
|
|
return -EINVAL;
|
|
}
|
|
|
|
BT_MESH_MODEL_BUF_DEFINE(msg, OP_SOL_PDU_RPL_ITEM_CLEAR,
|
|
range_len >= 2 ? 3 : 2);
|
|
|
|
bt_mesh_model_msg_init(&msg, OP_SOL_PDU_RPL_ITEM_CLEAR_UNACKED);
|
|
|
|
sol_pdu_rpl_clear_pdu_create(range_start, range_len, &msg);
|
|
|
|
return bt_mesh_msg_send(cli->model, ctx, &msg);
|
|
|
|
}
|
|
|
|
const struct bt_mesh_model_op _bt_mesh_sol_pdu_rpl_cli_op[] = {
|
|
{ OP_SOL_PDU_RPL_ITEM_STATUS, BT_MESH_LEN_MIN(2), handle_status },
|
|
|
|
BT_MESH_MODEL_OP_END
|
|
};
|
|
|
|
void bt_mesh_sol_pdu_rpl_cli_timeout_set(int32_t timeout)
|
|
{
|
|
msg_timeout = timeout;
|
|
}
|
|
|
|
static int sol_pdu_rpl_cli_init(const struct bt_mesh_model *mod)
|
|
{
|
|
if (!bt_mesh_model_in_primary(mod)) {
|
|
LOG_ERR("Solicitation PDU RPL Configuration client not in primary element");
|
|
return -EINVAL;
|
|
}
|
|
|
|
msg_timeout = CONFIG_BT_MESH_SOL_PDU_RPL_CLI_TIMEOUT;
|
|
|
|
cli = mod->rt->user_data;
|
|
cli->model = mod;
|
|
bt_mesh_msg_ack_ctx_init(&cli->ack_ctx);
|
|
return 0;
|
|
}
|
|
|
|
const struct bt_mesh_model_cb _bt_mesh_sol_pdu_rpl_cli_cb = {
|
|
.init = sol_pdu_rpl_cli_init,
|
|
};
|