/* * Copyright (c) 2022 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include "foundation.h" #include "msg.h" #define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL #include 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, };