zephyr/subsys/bluetooth/mesh/adv.c
Lingao Meng 56785c173b Bluetooth: Mesh: Add Multi Advertising Sets Support
This PR add multi advertising sets for bluetooth mesh adv bearer.
At the present, the local mesh network occupy single advertising.
And GATT Services Advertising use a single advertising, if support.

One or more advertising sets maybe used by relay node.

Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
2021-12-02 09:23:54 +02:00

269 lines
5.9 KiB
C

/*
* Copyright (c) 2018 Nordic Semiconductor ASA
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <debug/stack.h>
#include <sys/util.h>
#include <net/buf.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/conn.h>
#include <bluetooth/mesh.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_ADV)
#define LOG_MODULE_NAME bt_mesh_adv
#include "common/log.h"
#include "adv.h"
#include "net.h"
#include "foundation.h"
#include "beacon.h"
#include "host/ecc.h"
#include "prov.h"
#include "proxy.h"
/* Window and Interval are equal for continuous scanning */
#define MESH_SCAN_INTERVAL BT_MESH_ADV_SCAN_UNIT(BT_MESH_SCAN_INTERVAL_MS)
#define MESH_SCAN_WINDOW BT_MESH_ADV_SCAN_UNIT(BT_MESH_SCAN_WINDOW_MS)
typedef struct bt_mesh_adv *(*bt_mesh_adv_alloc_t)(int id);
const uint8_t bt_mesh_adv_type[BT_MESH_ADV_TYPES] = {
[BT_MESH_ADV_PROV] = BT_DATA_MESH_PROV,
[BT_MESH_ADV_DATA] = BT_DATA_MESH_MESSAGE,
[BT_MESH_ADV_BEACON] = BT_DATA_MESH_BEACON,
[BT_MESH_ADV_URI] = BT_DATA_URI,
};
static K_FIFO_DEFINE(bt_mesh_adv_queue);
static K_FIFO_DEFINE(bt_mesh_relay_queue);
static void adv_buf_destroy(struct net_buf *buf)
{
struct bt_mesh_adv adv = *BT_MESH_ADV(buf);
net_buf_destroy(buf);
bt_mesh_adv_send_end(0, &adv);
}
NET_BUF_POOL_DEFINE(adv_buf_pool, CONFIG_BT_MESH_ADV_BUF_COUNT,
BT_MESH_ADV_DATA_SIZE, BT_MESH_ADV_USER_DATA_SIZE,
adv_buf_destroy);
static struct bt_mesh_adv adv_pool[CONFIG_BT_MESH_ADV_BUF_COUNT];
static struct bt_mesh_adv *adv_alloc(int id)
{
return &adv_pool[id];
}
struct net_buf *bt_mesh_adv_create_from_pool(struct net_buf_pool *pool,
bt_mesh_adv_alloc_t get_id,
enum bt_mesh_adv_type type,
enum bt_mesh_adv_tag tag,
uint8_t xmit, k_timeout_t timeout)
{
struct bt_mesh_adv *adv;
struct net_buf *buf;
if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) {
BT_WARN("Refusing to allocate buffer while suspended");
return NULL;
}
buf = net_buf_alloc(pool, timeout);
if (!buf) {
return NULL;
}
adv = get_id(net_buf_id(buf));
BT_MESH_ADV(buf) = adv;
(void)memset(adv, 0, sizeof(*adv));
adv->type = type;
adv->tag = tag;
adv->xmit = xmit;
return buf;
}
struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type,
enum bt_mesh_adv_tag tag,
uint8_t xmit, k_timeout_t timeout)
{
return bt_mesh_adv_create_from_pool(&adv_buf_pool, adv_alloc, type,
tag, xmit, timeout);
}
static struct net_buf *process_events(struct k_poll_event *ev, int count)
{
for (; count; ev++, count--) {
BT_DBG("ev->state %u", ev->state);
switch (ev->state) {
case K_POLL_STATE_FIFO_DATA_AVAILABLE:
return net_buf_get(ev->fifo, K_NO_WAIT);
case K_POLL_STATE_NOT_READY:
case K_POLL_STATE_CANCELLED:
break;
default:
BT_WARN("Unexpected k_poll event state %u", ev->state);
break;
}
}
return NULL;
}
struct net_buf *bt_mesh_adv_buf_get(k_timeout_t timeout)
{
int err;
struct k_poll_event events[] = {
K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&bt_mesh_adv_queue,
0),
#if defined(CONFIG_BT_MESH_RELAY)
K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&bt_mesh_relay_queue,
0),
#endif /* CONFIG_BT_MESH_RELAY */
};
err = k_poll(events, ARRAY_SIZE(events), timeout);
if (err) {
return NULL;
}
return process_events(events, ARRAY_SIZE(events));
}
struct net_buf *bt_mesh_adv_buf_relay_get(k_timeout_t timeout)
{
return net_buf_get(&bt_mesh_relay_queue, timeout);
}
void bt_mesh_adv_buf_get_cancel(void)
{
BT_DBG("");
k_fifo_cancel_wait(&bt_mesh_adv_queue);
#if defined(CONFIG_BT_MESH_RELAY)
k_fifo_cancel_wait(&bt_mesh_relay_queue);
#endif /* CONFIG_BT_MESH_RELAY */
}
void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb,
void *cb_data)
{
BT_DBG("type 0x%02x len %u: %s", BT_MESH_ADV(buf)->type, buf->len,
bt_hex(buf->data, buf->len));
BT_MESH_ADV(buf)->cb = cb;
BT_MESH_ADV(buf)->cb_data = cb_data;
BT_MESH_ADV(buf)->busy = 1U;
if (BT_MESH_ADV(buf)->tag == BT_MESH_LOCAL_ADV) {
net_buf_put(&bt_mesh_adv_queue, net_buf_ref(buf));
bt_mesh_adv_buf_local_ready();
} else {
net_buf_put(&bt_mesh_relay_queue, net_buf_ref(buf));
bt_mesh_adv_buf_relay_ready();
}
}
static void bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi,
uint8_t adv_type, struct net_buf_simple *buf)
{
if (adv_type != BT_GAP_ADV_TYPE_ADV_NONCONN_IND) {
return;
}
BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len));
while (buf->len > 1) {
struct net_buf_simple_state state;
uint8_t len, type;
len = net_buf_simple_pull_u8(buf);
/* Check for early termination */
if (len == 0U) {
return;
}
if (len > buf->len) {
BT_WARN("AD malformed");
return;
}
net_buf_simple_save(buf, &state);
type = net_buf_simple_pull_u8(buf);
buf->len = len - 1;
switch (type) {
case BT_DATA_MESH_MESSAGE:
bt_mesh_net_recv(buf, rssi, BT_MESH_NET_IF_ADV);
break;
#if defined(CONFIG_BT_MESH_PB_ADV)
case BT_DATA_MESH_PROV:
bt_mesh_pb_adv_recv(buf);
break;
#endif
case BT_DATA_MESH_BEACON:
bt_mesh_beacon_recv(buf);
break;
default:
break;
}
net_buf_simple_restore(buf, &state);
net_buf_simple_pull(buf, len);
}
}
int bt_mesh_scan_enable(void)
{
struct bt_le_scan_param scan_param = {
.type = BT_HCI_LE_SCAN_PASSIVE,
.options = BT_LE_SCAN_OPT_NONE,
.interval = MESH_SCAN_INTERVAL,
.window = MESH_SCAN_WINDOW };
int err;
BT_DBG("");
err = bt_le_scan_start(&scan_param, bt_mesh_scan_cb);
if (err && err != -EALREADY) {
BT_ERR("starting scan failed (err %d)", err);
return err;
}
return 0;
}
int bt_mesh_scan_disable(void)
{
int err;
BT_DBG("");
err = bt_le_scan_stop();
if (err && err != -EALREADY) {
BT_ERR("stopping scan failed (err %d)", err);
return err;
}
return 0;
}