1 /*
2  * Copyright (c) 2020 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <string.h>
7 #include <zephyr/bluetooth/mesh.h>
8 #include <zephyr/bluetooth/conn.h>
9 #include <common/bt_str.h>
10 #include "access.h"
11 #include "prov.h"
12 #include "rpr.h"
13 
14 #define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(bt_mesh_rpr_cli);
17 
18 #define LINK_TIMEOUT_SECONDS_DEFAULT 10
19 
20 BUILD_ASSERT(BT_MESH_MODEL_OP_LEN(RPR_OP_PDU_SEND) == 2, "Assumes PDU send is a 2 byte opcode");
21 
22 #define LINK_CTX(_srv, _send_rel)                                              \
23 	{                                                                      \
24 		.net_idx = (_srv)->net_idx, .app_idx = BT_MESH_KEY_DEV_REMOTE, \
25 		.addr = (_srv)->addr, .send_ttl = (_srv)->ttl,                 \
26 		.send_rel = (_send_rel),                                       \
27 	}
28 
29 enum {
30 	BEARER_LINK_IDLE,
31 	BEARER_LINK_OPENING,
32 	BEARER_LINK_OPENED,
33 };
34 
35 static struct {
36 	int link;
37 	const struct prov_bearer_cb *cb;
38 	struct bt_mesh_rpr_cli *cli;
39 	struct {
40 		prov_bearer_send_complete_t cb;
41 	} tx;
42 } bearer;
43 
44 static int32_t tx_timeout = (2 * MSEC_PER_SEC);
45 
46 static void link_reset(struct bt_mesh_rpr_cli *cli);
47 static void link_closed(struct bt_mesh_rpr_cli *cli,
48 			enum bt_mesh_rpr_status status);
49 
link_report(struct bt_mesh_rpr_cli * cli,struct bt_mesh_rpr_node * srv,struct bt_mesh_rpr_link * link)50 static void link_report(struct bt_mesh_rpr_cli *cli,
51 			struct bt_mesh_rpr_node *srv,
52 			struct bt_mesh_rpr_link *link)
53 {
54 	struct pb_remote_ctx ctx = { cli, srv };
55 
56 	if (link->state == BT_MESH_RPR_LINK_ACTIVE &&
57 	    bearer.link == BEARER_LINK_OPENING) {
58 		bearer.link = BEARER_LINK_OPENED;
59 		LOG_DBG("Opened");
60 		bearer.cb->link_opened(&pb_remote_cli, &ctx);
61 
62 		/* PB-Remote Open Link procedure timeout is configurable, but the provisioning
63 		 * protocol timeout is not. Use default provisioning protocol timeout.
64 		 */
65 		cli->link.time = PROTOCOL_TIMEOUT_SEC;
66 		return;
67 	}
68 
69 	if (link->state == BT_MESH_RPR_LINK_IDLE &&
70 	    bearer.link != BEARER_LINK_IDLE) {
71 		bearer.link = BEARER_LINK_IDLE;
72 
73 		LOG_DBG("Closed (%u)", link->status);
74 		bearer.cb->link_closed(&pb_remote_cli, &ctx,
75 				       ((link->status == BT_MESH_RPR_SUCCESS) ?
76 						PROV_BEARER_LINK_STATUS_SUCCESS :
77 						PROV_BEARER_LINK_STATUS_FAIL));
78 	}
79 }
80 
tx_complete(struct bt_mesh_rpr_cli * cli,int err,void * cb_data)81 static void tx_complete(struct bt_mesh_rpr_cli *cli, int err, void *cb_data)
82 {
83 	LOG_DBG("%d", err);
84 
85 	cli->link.tx_pdu++;
86 	bt_mesh_msg_ack_ctx_clear(&cli->prov_ack_ctx);
87 
88 	if (bearer.tx.cb) {
89 		bearer.tx.cb(err, cb_data);
90 	}
91 }
92 
handle_extended_scan_report(const struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)93 static int handle_extended_scan_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
94 				       struct net_buf_simple *buf)
95 {
96 	struct bt_mesh_rpr_node srv = RPR_NODE(ctx);
97 	struct bt_mesh_rpr_cli *cli = mod->rt->user_data;
98 	struct bt_mesh_rpr_unprov dev = { 0 };
99 	enum bt_mesh_rpr_status status;
100 	bool found_dev = false;
101 
102 	status = net_buf_simple_pull_u8(buf);
103 	if (status != BT_MESH_RPR_SUCCESS) {
104 		LOG_WRN("scan report fail (%u)", status);
105 		return 0;
106 	}
107 
108 	memcpy(dev.uuid, net_buf_simple_pull_mem(buf, 16), 16);
109 	if (buf->len >= 2) {
110 		dev.oob = net_buf_simple_pull_le16(buf);
111 		found_dev = true;
112 		LOG_DBG("0x%04x: %s oob: 0x%04x adv data: %s", srv.addr,
113 		       bt_hex(dev.uuid, 16), dev.oob,
114 		       bt_hex(buf->data, buf->len));
115 	} else {
116 		LOG_DBG("0x%04x: %s not found.", srv.addr, bt_hex(dev.uuid, 16));
117 	}
118 
119 	if (cli->scan_report && found_dev) {
120 		cli->scan_report(cli, &srv, &dev, buf);
121 	}
122 
123 	return 0;
124 }
125 
handle_link_report(const struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)126 static int handle_link_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
127 			      struct net_buf_simple *buf)
128 {
129 	struct bt_mesh_rpr_node srv = RPR_NODE(ctx);
130 	struct bt_mesh_rpr_cli *cli = mod->rt->user_data;
131 	struct bt_mesh_rpr_link link;
132 	uint8_t reason = PROV_BEARER_LINK_STATUS_SUCCESS;
133 
134 	link.status = net_buf_simple_pull_u8(buf);
135 	link.state = net_buf_simple_pull_u8(buf);
136 	if (buf->len == 1) {
137 		reason = net_buf_simple_pull_u8(buf);
138 	} else if (buf->len) {
139 		LOG_WRN("Invalid link report len");
140 		return -EINVAL;
141 	}
142 
143 	if (cli->link.srv.addr != srv.addr) {
144 		LOG_DBG("Link report from unknown server 0x%04x", srv.addr);
145 		return 0;
146 	}
147 
148 	k_work_reschedule(&cli->link.timeout, K_SECONDS(cli->link.time));
149 
150 	cli->link.state = link.state;
151 
152 	LOG_DBG("0x%04x: status: %u state: %u reason: %u", srv.addr, link.status, link.state,
153 		reason);
154 
155 	if (link.state == BT_MESH_RPR_LINK_IDLE) {
156 		link_reset(cli);
157 	}
158 
159 	link_report(cli, &cli->link.srv, &link);
160 
161 	return 0;
162 }
163 
handle_link_status(const struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)164 static int handle_link_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
165 			      struct net_buf_simple *buf)
166 {
167 	struct bt_mesh_rpr_cli *cli = mod->rt->user_data;
168 	struct bt_mesh_rpr_node srv = RPR_NODE(ctx);
169 	struct bt_mesh_rpr_link *rsp;
170 	struct bt_mesh_rpr_link link;
171 
172 	link.status = net_buf_simple_pull_u8(buf);
173 	link.state = net_buf_simple_pull_u8(buf);
174 
175 	LOG_DBG("0x%04x: status: %u state: %u", srv.addr, link.status,
176 	       link.state);
177 
178 	if (bt_mesh_msg_ack_ctx_match(&cli->prov_ack_ctx, RPR_OP_LINK_STATUS,
179 				      srv.addr, (void **)&rsp)) {
180 		*rsp = link;
181 		bt_mesh_msg_ack_ctx_rx(&cli->prov_ack_ctx);
182 	}
183 
184 	if (cli->link.srv.addr == srv.addr) {
185 		k_work_reschedule(&cli->link.timeout, K_SECONDS(cli->link.time));
186 
187 		cli->link.state = link.state;
188 		if (link.state == BT_MESH_RPR_LINK_IDLE) {
189 			cli->link.srv.addr = BT_MESH_ADDR_UNASSIGNED;
190 		}
191 
192 		link_report(cli, &cli->link.srv, &link);
193 	}
194 
195 	return 0;
196 }
197 
handle_pdu_outbound_report(const struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)198 static int handle_pdu_outbound_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
199 				      struct net_buf_simple *buf)
200 {
201 	struct bt_mesh_rpr_cli *cli = mod->rt->user_data;
202 	struct bt_mesh_rpr_node srv = RPR_NODE(ctx);
203 	void *cb_data;
204 	uint8_t num;
205 
206 	if (srv.addr != cli->link.srv.addr) {
207 		LOG_WRN("Outbound report from unknown server 0x%04x", srv.addr);
208 		return 0;
209 	}
210 
211 	num = net_buf_simple_pull_u8(buf);
212 
213 	LOG_DBG("0x%04x: %u", srv.addr, num);
214 
215 	k_work_reschedule(&cli->link.timeout, K_SECONDS(cli->link.time));
216 
217 	if (!bt_mesh_msg_ack_ctx_match(&cli->prov_ack_ctx, RPR_OP_PDU_OUTBOUND_REPORT,
218 				       srv.addr, &cb_data) ||
219 	    num != cli->link.tx_pdu) {
220 		LOG_WRN("Non-matching PDU report (%u)", num);
221 		return 0;
222 	}
223 
224 	tx_complete(cli, 0, cb_data);
225 
226 	return 0;
227 }
228 
handle_pdu_report(const struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)229 static int handle_pdu_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
230 			     struct net_buf_simple *buf)
231 {
232 	struct bt_mesh_rpr_cli *cli = mod->rt->user_data;
233 	struct bt_mesh_rpr_node srv = RPR_NODE(ctx);
234 	struct pb_remote_ctx cb_ctx = {
235 		cli,
236 		&cli->link.srv,
237 	};
238 	uint8_t pdu;
239 
240 	if (cli->link.srv.addr != srv.addr) {
241 		LOG_WRN("PDU report from unknown server 0x%04x", srv.addr);
242 		return 0;
243 	}
244 
245 	k_work_reschedule(&cli->link.timeout, K_SECONDS(cli->link.time));
246 
247 	pdu = net_buf_simple_pull_u8(buf);
248 	if (pdu <= cli->link.rx_pdu) {
249 		LOG_WRN("Duplicate rx %u", pdu);
250 		return 0;
251 	}
252 
253 	LOG_DBG("0x%04x: %u (%u bytes)", srv.addr, pdu, buf->len);
254 
255 	bearer.cb->recv(&pb_remote_cli, &cb_ctx, buf);
256 
257 	return 0;
258 }
259 
handle_scan_caps_status(const struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)260 static int handle_scan_caps_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
261 				   struct net_buf_simple *buf)
262 {
263 	struct bt_mesh_rpr_cli *cli = mod->rt->user_data;
264 	struct bt_mesh_rpr_node srv = RPR_NODE(ctx);
265 	struct bt_mesh_rpr_caps *caps;
266 
267 	if (!bt_mesh_msg_ack_ctx_match(&cli->scan_ack_ctx, RPR_OP_SCAN_CAPS_STATUS,
268 				       srv.addr, (void **)&caps)) {
269 		LOG_WRN("Unexpected scan caps rsp from 0x%04x", srv.addr);
270 		return 0;
271 	}
272 
273 	caps->max_devs = net_buf_simple_pull_u8(buf);
274 	caps->active_scan = net_buf_simple_pull_u8(buf);
275 
276 	LOG_DBG("max devs: %u active scan: %u", caps->max_devs,
277 	       caps->active_scan);
278 
279 	bt_mesh_msg_ack_ctx_rx(&cli->scan_ack_ctx);
280 
281 	return 0;
282 }
283 
handle_scan_report(const struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)284 static int handle_scan_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
285 			      struct net_buf_simple *buf)
286 {
287 	struct bt_mesh_rpr_cli *cli = mod->rt->user_data;
288 	struct bt_mesh_rpr_node srv = RPR_NODE(ctx);
289 	struct bt_mesh_rpr_unprov dev = { 0 };
290 
291 	dev.rssi = net_buf_simple_pull_u8(buf);
292 	memcpy(dev.uuid, net_buf_simple_pull_mem(buf, 16), 16);
293 	dev.oob = net_buf_simple_pull_le16(buf);
294 	if (buf->len == 4) {
295 		memcpy(&dev.hash, net_buf_simple_pull_mem(buf, 4), 4);
296 		dev.flags = BT_MESH_RPR_UNPROV_HASH;
297 	} else if (buf->len) {
298 		return -EINVAL;
299 	}
300 
301 	if (IS_ENABLED(CONFIG_BT_MESH_MODEL_LOG_LEVEL_DBG)) {
302 		struct bt_uuid_128 uuid_repr = { .uuid = { BT_UUID_TYPE_128 } };
303 
304 		memcpy(uuid_repr.val, dev.uuid, 16);
305 		LOG_DBG("0x%04x: %s oob: 0x%04x %ddBm", srv.addr,
306 		       bt_uuid_str(&uuid_repr.uuid), dev.oob, dev.rssi);
307 	}
308 
309 	if (cli->scan_report) {
310 		cli->scan_report(cli, &srv, &dev, NULL);
311 	}
312 
313 	return 0;
314 }
315 
handle_scan_status(const struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)316 static int handle_scan_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
317 			      struct net_buf_simple *buf)
318 {
319 	struct bt_mesh_rpr_cli *cli = mod->rt->user_data;
320 	struct bt_mesh_rpr_scan_status *status;
321 	struct bt_mesh_rpr_node srv = RPR_NODE(ctx);
322 
323 	if (!bt_mesh_msg_ack_ctx_match(&cli->scan_ack_ctx, RPR_OP_SCAN_STATUS,
324 				       srv.addr, (void **)&status)) {
325 		LOG_WRN("Unexpected scan status from 0x%04x", srv.addr);
326 		return 0;
327 	}
328 
329 	status->status = net_buf_simple_pull_u8(buf);
330 	status->scan = net_buf_simple_pull_u8(buf);
331 	status->max_devs = net_buf_simple_pull_u8(buf);
332 	status->timeout = net_buf_simple_pull_u8(buf);
333 
334 	LOG_DBG("status: %u state: %u max devs: %u timeout: %u seconds",
335 	       status->status, status->scan, status->max_devs, status->timeout);
336 	bt_mesh_msg_ack_ctx_rx(&cli->scan_ack_ctx);
337 
338 	return 0;
339 }
340 
341 const struct bt_mesh_model_op _bt_mesh_rpr_cli_op[] = {
342 	{ RPR_OP_EXTENDED_SCAN_REPORT, BT_MESH_LEN_MIN(17), handle_extended_scan_report },
343 	{ RPR_OP_LINK_REPORT, BT_MESH_LEN_MIN(2), handle_link_report },
344 	{ RPR_OP_LINK_STATUS, BT_MESH_LEN_EXACT(2), handle_link_status },
345 	{ RPR_OP_PDU_OUTBOUND_REPORT, BT_MESH_LEN_EXACT(1), handle_pdu_outbound_report },
346 	{ RPR_OP_PDU_REPORT, BT_MESH_LEN_MIN(2), handle_pdu_report },
347 	{ RPR_OP_SCAN_CAPS_STATUS, BT_MESH_LEN_EXACT(2), handle_scan_caps_status },
348 	{ RPR_OP_SCAN_REPORT, BT_MESH_LEN_MIN(19), handle_scan_report },
349 	{ RPR_OP_SCAN_STATUS, BT_MESH_LEN_EXACT(4), handle_scan_status },
350 	BT_MESH_MODEL_OP_END,
351 };
352 
link_timeout(struct k_work * work)353 static void link_timeout(struct k_work *work)
354 {
355 	struct bt_mesh_rpr_cli *cli = CONTAINER_OF(k_work_delayable_from_work(work),
356 						   struct bt_mesh_rpr_cli, link.timeout);
357 
358 	if (bearer.link != BEARER_LINK_IDLE) {
359 		LOG_DBG("");
360 		link_closed(cli, BT_MESH_RPR_ERR_LINK_CLOSED_BY_CLIENT);
361 	}
362 }
363 
rpr_cli_init(const struct bt_mesh_model * mod)364 static int rpr_cli_init(const struct bt_mesh_model *mod)
365 {
366 	if (mod->rt->elem_idx) {
367 		LOG_ERR("Remote provisioning client must be initialized "
368 			"on first element");
369 		return -EINVAL;
370 	}
371 
372 	struct bt_mesh_rpr_cli *cli = mod->rt->user_data;
373 
374 	cli->mod = mod;
375 	cli->link.time = LINK_TIMEOUT_SECONDS_DEFAULT;
376 
377 	bt_mesh_msg_ack_ctx_init(&cli->scan_ack_ctx);
378 	bt_mesh_msg_ack_ctx_init(&cli->prov_ack_ctx);
379 	k_work_init_delayable(&cli->link.timeout, link_timeout);
380 	mod->keys[0] = BT_MESH_KEY_DEV_ANY;
381 	mod->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY;
382 
383 	return 0;
384 }
385 
386 const struct bt_mesh_model_cb _bt_mesh_rpr_cli_cb = {
387 	.init = rpr_cli_init,
388 };
389 
pdu_send_start(uint16_t duration,int err,void * cb_data)390 static void pdu_send_start(uint16_t duration, int err, void *cb_data)
391 {
392 	struct bt_mesh_rpr_cli *cli = cb_data;
393 
394 	if (err) {
395 		LOG_ERR("PDU Send failed: %d", err);
396 
397 		link_closed(cli,
398 			    BT_MESH_RPR_ERR_LINK_CLOSED_AS_CANNOT_SEND_PDU);
399 	}
400 }
401 
pdu_send_end(int err,void * cb_data)402 static void pdu_send_end(int err, void *cb_data)
403 {
404 	struct bt_mesh_rpr_cli *cli = cb_data;
405 
406 	if (err) {
407 		LOG_ERR("PDU Send failed: %d", err);
408 
409 		link_closed(cli,
410 			    BT_MESH_RPR_ERR_LINK_CLOSED_AS_CANNOT_SEND_PDU);
411 		return;
412 	}
413 
414 	k_work_reschedule(&cli->link.timeout, K_SECONDS(cli->link.time));
415 }
416 
417 static const struct bt_mesh_send_cb pdu_send_cb = {
418 	.start = pdu_send_start,
419 	.end = pdu_send_end,
420 };
421 
tx_wait(struct bt_mesh_rpr_cli * cli,struct bt_mesh_msg_ack_ctx * ack_ctx,const struct bt_mesh_rpr_node * srv,struct net_buf_simple * buf,uint32_t rsp,void * rsp_ctx)422 static int tx_wait(struct bt_mesh_rpr_cli *cli,
423 		   struct bt_mesh_msg_ack_ctx *ack_ctx, const struct bt_mesh_rpr_node *srv,
424 		   struct net_buf_simple *buf, uint32_t rsp, void *rsp_ctx)
425 {
426 	struct bt_mesh_msg_ctx ctx = LINK_CTX(srv, false);
427 	int err;
428 
429 	err = bt_mesh_msg_ack_ctx_prepare(ack_ctx, rsp, srv->addr, rsp_ctx);
430 	if (err) {
431 		return err;
432 	}
433 
434 	err = bt_mesh_model_send(cli->mod, &ctx, buf, NULL, NULL);
435 	if (err) {
436 		bt_mesh_msg_ack_ctx_clear(ack_ctx);
437 		LOG_WRN("TX fail");
438 		return err;
439 	}
440 
441 	err = bt_mesh_msg_ack_ctx_wait(ack_ctx, K_MSEC(tx_timeout));
442 
443 	bt_mesh_msg_ack_ctx_clear(ack_ctx);
444 	return err;
445 }
446 
link_init(struct bt_mesh_rpr_cli * cli,const struct bt_mesh_rpr_node * srv)447 static void link_init(struct bt_mesh_rpr_cli *cli,
448 		      const struct bt_mesh_rpr_node *srv)
449 {
450 	cli->link.srv = *srv;
451 	cli->link.state = BT_MESH_RPR_LINK_IDLE;
452 	cli->link.rx_pdu = 0;
453 	cli->link.tx_pdu = 1;
454 	k_work_reschedule(&cli->link.timeout, K_SECONDS(cli->link.time));
455 }
456 
link_reset(struct bt_mesh_rpr_cli * cli)457 static void link_reset(struct bt_mesh_rpr_cli *cli)
458 {
459 	k_work_cancel_delayable(&cli->link.timeout);
460 	cli->link.srv.addr = BT_MESH_ADDR_UNASSIGNED;
461 	cli->link.state = BT_MESH_RPR_LINK_IDLE;
462 	bt_mesh_msg_ack_ctx_clear(&cli->prov_ack_ctx);
463 }
464 
link_closed(struct bt_mesh_rpr_cli * cli,enum bt_mesh_rpr_status status)465 static void link_closed(struct bt_mesh_rpr_cli *cli,
466 			enum bt_mesh_rpr_status status)
467 {
468 	struct bt_mesh_rpr_node srv = cli->link.srv;
469 	struct bt_mesh_rpr_link link = {
470 		.status = status,
471 		.state = BT_MESH_RPR_LINK_IDLE,
472 	};
473 
474 	LOG_DBG("0x%04x: status: %u state: %u rx: %u tx: %u", srv.addr, link.status,
475 		cli->link.state, cli->link.rx_pdu, cli->link.tx_pdu);
476 
477 	link_reset(cli);
478 
479 	link_report(cli, &srv, &link);
480 }
481 
bt_mesh_rpr_scan_caps_get(struct bt_mesh_rpr_cli * cli,const struct bt_mesh_rpr_node * srv,struct bt_mesh_rpr_caps * caps)482 int bt_mesh_rpr_scan_caps_get(struct bt_mesh_rpr_cli *cli,
483 			      const struct bt_mesh_rpr_node *srv,
484 			      struct bt_mesh_rpr_caps *caps)
485 {
486 	BT_MESH_MODEL_BUF_DEFINE(buf, RPR_OP_SCAN_CAPS_GET, 0);
487 	bt_mesh_model_msg_init(&buf, RPR_OP_SCAN_CAPS_GET);
488 
489 	return tx_wait(cli, &cli->scan_ack_ctx, srv, &buf, RPR_OP_SCAN_CAPS_STATUS, caps);
490 }
491 
bt_mesh_rpr_scan_get(struct bt_mesh_rpr_cli * cli,const struct bt_mesh_rpr_node * srv,struct bt_mesh_rpr_scan_status * status)492 int bt_mesh_rpr_scan_get(struct bt_mesh_rpr_cli *cli,
493 			 const struct bt_mesh_rpr_node *srv,
494 			 struct bt_mesh_rpr_scan_status *status)
495 {
496 	BT_MESH_MODEL_BUF_DEFINE(buf, RPR_OP_SCAN_GET, 0);
497 	bt_mesh_model_msg_init(&buf, RPR_OP_SCAN_GET);
498 
499 	return tx_wait(cli, &cli->scan_ack_ctx, srv, &buf, RPR_OP_SCAN_STATUS, status);
500 }
501 
bt_mesh_rpr_scan_start(struct bt_mesh_rpr_cli * cli,const struct bt_mesh_rpr_node * srv,const uint8_t uuid[16],uint8_t timeout,uint8_t max_devs,struct bt_mesh_rpr_scan_status * status)502 int bt_mesh_rpr_scan_start(struct bt_mesh_rpr_cli *cli,
503 			   const struct bt_mesh_rpr_node *srv,
504 			   const uint8_t uuid[16], uint8_t timeout,
505 			   uint8_t max_devs,
506 			   struct bt_mesh_rpr_scan_status *status)
507 {
508 	if (!timeout) {
509 		return -EINVAL;
510 	}
511 
512 	BT_MESH_MODEL_BUF_DEFINE(buf, RPR_OP_SCAN_START, 18);
513 	bt_mesh_model_msg_init(&buf, RPR_OP_SCAN_START);
514 
515 	net_buf_simple_add_u8(&buf, max_devs);
516 	net_buf_simple_add_u8(&buf, timeout);
517 
518 	if (uuid) {
519 		net_buf_simple_add_mem(&buf, uuid, 16);
520 	}
521 
522 	return tx_wait(cli, &cli->scan_ack_ctx, srv, &buf, RPR_OP_SCAN_STATUS, status);
523 }
524 
bt_mesh_rpr_scan_start_ext(struct bt_mesh_rpr_cli * cli,const struct bt_mesh_rpr_node * srv,const uint8_t uuid[16],uint8_t timeout,const uint8_t * ad_types,size_t ad_count)525 int bt_mesh_rpr_scan_start_ext(struct bt_mesh_rpr_cli *cli,
526 			       const struct bt_mesh_rpr_node *srv,
527 			       const uint8_t uuid[16], uint8_t timeout,
528 			       const uint8_t *ad_types, size_t ad_count)
529 {
530 	struct bt_mesh_msg_ctx ctx = LINK_CTX(srv, false);
531 
532 	if ((uuid && (timeout < BT_MESH_RPR_EXT_SCAN_TIME_MIN ||
533 		      timeout > BT_MESH_RPR_EXT_SCAN_TIME_MAX)) ||
534 	    !ad_count || ad_count > CONFIG_BT_MESH_RPR_AD_TYPES_MAX) {
535 		return -EINVAL;
536 	}
537 
538 	BT_MESH_MODEL_BUF_DEFINE(buf, RPR_OP_EXTENDED_SCAN_START,
539 				 18 + CONFIG_BT_MESH_RPR_AD_TYPES_MAX);
540 	bt_mesh_model_msg_init(&buf, RPR_OP_EXTENDED_SCAN_START);
541 
542 	net_buf_simple_add_u8(&buf, ad_count);
543 	net_buf_simple_add_mem(&buf, ad_types, ad_count);
544 	if (uuid) {
545 		net_buf_simple_add_mem(&buf, uuid, 16);
546 		net_buf_simple_add_u8(&buf, timeout);
547 	}
548 
549 	return bt_mesh_model_send(cli->mod, &ctx, &buf, NULL, NULL);
550 }
551 
bt_mesh_rpr_scan_stop(struct bt_mesh_rpr_cli * cli,const struct bt_mesh_rpr_node * srv,struct bt_mesh_rpr_scan_status * status)552 int bt_mesh_rpr_scan_stop(struct bt_mesh_rpr_cli *cli,
553 			  const struct bt_mesh_rpr_node *srv,
554 			  struct bt_mesh_rpr_scan_status *status)
555 {
556 	BT_MESH_MODEL_BUF_DEFINE(buf, RPR_OP_SCAN_STOP, 0);
557 	bt_mesh_model_msg_init(&buf, RPR_OP_SCAN_STOP);
558 
559 	return tx_wait(cli, &cli->scan_ack_ctx, srv, &buf, RPR_OP_SCAN_STATUS, status);
560 }
561 
bt_mesh_rpr_link_get(struct bt_mesh_rpr_cli * cli,const struct bt_mesh_rpr_node * srv,struct bt_mesh_rpr_link * rsp)562 int bt_mesh_rpr_link_get(struct bt_mesh_rpr_cli *cli,
563 			 const struct bt_mesh_rpr_node *srv,
564 			 struct bt_mesh_rpr_link *rsp)
565 {
566 	BT_MESH_MODEL_BUF_DEFINE(buf, RPR_OP_LINK_GET, 0);
567 	bt_mesh_model_msg_init(&buf, RPR_OP_LINK_GET);
568 
569 	return tx_wait(cli, &cli->prov_ack_ctx, srv, &buf, RPR_OP_LINK_STATUS, rsp);
570 }
571 
bt_mesh_rpr_link_close(struct bt_mesh_rpr_cli * cli,const struct bt_mesh_rpr_node * srv,struct bt_mesh_rpr_link * rsp)572 int bt_mesh_rpr_link_close(struct bt_mesh_rpr_cli *cli,
573 			   const struct bt_mesh_rpr_node *srv,
574 			   struct bt_mesh_rpr_link *rsp)
575 {
576 	BT_MESH_MODEL_BUF_DEFINE(buf, RPR_OP_LINK_CLOSE, 1);
577 	bt_mesh_model_msg_init(&buf, RPR_OP_LINK_CLOSE);
578 	net_buf_simple_add_u8(&buf, PROV_BEARER_LINK_STATUS_FAIL);
579 
580 	return tx_wait(cli, &cli->prov_ack_ctx, srv, &buf, RPR_OP_LINK_STATUS, rsp);
581 }
582 
link_open_prov(struct bt_mesh_rpr_cli * cli,const struct bt_mesh_rpr_node * srv,const uint8_t uuid[16],uint8_t timeout)583 static int link_open_prov(struct bt_mesh_rpr_cli *cli,
584 			  const struct bt_mesh_rpr_node *srv, const uint8_t uuid[16],
585 			  uint8_t timeout)
586 {
587 	struct bt_mesh_msg_ctx ctx = LINK_CTX(srv, false);
588 
589 	BT_MESH_MODEL_BUF_DEFINE(buf, RPR_OP_LINK_OPEN, 17);
590 	bt_mesh_model_msg_init(&buf, RPR_OP_LINK_OPEN);
591 
592 	net_buf_simple_add_mem(&buf, uuid, 16);
593 
594 	if (cli->link.time != LINK_TIMEOUT_SECONDS_DEFAULT) {
595 		net_buf_simple_add_u8(&buf, cli->link.time);
596 	}
597 
598 	return bt_mesh_model_send(cli->mod, &ctx, &buf, NULL, NULL);
599 }
600 
link_open_node(struct bt_mesh_rpr_cli * cli,const struct bt_mesh_rpr_node * srv,enum bt_mesh_rpr_node_refresh type)601 static int link_open_node(struct bt_mesh_rpr_cli *cli,
602 			  const struct bt_mesh_rpr_node *srv,
603 			  enum bt_mesh_rpr_node_refresh type)
604 {
605 	struct bt_mesh_msg_ctx ctx = LINK_CTX(srv, false);
606 
607 	BT_MESH_MODEL_BUF_DEFINE(buf, RPR_OP_LINK_OPEN, 1);
608 	bt_mesh_model_msg_init(&buf, RPR_OP_LINK_OPEN);
609 
610 	net_buf_simple_add_u8(&buf, type);
611 
612 	return bt_mesh_model_send(cli->mod, &ctx, &buf, NULL, NULL);
613 }
614 
link_close(struct bt_mesh_rpr_cli * cli,enum prov_bearer_link_status status)615 static int link_close(struct bt_mesh_rpr_cli *cli,
616 		      enum prov_bearer_link_status status)
617 {
618 	struct bt_mesh_msg_ctx ctx = LINK_CTX(&cli->link.srv, false);
619 	int err;
620 
621 	if (cli->link.srv.addr == BT_MESH_ADDR_UNASSIGNED) {
622 		return -EALREADY;
623 	}
624 
625 	BT_MESH_MODEL_BUF_DEFINE(buf, RPR_OP_LINK_CLOSE, 1);
626 	bt_mesh_model_msg_init(&buf, RPR_OP_LINK_CLOSE);
627 
628 	net_buf_simple_add_u8(&buf, status);
629 
630 	err = bt_mesh_model_send(cli->mod, &ctx, &buf, NULL, NULL);
631 	if (err) {
632 		link_reset(cli);
633 	}
634 
635 	k_work_reschedule(&cli->link.timeout, K_SECONDS(cli->link.time));
636 	return err;
637 }
638 
send(struct bt_mesh_rpr_cli * cli,struct net_buf_simple * buf,void * cb_data)639 static int send(struct bt_mesh_rpr_cli *cli, struct net_buf_simple *buf,
640 		void *cb_data)
641 {
642 	struct bt_mesh_msg_ctx ctx = LINK_CTX(&cli->link.srv, true);
643 	int err;
644 
645 	if (cli->link.srv.addr == BT_MESH_ADDR_UNASSIGNED) {
646 		LOG_ERR("No server");
647 		return -ESHUTDOWN;
648 	}
649 
650 	if (net_buf_simple_headroom(buf) < 3) {
651 		LOG_ERR("Invalid buffer");
652 		return -EINVAL;
653 	}
654 
655 	err = bt_mesh_msg_ack_ctx_prepare(&cli->prov_ack_ctx,
656 					  RPR_OP_PDU_OUTBOUND_REPORT,
657 					  cli->link.srv.addr, cb_data);
658 	if (err) {
659 		LOG_ERR("Busy");
660 		return err;
661 	}
662 
663 	LOG_DBG("0x%02x", buf->data[0]);
664 
665 	net_buf_simple_push_u8(buf, cli->link.tx_pdu);
666 	/* Assumes opcode is 2 bytes. Build assert at top of file ensures this.
667 	 */
668 	net_buf_simple_push_be16(buf, RPR_OP_PDU_SEND);
669 
670 	err = bt_mesh_model_send(cli->mod, &ctx, buf, &pdu_send_cb, cli);
671 	if (err) {
672 		link_closed(cli,
673 			    BT_MESH_RPR_ERR_LINK_CLOSED_AS_CANNOT_SEND_PDU);
674 	}
675 
676 	return err;
677 }
678 
bt_mesh_rpr_cli_timeout_get(void)679 int32_t bt_mesh_rpr_cli_timeout_get(void)
680 {
681 	return tx_timeout;
682 }
683 
bt_mesh_rpr_cli_timeout_set(int32_t timeout)684 void bt_mesh_rpr_cli_timeout_set(int32_t timeout)
685 {
686 	tx_timeout = timeout;
687 }
688 
689 /*******************************************************************************
690  * Prov bearer interface
691  ******************************************************************************/
692 
pb_send(struct net_buf_simple * buf,prov_bearer_send_complete_t cb,void * cb_data)693 static int pb_send(struct net_buf_simple *buf, prov_bearer_send_complete_t cb,
694 		   void *cb_data)
695 {
696 	bearer.tx.cb = cb;
697 	return send(bearer.cli, buf, cb_data);
698 }
699 
pb_clear_tx(void)700 static void pb_clear_tx(void)
701 {
702 	/* Nothing can be done */
703 }
704 
pb_link_open(const uint8_t uuid[16],uint8_t timeout,const struct prov_bearer_cb * cb,void * cb_data)705 static int pb_link_open(const uint8_t uuid[16], uint8_t timeout,
706 			const struct prov_bearer_cb *cb, void *cb_data)
707 {
708 	struct pb_remote_ctx *ctx = cb_data;
709 	struct bt_mesh_rpr_cli *cli = ctx->cli;
710 	const struct bt_mesh_rpr_node *srv = ctx->srv;
711 	int err;
712 
713 	if (cli->link.srv.addr != BT_MESH_ADDR_UNASSIGNED) {
714 		return -EBUSY;
715 	}
716 
717 	bearer.cli = ctx->cli;
718 	bearer.cb = cb;
719 
720 	cli->link.time = timeout ? timeout : LINK_TIMEOUT_SECONDS_DEFAULT;
721 
722 	LOG_DBG("timeout: %d", cli->link.time);
723 
724 	link_init(cli, srv);
725 
726 	if (uuid) {
727 		err = link_open_prov(cli, srv, uuid, timeout);
728 	} else {
729 		err = link_open_node(cli, srv, ctx->refresh);
730 	}
731 
732 	if (err) {
733 		link_reset(cli);
734 		return err;
735 	}
736 
737 	bearer.link = BEARER_LINK_OPENING;
738 
739 	return 0;
740 }
741 
pb_link_close(enum prov_bearer_link_status status)742 static void pb_link_close(enum prov_bearer_link_status status)
743 {
744 	int err;
745 
746 	err = link_close(bearer.cli, status);
747 	if (err) {
748 		LOG_ERR("Link close failed (%d)", err);
749 	}
750 }
751 
752 const struct prov_bearer pb_remote_cli = {
753 	.type = BT_MESH_PROV_REMOTE,
754 	.send = pb_send,
755 	.clear_tx = pb_clear_tx,
756 	.link_open = pb_link_open,
757 	.link_close = pb_link_close,
758 };
759