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