xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/mesh/src/proxy.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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