xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/mesh/src/adv.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1 /*  Bluetooth Mesh */
2 
3 /*
4  * Copyright (c) 2018 Nordic Semiconductor ASA
5  * Copyright (c) 2017 Intel Corporation
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 #include "mesh/mesh.h"
11 
12 #include "syscfg/syscfg.h"
13 #define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_ADV))
14 #include "host/ble_hs_log.h"
15 
16 #include "host/ble_hs_adv.h"
17 #include "host/ble_gap.h"
18 #include "nimble/hci_common.h"
19 #include "mesh/porting.h"
20 
21 #include "adv.h"
22 #include "net.h"
23 #include "foundation.h"
24 #include "beacon.h"
25 #include "prov.h"
26 #include "proxy.h"
27 
28 /* Convert from ms to 0.625ms units */
29 #define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5)
30 
31 /* Window and Interval are equal for continuous scanning */
32 #define MESH_SCAN_INTERVAL_MS 10
33 #define MESH_SCAN_WINDOW_MS   10
34 #define MESH_SCAN_INTERVAL    ADV_SCAN_UNIT(MESH_SCAN_INTERVAL_MS)
35 #define MESH_SCAN_WINDOW      ADV_SCAN_UNIT(MESH_SCAN_WINDOW_MS)
36 
37 /* Pre-5.0 controllers enforce a minimum interval of 100ms
38  * whereas 5.0+ controllers can go down to 20ms.
39  */
40 #define ADV_INT_DEFAULT_MS 100
41 #define ADV_INT_FAST_MS    20
42 
43 static s32_t adv_int_min =  ADV_INT_DEFAULT_MS;
44 
45 /* TinyCrypt PRNG consumes a lot of stack space, so we need to have
46  * an increased call stack whenever it's used.
47  */
48 #if MYNEWT
49 #define ADV_STACK_SIZE 768
50 OS_TASK_STACK_DEFINE(g_blemesh_stack, ADV_STACK_SIZE);
51 struct os_task adv_task;
52 #endif
53 
54 static struct ble_npl_eventq adv_queue;
55 extern u8_t g_mesh_addr_type;
56 
57 static os_membuf_t adv_buf_mem[OS_MEMPOOL_SIZE(
58 		MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT),
59 		BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE)];
60 
61 struct os_mbuf_pool adv_os_mbuf_pool;
62 static struct os_mempool adv_buf_mempool;
63 
64 static const u8_t adv_type[] = {
65 	[BT_MESH_ADV_PROV]   = BLE_HS_ADV_TYPE_MESH_PROV,
66 	[BT_MESH_ADV_DATA]   = BLE_HS_ADV_TYPE_MESH_MESSAGE,
67 	[BT_MESH_ADV_BEACON] = BLE_HS_ADV_TYPE_MESH_BEACON,
68 	[BT_MESH_ADV_URI]    = BLE_HS_ADV_TYPE_URI,
69 };
70 
71 
72 static struct bt_mesh_adv adv_pool[CONFIG_BT_MESH_ADV_BUF_COUNT];
73 
adv_alloc(int id)74 static struct bt_mesh_adv *adv_alloc(int id)
75 {
76 	return &adv_pool[id];
77 }
78 
adv_send_start(u16_t duration,int err,const struct bt_mesh_send_cb * cb,void * cb_data)79 static inline void adv_send_start(u16_t duration, int err,
80 				  const struct bt_mesh_send_cb *cb,
81 				  void *cb_data)
82 {
83 	if (cb && cb->start) {
84 		cb->start(duration, err, cb_data);
85 	}
86 }
87 
adv_send_end(int err,const struct bt_mesh_send_cb * cb,void * cb_data)88 static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb,
89 				void *cb_data)
90 {
91 	if (cb && cb->end) {
92 		cb->end(err, cb_data);
93 	}
94 }
95 
adv_send(struct os_mbuf * buf)96 static inline void adv_send(struct os_mbuf *buf)
97 {
98 	const struct bt_mesh_send_cb *cb = BT_MESH_ADV(buf)->cb;
99 	void *cb_data = BT_MESH_ADV(buf)->cb_data;
100 	struct ble_gap_adv_params param = { 0 };
101 	u16_t duration, adv_int;
102 	struct bt_data ad;
103 	int err;
104 
105 	adv_int = max(adv_int_min,
106 		      BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit));
107 	duration = (MESH_SCAN_WINDOW_MS +
108 		    ((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) *
109 		     (adv_int + 10)));
110 
111 	BT_DBG("type %u om_len %u: %s", BT_MESH_ADV(buf)->type,
112 	       buf->om_len, bt_hex(buf->om_data, buf->om_len));
113 	BT_DBG("count %u interval %ums duration %ums",
114 	       BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, adv_int,
115 	       duration);
116 
117 	ad.type = adv_type[BT_MESH_ADV(buf)->type];
118 	ad.data_len = buf->om_len;
119 	ad.data = buf->om_data;
120 
121 	param.itvl_min = ADV_SCAN_UNIT(adv_int);
122 	param.itvl_max = param.itvl_min;
123 	param.conn_mode = BLE_GAP_CONN_MODE_NON;
124 
125 	err = bt_le_adv_start(&param, &ad, 1, NULL, 0);
126 	net_buf_unref(buf);
127 	adv_send_start(duration, err, cb, cb_data);
128 	if (err) {
129 		BT_ERR("Advertising failed: err %d", err);
130 		return;
131 	}
132 
133 	BT_DBG("Advertising started. Sleeping %u ms", duration);
134 
135 	k_sleep(K_MSEC(duration));
136 
137 	err = bt_le_adv_stop(false);
138 	adv_send_end(err, cb, cb_data);
139 	if (err) {
140 		BT_ERR("Stopping advertising failed: err %d", err);
141 		return;
142 	}
143 
144 	BT_DBG("Advertising stopped");
145 }
146 
147 void
mesh_adv_thread(void * args)148 mesh_adv_thread(void *args)
149 {
150 	static struct ble_npl_event *ev;
151 	struct os_mbuf *buf;
152 #if (MYNEWT_VAL(BLE_MESH_PROXY))
153 	s32_t timeout;
154 #endif
155 
156 	BT_DBG("started");
157 
158 	while (1) {
159 #if (MYNEWT_VAL(BLE_MESH_PROXY))
160 		ev = ble_npl_eventq_get(&adv_queue, 0);
161 		while (!ev) {
162 			timeout = bt_mesh_proxy_adv_start();
163 			BT_DBG("Proxy Advertising up to %d ms", timeout);
164 
165 			// FIXME: should we redefine K_SECONDS macro instead in glue?
166 			if (timeout != K_FOREVER) {
167 				timeout = ble_npl_time_ms_to_ticks32(timeout);
168 			}
169 
170 			ev = ble_npl_eventq_get(&adv_queue, timeout);
171 			bt_mesh_proxy_adv_stop();
172 		}
173 #else
174 		ev = ble_npl_eventq_get(&adv_queue, BLE_NPL_TIME_FOREVER);
175 #endif
176 
177 		if (!ev || !ble_npl_event_get_arg(ev)) {
178 			continue;
179 		}
180 
181 		buf = ble_npl_event_get_arg(ev);
182 
183 		/* busy == 0 means this was canceled */
184 		if (BT_MESH_ADV(buf)->busy) {
185 			BT_MESH_ADV(buf)->busy = 0;
186 			adv_send(buf);
187 		}
188 
189 		/* os_sched(NULL); */
190 	}
191 }
192 
bt_mesh_adv_update(void)193 void bt_mesh_adv_update(void)
194 {
195 	static struct ble_npl_event ev = { };
196 
197 	BT_DBG("");
198 
199 	ble_npl_eventq_put(&adv_queue, &ev);
200 }
201 
bt_mesh_adv_create_from_pool(struct os_mbuf_pool * pool,bt_mesh_adv_alloc_t get_id,enum bt_mesh_adv_type type,u8_t xmit,s32_t timeout)202 struct os_mbuf *bt_mesh_adv_create_from_pool(struct os_mbuf_pool *pool,
203 					     bt_mesh_adv_alloc_t get_id,
204 					     enum bt_mesh_adv_type type,
205 					     u8_t xmit, s32_t timeout)
206 {
207 	struct bt_mesh_adv *adv;
208 	struct os_mbuf *buf;
209 
210 	buf = os_mbuf_get_pkthdr(pool, BT_MESH_ADV_USER_DATA_SIZE);
211 	if (!buf) {
212 		return NULL;
213 	}
214 
215 	adv = get_id(net_buf_id(buf));
216 	BT_MESH_ADV(buf) = adv;
217 
218 	memset(adv, 0, sizeof(*adv));
219 
220 	adv->type         = type;
221 	adv->xmit         = xmit;
222 
223 	adv->ref_cnt = 1;
224 	ble_npl_event_set_arg(&adv->ev, buf);
225 
226 	return buf;
227 }
228 
bt_mesh_adv_create(enum bt_mesh_adv_type type,u8_t xmit,s32_t timeout)229 struct os_mbuf *bt_mesh_adv_create(enum bt_mesh_adv_type type, u8_t xmit,
230 				   s32_t timeout)
231 {
232 	return bt_mesh_adv_create_from_pool(&adv_os_mbuf_pool, adv_alloc, type,
233 					    xmit, timeout);
234 }
235 
bt_mesh_adv_send(struct os_mbuf * buf,const struct bt_mesh_send_cb * cb,void * cb_data)236 void bt_mesh_adv_send(struct os_mbuf *buf, const struct bt_mesh_send_cb *cb,
237 		      void *cb_data)
238 {
239 	BT_DBG("buf %p, type 0x%02x len %u: %s", buf, BT_MESH_ADV(buf)->type, buf->om_len,
240 	       bt_hex(buf->om_data, buf->om_len));
241 
242 	BT_MESH_ADV(buf)->cb = cb;
243 	BT_MESH_ADV(buf)->cb_data = cb_data;
244 	BT_MESH_ADV(buf)->busy = 1;
245 
246 	net_buf_put(&adv_queue, net_buf_ref(buf));
247 }
248 
bt_mesh_scan_cb(const bt_addr_le_t * addr,s8_t rssi,u8_t adv_type,struct os_mbuf * buf)249 static void bt_mesh_scan_cb(const bt_addr_le_t *addr, s8_t rssi,
250 			    u8_t adv_type, struct os_mbuf *buf)
251 {
252 	if (adv_type != BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
253 		return;
254 	}
255 
256 #if BT_MESH_EXTENDED_DEBUG
257 	BT_DBG("len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
258 #endif
259 
260 	while (buf->om_len > 1) {
261 		struct net_buf_simple_state state;
262 		u8_t len, type;
263 
264 		len = net_buf_simple_pull_u8(buf);
265 		/* Check for early termination */
266 		if (len == 0) {
267 			return;
268 		}
269 
270 		if (len > buf->om_len) {
271 			BT_WARN("AD malformed");
272 			return;
273 		}
274 
275 		net_buf_simple_save(buf, &state);
276 
277 		type = net_buf_simple_pull_u8(buf);
278 
279 		switch (type) {
280 		case BLE_HS_ADV_TYPE_MESH_MESSAGE:
281 			bt_mesh_net_recv(buf, rssi, BT_MESH_NET_IF_ADV);
282 			break;
283 #if MYNEWT_VAL(BLE_MESH_PB_ADV)
284 		case BLE_HS_ADV_TYPE_MESH_PROV:
285 			bt_mesh_pb_adv_recv(buf);
286 			break;
287 #endif
288 		case BLE_HS_ADV_TYPE_MESH_BEACON:
289 			bt_mesh_beacon_recv(buf);
290 			break;
291 		default:
292 			break;
293 		}
294 
295 		net_buf_simple_restore(buf, &state);
296 		net_buf_simple_pull(buf, len);
297 	}
298 }
299 
bt_mesh_adv_init(void)300 void bt_mesh_adv_init(void)
301 {
302 	int rc;
303 
304 	rc = os_mempool_init(&adv_buf_mempool, MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT),
305 			     BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE,
306 			     adv_buf_mem, "adv_buf_pool");
307 	assert(rc == 0);
308 
309 	rc = os_mbuf_pool_init(&adv_os_mbuf_pool, &adv_buf_mempool,
310 			       BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE,
311 			       MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT));
312 	assert(rc == 0);
313 
314 	ble_npl_eventq_init(&adv_queue);
315 
316 #if MYNEWT
317 	os_task_init(&adv_task, "mesh_adv", mesh_adv_thread, NULL,
318 	             MYNEWT_VAL(BLE_MESH_ADV_TASK_PRIO), OS_WAIT_FOREVER,
319 	             g_blemesh_stack, ADV_STACK_SIZE);
320 #endif
321 
322 	/* For BT5 controllers we can have fast advertising interval */
323 	if (ble_hs_hci_get_hci_version() >= BLE_HCI_VER_BCS_5_0) {
324 	    adv_int_min = ADV_INT_FAST_MS;
325 	}
326 }
327 
328 int
ble_adv_gap_mesh_cb(struct ble_gap_event * event,void * arg)329 ble_adv_gap_mesh_cb(struct ble_gap_event *event, void *arg)
330 {
331 #if MYNEWT_VAL(BLE_EXT_ADV)
332 	struct ble_gap_ext_disc_desc *ext_desc;
333 #endif
334 	struct ble_gap_disc_desc *desc;
335 	struct os_mbuf *buf = NULL;
336 
337 #if BT_MESH_EXTENDED_DEBUG
338 	BT_DBG("event->type %d", event->type);
339 #endif
340 
341 	switch (event->type) {
342 #if MYNEWT_VAL(BLE_EXT_ADV)
343 	case BLE_GAP_EVENT_EXT_DISC:
344 		ext_desc = &event->ext_disc;
345 		buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0);
346 		if (!buf || os_mbuf_append(buf, ext_desc->data, ext_desc->length_data)) {
347 			BT_ERR("Could not append data");
348 			goto done;
349 		}
350 		bt_mesh_scan_cb(&ext_desc->addr, ext_desc->rssi,
351 				ext_desc->legacy_event_type, buf);
352 		break;
353 #endif
354 	case BLE_GAP_EVENT_DISC:
355 		desc = &event->disc;
356 		buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0);
357 		if (!buf || os_mbuf_append(buf, desc->data, desc->length_data)) {
358 			BT_ERR("Could not append data");
359 			goto done;
360 		}
361 
362 		bt_mesh_scan_cb(&desc->addr, desc->rssi, desc->event_type, buf);
363 		break;
364 	default:
365 		break;
366 	}
367 
368 done:
369 	if (buf) {
370 		os_mbuf_free_chain(buf);
371 	}
372 
373 	return 0;
374 }
375 
bt_mesh_scan_enable(void)376 int bt_mesh_scan_enable(void)
377 {
378 #if MYNEWT_VAL(BLE_EXT_ADV)
379 	struct ble_gap_ext_disc_params uncoded_params =
380 		{ .itvl = MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW,
381 		.passive = 1 };
382 
383 	BT_DBG("");
384 
385 	return ble_gap_ext_disc(g_mesh_addr_type, 0, 0, 0, 0, 0,
386 				&uncoded_params, NULL, NULL, NULL);
387 #else
388 	struct ble_gap_disc_params scan_param =
389 		{ .passive = 1, .filter_duplicates = 0, .itvl =
390 		  MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW };
391 
392 	BT_DBG("");
393 
394 	return ble_gap_disc(g_mesh_addr_type, BLE_HS_FOREVER, &scan_param, NULL, NULL);
395 #endif
396 }
397 
bt_mesh_scan_disable(void)398 int bt_mesh_scan_disable(void)
399 {
400 	BT_DBG("");
401 
402 	return ble_gap_disc_cancel();
403 }
404