1 /*
2 * Copyright (c) 2018 Nordic Semiconductor ASA
3 * Copyright (c) 2017 Intel Corporation
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/kernel.h>
9 #include <zephyr/debug/stack.h>
10 #include <zephyr/sys/util.h>
11
12 #include <zephyr/net/buf.h>
13 #include <zephyr/bluetooth/bluetooth.h>
14 #include <zephyr/bluetooth/hci.h>
15 #include <zephyr/bluetooth/conn.h>
16 #include <zephyr/bluetooth/mesh.h>
17
18 #include "common/bt_str.h"
19
20 #include "net.h"
21 #include "foundation.h"
22 #include "beacon.h"
23 #include "prov.h"
24 #include "proxy.h"
25 #include "pb_gatt_srv.h"
26 #include "solicitation.h"
27 #include "statistic.h"
28
29 #define LOG_LEVEL CONFIG_BT_MESH_ADV_LOG_LEVEL
30 #include <zephyr/logging/log.h>
31 LOG_MODULE_REGISTER(bt_mesh_adv);
32
33 /* Window and Interval are equal for continuous scanning */
34 #define MESH_SCAN_INTERVAL BT_MESH_ADV_SCAN_UNIT(BT_MESH_SCAN_INTERVAL_MS)
35 #define MESH_SCAN_WINDOW BT_MESH_ADV_SCAN_UNIT(BT_MESH_SCAN_WINDOW_MS)
36
37 const uint8_t bt_mesh_adv_type[BT_MESH_ADV_TYPES] = {
38 [BT_MESH_ADV_PROV] = BT_DATA_MESH_PROV,
39 [BT_MESH_ADV_DATA] = BT_DATA_MESH_MESSAGE,
40 [BT_MESH_ADV_BEACON] = BT_DATA_MESH_BEACON,
41 [BT_MESH_ADV_URI] = BT_DATA_URI,
42 };
43
44 static bool active_scanning;
45 static K_FIFO_DEFINE(bt_mesh_adv_queue);
46 static K_FIFO_DEFINE(bt_mesh_relay_queue);
47 static K_FIFO_DEFINE(bt_mesh_friend_queue);
48
49 K_MEM_SLAB_DEFINE_STATIC(local_adv_pool, sizeof(struct bt_mesh_adv),
50 CONFIG_BT_MESH_ADV_BUF_COUNT, __alignof__(struct bt_mesh_adv));
51
52 #if defined(CONFIG_BT_MESH_RELAY_BUF_COUNT)
53 K_MEM_SLAB_DEFINE_STATIC(relay_adv_pool, sizeof(struct bt_mesh_adv),
54 CONFIG_BT_MESH_RELAY_BUF_COUNT, __alignof__(struct bt_mesh_adv));
55 #endif
56
57 #if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE)
58 K_MEM_SLAB_DEFINE_STATIC(friend_adv_pool, sizeof(struct bt_mesh_adv),
59 CONFIG_BT_MESH_FRIEND_LPN_COUNT, __alignof__(struct bt_mesh_adv));
60 #endif
61
bt_mesh_adv_send_start(uint16_t duration,int err,struct bt_mesh_adv_ctx * ctx)62 void bt_mesh_adv_send_start(uint16_t duration, int err, struct bt_mesh_adv_ctx *ctx)
63 {
64 if (!ctx->started) {
65 ctx->started = 1;
66
67 if (ctx->cb && ctx->cb->start) {
68 ctx->cb->start(duration, err, ctx->cb_data);
69 }
70
71 if (err) {
72 ctx->cb = NULL;
73 } else if (IS_ENABLED(CONFIG_BT_MESH_STATISTIC)) {
74 bt_mesh_stat_succeeded_count(ctx);
75 }
76 }
77 }
78
bt_mesh_adv_send_end(int err,struct bt_mesh_adv_ctx const * ctx)79 void bt_mesh_adv_send_end(int err, struct bt_mesh_adv_ctx const *ctx)
80 {
81 if (ctx->started && ctx->cb && ctx->cb->end) {
82 ctx->cb->end(err, ctx->cb_data);
83 }
84 }
85
adv_create_from_pool(struct k_mem_slab * buf_pool,enum bt_mesh_adv_type type,enum bt_mesh_adv_tag tag,uint8_t xmit,k_timeout_t timeout)86 static struct bt_mesh_adv *adv_create_from_pool(struct k_mem_slab *buf_pool,
87 enum bt_mesh_adv_type type,
88 enum bt_mesh_adv_tag tag,
89 uint8_t xmit, k_timeout_t timeout)
90 {
91 struct bt_mesh_adv_ctx *ctx;
92 struct bt_mesh_adv *adv;
93 int err;
94
95 if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) {
96 LOG_WRN("Refusing to allocate buffer while suspended");
97 return NULL;
98 }
99
100 err = k_mem_slab_alloc(buf_pool, (void **)&adv, timeout);
101 if (err) {
102 return NULL;
103 }
104
105 adv->__ref = 1;
106
107 net_buf_simple_init_with_data(&adv->b, adv->__bufs, BT_MESH_ADV_DATA_SIZE);
108 net_buf_simple_reset(&adv->b);
109
110 ctx = &adv->ctx;
111
112 (void)memset(ctx, 0, sizeof(*ctx));
113
114 ctx->type = type;
115 ctx->tag = tag;
116 ctx->xmit = xmit;
117
118 return adv;
119 }
120
bt_mesh_adv_ref(struct bt_mesh_adv * adv)121 struct bt_mesh_adv *bt_mesh_adv_ref(struct bt_mesh_adv *adv)
122 {
123 __ASSERT_NO_MSG(adv->__ref < UINT8_MAX);
124
125 adv->__ref++;
126
127 return adv;
128 }
129
bt_mesh_adv_unref(struct bt_mesh_adv * adv)130 void bt_mesh_adv_unref(struct bt_mesh_adv *adv)
131 {
132 __ASSERT_NO_MSG(adv->__ref > 0);
133
134 if (--adv->__ref > 0) {
135 return;
136 }
137
138 struct k_mem_slab *slab = &local_adv_pool;
139
140 #if defined(CONFIG_BT_MESH_RELAY)
141 if (adv->ctx.tag == BT_MESH_ADV_TAG_RELAY) {
142 slab = &relay_adv_pool;
143 }
144 #endif
145
146 #if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE)
147 if (adv->ctx.tag == BT_MESH_ADV_TAG_FRIEND) {
148 slab = &friend_adv_pool;
149 }
150 #endif
151
152 k_mem_slab_free(slab, (void *)adv);
153 }
154
bt_mesh_adv_create(enum bt_mesh_adv_type type,enum bt_mesh_adv_tag tag,uint8_t xmit,k_timeout_t timeout)155 struct bt_mesh_adv *bt_mesh_adv_create(enum bt_mesh_adv_type type,
156 enum bt_mesh_adv_tag tag,
157 uint8_t xmit, k_timeout_t timeout)
158 {
159 #if defined(CONFIG_BT_MESH_RELAY)
160 if (tag == BT_MESH_ADV_TAG_RELAY) {
161 return adv_create_from_pool(&relay_adv_pool,
162 type, tag, xmit, timeout);
163 }
164 #endif
165
166 #if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE)
167 if (tag == BT_MESH_ADV_TAG_FRIEND) {
168 return adv_create_from_pool(&friend_adv_pool,
169 type, tag, xmit, timeout);
170 }
171 #endif
172
173 return adv_create_from_pool(&local_adv_pool, type,
174 tag, xmit, timeout);
175 }
176
process_events(struct k_poll_event * ev,int count)177 static struct bt_mesh_adv *process_events(struct k_poll_event *ev, int count)
178 {
179 for (; count; ev++, count--) {
180 LOG_DBG("ev->state %u", ev->state);
181
182 switch (ev->state) {
183 case K_POLL_STATE_FIFO_DATA_AVAILABLE:
184 return k_fifo_get(ev->fifo, K_NO_WAIT);
185 case K_POLL_STATE_NOT_READY:
186 case K_POLL_STATE_CANCELLED:
187 break;
188 default:
189 LOG_WRN("Unexpected k_poll event state %u", ev->state);
190 break;
191 }
192 }
193
194 return NULL;
195 }
196
bt_mesh_adv_get(k_timeout_t timeout)197 struct bt_mesh_adv *bt_mesh_adv_get(k_timeout_t timeout)
198 {
199 int err;
200 struct k_poll_event events[] = {
201 K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE,
202 K_POLL_MODE_NOTIFY_ONLY,
203 &bt_mesh_adv_queue,
204 0),
205 #if defined(CONFIG_BT_MESH_RELAY) && \
206 (defined(CONFIG_BT_MESH_ADV_LEGACY) || \
207 defined(CONFIG_BT_MESH_ADV_EXT_RELAY_USING_MAIN_ADV_SET) || \
208 !(CONFIG_BT_MESH_RELAY_ADV_SETS))
209 K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE,
210 K_POLL_MODE_NOTIFY_ONLY,
211 &bt_mesh_relay_queue,
212 0),
213 #endif
214 };
215
216 err = k_poll(events, ARRAY_SIZE(events), timeout);
217 if (err) {
218 return NULL;
219 }
220
221 return process_events(events, ARRAY_SIZE(events));
222 }
223
bt_mesh_adv_get_by_tag(enum bt_mesh_adv_tag_bit tags,k_timeout_t timeout)224 struct bt_mesh_adv *bt_mesh_adv_get_by_tag(enum bt_mesh_adv_tag_bit tags, k_timeout_t timeout)
225 {
226 if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) &&
227 tags & BT_MESH_ADV_TAG_BIT_FRIEND) {
228 return k_fifo_get(&bt_mesh_friend_queue, timeout);
229 }
230
231 if (IS_ENABLED(CONFIG_BT_MESH_RELAY) &&
232 !(tags & BT_MESH_ADV_TAG_BIT_LOCAL)) {
233 return k_fifo_get(&bt_mesh_relay_queue, timeout);
234 }
235
236 return bt_mesh_adv_get(timeout);
237 }
238
bt_mesh_adv_get_cancel(void)239 void bt_mesh_adv_get_cancel(void)
240 {
241 LOG_DBG("");
242
243 k_fifo_cancel_wait(&bt_mesh_adv_queue);
244
245 if (IS_ENABLED(CONFIG_BT_MESH_RELAY)) {
246 k_fifo_cancel_wait(&bt_mesh_relay_queue);
247 }
248
249 if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE)) {
250 k_fifo_cancel_wait(&bt_mesh_friend_queue);
251 }
252 }
253
bt_mesh_adv_send(struct bt_mesh_adv * adv,const struct bt_mesh_send_cb * cb,void * cb_data)254 void bt_mesh_adv_send(struct bt_mesh_adv *adv, const struct bt_mesh_send_cb *cb,
255 void *cb_data)
256 {
257 LOG_DBG("type 0x%02x len %u: %s", adv->ctx.type, adv->b.len,
258 bt_hex(adv->b.data, adv->b.len));
259
260 if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) {
261 LOG_WRN("Sending advertisement while suspended");
262 }
263
264 adv->ctx.cb = cb;
265 adv->ctx.cb_data = cb_data;
266 adv->ctx.busy = 1U;
267
268 if (IS_ENABLED(CONFIG_BT_MESH_STATISTIC)) {
269 bt_mesh_stat_planned_count(&adv->ctx);
270 }
271
272 if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) &&
273 adv->ctx.tag == BT_MESH_ADV_TAG_FRIEND) {
274 k_fifo_put(&bt_mesh_friend_queue, bt_mesh_adv_ref(adv));
275 bt_mesh_adv_friend_ready();
276 return;
277 }
278
279 if ((IS_ENABLED(CONFIG_BT_MESH_RELAY) &&
280 adv->ctx.tag == BT_MESH_ADV_TAG_RELAY) ||
281 (IS_ENABLED(CONFIG_BT_MESH_PB_ADV_USE_RELAY_SETS) &&
282 adv->ctx.tag == BT_MESH_ADV_TAG_PROV)) {
283 k_fifo_put(&bt_mesh_relay_queue, bt_mesh_adv_ref(adv));
284 bt_mesh_adv_relay_ready();
285 return;
286 }
287
288 k_fifo_put(&bt_mesh_adv_queue, bt_mesh_adv_ref(adv));
289 bt_mesh_adv_local_ready();
290 }
291
bt_mesh_adv_gatt_send(void)292 int bt_mesh_adv_gatt_send(void)
293 {
294 if (bt_mesh_is_provisioned()) {
295 if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) {
296 LOG_DBG("Proxy Advertising");
297 return bt_mesh_proxy_adv_start();
298 }
299 } else if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) {
300 LOG_DBG("PB-GATT Advertising");
301 return bt_mesh_pb_gatt_srv_adv_start();
302 }
303
304 return -ENOTSUP;
305 }
306
bt_mesh_scan_cb(const bt_addr_le_t * addr,int8_t rssi,uint8_t adv_type,struct net_buf_simple * buf)307 static void bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi,
308 uint8_t adv_type, struct net_buf_simple *buf)
309 {
310 if (adv_type != BT_GAP_ADV_TYPE_ADV_NONCONN_IND) {
311 return;
312 }
313
314 LOG_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len));
315
316 while (buf->len > 1) {
317 struct net_buf_simple_state state;
318 uint8_t len, type;
319
320 len = net_buf_simple_pull_u8(buf);
321 /* Check for early termination */
322 if (len == 0U) {
323 return;
324 }
325
326 if (len > buf->len) {
327 LOG_WRN("AD malformed");
328 return;
329 }
330
331 net_buf_simple_save(buf, &state);
332
333 type = net_buf_simple_pull_u8(buf);
334
335 buf->len = len - 1;
336
337 switch (type) {
338 case BT_DATA_MESH_MESSAGE:
339 bt_mesh_net_recv(buf, rssi, BT_MESH_NET_IF_ADV);
340 break;
341 #if defined(CONFIG_BT_MESH_PB_ADV)
342 case BT_DATA_MESH_PROV:
343 bt_mesh_pb_adv_recv(buf);
344 break;
345 #endif
346 case BT_DATA_MESH_BEACON:
347 bt_mesh_beacon_recv(buf);
348 break;
349 case BT_DATA_UUID16_SOME:
350 /* Fall through */
351 case BT_DATA_UUID16_ALL:
352 if (IS_ENABLED(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV)) {
353 /* Restore buffer with Solicitation PDU */
354 net_buf_simple_restore(buf, &state);
355 bt_mesh_sol_recv(buf, len - 1);
356 }
357 break;
358 default:
359 break;
360 }
361
362 net_buf_simple_restore(buf, &state);
363 net_buf_simple_pull(buf, len);
364 }
365 }
366
bt_mesh_scan_active_set(bool active)367 int bt_mesh_scan_active_set(bool active)
368 {
369 if (active_scanning == active) {
370 return 0;
371 }
372
373 active_scanning = active;
374 bt_mesh_scan_disable();
375 return bt_mesh_scan_enable();
376 }
377
bt_mesh_scan_enable(void)378 int bt_mesh_scan_enable(void)
379 {
380 struct bt_le_scan_param scan_param = {
381 .type = active_scanning ? BT_HCI_LE_SCAN_ACTIVE :
382 BT_HCI_LE_SCAN_PASSIVE,
383 .interval = MESH_SCAN_INTERVAL,
384 .window = MESH_SCAN_WINDOW
385 };
386 int err;
387
388 LOG_DBG("");
389
390 err = bt_le_scan_start(&scan_param, bt_mesh_scan_cb);
391 if (err && err != -EALREADY) {
392 LOG_ERR("starting scan failed (err %d)", err);
393 return err;
394 }
395
396 return 0;
397 }
398
bt_mesh_scan_disable(void)399 int bt_mesh_scan_disable(void)
400 {
401 int err;
402
403 LOG_DBG("");
404
405 err = bt_le_scan_stop();
406 if (err && err != -EALREADY) {
407 LOG_ERR("stopping scan failed (err %d)", err);
408 return err;
409 }
410
411 return 0;
412 }
413