1 /* Bluetooth Mesh */
2
3 /*
4 * Copyright (c) 2017 Intel Corporation
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include "syscfg/syscfg.h"
10 #define MESH_LOG_MODULE BLE_MESH_PROXY_LOG
11
12 #if MYNEWT_VAL(BLE_MESH_PROXY)
13
14 #include "mesh/mesh.h"
15 #include "host/ble_att.h"
16 #include "services/gatt/ble_svc_gatt.h"
17 #include "../../host/src/ble_hs_priv.h"
18
19 #include "mesh_priv.h"
20 #include "adv.h"
21 #include "net.h"
22 #include "prov.h"
23 #include "beacon.h"
24 #include "foundation.h"
25 #include "access.h"
26 #include "proxy.h"
27
28 #define PDU_TYPE(data) (data[0] & BIT_MASK(6))
29 #define PDU_SAR(data) (data[0] >> 6)
30
31 /* Mesh Profile 1.0 Section 6.6:
32 * "The timeout for the SAR transfer is 20 seconds. When the timeout
33 * expires, the Proxy Server shall disconnect."
34 */
35 #define PROXY_SAR_TIMEOUT K_SECONDS(20)
36
37 #define SAR_COMPLETE 0x00
38 #define SAR_FIRST 0x01
39 #define SAR_CONT 0x02
40 #define SAR_LAST 0x03
41
42 #define CFG_FILTER_SET 0x00
43 #define CFG_FILTER_ADD 0x01
44 #define CFG_FILTER_REMOVE 0x02
45 #define CFG_FILTER_STATUS 0x03
46
47 /** @def BT_UUID_MESH_PROV
48 * @brief Mesh Provisioning Service
49 */
50 ble_uuid16_t BT_UUID_MESH_PROV = BLE_UUID16_INIT(0x1827);
51 #define BT_UUID_MESH_PROV_VAL 0x1827
52 /** @def BT_UUID_MESH_PROXY
53 * @brief Mesh Proxy Service
54 */
55 ble_uuid16_t BT_UUID_MESH_PROXY = BLE_UUID16_INIT(0x1828);
56 #define BT_UUID_MESH_PROXY_VAL 0x1828
57 /** @def BT_UUID_GATT_CCC
58 * @brief GATT Client Characteristic Configuration
59 */
60 ble_uuid16_t BT_UUID_GATT_CCC = BLE_UUID16_INIT(0x2902);
61 #define BT_UUID_GATT_CCC_VAL 0x2902
62 /** @def BT_UUID_MESH_PROV_DATA_IN
63 * @brief Mesh Provisioning Data In
64 */
65 ble_uuid16_t BT_UUID_MESH_PROV_DATA_IN = BLE_UUID16_INIT(0x2adb);
66 #define BT_UUID_MESH_PROV_DATA_IN_VAL 0x2adb
67 /** @def BT_UUID_MESH_PROV_DATA_OUT
68 * @brief Mesh Provisioning Data Out
69 */
70 ble_uuid16_t BT_UUID_MESH_PROV_DATA_OUT = BLE_UUID16_INIT(0x2adc);
71 #define BT_UUID_MESH_PROV_DATA_OUT_VAL 0x2adc
72 /** @def BT_UUID_MESH_PROXY_DATA_IN
73 * @brief Mesh Proxy Data In
74 */
75 ble_uuid16_t BT_UUID_MESH_PROXY_DATA_IN = BLE_UUID16_INIT(0x2add);
76 #define BT_UUID_MESH_PROXY_DATA_IN_VAL 0x2add
77 /** @def BT_UUID_MESH_PROXY_DATA_OUT
78 * @brief Mesh Proxy Data Out
79 */
80 ble_uuid16_t BT_UUID_MESH_PROXY_DATA_OUT = BLE_UUID16_INIT(0x2ade);
81 #define BT_UUID_MESH_PROXY_DATA_OUT_VAL 0x2ade
82
83 #define PDU_HDR(sar, type) (sar << 6 | (type & BIT_MASK(6)))
84
85 #define CLIENT_BUF_SIZE 68
86
87 static const struct ble_gap_adv_params slow_adv_param = {
88 .conn_mode = (BLE_GAP_CONN_MODE_UND),
89 .disc_mode = (BLE_GAP_DISC_MODE_GEN),
90 .itvl_min = BT_GAP_ADV_SLOW_INT_MIN,
91 .itvl_max = BT_GAP_ADV_SLOW_INT_MAX,
92 };
93
94 static const struct ble_gap_adv_params fast_adv_param = {
95 .conn_mode = (BLE_GAP_CONN_MODE_UND),
96 .disc_mode = (BLE_GAP_DISC_MODE_GEN),
97 .itvl_min = BT_GAP_ADV_FAST_INT_MIN_2,
98 .itvl_max = BT_GAP_ADV_FAST_INT_MAX_2,
99 };
100
101 static bool proxy_adv_enabled;
102
103 #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
104 static void proxy_send_beacons(struct ble_npl_event *work);
105 #endif
106
107 #if (MYNEWT_VAL(BLE_MESH_PB_GATT))
108 static bool prov_fast_adv;
109 #endif
110
111 static struct bt_mesh_proxy_client {
112 uint16_t conn_handle;
113 u16_t filter[MYNEWT_VAL(BLE_MESH_PROXY_FILTER_SIZE)];
114 enum __packed {
115 NONE,
116 WHITELIST,
117 BLACKLIST,
118 PROV,
119 } filter_type;
120 u8_t msg_type;
121 #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
122 struct ble_npl_callout send_beacons;
123 #endif
124 struct k_delayed_work sar_timer;
125 struct os_mbuf *buf;
126 } clients[MYNEWT_VAL(BLE_MAX_CONNECTIONS)] = {
127 [0 ...(MYNEWT_VAL(BLE_MAX_CONNECTIONS) - 1)] = { 0 },
128 };
129
130 /* Track which service is enabled */
131 static enum {
132 MESH_GATT_NONE,
133 MESH_GATT_PROV,
134 MESH_GATT_PROXY,
135 } gatt_svc = MESH_GATT_NONE;
136
137 static struct {
138 uint16_t proxy_h;
139 uint16_t proxy_data_out_h;
140 uint16_t prov_h;
141 uint16_t prov_data_in_h;
142 uint16_t prov_data_out_h;
143 } svc_handles;
144
resolve_svc_handles(void)145 static void resolve_svc_handles(void)
146 {
147 int rc;
148
149 /* Either all handles are already resolved, or none of them */
150 if (svc_handles.prov_data_out_h) {
151 return;
152 }
153
154 /*
155 * We assert if attribute is not found since at this stage all attributes
156 * shall be already registered and thus shall be found.
157 */
158 rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL),
159 &svc_handles.proxy_h);
160 assert(rc == 0);
161 rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL),
162 BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_OUT_VAL),
163 NULL, &svc_handles.proxy_data_out_h);
164 assert(rc == 0);
165 rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL),
166 &svc_handles.prov_h);
167 assert(rc == 0);
168 rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL),
169 BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_IN_VAL),
170 NULL, &svc_handles.prov_data_in_h);
171 assert(rc == 0);
172 rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL),
173 BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_OUT_VAL),
174 NULL, &svc_handles.prov_data_out_h);
175 assert(rc == 0);
176 }
177
find_client(uint16_t conn_handle)178 static struct bt_mesh_proxy_client *find_client(uint16_t conn_handle)
179 {
180 int i;
181
182 for (i = 0; i < ARRAY_SIZE(clients); i++) {
183 if (clients[i].conn_handle == conn_handle) {
184 return &clients[i];
185 }
186 }
187
188 return NULL;
189 }
190
191 #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
192 /* Next subnet in queue to be advertised */
193 static int next_idx;
194
195 static int proxy_segment_and_send(uint16_t conn_handle, u8_t type,
196 struct os_mbuf *msg);
197
filter_set(struct bt_mesh_proxy_client * client,struct os_mbuf * buf)198 static int filter_set(struct bt_mesh_proxy_client *client,
199 struct os_mbuf *buf)
200 {
201 u8_t type;
202
203 if (buf->om_len < 1) {
204 BT_WARN("Too short Filter Set message");
205 return -EINVAL;
206 }
207
208 type = net_buf_simple_pull_u8(buf);
209 BT_DBG("type 0x%02x", type);
210
211 switch (type) {
212 case 0x00:
213 memset(client->filter, 0, sizeof(client->filter));
214 client->filter_type = WHITELIST;
215 break;
216
217 case 0x01:
218 memset(client->filter, 0, sizeof(client->filter));
219 client->filter_type = BLACKLIST;
220 break;
221
222 default:
223 BT_WARN("Prohibited Filter Type 0x%02x", type);
224 return -EINVAL;
225 }
226
227 return 0;
228 }
229
filter_add(struct bt_mesh_proxy_client * client,u16_t addr)230 static void filter_add(struct bt_mesh_proxy_client *client, u16_t addr)
231 {
232 int i;
233 BT_DBG("addr 0x%04x", addr);
234
235 if (addr == BT_MESH_ADDR_UNASSIGNED) {
236 return;
237 }
238
239 for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
240 if (client->filter[i] == addr) {
241 return;
242 }
243 }
244
245 for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
246 if (client->filter[i] == BT_MESH_ADDR_UNASSIGNED) {
247 client->filter[i] = addr;
248 return;
249 }
250 }
251 }
252
filter_remove(struct bt_mesh_proxy_client * client,u16_t addr)253 static void filter_remove(struct bt_mesh_proxy_client *client, u16_t addr)
254 {
255 int i;
256 BT_DBG("addr 0x%04x", addr);
257
258 if (addr == BT_MESH_ADDR_UNASSIGNED) {
259 return;
260 }
261
262 for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
263 if (client->filter[i] == addr) {
264 client->filter[i] = BT_MESH_ADDR_UNASSIGNED;
265 return;
266 }
267 }
268 }
269
send_filter_status(struct bt_mesh_proxy_client * client,struct bt_mesh_net_rx * rx,struct os_mbuf * buf)270 static void send_filter_status(struct bt_mesh_proxy_client *client,
271 struct bt_mesh_net_rx *rx,
272 struct os_mbuf *buf)
273 {
274 struct bt_mesh_net_tx tx = {
275 .sub = rx->sub,
276 .ctx = &rx->ctx,
277 .src = bt_mesh_primary_addr(),
278 };
279 u16_t filter_size;
280 int i, err;
281 /* Configuration messages always have dst unassigned */
282 tx.ctx->addr = BT_MESH_ADDR_UNASSIGNED;
283 net_buf_simple_init(buf, 10); // 10:reserve_head
284 net_buf_simple_add_u8(buf, CFG_FILTER_STATUS);
285
286 if (client->filter_type == WHITELIST) {
287 net_buf_simple_add_u8(buf, 0x00);
288 } else {
289 net_buf_simple_add_u8(buf, 0x01);
290 }
291
292 for (filter_size = 0, i = 0; i < ARRAY_SIZE(client->filter); i++) {
293 if (client->filter[i] != BT_MESH_ADDR_UNASSIGNED) {
294 filter_size++;
295 }
296 }
297
298 net_buf_simple_add_be16(buf, filter_size);
299 BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
300 err = bt_mesh_net_encode(&tx, buf, true);
301 if (err) {
302 BT_ERR("Encoding Proxy cfg message failed (err %d)", err);
303 return;
304 }
305
306 err = proxy_segment_and_send(client->conn_handle, BT_MESH_PROXY_CONFIG, buf);
307 if (err) {
308 BT_ERR("Failed to send proxy cfg message (err %d)", err);
309 }
310 }
311
proxy_cfg(struct bt_mesh_proxy_client * client)312 static void proxy_cfg(struct bt_mesh_proxy_client *client)
313 {
314 struct os_mbuf *buf = NET_BUF_SIMPLE(29);
315 struct bt_mesh_net_rx rx;
316 u8_t opcode;
317 int err;
318 err = bt_mesh_net_decode(client->buf, BT_MESH_NET_IF_PROXY_CFG,
319 &rx, buf);
320 if (err) {
321 BT_ERR("Failed to decode Proxy Configuration (err %d)", err);
322 goto done;
323 }
324
325 /* Remove network headers */
326 net_buf_simple_pull(buf, BT_MESH_NET_HDR_LEN);
327 BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
328
329 if (buf->om_len < 1) {
330 BT_WARN("Too short proxy configuration PDU");
331 goto done;
332 }
333
334 opcode = net_buf_simple_pull_u8(buf);
335
336 switch (opcode) {
337 case CFG_FILTER_SET:
338 filter_set(client, buf);
339 send_filter_status(client, &rx, buf);
340 break;
341
342 case CFG_FILTER_ADD:
343 while (buf->om_len >= 2) { // 2:Analyzing conditions
344 u16_t addr;
345 addr = net_buf_simple_pull_be16(buf);
346 filter_add(client, addr);
347 }
348
349 send_filter_status(client, &rx, buf);
350 break;
351
352 case CFG_FILTER_REMOVE:
353 while (buf->om_len >= 2) { // 2:Analyzing conditions
354 u16_t addr;
355 addr = net_buf_simple_pull_be16(buf);
356 filter_remove(client, addr);
357 }
358
359 send_filter_status(client, &rx, buf);
360 break;
361
362 default:
363 BT_WARN("Unhandled configuration OpCode 0x%02x", opcode);
364 break;
365 }
366
367 done:
368 os_mbuf_free_chain(buf);
369 }
370
beacon_send(uint16_t conn_handle,struct bt_mesh_subnet * sub)371 static int beacon_send(uint16_t conn_handle, struct bt_mesh_subnet *sub)
372 {
373 struct os_mbuf *buf = NET_BUF_SIMPLE(23);
374 int rc;
375 net_buf_simple_init(buf, 1);
376 bt_mesh_beacon_create(sub, buf);
377 rc = proxy_segment_and_send(conn_handle, BT_MESH_PROXY_BEACON, buf);
378 os_mbuf_free_chain(buf);
379 return rc;
380 }
381
proxy_send_beacons(struct ble_npl_event * work)382 static void proxy_send_beacons(struct ble_npl_event *work)
383 {
384 struct bt_mesh_proxy_client *client;
385 int i;
386 client = ble_npl_event_get_arg(work);
387
388 for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
389 struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
390
391 if (sub->net_idx != BT_MESH_KEY_UNUSED) {
392 beacon_send(client->conn_handle, sub);
393 }
394 }
395 }
396
proxy_sar_timeout(struct ble_npl_event * work)397 static void proxy_sar_timeout(struct ble_npl_event *work)
398 {
399 struct bt_mesh_proxy_client *client;
400 int rc;
401 BT_WARN("Proxy SAR timeout");
402 client = ble_npl_event_get_arg(work);
403 assert(client != NULL);
404
405 if ((client->conn_handle != BLE_HS_CONN_HANDLE_NONE)) {
406 rc = ble_gap_terminate(client->conn_handle,
407 BLE_ERR_REM_USER_CONN_TERM);
408 assert(rc == 0);
409 }
410 }
411
bt_mesh_proxy_beacon_send(struct bt_mesh_subnet * sub)412 void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub)
413 {
414 int i;
415
416 if (!sub) {
417 /* NULL means we send on all subnets */
418 for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
419 if (bt_mesh.sub[i].net_idx != BT_MESH_KEY_UNUSED) {
420 bt_mesh_proxy_beacon_send(&bt_mesh.sub[i]);
421 }
422 }
423
424 return;
425 }
426
427 for (i = 0; i < ARRAY_SIZE(clients); i++) {
428 if (clients[i].conn_handle != BLE_HS_CONN_HANDLE_NONE) {
429 beacon_send(clients[i].conn_handle, sub);
430 }
431 }
432 }
433
bt_mesh_proxy_identity_start(struct bt_mesh_subnet * sub)434 void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub)
435 {
436 sub->node_id = BT_MESH_NODE_IDENTITY_RUNNING;
437 sub->node_id_start = k_uptime_get_32();
438 /* Prioritize the recently enabled subnet */
439 next_idx = sub - bt_mesh.sub;
440 }
441
bt_mesh_proxy_identity_stop(struct bt_mesh_subnet * sub)442 void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub)
443 {
444 sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED;
445 sub->node_id_start = 0;
446 }
447
bt_mesh_proxy_identity_enable(void)448 int bt_mesh_proxy_identity_enable(void)
449 {
450 int i, count = 0;
451 BT_DBG("");
452
453 if (!bt_mesh_is_provisioned()) {
454 return -EAGAIN;
455 }
456
457 for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
458 struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
459
460 if (sub->net_idx == BT_MESH_KEY_UNUSED) {
461 continue;
462 }
463
464 if (sub->node_id == BT_MESH_NODE_IDENTITY_NOT_SUPPORTED) {
465 continue;
466 }
467
468 bt_mesh_proxy_identity_start(sub);
469 count++;
470 }
471
472 if (count) {
473 bt_mesh_adv_update();
474 }
475
476 return 0;
477 }
478
479 #endif /* GATT_PROXY */
480
proxy_complete_pdu(struct bt_mesh_proxy_client * client)481 static void proxy_complete_pdu(struct bt_mesh_proxy_client *client)
482 {
483 switch (client->msg_type) {
484 #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
485
486 case BT_MESH_PROXY_NET_PDU:
487 BT_INFO("Mesh Network PDU");
488 bt_mesh_net_recv(client->buf, 0, BT_MESH_NET_IF_PROXY);
489 break;
490
491 case BT_MESH_PROXY_BEACON:
492 BT_INFO("Mesh Beacon PDU");
493 bt_mesh_beacon_recv(client->buf);
494 break;
495
496 case BT_MESH_PROXY_CONFIG:
497 BT_INFO("Mesh Configuration PDU");
498 proxy_cfg(client);
499 break;
500 #endif
501 #if (MYNEWT_VAL(BLE_MESH_PB_GATT))
502
503 case BT_MESH_PROXY_PROV:
504 BT_INFO("Mesh Provisioning PDU");
505 bt_mesh_pb_gatt_recv(client->conn_handle, client->buf);
506 break;
507 #endif
508
509 default:
510 BT_WARN("Unhandled Message Type 0x%02x", client->msg_type);
511 break;
512 }
513
514 net_buf_simple_init(client->buf, 0);
515 }
516
proxy_recv(uint16_t conn_handle,uint16_t attr_handle,struct ble_gatt_access_ctxt * ctxt,void * arg)517 static int proxy_recv(uint16_t conn_handle, uint16_t attr_handle,
518 struct ble_gatt_access_ctxt *ctxt, void *arg)
519 {
520 struct bt_mesh_proxy_client *client;
521 const u8_t *data = ctxt->om->om_data;
522 u16_t len = ctxt->om->om_len;
523 client = find_client(conn_handle);
524 if (!client) {
525 return -ENOTCONN;
526 }
527
528 if (len < 1) {
529 BT_WARN("Too small Proxy PDU");
530 return -EINVAL;
531 }
532
533 if ((attr_handle == svc_handles.prov_data_in_h) !=
534 (PDU_TYPE(data) == BT_MESH_PROXY_PROV)) {
535 BT_WARN("Proxy PDU type doesn't match GATT service");
536 return -EINVAL;
537 }
538
539 if (len - 1 > net_buf_simple_tailroom(client->buf)) {
540 BT_WARN("Too big proxy PDU");
541 return -EINVAL;
542 }
543
544 switch (PDU_SAR(data)) {
545 case SAR_COMPLETE:
546 if (client->buf->om_len) {
547 BT_WARN("Complete PDU while a pending incomplete one");
548 return -EINVAL;
549 }
550
551 client->msg_type = PDU_TYPE(data);
552 net_buf_simple_add_mem(client->buf, data + 1, len - 1);
553 proxy_complete_pdu(client);
554 break;
555
556 case SAR_FIRST:
557 if (client->buf->om_len) {
558 BT_WARN("First PDU while a pending incomplete one");
559 return -EINVAL;
560 }
561
562 k_delayed_work_submit(&client->sar_timer, PROXY_SAR_TIMEOUT);
563 client->msg_type = PDU_TYPE(data);
564 net_buf_simple_add_mem(client->buf, data + 1, len - 1);
565 break;
566
567 case SAR_CONT:
568 if (!client->buf->om_len) {
569 BT_WARN("Continuation with no prior data");
570 return -EINVAL;
571 }
572
573 if (client->msg_type != PDU_TYPE(data)) {
574 BT_WARN("Unexpected message type in continuation");
575 return -EINVAL;
576 }
577
578 k_delayed_work_submit(&client->sar_timer, PROXY_SAR_TIMEOUT);
579 net_buf_simple_add_mem(client->buf, data + 1, len - 1);
580 break;
581
582 case SAR_LAST:
583 if (!client->buf->om_len) {
584 BT_WARN("Last SAR PDU with no prior data");
585 return -EINVAL;
586 }
587
588 if (client->msg_type != PDU_TYPE(data)) {
589 BT_WARN("Unexpected message type in last SAR PDU");
590 return -EINVAL;
591 }
592
593 k_delayed_work_cancel(&client->sar_timer);
594 net_buf_simple_add_mem(client->buf, data + 1, len - 1);
595 proxy_complete_pdu(client);
596 break;
597 }
598
599 return len;
600 }
601
602 static int conn_count;
603
proxy_connected(uint16_t conn_handle)604 static void proxy_connected(uint16_t conn_handle)
605 {
606 struct bt_mesh_proxy_client *client;
607 int i;
608 BT_INFO("conn_handle %d", conn_handle);
609 conn_count++;
610 /* Since we use ADV_OPT_ONE_TIME */
611 proxy_adv_enabled = false;
612
613 /* Try to re-enable advertising in case it's possible */
614 if (conn_count < CONFIG_BT_MAX_CONN) {
615 bt_mesh_adv_update();
616 }
617
618 for (client = NULL, i = 0; i < ARRAY_SIZE(clients); i++) {
619 if (clients[i].conn_handle == BLE_HS_CONN_HANDLE_NONE) {
620 client = &clients[i];
621 break;
622 }
623 }
624
625 if (!client) {
626 BT_ERR("No free Proxy Client objects");
627 return;
628 }
629
630 client->conn_handle = conn_handle;
631 client->filter_type = NONE;
632 memset(client->filter, 0, sizeof(client->filter));
633 net_buf_simple_init(client->buf, 0);
634 }
635
proxy_disconnected(uint16_t conn_handle,int reason)636 static void proxy_disconnected(uint16_t conn_handle, int reason)
637 {
638 int i;
639 bool disconnected = false;
640
641 for (i = 0; i < ARRAY_SIZE(clients); i++) {
642 struct bt_mesh_proxy_client *client = &clients[i];
643
644 if (client->conn_handle == conn_handle) {
645 if ((MYNEWT_VAL(BLE_MESH_PB_GATT)) &&
646 client->filter_type == PROV) {
647 bt_mesh_pb_gatt_close(conn_handle);
648 }
649
650 k_delayed_work_cancel(&client->sar_timer);
651 client->conn_handle = BLE_HS_CONN_HANDLE_NONE;
652 conn_count--;
653 disconnected = true;
654 break;
655 }
656 }
657
658 if (disconnected) {
659 BT_INFO("conn_handle %d reason %d", conn_handle, reason);
660 bt_mesh_adv_update();
661 }
662 }
663
bt_mesh_proxy_get_buf(void)664 struct os_mbuf *bt_mesh_proxy_get_buf(void)
665 {
666 struct os_mbuf *buf = clients[0].buf;
667
668 if (buf != NULL) {
669 net_buf_simple_init(buf, 0);
670 }
671
672 return buf;
673 }
674
675 #if (MYNEWT_VAL(BLE_MESH_PB_GATT))
prov_ccc_write(uint16_t conn_handle)676 static void prov_ccc_write(uint16_t conn_handle)
677 {
678 struct bt_mesh_proxy_client *client;
679 BT_DBG("conn_handle %d", conn_handle);
680 /* If a connection exists there must be a client */
681 client = find_client(conn_handle);
682 __ASSERT(client, "No client for connection");
683
684 if (client->filter_type == NONE) {
685 client->filter_type = PROV;
686 bt_mesh_pb_gatt_open(conn_handle);
687 }
688 }
689
bt_mesh_proxy_prov_enable(void)690 int bt_mesh_proxy_prov_enable(void)
691 {
692 uint16_t handle;
693 int rc;
694 int i;
695 BT_DBG("");
696
697 if (gatt_svc == MESH_GATT_PROV) {
698 return -EALREADY;
699 }
700
701 if (gatt_svc != MESH_GATT_NONE) {
702 return -EBUSY;
703 }
704
705 rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), &handle);
706 assert(rc == 0);
707 ble_gatts_svc_set_visibility(handle, 1);
708 ble_svc_gatt_changed(svc_handles.prov_h, 0xffff);
709 gatt_svc = MESH_GATT_PROV;
710 prov_fast_adv = true;
711
712 for (i = 0; i < ARRAY_SIZE(clients); i++) {
713 if (clients[i].conn_handle != BLE_HS_CONN_HANDLE_NONE) {
714 clients[i].filter_type = PROV;
715 }
716 }
717
718 return 0;
719 }
720
bt_mesh_proxy_prov_disable(bool disconnect)721 int bt_mesh_proxy_prov_disable(bool disconnect)
722 {
723 uint16_t handle;
724 int rc;
725 int i;
726 BT_DBG("");
727
728 if (gatt_svc == MESH_GATT_NONE) {
729 return -EALREADY;
730 }
731
732 if (gatt_svc != MESH_GATT_PROV) {
733 return -EBUSY;
734 }
735
736 rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), &handle);
737 assert(rc == 0);
738 ble_gatts_svc_set_visibility(handle, 0);
739 ble_svc_gatt_changed(svc_handles.prov_h, 0xffff);
740 gatt_svc = MESH_GATT_NONE;
741
742 for (i = 0; i < ARRAY_SIZE(clients); i++) {
743 struct bt_mesh_proxy_client *client = &clients[i];
744
745 if ((client->conn_handle == BLE_HS_CONN_HANDLE_NONE)
746 || (client->filter_type != PROV)) {
747 continue;
748 }
749
750 if (disconnect) {
751 rc = ble_gap_terminate(client->conn_handle,
752 BLE_ERR_REM_USER_CONN_TERM);
753 assert(rc == 0);
754 } else {
755 bt_mesh_pb_gatt_close(client->conn_handle);
756 client->filter_type = NONE;
757 }
758 }
759
760 bt_mesh_adv_update();
761 return 0;
762 }
763 #endif /* MYNEWT_VAL(BLE_MESH_PB_GATT) */
764
765 #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
proxy_ccc_write(uint16_t conn_handle)766 static void proxy_ccc_write(uint16_t conn_handle)
767 {
768 struct bt_mesh_proxy_client *client;
769 BT_DBG("conn_handle %d", conn_handle);
770 client = find_client(conn_handle);
771 __ASSERT(client, "No client for connection");
772
773 if (client->filter_type == NONE) {
774 client->filter_type = WHITELIST;
775 k_work_add_arg(&client->send_beacons, client);
776 k_work_submit(&client->send_beacons);
777 }
778 }
779
bt_mesh_proxy_gatt_enable(void)780 int bt_mesh_proxy_gatt_enable(void)
781 {
782 uint16_t handle;
783 int rc;
784 int i;
785 BT_DBG("");
786
787 if (gatt_svc == MESH_GATT_PROXY) {
788 return -EALREADY;
789 }
790
791 if (gatt_svc != MESH_GATT_NONE) {
792 return -EBUSY;
793 }
794
795 rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle);
796 assert(rc == 0);
797 ble_gatts_svc_set_visibility(handle, 1);
798 ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff);
799 gatt_svc = MESH_GATT_PROXY;
800
801 for (i = 0; i < ARRAY_SIZE(clients); i++) {
802 if (clients[i].conn_handle != BLE_HS_CONN_HANDLE_NONE) {
803 clients[i].filter_type = WHITELIST;
804 }
805 }
806
807 return 0;
808 }
809
bt_mesh_proxy_gatt_disconnect(void)810 void bt_mesh_proxy_gatt_disconnect(void)
811 {
812 int rc;
813 int i;
814 BT_DBG("");
815
816 for (i = 0; i < ARRAY_SIZE(clients); i++) {
817 struct bt_mesh_proxy_client *client = &clients[i];
818
819 if ((client->conn_handle != BLE_HS_CONN_HANDLE_NONE) &&
820 (client->filter_type == WHITELIST ||
821 client->filter_type == BLACKLIST)) {
822 client->filter_type = NONE;
823 rc = ble_gap_terminate(client->conn_handle,
824 BLE_ERR_REM_USER_CONN_TERM);
825 assert(rc == 0);
826 }
827 }
828 }
829
bt_mesh_proxy_gatt_disable(void)830 int bt_mesh_proxy_gatt_disable(void)
831 {
832 uint16_t handle;
833 int rc;
834 BT_DBG("");
835
836 if (gatt_svc == MESH_GATT_NONE) {
837 return -EALREADY;
838 }
839
840 if (gatt_svc != MESH_GATT_PROXY) {
841 return -EBUSY;
842 }
843
844 bt_mesh_proxy_gatt_disconnect();
845 rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle);
846 assert(rc == 0);
847 ble_gatts_svc_set_visibility(handle, 0);
848 ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff);
849 gatt_svc = MESH_GATT_NONE;
850 return 0;
851 }
852
bt_mesh_proxy_addr_add(struct os_mbuf * buf,u16_t addr)853 void bt_mesh_proxy_addr_add(struct os_mbuf *buf, u16_t addr)
854 {
855 struct bt_mesh_proxy_client *client = NULL;
856 int i;
857
858 for (i = 0; i < ARRAY_SIZE(clients); i++) {
859 client = &clients[i];
860
861 if (client->buf == buf) {
862 break;
863 }
864 }
865
866 assert(client);
867 BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr);
868
869 if (client->filter_type == WHITELIST) {
870 filter_add(client, addr);
871 } else if (client->filter_type == BLACKLIST) {
872 filter_remove(client, addr);
873 }
874 }
875
client_filter_match(struct bt_mesh_proxy_client * client,u16_t addr)876 static bool client_filter_match(struct bt_mesh_proxy_client *client,
877 u16_t addr)
878 {
879 int i;
880 BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr);
881
882 if (client->filter_type == BLACKLIST) {
883 for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
884 if (client->filter[i] == addr) {
885 return false;
886 }
887 }
888
889 return true;
890 }
891
892 if (addr == BT_MESH_ADDR_ALL_NODES) {
893 return true;
894 }
895
896 if (client->filter_type == WHITELIST) {
897 for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
898 if (client->filter[i] == addr) {
899 return true;
900 }
901 }
902 }
903
904 return false;
905 }
906
bt_mesh_proxy_relay(struct os_mbuf * buf,u16_t dst)907 bool bt_mesh_proxy_relay(struct os_mbuf *buf, u16_t dst)
908 {
909 bool relayed = false;
910 int i;
911 BT_DBG("%u bytes to dst 0x%04x", buf->om_len, dst);
912
913 for (i = 0; i < ARRAY_SIZE(clients); i++) {
914 struct bt_mesh_proxy_client *client = &clients[i];
915 struct os_mbuf *msg;
916
917 if (client->conn_handle == BLE_HS_CONN_HANDLE_NONE) {
918 continue;
919 }
920
921 if (!client_filter_match(client, dst)) {
922 continue;
923 }
924
925 /* Proxy PDU sending modifies the original buffer,
926 * so we need to make a copy.
927 */
928 msg = NET_BUF_SIMPLE(32); // 32:size
929 net_buf_simple_init(msg, 1);
930 net_buf_simple_add_mem(msg, buf->om_data, buf->om_len);
931 bt_mesh_proxy_send(client->conn_handle, BT_MESH_PROXY_NET_PDU, msg);
932 os_mbuf_free_chain(msg);
933 relayed = true;
934 }
935
936 return relayed;
937 }
938
939 #endif /* MYNEWT_VAL(BLE_MESH_GATT_PROXY) */
940
proxy_send(uint16_t conn_handle,const void * data,u16_t len)941 static int proxy_send(uint16_t conn_handle, const void *data, u16_t len)
942 {
943 struct os_mbuf *om;
944 BT_DBG("%u bytes: %s", len, bt_hex(data, len));
945 #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
946
947 if (gatt_svc == MESH_GATT_PROXY) {
948 om = ble_hs_mbuf_from_flat(data, len);
949 assert(om);
950 ble_gattc_notify_custom(conn_handle, svc_handles.proxy_data_out_h, om);
951 }
952
953 #endif
954 #if (MYNEWT_VAL(BLE_MESH_PB_GATT))
955
956 if (gatt_svc == MESH_GATT_PROV) {
957 om = ble_hs_mbuf_from_flat(data, len);
958 assert(om);
959 ble_gattc_notify_custom(conn_handle, svc_handles.prov_data_out_h, om);
960 }
961
962 #endif
963 return 0;
964 }
965
proxy_segment_and_send(uint16_t conn_handle,u8_t type,struct os_mbuf * msg)966 static int proxy_segment_and_send(uint16_t conn_handle, u8_t type,
967 struct os_mbuf *msg)
968 {
969 u16_t mtu;
970 BT_DBG("conn_handle %d type 0x%02x len %u: %s", conn_handle, type, msg->om_len,
971 bt_hex(msg->om_data, msg->om_len));
972 /* ATT_MTU - OpCode (1 byte) - Handle (2 bytes) */
973 mtu = ble_att_mtu(conn_handle) - 3; // 3:byte alignment
974 if (mtu > msg->om_len) {
975 net_buf_simple_push_u8(msg, PDU_HDR((SAR_COMPLETE), (type)));
976 return proxy_send(conn_handle, msg->om_data, msg->om_len);
977 }
978
979 net_buf_simple_push_u8(msg, PDU_HDR((SAR_FIRST), (type)));
980 proxy_send(conn_handle, msg->om_data, mtu);
981 net_buf_simple_pull(msg, mtu);
982
983 while (msg->om_len) {
984 if (msg->om_len + 1 < mtu) {
985 net_buf_simple_push_u8(msg, PDU_HDR((SAR_LAST), (type)));
986 proxy_send(conn_handle, msg->om_data, msg->om_len);
987 break;
988 }
989
990 net_buf_simple_push_u8(msg, PDU_HDR((SAR_CONT), (type)));
991 proxy_send(conn_handle, msg->om_data, mtu);
992 net_buf_simple_pull(msg, mtu);
993 }
994
995 return 0;
996 }
997
bt_mesh_proxy_send(uint16_t conn_handle,u8_t type,struct os_mbuf * msg)998 int bt_mesh_proxy_send(uint16_t conn_handle, u8_t type,
999 struct os_mbuf *msg)
1000 {
1001 struct bt_mesh_proxy_client *client = find_client(conn_handle);
1002
1003 if (!client) {
1004 BT_ERR("No Proxy Client found");
1005 return -ENOTCONN;
1006 }
1007
1008 if ((client->filter_type == PROV) != (type == BT_MESH_PROXY_PROV)) {
1009 BT_ERR("Invalid PDU type for Proxy Client");
1010 return -EINVAL;
1011 }
1012
1013 return proxy_segment_and_send(conn_handle, type, msg);
1014 }
1015
1016 #if (MYNEWT_VAL(BLE_MESH_PB_GATT))
1017 static u8_t prov_svc_data[20] = { 0x27, 0x18, };
1018
1019 static const struct bt_data prov_ad[] = {
1020 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
1021 BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0x27, 0x18),
1022 BT_DATA(BT_DATA_SVC_DATA16, prov_svc_data, sizeof(prov_svc_data)),
1023 };
1024 #endif /* PB_GATT */
1025
1026 #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
1027
1028 #define ID_TYPE_NET 0x00
1029 #define ID_TYPE_NODE 0x01
1030
1031 #define NODE_ID_LEN 19
1032 #define NET_ID_LEN 11
1033
1034 #define NODE_ID_TIMEOUT K_SECONDS(CONFIG_BT_MESH_NODE_ID_TIMEOUT)
1035
1036 static u8_t proxy_svc_data[NODE_ID_LEN] = { 0x28, 0x18, };
1037
1038 static const struct bt_data node_id_ad[] = {
1039 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
1040 BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0x28, 0x18),
1041 BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NODE_ID_LEN),
1042 };
1043
1044 static const struct bt_data net_id_ad[] = {
1045 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
1046 BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0x28, 0x18),
1047 BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NET_ID_LEN),
1048 };
1049
node_id_adv(struct bt_mesh_subnet * sub)1050 static int node_id_adv(struct bt_mesh_subnet *sub)
1051 {
1052 u8_t tmp[16];
1053 int err;
1054 BT_DBG("");
1055 proxy_svc_data[2] = ID_TYPE_NODE; // 2:array element
1056 err = bt_rand(proxy_svc_data + 11, 8); // 11:byte alignment, 8:len
1057 if (err) {
1058 return err;
1059 }
1060
1061 memset(tmp, 0, 6); // 6:size
1062 memcpy(tmp + 6, proxy_svc_data + 11, 8); // 11:byte alignment, 8:len
1063 sys_put_be16(bt_mesh_primary_addr(), tmp + 14); // 14:byte alignment
1064 err = bt_encrypt_be(sub->keys[sub->kr_flag].identity, tmp, tmp);
1065 if (err) {
1066 return err;
1067 }
1068
1069 memcpy(proxy_svc_data + 3, tmp + 8, 8); // 3:byte alignment, 8:len
1070 err = bt_le_adv_start(&fast_adv_param, node_id_ad,
1071 ARRAY_SIZE(node_id_ad), NULL, 0);
1072 if (err) {
1073 BT_WARN("Failed to advertise using Node ID (err %d)", err);
1074 return err;
1075 }
1076
1077 proxy_adv_enabled = true;
1078 return 0;
1079 }
1080
net_id_adv(struct bt_mesh_subnet * sub)1081 static int net_id_adv(struct bt_mesh_subnet *sub)
1082 {
1083 int err;
1084 BT_DBG("");
1085 proxy_svc_data[2] = ID_TYPE_NET; // 2:array element
1086 BT_DBG("Advertising with NetId %s",
1087 bt_hex(sub->keys[sub->kr_flag].net_id, 8)); // 8:len
1088 memcpy(proxy_svc_data + 3, sub->keys[sub->kr_flag].net_id, 8); // 8:size
1089 err = bt_le_adv_start(&slow_adv_param, net_id_ad,
1090 ARRAY_SIZE(net_id_ad), NULL, 0);
1091 if (err) {
1092 BT_WARN("Failed to advertise using Network ID (err %d)", err);
1093 return err;
1094 }
1095
1096 proxy_adv_enabled = true;
1097 return 0;
1098 }
1099
advertise_subnet(struct bt_mesh_subnet * sub)1100 static bool advertise_subnet(struct bt_mesh_subnet *sub)
1101 {
1102 if (sub->net_idx == BT_MESH_KEY_UNUSED) {
1103 return false;
1104 }
1105
1106 return (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING ||
1107 bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_NOT_SUPPORTED);
1108 }
1109
next_sub(void)1110 static struct bt_mesh_subnet *next_sub(void)
1111 {
1112 int i;
1113
1114 for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
1115 struct bt_mesh_subnet *sub;
1116 sub = &bt_mesh.sub[(i + next_idx) % ARRAY_SIZE(bt_mesh.sub)];
1117 if (advertise_subnet(sub)) {
1118 next_idx = (next_idx + 1) % ARRAY_SIZE(bt_mesh.sub);
1119 return sub;
1120 }
1121 }
1122
1123 return NULL;
1124 }
1125
sub_count(void)1126 static int sub_count(void)
1127 {
1128 int i, count = 0;
1129
1130 for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
1131 struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
1132
1133 if (advertise_subnet(sub)) {
1134 count++;
1135 }
1136 }
1137
1138 return count;
1139 }
1140
gatt_proxy_advertise(struct bt_mesh_subnet * sub)1141 static s32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub)
1142 {
1143 s32_t remaining = K_FOREVER;
1144 int subnet_count;
1145 BT_DBG("");
1146
1147 if (conn_count == CONFIG_BT_MAX_CONN) {
1148 BT_DBG("Connectable advertising deferred (max connections)");
1149 return remaining;
1150 }
1151
1152 if (!sub) {
1153 BT_WARN("No subnets to advertise on");
1154 return remaining;
1155 }
1156
1157 if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) {
1158 u32_t active = k_uptime_get_32() - sub->node_id_start;
1159 if (active < NODE_ID_TIMEOUT) {
1160 remaining = NODE_ID_TIMEOUT - active;
1161 BT_DBG("Node ID active for %u ms, %d ms remaining",
1162 (unsigned) active, (int) remaining);
1163 node_id_adv(sub);
1164 } else {
1165 bt_mesh_proxy_identity_stop(sub);
1166 BT_DBG("Node ID stopped");
1167 }
1168 }
1169
1170 if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) {
1171 net_id_adv(sub);
1172 }
1173
1174 subnet_count = sub_count();
1175 BT_DBG("sub_count %u", subnet_count);
1176
1177 if (subnet_count > 1) {
1178 s32_t max_timeout;
1179 /* We use NODE_ID_TIMEOUT as a starting point since it may
1180 * be less than 60 seconds. Divide this period into at least
1181 * 6 slices, but make sure that a slice is at least one
1182 * second long (to avoid excessive rotation).
1183 */
1184 max_timeout = NODE_ID_TIMEOUT / max(subnet_count, 6); // 6:byte alignment
1185 max_timeout = max(max_timeout, K_SECONDS(1));
1186 if (remaining > max_timeout || remaining < 0) {
1187 remaining = max_timeout;
1188 }
1189 }
1190
1191 BT_DBG("Advertising %d ms for net_idx 0x%04x",
1192 (int) remaining, sub->net_idx);
1193 return remaining;
1194 }
1195 #endif /* GATT_PROXY */
1196
1197 #if (MYNEWT_VAL(BLE_MESH_PB_GATT))
gatt_prov_adv_create(struct bt_data prov_sd[2])1198 static size_t gatt_prov_adv_create(struct bt_data prov_sd[2])
1199 {
1200 const struct bt_mesh_prov *prov = bt_mesh_prov_get();
1201 const char *name = CONFIG_BT_DEVICE_NAME;
1202 size_t name_len = strlen(name);
1203 size_t prov_sd_len = 0;
1204 size_t sd_space = 31; // 31:byte alignment
1205 memcpy(prov_svc_data + 2, prov->uuid, 16); // 2:byte alignment, 16:size
1206 sys_put_be16(prov->oob_info, prov_svc_data + 18); // 18:byte alignment
1207
1208 if (prov->uri) {
1209 size_t uri_len = strlen(prov->uri);
1210 if (uri_len > 29) { // 29:Analyzing conditions
1211 /* There's no way to shorten an URI */
1212 BT_WARN("Too long URI to fit advertising packet");
1213 } else {
1214 prov_sd[0].type = BT_DATA_URI;
1215 prov_sd[0].data_len = uri_len;
1216 prov_sd[0].data = (void *)prov->uri;
1217 sd_space -= 2 + uri_len; // 2:byte alignment
1218 prov_sd_len++;
1219 }
1220 }
1221
1222 if (sd_space > 2 && name_len > 0) { // 2:Analyzing conditions
1223 sd_space -= 2; // 2:byte alignment
1224 if (sd_space < name_len) {
1225 prov_sd[prov_sd_len].type = BT_DATA_NAME_SHORTENED;
1226 prov_sd[prov_sd_len].data_len = sd_space;
1227 } else {
1228 prov_sd[prov_sd_len].type = BT_DATA_NAME_COMPLETE;
1229 prov_sd[prov_sd_len].data_len = name_len;
1230 }
1231
1232 prov_sd[prov_sd_len].data = (void *)name;
1233 prov_sd_len++;
1234 }
1235
1236 return prov_sd_len;
1237 }
1238 #endif /* PB_GATT */
1239
bt_mesh_proxy_adv_start(void)1240 s32_t bt_mesh_proxy_adv_start(void)
1241 {
1242 BT_DBG("");
1243
1244 if (gatt_svc == MESH_GATT_NONE) {
1245 return K_FOREVER;
1246 }
1247
1248 #if (MYNEWT_VAL(BLE_MESH_PB_GATT))
1249
1250 if (!bt_mesh_is_provisioned()) {
1251 const struct ble_gap_adv_params *param;
1252 struct bt_data prov_sd[2];
1253 size_t prov_sd_len;
1254
1255 if (prov_fast_adv) {
1256 param = &fast_adv_param;
1257 } else {
1258 param = &slow_adv_param;
1259 }
1260
1261 prov_sd_len = gatt_prov_adv_create(prov_sd);
1262 if (bt_le_adv_start(param, prov_ad, ARRAY_SIZE(prov_ad),
1263 prov_sd, prov_sd_len) == 0) {
1264 proxy_adv_enabled = true;
1265
1266 /* Advertise 60 seconds using fast interval */
1267 if (prov_fast_adv) {
1268 prov_fast_adv = false;
1269 return K_SECONDS(60); // 60:60s
1270 }
1271 }
1272 }
1273
1274 #endif /* PB_GATT */
1275 #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
1276
1277 if (bt_mesh_is_provisioned()) {
1278 return gatt_proxy_advertise(next_sub());
1279 }
1280
1281 #endif /* GATT_PROXY */
1282 return K_FOREVER;
1283 }
1284
bt_mesh_proxy_adv_stop(void)1285 void bt_mesh_proxy_adv_stop(void)
1286 {
1287 int err;
1288 BT_DBG("adv_enabled %u", proxy_adv_enabled);
1289
1290 if (!proxy_adv_enabled) {
1291 return;
1292 }
1293
1294 err = bt_le_adv_stop(true);
1295 if (err) {
1296 BT_ERR("Failed to stop advertising (err %d)", err);
1297 } else {
1298 proxy_adv_enabled = false;
1299 }
1300 }
1301
ble_mesh_handle_connect(struct ble_gap_event * event,void * arg)1302 static void ble_mesh_handle_connect(struct ble_gap_event *event, void *arg)
1303 {
1304 #if MYNEWT_VAL(BLE_EXT_ADV)
1305
1306 /* When EXT ADV is enabled then mesh proxy is connected
1307 * when proxy advertising instance is completed.
1308 * Therefore no need to handle BLE_GAP_EVENT_CONNECT
1309 */
1310 if (event->type == BLE_GAP_EVENT_ADV_COMPLETE) {
1311 /* Reason 0 means advertising has been completed because
1312 * connection has been established
1313 */
1314 if (event->adv_complete.reason != 0) {
1315 return;
1316 }
1317
1318 if (event->adv_complete.instance != BT_MESH_ADV_GATT_INST) {
1319 return;
1320 }
1321
1322 proxy_connected(event->adv_complete.conn_handle);
1323 }
1324
1325 #else
1326
1327 if (event->type == BLE_GAP_EVENT_CONNECT) {
1328 proxy_connected(event->connect.conn_handle);
1329 }
1330
1331 #endif
1332 }
1333
ble_mesh_proxy_gap_event(struct ble_gap_event * event,void * arg)1334 int ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg)
1335 {
1336 if ((event->type == BLE_GAP_EVENT_CONNECT) ||
1337 (event->type == BLE_GAP_EVENT_ADV_COMPLETE)) {
1338 ble_mesh_handle_connect(event, arg);
1339 } else if (event->type == BLE_GAP_EVENT_DISCONNECT) {
1340 proxy_disconnected(event->disconnect.conn.conn_handle,
1341 event->disconnect.reason);
1342 } else if (event->type == BLE_GAP_EVENT_SUBSCRIBE) {
1343 if (event->subscribe.attr_handle == svc_handles.proxy_data_out_h) {
1344 #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
1345 proxy_ccc_write(event->subscribe.conn_handle);
1346 #endif
1347 } else if (event->subscribe.attr_handle ==
1348 svc_handles.prov_data_out_h) {
1349 #if (MYNEWT_VAL(BLE_MESH_PB_GATT))
1350 prov_ccc_write(event->subscribe.conn_handle);
1351 #endif
1352 }
1353 }
1354
1355 return 0;
1356 }
1357
dummy_access_cb(uint16_t conn_handle,uint16_t attr_handle,struct ble_gatt_access_ctxt * ctxt,void * arg)1358 static int dummy_access_cb(uint16_t conn_handle, uint16_t attr_handle,
1359 struct ble_gatt_access_ctxt *ctxt, void *arg)
1360 {
1361 /*
1362 * We should never never enter this callback - it's attached to notify-only
1363 * characteristic which are notified directly from mbuf. And we can't pass
1364 * NULL as access_cb because gatts will assert on init...
1365 */
1366 BLE_HS_DBG_ASSERT(0);
1367 return 0;
1368 }
1369
1370 static const struct ble_gatt_svc_def svc_defs [] = {
1371 {
1372 .type = BLE_GATT_SVC_TYPE_PRIMARY,
1373 .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL),
1374 .characteristics = (struct ble_gatt_chr_def[])
1375 { {
1376 .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_IN_VAL),
1377 .access_cb = proxy_recv,
1378 .flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
1379 }, {
1380 .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_OUT_VAL),
1381 .access_cb = dummy_access_cb,
1382 .flags = BLE_GATT_CHR_F_NOTIFY,
1383 }, {
1384 0, /* No more characteristics in this service. */
1385 }
1386 },
1387 }, {
1388 .type = BLE_GATT_SVC_TYPE_PRIMARY,
1389 .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL),
1390 .characteristics = (struct ble_gatt_chr_def[])
1391 { {
1392 .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_IN_VAL),
1393 .access_cb = proxy_recv,
1394 .flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
1395 }, {
1396 .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_OUT_VAL),
1397 .access_cb = dummy_access_cb,
1398 .flags = BLE_GATT_CHR_F_NOTIFY,
1399 }, {
1400 0, /* No more characteristics in this service. */
1401 }
1402 },
1403 }, {
1404 0, /* No more services. */
1405 },
1406 };
1407
bt_mesh_proxy_svcs_register(void)1408 int bt_mesh_proxy_svcs_register(void)
1409 {
1410 int rc;
1411 rc = ble_gatts_count_cfg(svc_defs);
1412 assert(rc == 0);
1413 rc = ble_gatts_add_svcs(svc_defs);
1414 assert(rc == 0);
1415 return 0;
1416 }
1417
bt_mesh_proxy_init(void)1418 int bt_mesh_proxy_init(void)
1419 {
1420 int i;
1421
1422 for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); ++i) {
1423 #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
1424 k_work_init(&clients[i].send_beacons, proxy_send_beacons);
1425 #endif
1426 clients[i].buf = NET_BUF_SIMPLE(CLIENT_BUF_SIZE);
1427 clients[i].conn_handle = BLE_HS_CONN_HANDLE_NONE;
1428 k_delayed_work_init(&clients[i].sar_timer, proxy_sar_timeout);
1429 k_delayed_work_add_arg(&clients[i].sar_timer, &clients[i]);
1430 }
1431
1432 resolve_svc_handles();
1433 ble_gatts_svc_set_visibility(svc_handles.proxy_h, 0);
1434 ble_gatts_svc_set_visibility(svc_handles.prov_h, 0);
1435 return 0;
1436 }
1437
1438 #endif /* MYNEWT_VAL(BLE_MESH_PROXY) */