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