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