1 /*
2 * Copyright (c) 2020 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/bluetooth/mesh.h>
8 #include "net.h"
9 #include "foundation.h"
10 #include "access.h"
11 #include "msg.h"
12
13 #define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(bt_mesh_priv_beacon_cli);
16
17 static struct bt_mesh_priv_beacon_cli *cli;
18
19 static int32_t msg_timeout;
20
handle_beacon_status(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)21 static int handle_beacon_status(const struct bt_mesh_model *model,
22 struct bt_mesh_msg_ctx *ctx,
23 struct net_buf_simple *buf)
24 {
25 struct bt_mesh_priv_beacon *rsp;
26 uint8_t beacon, rand_int;
27
28 beacon = net_buf_simple_pull_u8(buf);
29 rand_int = net_buf_simple_pull_u8(buf);
30
31 if (beacon != BT_MESH_BEACON_DISABLED &&
32 beacon != BT_MESH_BEACON_ENABLED) {
33 LOG_WRN("Invalid beacon value 0x%02x", beacon);
34 return -EINVAL;
35 }
36
37 LOG_DBG("0x%02x (%u s)", beacon, 10U * rand_int);
38
39 if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_PRIV_BEACON_STATUS, ctx->addr,
40 (void **)&rsp)) {
41 rsp->enabled = beacon;
42 rsp->rand_interval = rand_int;
43
44 bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
45 }
46
47 if (cli->cb && cli->cb->priv_beacon_status) {
48 struct bt_mesh_priv_beacon state = {
49 .enabled = beacon,
50 .rand_interval = rand_int,
51 };
52
53 cli->cb->priv_beacon_status(cli, ctx->addr, &state);
54 }
55
56 return 0;
57 }
58
handle_gatt_proxy_status(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)59 static int handle_gatt_proxy_status(const struct bt_mesh_model *model,
60 struct bt_mesh_msg_ctx *ctx,
61 struct net_buf_simple *buf)
62 {
63 uint8_t *rsp;
64 uint8_t proxy;
65
66 proxy = net_buf_simple_pull_u8(buf);
67
68 if (proxy != BT_MESH_GATT_PROXY_DISABLED &&
69 proxy != BT_MESH_GATT_PROXY_ENABLED &&
70 proxy != BT_MESH_GATT_PROXY_NOT_SUPPORTED) {
71 LOG_WRN("Invalid GATT proxy value 0x%02x", proxy);
72 return -EINVAL;
73 }
74
75 if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_PRIV_GATT_PROXY_STATUS, ctx->addr,
76 (void **)&rsp)) {
77 *rsp = proxy;
78
79 bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
80 }
81
82 if (cli->cb && cli->cb->priv_gatt_proxy_status) {
83 cli->cb->priv_gatt_proxy_status(cli, ctx->addr, proxy);
84 }
85
86 return 0;
87 }
88
handle_node_id_status(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)89 static int handle_node_id_status(const struct bt_mesh_model *model,
90 struct bt_mesh_msg_ctx *ctx,
91 struct net_buf_simple *buf)
92 {
93 struct bt_mesh_priv_node_id *rsp;
94 uint8_t status, node_id;
95 uint16_t net_idx;
96
97 status = net_buf_simple_pull_u8(buf);
98 net_idx = net_buf_simple_pull_le16(buf);
99 node_id = net_buf_simple_pull_u8(buf);
100
101 if (node_id != BT_MESH_NODE_IDENTITY_STOPPED &&
102 node_id != BT_MESH_NODE_IDENTITY_RUNNING &&
103 node_id != BT_MESH_NODE_IDENTITY_NOT_SUPPORTED) {
104 LOG_WRN("Invalid node ID value 0x%02x", node_id);
105 return -EINVAL;
106 }
107
108 if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_PRIV_NODE_ID_STATUS, ctx->addr,
109 (void **)&rsp)) {
110 rsp->net_idx = net_idx;
111 rsp->status = status;
112 rsp->state = node_id;
113
114 bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
115 }
116
117 if (cli->cb && cli->cb->priv_node_id_status) {
118 struct bt_mesh_priv_node_id state = {
119 .net_idx = net_idx,
120 .status = status,
121 .state = node_id,
122 };
123
124 cli->cb->priv_node_id_status(cli, ctx->addr, &state);
125 }
126
127 return 0;
128 }
129
130 const struct bt_mesh_model_op bt_mesh_priv_beacon_cli_op[] = {
131 { OP_PRIV_BEACON_STATUS, BT_MESH_LEN_EXACT(2), handle_beacon_status },
132 { OP_PRIV_GATT_PROXY_STATUS, BT_MESH_LEN_EXACT(1), handle_gatt_proxy_status },
133 { OP_PRIV_NODE_ID_STATUS, BT_MESH_LEN_EXACT(4), handle_node_id_status },
134 BT_MESH_MODEL_OP_END,
135 };
136
priv_beacon_cli_init(const struct bt_mesh_model * model)137 static int priv_beacon_cli_init(const struct bt_mesh_model *model)
138 {
139 if (!bt_mesh_model_in_primary(model)) {
140 LOG_ERR("Private Beacon Client only allowed in primary element");
141 return -EINVAL;
142 }
143
144 cli = model->rt->user_data;
145 cli->model = model;
146 msg_timeout = 2 * MSEC_PER_SEC;
147 model->keys[0] = BT_MESH_KEY_DEV_ANY;
148 model->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY;
149
150 bt_mesh_msg_ack_ctx_init(&cli->ack_ctx);
151
152 return 0;
153 }
154
155 const struct bt_mesh_model_cb bt_mesh_priv_beacon_cli_cb = {
156 .init = priv_beacon_cli_init,
157 };
158
bt_mesh_priv_beacon_cli_set(uint16_t net_idx,uint16_t addr,struct bt_mesh_priv_beacon * val,struct bt_mesh_priv_beacon * rsp)159 int bt_mesh_priv_beacon_cli_set(uint16_t net_idx, uint16_t addr, struct bt_mesh_priv_beacon *val,
160 struct bt_mesh_priv_beacon *rsp)
161 {
162 struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr);
163 const struct bt_mesh_msg_rsp_ctx rsp_ctx = {
164 .ack = &cli->ack_ctx,
165 .op = OP_PRIV_BEACON_STATUS,
166 .user_data = rsp,
167 .timeout = msg_timeout,
168 };
169
170 BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_BEACON_SET, 2);
171 bt_mesh_model_msg_init(&buf, OP_PRIV_BEACON_SET);
172
173 net_buf_simple_add_u8(&buf, val->enabled);
174 if (val->rand_interval) {
175 net_buf_simple_add_u8(&buf, val->rand_interval);
176 }
177
178 return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, rsp ? &rsp_ctx : NULL);
179 }
180
bt_mesh_priv_beacon_cli_get(uint16_t net_idx,uint16_t addr,struct bt_mesh_priv_beacon * val)181 int bt_mesh_priv_beacon_cli_get(uint16_t net_idx, uint16_t addr, struct bt_mesh_priv_beacon *val)
182 {
183 struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr);
184 const struct bt_mesh_msg_rsp_ctx rsp_ctx = {
185 .ack = &cli->ack_ctx,
186 .op = OP_PRIV_BEACON_STATUS,
187 .user_data = val,
188 .timeout = msg_timeout,
189 };
190
191 BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_BEACON_GET, 0);
192 bt_mesh_model_msg_init(&buf, OP_PRIV_BEACON_GET);
193
194 return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, val ? &rsp_ctx : NULL);
195 }
196
bt_mesh_priv_beacon_cli_gatt_proxy_set(uint16_t net_idx,uint16_t addr,uint8_t val,uint8_t * rsp)197 int bt_mesh_priv_beacon_cli_gatt_proxy_set(uint16_t net_idx, uint16_t addr, uint8_t val,
198 uint8_t *rsp)
199 {
200 struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr);
201 const struct bt_mesh_msg_rsp_ctx rsp_ctx = {
202 .ack = &cli->ack_ctx,
203 .op = OP_PRIV_GATT_PROXY_STATUS,
204 .user_data = rsp,
205 .timeout = msg_timeout,
206 };
207
208 if ((val != BT_MESH_GATT_PROXY_DISABLED &&
209 val != BT_MESH_GATT_PROXY_ENABLED)) {
210 return -EINVAL;
211 }
212
213 BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_GATT_PROXY_SET, 1);
214 bt_mesh_model_msg_init(&buf, OP_PRIV_GATT_PROXY_SET);
215
216 net_buf_simple_add_u8(&buf, val);
217
218 return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, rsp ? &rsp_ctx : NULL);
219 }
220
bt_mesh_priv_beacon_cli_gatt_proxy_get(uint16_t net_idx,uint16_t addr,uint8_t * val)221 int bt_mesh_priv_beacon_cli_gatt_proxy_get(uint16_t net_idx, uint16_t addr, uint8_t *val)
222 {
223 struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr);
224 const struct bt_mesh_msg_rsp_ctx rsp_ctx = {
225 .ack = &cli->ack_ctx,
226 .op = OP_PRIV_GATT_PROXY_STATUS,
227 .user_data = val,
228 .timeout = msg_timeout,
229 };
230
231 BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_GATT_PROXY_GET, 0);
232 bt_mesh_model_msg_init(&buf, OP_PRIV_GATT_PROXY_GET);
233
234 return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, val ? &rsp_ctx : NULL);
235 }
236
bt_mesh_priv_beacon_cli_node_id_set(uint16_t net_idx,uint16_t addr,struct bt_mesh_priv_node_id * val,struct bt_mesh_priv_node_id * rsp)237 int bt_mesh_priv_beacon_cli_node_id_set(uint16_t net_idx, uint16_t addr,
238 struct bt_mesh_priv_node_id *val,
239 struct bt_mesh_priv_node_id *rsp)
240 {
241 struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr);
242 const struct bt_mesh_msg_rsp_ctx rsp_ctx = {
243 .ack = &cli->ack_ctx,
244 .op = OP_PRIV_NODE_ID_STATUS,
245 .user_data = rsp,
246 .timeout = msg_timeout,
247 };
248
249 if (val->net_idx > 0xfff ||
250 (val->state != BT_MESH_NODE_IDENTITY_STOPPED &&
251 val->state != BT_MESH_NODE_IDENTITY_RUNNING)) {
252 return -EINVAL;
253 }
254
255 BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_NODE_ID_SET, 3);
256 bt_mesh_model_msg_init(&buf, OP_PRIV_NODE_ID_SET);
257
258 net_buf_simple_add_le16(&buf, val->net_idx);
259 net_buf_simple_add_u8(&buf, val->state);
260
261 return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, rsp ? &rsp_ctx : NULL);
262 }
263
bt_mesh_priv_beacon_cli_node_id_get(uint16_t net_idx,uint16_t addr,uint16_t key_net_idx,struct bt_mesh_priv_node_id * val)264 int bt_mesh_priv_beacon_cli_node_id_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx,
265 struct bt_mesh_priv_node_id *val)
266 {
267 struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr);
268 const struct bt_mesh_msg_rsp_ctx rsp_ctx = {
269 .ack = &cli->ack_ctx,
270 .op = OP_PRIV_NODE_ID_STATUS,
271 .user_data = val,
272 .timeout = msg_timeout,
273 };
274
275 BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_NODE_ID_GET, 2);
276 bt_mesh_model_msg_init(&buf, OP_PRIV_NODE_ID_GET);
277
278 net_buf_simple_add_le16(&buf, key_net_idx);
279
280 return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, val ? &rsp_ctx : NULL);
281 }
282