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