2017-06-16 12:30:54 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2017 Intel Corporation
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
includes: prefer <zephyr/kernel.h> over <zephyr/zephyr.h>
As of today <zephyr/zephyr.h> is 100% equivalent to <zephyr/kernel.h>.
This patch proposes to then include <zephyr/kernel.h> instead of
<zephyr/zephyr.h> since it is more clear that you are including the
Kernel APIs and (probably) nothing else. <zephyr/zephyr.h> sounds like a
catch-all header that may be confusing. Most applications need to
include a bunch of other things to compile, e.g. driver headers or
subsystem headers like BT, logging, etc.
The idea of a catch-all header in Zephyr is probably not feasible
anyway. Reason is that Zephyr is not a library, like it could be for
example `libpython`. Zephyr provides many utilities nowadays: a kernel,
drivers, subsystems, etc and things will likely grow. A catch-all header
would be massive, difficult to keep up-to-date. It is also likely that
an application will only build a small subset. Note that subsystem-level
headers may use a catch-all approach to make things easier, though.
NOTE: This patch is **NOT** removing the header, just removing its usage
in-tree. I'd advocate for its deprecation (add a #warning on it), but I
understand many people will have concerns.
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
2022-08-25 09:58:46 +02:00
|
|
|
#include <zephyr/kernel.h>
|
2017-06-16 12:30:54 +03:00
|
|
|
#include <errno.h>
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/sys/util.h>
|
2020-06-02 12:04:53 +02:00
|
|
|
#include <zephyr/sys/byteorder.h>
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/net/buf.h>
|
|
|
|
#include <zephyr/bluetooth/bluetooth.h>
|
|
|
|
#include <zephyr/bluetooth/conn.h>
|
|
|
|
#include <zephyr/bluetooth/mesh.h>
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2022-10-25 08:48:54 +02:00
|
|
|
#include "common/bt_str.h"
|
2017-06-16 12:30:54 +03:00
|
|
|
|
|
|
|
#include "adv.h"
|
|
|
|
#include "mesh.h"
|
|
|
|
#include "net.h"
|
2021-08-09 12:18:08 +02:00
|
|
|
#include "host/ecc.h"
|
2017-06-16 12:30:54 +03:00
|
|
|
#include "prov.h"
|
|
|
|
#include "crypto.h"
|
|
|
|
#include "beacon.h"
|
2020-06-02 12:04:53 +02:00
|
|
|
#include "cfg.h"
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
#define LOG_LEVEL CONFIG_BT_MESH_BEACON_LOG_LEVEL
|
|
|
|
#include <zephyr/logging/log.h>
|
|
|
|
LOG_MODULE_REGISTER(bt_mesh_beacon);
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
#define PROVISIONED_INTERVAL K_SECONDS(10)
|
|
|
|
|
|
|
|
#define BEACON_TYPE_UNPROVISIONED 0x00
|
|
|
|
#define BEACON_TYPE_SECURE 0x01
|
2020-06-02 12:04:53 +02:00
|
|
|
#define BEACON_TYPE_PRIVATE 0x02
|
2017-06-16 12:30:54 +03:00
|
|
|
|
|
|
|
/* 3 transmissions, 20ms interval */
|
2018-06-04 14:06:48 +02:00
|
|
|
#define UNPROV_XMIT BT_MESH_TRANSMIT(2, 20)
|
2017-06-16 12:30:54 +03:00
|
|
|
|
|
|
|
/* 1 transmission, 20ms interval */
|
2018-06-04 14:06:48 +02:00
|
|
|
#define PROV_XMIT BT_MESH_TRANSMIT(0, 20)
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2021-04-15 16:10:25 +02:00
|
|
|
static struct k_work_delayable beacon_timer;
|
2020-06-02 12:04:53 +02:00
|
|
|
static struct {
|
|
|
|
/**
|
|
|
|
* Identifier for the current Private beacon random-value.
|
|
|
|
* Each time we regenerate the random-value, we'll update this idx.
|
|
|
|
* Whenever it's time for a subnet to create a beacon, it'll compare
|
|
|
|
* the subnet's beacon idx to determine whether the random value has
|
|
|
|
* changed since the last beacon was sent. If this is the case, we'll
|
|
|
|
* regenerate the beacon based on the new random value.
|
|
|
|
*/
|
|
|
|
uint16_t idx;
|
|
|
|
uint8_t val[13];
|
|
|
|
uint64_t timestamp;
|
|
|
|
} priv_random;
|
|
|
|
|
|
|
|
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
|
|
|
static int private_beacon_create(struct bt_mesh_subnet *sub,
|
|
|
|
struct net_buf_simple *buf);
|
|
|
|
static int private_beacon_update(struct bt_mesh_subnet *sub);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static bool beacon_cache_match(struct bt_mesh_subnet *sub, void *auth)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
2020-06-02 12:04:53 +02:00
|
|
|
return !memcmp(sub->beacon_cache, auth, sizeof(sub->beacon_cache));
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
static void cache_add(const uint8_t auth[8], struct bt_mesh_subnet *sub)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
2020-06-02 12:04:53 +02:00
|
|
|
memcpy(sub->beacon_cache, auth, sizeof(sub->beacon_cache));
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2022-03-02 17:19:42 +08:00
|
|
|
void bt_mesh_beacon_cache_clear(struct bt_mesh_subnet *sub)
|
|
|
|
{
|
2020-06-02 12:04:53 +02:00
|
|
|
(void)memset(sub->beacon_cache, 0, sizeof(sub->beacon_cache));
|
2022-03-02 17:19:42 +08:00
|
|
|
}
|
|
|
|
|
2017-11-17 12:40:18 +02:00
|
|
|
static void beacon_complete(int err, void *user_data)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
2017-11-17 11:58:06 +02:00
|
|
|
struct bt_mesh_subnet *sub = user_data;
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("err %d", err);
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2017-11-17 12:40:18 +02:00
|
|
|
sub->beacon_sent = k_uptime_get_32();
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
static void secure_beacon_create(struct bt_mesh_subnet *sub,
|
|
|
|
struct net_buf_simple *buf)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint8_t flags = bt_mesh_net_flags(sub);
|
2017-06-16 12:30:54 +03:00
|
|
|
struct bt_mesh_subnet_keys *keys;
|
|
|
|
|
|
|
|
net_buf_simple_add_u8(buf, BEACON_TYPE_SECURE);
|
|
|
|
|
2020-08-25 11:03:42 +02:00
|
|
|
keys = &sub->keys[SUBNET_KEY_TX_IDX(sub)];
|
2017-06-16 12:30:54 +03:00
|
|
|
|
|
|
|
net_buf_simple_add_u8(buf, flags);
|
|
|
|
|
|
|
|
/* Network ID */
|
|
|
|
net_buf_simple_add_mem(buf, keys->net_id, 8);
|
|
|
|
|
|
|
|
/* IV Index */
|
|
|
|
net_buf_simple_add_be32(buf, bt_mesh.iv_index);
|
|
|
|
|
|
|
|
net_buf_simple_add_mem(buf, sub->auth, 8);
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("net_idx 0x%04x flags 0x%02x NetID %s", sub->net_idx, flags,
|
|
|
|
bt_hex(keys->net_id, 8));
|
|
|
|
LOG_DBG("IV Index 0x%08x Auth %s", bt_mesh.iv_index, bt_hex(sub->auth, 8));
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
|
|
|
static int private_random_update(void)
|
|
|
|
{
|
|
|
|
uint8_t interval = bt_mesh_priv_beacon_update_interval_get();
|
|
|
|
uint64_t uptime = k_uptime_get();
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* The Private beacon random value should change every N seconds to maintain privacy.
|
|
|
|
* N = (10 * interval) seconds, or on every beacon creation, if the interval is 0.
|
|
|
|
*/
|
|
|
|
if (interval &&
|
|
|
|
uptime - priv_random.timestamp < (10 * interval * MSEC_PER_SEC)) {
|
|
|
|
/* Not time yet */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bt_rand(priv_random.val, sizeof(priv_random.val));
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the index to indicate to all subnets that the private beacon must be regenerated.
|
|
|
|
* Each subnet maintains the random index their private beacon data was generated with.
|
|
|
|
*/
|
|
|
|
priv_random.idx++;
|
|
|
|
priv_random.timestamp = uptime;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int private_beacon_update(struct bt_mesh_subnet *sub)
|
|
|
|
{
|
|
|
|
struct bt_mesh_subnet_keys *keys = &sub->keys[SUBNET_KEY_TX_IDX(sub)];
|
|
|
|
uint8_t flags = bt_mesh_net_flags(sub);
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = bt_mesh_beacon_encrypt(keys->priv_beacon, flags, bt_mesh.iv_index,
|
|
|
|
priv_random.val, sub->priv_beacon.data,
|
|
|
|
sub->auth);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub->priv_beacon.idx = priv_random.idx;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int private_beacon_create(struct bt_mesh_subnet *sub,
|
|
|
|
struct net_buf_simple *buf)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* Refresh beacon data */
|
|
|
|
err = private_random_update();
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sub->priv_beacon.idx != priv_random.idx) {
|
|
|
|
err = private_beacon_update(sub);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
net_buf_simple_add_u8(buf, BEACON_TYPE_PRIVATE);
|
|
|
|
net_buf_simple_add_mem(buf, priv_random.val, 13);
|
|
|
|
net_buf_simple_add_mem(buf, sub->priv_beacon.data, 5);
|
|
|
|
net_buf_simple_add_mem(buf, sub->auth, 8);
|
|
|
|
|
|
|
|
LOG_DBG("0x%03x", sub->net_idx);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
|
|
|
|
struct net_buf_simple *buf)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
|
|
|
if (bt_mesh_priv_beacon_get() == BT_MESH_FEATURE_ENABLED) {
|
|
|
|
return private_beacon_create(sub, buf);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
secure_beacon_create(sub, buf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-11-10 13:12:53 +02:00
|
|
|
/* If the interval has passed or is within 5 seconds from now send a beacon */
|
2020-04-06 13:56:14 +02:00
|
|
|
#define BEACON_THRESHOLD(sub) \
|
|
|
|
((10 * ((sub)->beacons_last + 1)) * MSEC_PER_SEC - (5 * MSEC_PER_SEC))
|
2017-11-10 13:12:53 +02:00
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
static bool net_beacon_send(struct bt_mesh_subnet *sub, void *cb_data)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
2017-11-17 15:19:51 +02:00
|
|
|
static const struct bt_mesh_send_cb send_cb = {
|
|
|
|
.end = beacon_complete,
|
2017-11-17 12:40:18 +02:00
|
|
|
};
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t now = k_uptime_get_32();
|
2020-08-25 11:03:42 +02:00
|
|
|
struct net_buf *buf;
|
|
|
|
uint32_t time_diff;
|
2022-02-25 15:13:08 +01:00
|
|
|
uint32_t time_since_last_recv;
|
2020-06-02 12:04:53 +02:00
|
|
|
int err;
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("");
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2020-08-25 11:03:42 +02:00
|
|
|
time_diff = now - sub->beacon_sent;
|
2022-02-25 15:13:08 +01:00
|
|
|
time_since_last_recv = now - sub->beacon_recv;
|
2020-08-25 11:03:42 +02:00
|
|
|
if (time_diff < (600 * MSEC_PER_SEC) &&
|
2022-02-25 15:13:08 +01:00
|
|
|
(time_diff < BEACON_THRESHOLD(sub) ||
|
|
|
|
time_since_last_recv < (10 * MSEC_PER_SEC))) {
|
2022-01-13 07:48:53 +01:00
|
|
|
return false;
|
2020-08-25 11:03:42 +02:00
|
|
|
}
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2021-11-11 10:26:52 +08:00
|
|
|
buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, BT_MESH_LOCAL_ADV,
|
|
|
|
PROV_XMIT, K_NO_WAIT);
|
2020-08-25 11:03:42 +02:00
|
|
|
if (!buf) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Unable to allocate beacon buffer");
|
2022-01-13 07:48:53 +01:00
|
|
|
return true; /* Bail out */
|
2020-08-25 11:03:42 +02:00
|
|
|
}
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
err = bt_mesh_beacon_create(sub, &buf->b);
|
|
|
|
if (err) {
|
|
|
|
return true; /* Bail out */
|
|
|
|
}
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2020-08-25 11:03:42 +02:00
|
|
|
bt_mesh_adv_send(buf, &send_cb, sub);
|
|
|
|
net_buf_unref(buf);
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2022-01-13 07:48:53 +01:00
|
|
|
return false;
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int unprovisioned_beacon_send(void)
|
|
|
|
{
|
2018-01-28 15:44:25 -08:00
|
|
|
const struct bt_mesh_prov *prov;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint8_t uri_hash[16] = { 0 };
|
2017-06-16 12:30:54 +03:00
|
|
|
struct net_buf *buf;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t oob_info;
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("");
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2021-11-11 10:26:52 +08:00
|
|
|
buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, BT_MESH_LOCAL_ADV,
|
|
|
|
UNPROV_XMIT, K_NO_WAIT);
|
2017-06-16 12:30:54 +03:00
|
|
|
if (!buf) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Unable to allocate beacon buffer");
|
2017-06-16 12:30:54 +03:00
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2018-01-28 15:44:25 -08:00
|
|
|
prov = bt_mesh_prov_get();
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
net_buf_add_u8(buf, BEACON_TYPE_UNPROVISIONED);
|
2018-01-28 15:44:25 -08:00
|
|
|
net_buf_add_mem(buf, prov->uuid, 16);
|
|
|
|
|
2021-08-09 16:43:16 +02:00
|
|
|
if (prov->uri && bt_mesh_s1_str(prov->uri, uri_hash) == 0) {
|
2018-01-28 15:44:25 -08:00
|
|
|
oob_info = prov->oob_info | BT_MESH_PROV_OOB_URI;
|
|
|
|
} else {
|
|
|
|
oob_info = prov->oob_info;
|
|
|
|
}
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2018-01-28 15:44:25 -08:00
|
|
|
net_buf_add_be16(buf, oob_info);
|
|
|
|
net_buf_add_mem(buf, uri_hash, 4);
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2017-11-17 11:58:06 +02:00
|
|
|
bt_mesh_adv_send(buf, NULL, NULL);
|
2017-06-16 12:30:54 +03:00
|
|
|
net_buf_unref(buf);
|
|
|
|
|
2018-01-28 15:44:25 -08:00
|
|
|
if (prov->uri) {
|
|
|
|
size_t len;
|
|
|
|
|
2021-11-11 10:26:52 +08:00
|
|
|
buf = bt_mesh_adv_create(BT_MESH_ADV_URI, BT_MESH_LOCAL_ADV,
|
|
|
|
UNPROV_XMIT, K_NO_WAIT);
|
2018-01-28 15:44:25 -08:00
|
|
|
if (!buf) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Unable to allocate URI buffer");
|
2018-01-28 15:44:25 -08:00
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = strlen(prov->uri);
|
|
|
|
if (net_buf_tailroom(buf) < len) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Too long URI to fit advertising data");
|
2018-01-28 15:44:25 -08:00
|
|
|
} else {
|
|
|
|
net_buf_add_mem(buf, prov->uri, len);
|
|
|
|
bt_mesh_adv_send(buf, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
net_buf_unref(buf);
|
|
|
|
}
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-13 12:18:43 +02:00
|
|
|
static void unprovisioned_beacon_recv(struct net_buf_simple *buf)
|
|
|
|
{
|
|
|
|
const struct bt_mesh_prov *prov;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint8_t *uuid;
|
|
|
|
uint16_t oob_info;
|
|
|
|
uint32_t uri_hash_val;
|
|
|
|
uint32_t *uri_hash = NULL;
|
2019-07-13 12:18:43 +02:00
|
|
|
|
2022-09-14 11:50:11 +02:00
|
|
|
prov = bt_mesh_prov_get();
|
|
|
|
|
|
|
|
if (!prov->unprovisioned_beacon) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-07-13 12:18:43 +02:00
|
|
|
if (buf->len != 18 && buf->len != 22) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Invalid unprovisioned beacon length (%u)", buf->len);
|
2019-07-13 12:18:43 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uuid = net_buf_simple_pull_mem(buf, 16);
|
|
|
|
oob_info = net_buf_simple_pull_be16(buf);
|
|
|
|
|
|
|
|
if (buf->len == 4) {
|
|
|
|
uri_hash_val = net_buf_simple_pull_be32(buf);
|
|
|
|
uri_hash = &uri_hash_val;
|
|
|
|
}
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("uuid %s", bt_hex(uuid, 16));
|
2019-07-13 12:18:43 +02:00
|
|
|
|
2022-09-14 11:50:11 +02:00
|
|
|
prov->unprovisioned_beacon(uuid,
|
|
|
|
(bt_mesh_prov_oob_info_t)oob_info,
|
|
|
|
uri_hash);
|
2019-07-13 12:18:43 +02:00
|
|
|
}
|
|
|
|
|
2020-08-25 11:03:42 +02:00
|
|
|
static void sub_update_beacon_observation(struct bt_mesh_subnet *sub)
|
|
|
|
{
|
|
|
|
sub->beacons_last = sub->beacons_cur;
|
|
|
|
sub->beacons_cur = 0U;
|
|
|
|
}
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
static void update_beacon_observation(void)
|
|
|
|
{
|
|
|
|
static bool first_half;
|
|
|
|
|
|
|
|
/* Observation period is 20 seconds, whereas the beacon timer
|
|
|
|
* runs every 10 seconds. We process what's happened during the
|
2022-03-16 21:07:43 +00:00
|
|
|
* window only after the second half.
|
2017-06-16 12:30:54 +03:00
|
|
|
*/
|
|
|
|
first_half = !first_half;
|
|
|
|
if (first_half) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-08-25 11:03:42 +02:00
|
|
|
bt_mesh_subnet_foreach(sub_update_beacon_observation);
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
static bool net_beacon_is_running(void)
|
|
|
|
{
|
|
|
|
return bt_mesh_beacon_enabled() ||
|
|
|
|
atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR) ||
|
|
|
|
(bt_mesh_priv_beacon_get() == BT_MESH_FEATURE_ENABLED);
|
|
|
|
}
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
static void beacon_send(struct k_work *work)
|
|
|
|
{
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("");
|
2017-06-16 12:30:54 +03:00
|
|
|
|
|
|
|
if (bt_mesh_is_provisioned()) {
|
2020-06-02 12:04:53 +02:00
|
|
|
if (!net_beacon_is_running()) {
|
2021-04-15 16:10:25 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
update_beacon_observation();
|
2020-06-02 12:04:53 +02:00
|
|
|
(void)bt_mesh_subnet_find(net_beacon_send, NULL);
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2021-04-15 16:10:25 +02:00
|
|
|
k_work_schedule(&beacon_timer, PROVISIONED_INTERVAL);
|
2020-08-10 10:55:21 +08:00
|
|
|
return;
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
2020-09-01 15:17:27 +03:00
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV)) {
|
2021-04-15 16:10:25 +02:00
|
|
|
/* Don't send anything if we have an active provisioning link */
|
|
|
|
if (!bt_mesh_prov_active()) {
|
|
|
|
unprovisioned_beacon_send();
|
|
|
|
}
|
|
|
|
|
|
|
|
k_work_schedule(&beacon_timer, K_SECONDS(CONFIG_BT_MESH_UNPROV_BEACON_INT));
|
2020-09-01 15:17:27 +03:00
|
|
|
}
|
2021-04-15 16:10:25 +02:00
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 11:03:42 +02:00
|
|
|
struct beacon_params {
|
2020-06-02 12:04:53 +02:00
|
|
|
union {
|
|
|
|
const uint8_t *net_id;
|
|
|
|
struct {
|
|
|
|
const uint8_t *data;
|
|
|
|
const uint8_t *random;
|
|
|
|
} private;
|
|
|
|
};
|
2020-08-25 11:03:42 +02:00
|
|
|
const uint8_t *auth;
|
|
|
|
uint32_t iv_index;
|
|
|
|
uint8_t flags;
|
|
|
|
|
|
|
|
bool new_key;
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool auth_match(struct bt_mesh_subnet_keys *keys,
|
|
|
|
const struct beacon_params *params)
|
|
|
|
{
|
|
|
|
uint8_t net_auth[8];
|
|
|
|
|
|
|
|
if (memcmp(params->net_id, keys->net_id, 8)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_mesh_beacon_auth(keys->beacon, params->flags, keys->net_id,
|
|
|
|
params->iv_index, net_auth);
|
|
|
|
|
|
|
|
if (memcmp(params->auth, net_auth, 8)) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Authentication Value %s != %s", bt_hex(params->auth, 8),
|
|
|
|
bt_hex(net_auth, 8));
|
2020-08-25 11:03:42 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
static bool secure_beacon_authenticate(struct bt_mesh_subnet *sub, void *cb_data)
|
2020-08-25 11:03:42 +02:00
|
|
|
{
|
|
|
|
struct beacon_params *params = cb_data;
|
|
|
|
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(sub->keys); i++) {
|
|
|
|
if (sub->keys[i].valid && auth_match(&sub->keys[i], params)) {
|
|
|
|
params->new_key = (i > 0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
static bool priv_beacon_decrypt(struct bt_mesh_subnet *sub, void *cb_data)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
2020-06-02 12:04:53 +02:00
|
|
|
struct beacon_params *params = cb_data;
|
|
|
|
uint8_t out[5];
|
|
|
|
int err;
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
for (int i = 0; i < ARRAY_SIZE(sub->keys); i++) {
|
|
|
|
if (!sub->keys[i].valid) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bt_mesh_beacon_decrypt(sub->keys[i].priv_beacon,
|
|
|
|
params->private.random,
|
|
|
|
params->private.data, params->auth,
|
|
|
|
out);
|
|
|
|
if (!err) {
|
|
|
|
params->new_key = (i > 0);
|
|
|
|
params->flags = out[0];
|
|
|
|
params->iv_index = sys_get_be32(&out[1]);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void net_beacon_register(struct bt_mesh_subnet *sub)
|
|
|
|
{
|
|
|
|
if (bt_mesh_beacon_enabled() && sub->beacons_cur < 0xff) {
|
|
|
|
sub->beacons_cur++;
|
|
|
|
sub->beacon_recv = k_uptime_get_32();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void net_beacon_recv(struct bt_mesh_subnet *sub,
|
|
|
|
const struct beacon_params *params)
|
|
|
|
{
|
|
|
|
bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(params->flags),
|
|
|
|
params->new_key);
|
|
|
|
|
|
|
|
/* If we have NetKey0 accept IV index initiation only from it */
|
|
|
|
if (bt_mesh_subnet_get(BT_MESH_KEY_PRIMARY) &&
|
|
|
|
sub->net_idx != BT_MESH_KEY_PRIMARY) {
|
|
|
|
LOG_WRN("Ignoring secure beacon on non-primary subnet");
|
2017-06-16 12:30:54 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
LOG_DBG("net_idx 0x%04x flags %u iv_index 0x%08x, "
|
|
|
|
"current iv_index 0x%08x",
|
|
|
|
sub->net_idx, params->flags, params->iv_index, bt_mesh.iv_index);
|
|
|
|
|
|
|
|
if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR) &&
|
|
|
|
(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) ==
|
|
|
|
BT_MESH_IV_UPDATE(params->flags))) {
|
|
|
|
bt_mesh_beacon_ivu_initiator(false);
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
bt_mesh_net_iv_update(params->iv_index,
|
|
|
|
BT_MESH_IV_UPDATE(params->flags));
|
|
|
|
}
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
static void net_beacon_resolve(struct beacon_params *params,
|
|
|
|
bool (*matcher)(struct bt_mesh_subnet *sub,
|
|
|
|
void *cb_data))
|
|
|
|
{
|
|
|
|
struct bt_mesh_subnet *sub;
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
sub = bt_mesh_subnet_find(beacon_cache_match, (void *)params->auth);
|
|
|
|
if (sub) {
|
|
|
|
/* We've seen this beacon before - just update the stats */
|
|
|
|
net_beacon_register(sub);
|
|
|
|
return;
|
|
|
|
}
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
sub = bt_mesh_subnet_find(matcher, params);
|
2017-06-16 12:30:54 +03:00
|
|
|
if (!sub) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("No subnet that matched beacon");
|
2017-06-16 12:30:54 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !params->new_key) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Ignoring Phase 2 KR Update secured using old key");
|
2017-06-16 12:30:54 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
cache_add(params->auth, sub);
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
net_beacon_recv(sub, params);
|
|
|
|
net_beacon_register(sub);
|
|
|
|
}
|
2020-06-22 13:29:04 +02:00
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
static void secure_beacon_recv(struct net_buf_simple *buf)
|
|
|
|
{
|
|
|
|
struct beacon_params params;
|
|
|
|
|
|
|
|
if (buf->len < 21) {
|
|
|
|
LOG_ERR("Too short secure beacon (len %u)", buf->len);
|
|
|
|
return;
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
params.flags = net_buf_simple_pull_u8(buf);
|
|
|
|
params.net_id = net_buf_simple_pull_mem(buf, 8);
|
|
|
|
params.iv_index = net_buf_simple_pull_be32(buf);
|
|
|
|
params.auth = buf->data;
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
net_beacon_resolve(¶ms, secure_beacon_authenticate);
|
|
|
|
}
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
static void private_beacon_recv(struct net_buf_simple *buf)
|
|
|
|
{
|
|
|
|
struct beacon_params params;
|
2017-10-31 16:16:28 +02:00
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
if (buf->len < 26) {
|
|
|
|
LOG_ERR("Too short private beacon (len %u)", buf->len);
|
|
|
|
return;
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
2020-06-02 12:04:53 +02:00
|
|
|
|
|
|
|
params.private.random = net_buf_simple_pull_mem(buf, 13);
|
|
|
|
params.private.data = net_buf_simple_pull_mem(buf, 5);
|
|
|
|
params.auth = buf->data;
|
|
|
|
|
|
|
|
net_beacon_resolve(¶ms, priv_beacon_decrypt);
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_mesh_beacon_recv(struct net_buf_simple *buf)
|
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint8_t type;
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len));
|
2017-06-16 12:30:54 +03:00
|
|
|
|
|
|
|
if (buf->len < 1) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Too short beacon");
|
2017-06-16 12:30:54 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = net_buf_simple_pull_u8(buf);
|
|
|
|
switch (type) {
|
|
|
|
case BEACON_TYPE_UNPROVISIONED:
|
2020-09-01 15:17:27 +03:00
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV)) {
|
|
|
|
unprovisioned_beacon_recv(buf);
|
|
|
|
}
|
2017-06-16 12:30:54 +03:00
|
|
|
break;
|
|
|
|
case BEACON_TYPE_SECURE:
|
|
|
|
secure_beacon_recv(buf);
|
|
|
|
break;
|
2020-06-02 12:04:53 +02:00
|
|
|
case BEACON_TYPE_PRIVATE:
|
|
|
|
private_beacon_recv(buf);
|
|
|
|
break;
|
2017-06-16 12:30:54 +03:00
|
|
|
default:
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Unknown beacon type 0x%02x", type);
|
2017-06-16 12:30:54 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-25 11:03:42 +02:00
|
|
|
void bt_mesh_beacon_update(struct bt_mesh_subnet *sub)
|
|
|
|
{
|
|
|
|
uint8_t flags = bt_mesh_net_flags(sub);
|
|
|
|
struct bt_mesh_subnet_keys *keys;
|
|
|
|
|
|
|
|
keys = &sub->keys[SUBNET_KEY_TX_IDX(sub)];
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("NetIndex 0x%03x Using %s key", sub->net_idx,
|
|
|
|
SUBNET_KEY_TX_IDX(sub) ? "new" : "current");
|
|
|
|
LOG_DBG("flags 0x%02x, IVI 0x%08x", flags, bt_mesh.iv_index);
|
2020-08-25 11:03:42 +02:00
|
|
|
|
2020-06-02 12:04:53 +02:00
|
|
|
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
|
|
|
/* Invalidate private beacon to force regeneration: */
|
|
|
|
sub->priv_beacon.idx = priv_random.idx - 1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bt_mesh_beacon_auth(keys->beacon, flags, keys->net_id, bt_mesh.iv_index,
|
|
|
|
sub->auth);
|
2020-08-25 11:03:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
|
|
|
|
{
|
2020-11-13 20:14:55 -08:00
|
|
|
if (evt != BT_MESH_KEY_DELETED) {
|
2020-08-25 11:03:42 +02:00
|
|
|
bt_mesh_beacon_update(sub);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-13 14:10:45 +08:00
|
|
|
BT_MESH_SUBNET_CB_DEFINE(beacon) = {
|
|
|
|
.evt_handler = subnet_evt,
|
|
|
|
};
|
2020-08-25 11:03:42 +02:00
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
void bt_mesh_beacon_init(void)
|
|
|
|
{
|
2021-04-15 16:10:25 +02:00
|
|
|
k_work_init_delayable(&beacon_timer, beacon_send);
|
2020-06-02 12:04:53 +02:00
|
|
|
|
|
|
|
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
|
|
|
private_random_update();
|
|
|
|
#endif
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_mesh_beacon_ivu_initiator(bool enable)
|
|
|
|
{
|
2019-01-25 15:57:45 +02:00
|
|
|
atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_INITIATOR, enable);
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2021-04-15 16:10:25 +02:00
|
|
|
/* Fire the beacon handler straight away if it's not already pending -
|
|
|
|
* in which case we'll fire according to the ongoing periodic sending.
|
|
|
|
* If beacons are disabled, the handler will exit early.
|
|
|
|
*
|
|
|
|
* An alternative solution would be to check whether beacons are enabled
|
|
|
|
* here, and cancel if not. As the cancel operation may fail, we would
|
|
|
|
* still have to implement an early exit mechanism, so we might as well
|
|
|
|
* just use this every time.
|
|
|
|
*/
|
|
|
|
k_work_schedule(&beacon_timer, K_NO_WAIT);
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2020-08-25 11:03:42 +02:00
|
|
|
static void subnet_beacon_enable(struct bt_mesh_subnet *sub)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
2020-08-25 11:03:42 +02:00
|
|
|
sub->beacons_last = 0U;
|
|
|
|
sub->beacons_cur = 0U;
|
|
|
|
|
|
|
|
bt_mesh_beacon_update(sub);
|
|
|
|
}
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2020-08-25 11:03:42 +02:00
|
|
|
void bt_mesh_beacon_enable(void)
|
|
|
|
{
|
2021-04-15 16:10:25 +02:00
|
|
|
if (bt_mesh_is_provisioned()) {
|
|
|
|
bt_mesh_subnet_foreach(subnet_beacon_enable);
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2021-04-15 16:10:25 +02:00
|
|
|
k_work_reschedule(&beacon_timer, K_NO_WAIT);
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_mesh_beacon_disable(void)
|
|
|
|
{
|
2020-06-02 12:04:53 +02:00
|
|
|
/* If this fails, we'll do an early exit in the work handler. */
|
|
|
|
(void)k_work_cancel_delayable(&beacon_timer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_mesh_beacon_priv_random_get(uint8_t *random, size_t size)
|
|
|
|
{
|
|
|
|
__ASSERT(size <= sizeof(priv_random.val), "Invalid random value size %u", size);
|
|
|
|
memcpy(random, priv_random.val, size);
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|