1 /*
2 * Copyright (c) 2022 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/bluetooth/mesh.h>
8
9 #include "foundation.h"
10 #include "msg.h"
11
12 #define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(bt_mesh_sol_pdu_rpl_cli);
15
16 static struct bt_mesh_sol_pdu_rpl_cli *cli;
17
18 static int32_t msg_timeout;
19
20 struct sol_rpl_param {
21 uint16_t *start;
22 uint8_t *len;
23 };
24
handle_status(const struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)25 static int handle_status(const struct bt_mesh_model *mod,
26 struct bt_mesh_msg_ctx *ctx,
27 struct net_buf_simple *buf)
28 {
29 struct sol_rpl_param *param;
30 uint16_t primary, range;
31 uint8_t len = 0;
32
33 LOG_DBG("");
34
35 if (buf->len > 3) {
36 return -EMSGSIZE;
37 }
38
39 range = net_buf_simple_pull_le16(buf);
40 primary = range >> 1;
41 if (primary == 0) {
42 return -EINVAL;
43 }
44
45 if (range & BIT(0)) {
46 if (buf->len == 0) {
47 return -EMSGSIZE;
48 }
49
50 len = net_buf_simple_pull_u8(buf);
51
52 if (len < 2) {
53 return -EINVAL;
54 }
55 }
56
57 LOG_DBG("SRPL clear status received: range start: %u, range len: %u",
58 primary, len);
59
60 if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_SOL_PDU_RPL_ITEM_STATUS,
61 ctx->addr, (void **)¶m)) {
62 if (param->start) {
63 *param->start = primary;
64 }
65
66 if (param->len) {
67 *param->len = len;
68 }
69
70 bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
71 }
72
73 if (cli->srpl_status) {
74 cli->srpl_status(cli, ctx->addr, primary, len);
75 }
76
77 return 0;
78 }
79
sol_pdu_rpl_clear_pdu_create(uint16_t range_start,uint8_t range_len,struct net_buf_simple * msg)80 static void sol_pdu_rpl_clear_pdu_create(uint16_t range_start, uint8_t range_len,
81 struct net_buf_simple *msg)
82 {
83 uint16_t range;
84
85 range = range_start << 1 | (range_len >= 2 ? 1U : 0);
86 net_buf_simple_add_le16(msg, range);
87 if (range_len >= 2) {
88 net_buf_simple_add_u8(msg, range_len);
89 }
90 }
91
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)92 int bt_mesh_sol_pdu_rpl_clear(struct bt_mesh_msg_ctx *ctx, uint16_t range_start,
93 uint8_t range_len, uint16_t *start_rsp, uint8_t *len_rsp)
94 {
95 struct sol_rpl_param param = {
96 .start = start_rsp,
97 .len = len_rsp,
98 };
99
100 const struct bt_mesh_msg_rsp_ctx rsp = {
101 .ack = &cli->ack_ctx,
102 .op = OP_SOL_PDU_RPL_ITEM_STATUS,
103 .user_data = ¶m,
104 .timeout = msg_timeout,
105 };
106
107 if (range_len == 1) {
108 LOG_ERR("Invalid range length");
109 return -EINVAL;
110 }
111
112 if ((range_start + (range_len > 1 ? range_len : 0)) > 0x8000 || range_start == 0) {
113 LOG_ERR("Range outside unicast address range");
114 return -EINVAL;
115 }
116
117 BT_MESH_MODEL_BUF_DEFINE(msg, OP_SOL_PDU_RPL_ITEM_CLEAR,
118 range_len >= 2 ? 3 : 2);
119
120 bt_mesh_model_msg_init(&msg, OP_SOL_PDU_RPL_ITEM_CLEAR);
121
122 sol_pdu_rpl_clear_pdu_create(range_start, range_len, &msg);
123
124 return bt_mesh_msg_ackd_send(cli->model, ctx, &msg,
125 (start_rsp && len_rsp) ? &rsp : NULL);
126 }
127
bt_mesh_sol_pdu_rpl_clear_unack(struct bt_mesh_msg_ctx * ctx,uint16_t range_start,uint8_t range_len)128 int bt_mesh_sol_pdu_rpl_clear_unack(struct bt_mesh_msg_ctx *ctx, uint16_t range_start,
129 uint8_t range_len)
130 {
131 if (range_len == 1) {
132 LOG_ERR("Invalid range length");
133 return -EINVAL;
134 }
135
136 if ((range_start + (range_len > 1 ? range_len : 0)) > 0x8000 || range_start == 0) {
137 LOG_ERR("Range outside unicast address range");
138 return -EINVAL;
139 }
140
141 BT_MESH_MODEL_BUF_DEFINE(msg, OP_SOL_PDU_RPL_ITEM_CLEAR,
142 range_len >= 2 ? 3 : 2);
143
144 bt_mesh_model_msg_init(&msg, OP_SOL_PDU_RPL_ITEM_CLEAR_UNACKED);
145
146 sol_pdu_rpl_clear_pdu_create(range_start, range_len, &msg);
147
148 return bt_mesh_msg_send(cli->model, ctx, &msg);
149
150 }
151
152 const struct bt_mesh_model_op _bt_mesh_sol_pdu_rpl_cli_op[] = {
153 { OP_SOL_PDU_RPL_ITEM_STATUS, BT_MESH_LEN_MIN(2), handle_status },
154
155 BT_MESH_MODEL_OP_END
156 };
157
bt_mesh_sol_pdu_rpl_cli_timeout_set(int32_t timeout)158 void bt_mesh_sol_pdu_rpl_cli_timeout_set(int32_t timeout)
159 {
160 msg_timeout = timeout;
161 }
162
sol_pdu_rpl_cli_init(const struct bt_mesh_model * mod)163 static int sol_pdu_rpl_cli_init(const struct bt_mesh_model *mod)
164 {
165 if (!bt_mesh_model_in_primary(mod)) {
166 LOG_ERR("Solicitation PDU RPL Configuration client not in primary element");
167 return -EINVAL;
168 }
169
170 msg_timeout = CONFIG_BT_MESH_SOL_PDU_RPL_CLI_TIMEOUT;
171
172 cli = mod->rt->user_data;
173 cli->model = mod;
174 bt_mesh_msg_ack_ctx_init(&cli->ack_ctx);
175 return 0;
176 }
177
178 const struct bt_mesh_model_cb _bt_mesh_sol_pdu_rpl_cli_cb = {
179 .init = sol_pdu_rpl_cli_init,
180 };
181