diff --git a/include/bluetooth/mesh.h b/include/bluetooth/mesh.h index aa5e06987aa..bd38cf80188 100644 --- a/include/bluetooth/mesh.h +++ b/include/bluetooth/mesh.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include diff --git a/include/bluetooth/mesh/cfg_srv.h b/include/bluetooth/mesh/cfg_srv.h index 9db9c85fb91..d1fdc5a2b83 100644 --- a/include/bluetooth/mesh/cfg_srv.h +++ b/include/bluetooth/mesh/cfg_srv.h @@ -34,8 +34,11 @@ struct bt_mesh_cfg_srv { uint8_t frnd; /**< Friend state */ uint8_t default_ttl; /**< Default TTL */ - /** Heartbeat Publication parameters */ - struct bt_mesh_hb_pub { + /** Heartbeat Publication parameters. + * + * @deprecated in favor of standalone API in bluetooth/mesh/heartbeat.h. + */ + struct { struct k_delayed_work timer; /** Destination address. */ @@ -55,10 +58,13 @@ struct bt_mesh_cfg_srv { uint16_t feat; /** Network index used for publishing. */ uint16_t net_idx; - } hb_pub; + } hb_pub __deprecated; - /** Heartbeat Subscription parameters. */ - struct bt_mesh_hb_sub { + /** Heartbeat Subscription parameters. + * + * @deprecated in favor of standalone API in bluetooth/mesh/heartbeat.h. + */ + struct { /** Subscription period exipration timestamp. */ int64_t expiry; /** Source address to receive Heartbeats from. */ @@ -93,9 +99,12 @@ struct bt_mesh_cfg_srv { * @ref BT_MESH_FEAT_PROXY, * @ref BT_MESH_FEAT_FRIEND and * @ref BT_MESH_FEAT_LOW_POWER. + * + * @deprecated Please use the @ref bt_mesh_hb_cb registration + * function. */ void (*func)(uint8_t hops, uint16_t feat); - } hb_sub; + } hb_sub __deprecated; }; /** @def BT_MESH_MODEL_CFG_SRV diff --git a/include/bluetooth/mesh/heartbeat.h b/include/bluetooth/mesh/heartbeat.h new file mode 100644 index 00000000000..48285e11470 --- /dev/null +++ b/include/bluetooth/mesh/heartbeat.h @@ -0,0 +1,135 @@ +/** @file + * @brief Bluetooth Mesh Heartbeat API. + */ + +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_HEARTBEAT_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_HEARTBEAT_H_ + +#include + +/** + * @brief Bluetooth Mesh + * @defgroup bt_mesh_heartbeat Bluetooth Mesh Heartbeat + * @ingroup bt_mesh + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** Heartbeat Publication parameters */ +struct bt_mesh_hb_pub { + /** Destination address. */ + uint16_t dst; + /** Remaining publish count. */ + uint16_t count; + /** Time To Live value. */ + uint8_t ttl; + /** + * Bitmap of features that trigger a Heartbeat publication if + * they change. Legal values are @ref BT_MESH_FEAT_RELAY, + * @ref BT_MESH_FEAT_PROXY, @ref BT_MESH_FEAT_FRIEND and + * @ref BT_MESH_FEAT_LOW_POWER. + */ + uint16_t feat; + /** Network index used for publishing. */ + uint16_t net_idx; + /** Publication period in seconds. */ + uint32_t period; +}; + +/** Heartbeat Subscription parameters. */ +struct bt_mesh_hb_sub { + /** Subscription period in seconds. */ + uint32_t period; + /** Remaining subscription time in seconds. */ + uint32_t remaining; + /** Source address to receive Heartbeats from. */ + uint16_t src; + /** Destination address to received Heartbeats on. */ + uint16_t dst; + /** The number of received Heartbeat messages so far. */ + uint16_t count; + /** + * Minimum hops in received messages, ie the shortest registered + * path from the publishing node to the subscribing node. A + * Heartbeat received from an immediate neighbor has hop + * count = 1. + */ + uint8_t min_hops; + /** + * Maximum hops in received messages, ie the longest registered + * path from the publishing node to the subscribing node. A + * Heartbeat received from an immediate neighbor has hop + * count = 1. + */ + uint8_t max_hops; +}; + +/** Heartbeat callback structure */ +struct bt_mesh_hb_cb { + /** @brief Receive callback for heartbeats. + * + * Gets called on every received Heartbeat that matches the current + * Heartbeat subscription parameters. + * + * @param sub Current Heartbeat subscription parameters. + * @param hops The number of hops the Heartbeat was received + * with. + * @param feat The feature set of the publishing node. The + * value is a bitmap of @ref BT_MESH_FEAT_RELAY, + * @ref BT_MESH_FEAT_PROXY, + * @ref BT_MESH_FEAT_FRIEND and + * @ref BT_MESH_FEAT_LOW_POWER. + */ + void (*recv)(const struct bt_mesh_hb_sub *sub, uint8_t hops, + uint16_t feat); + + /** @brief Subscription end callback for heartbeats. + * + * Gets called when the subscription period ends, providing a summary + * of the received heartbeat messages. + * + * @param sub Current Heartbeat subscription parameters. + */ + void (*sub_end)(const struct bt_mesh_hb_sub *sub); +}; + +/** @def BT_MESH_HB_CB_DEFINE + * + * @brief Register a callback structure for Heartbeat events. + * + * Registers a callback structure that will be called whenever Heartbeat + * events occur + * + * @param _name Name of callback structure. + */ +#define BT_MESH_HB_CB_DEFINE(_name) \ + static const Z_STRUCT_SECTION_ITERABLE(bt_mesh_hb_cb, _name) + +/** @brief Get the current Heartbeat publication parameters. + * + * @param get Heartbeat publication parameters return buffer. + */ +void bt_mesh_hb_pub_get(struct bt_mesh_hb_pub *get); + +/** @brief Get the current Heartbeat subscription parameters. + * + * @param get Heartbeat subscription parameters return buffer. + */ +void bt_mesh_hb_sub_get(struct bt_mesh_hb_sub *get); + +#ifdef __cplusplus +} +#endif +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_HEARTBEAT_H_ */ diff --git a/include/linker/common-rom.ld b/include/linker/common-rom.ld index 7dc7d682208..1ac39ddbfda 100644 --- a/include/linker/common-rom.ld +++ b/include/linker/common-rom.ld @@ -105,6 +105,8 @@ #if defined(CONFIG_BT_MESH) Z_ITERABLE_SECTION_ROM(bt_mesh_subnet_cb, 4) Z_ITERABLE_SECTION_ROM(bt_mesh_app_key_cb, 4) + + Z_ITERABLE_SECTION_ROM(bt_mesh_hb_cb, 4) #endif #if defined(CONFIG_BT_MESH_FRIEND) diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index 8f172c295e7..5d959c7733f 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -12,6 +12,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH app_keys.c transport.c rpl.c + heartbeat.c crypto.c access.c cfg_srv.c diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index 405ba28454a..f49dfd0b318 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -30,6 +30,7 @@ #include "rpl.h" #include "lpn.h" #include "transport.h" +#include "heartbeat.h" #include "crypto.h" #include "access.h" #include "beacon.h" @@ -620,9 +621,7 @@ static void gatt_proxy_set(struct bt_mesh_model *model, bt_mesh_store_cfg(); } - if (cfg->hb_pub.feat & BT_MESH_FEAT_PROXY) { - (void)bt_mesh_heartbeat_send(NULL, NULL); - } + bt_mesh_hb_feature_changed(BT_MESH_FEAT_PROXY); send_status: send_gatt_proxy_status(model, ctx); @@ -726,9 +725,7 @@ static void relay_set(struct bt_mesh_model *model, BT_MESH_TRANSMIT_COUNT(cfg->relay_retransmit), BT_MESH_TRANSMIT_INT(cfg->relay_retransmit)); - if ((cfg->hb_pub.feat & BT_MESH_FEAT_RELAY) && change) { - (void)bt_mesh_heartbeat_send(NULL, NULL); - } + bt_mesh_hb_feature_changed(BT_MESH_FEAT_RELAY); } else { BT_WARN("Invalid Relay value 0x%02x", buf->data[0]); return; @@ -1699,18 +1696,6 @@ static void net_key_update(struct bt_mesh_model *model, send_net_key_status(model, ctx, idx, status); } -static void hb_pub_disable(struct bt_mesh_cfg_srv *cfg) -{ - BT_DBG(""); - - cfg->hb_pub.dst = BT_MESH_ADDR_UNASSIGNED; - cfg->hb_pub.count = 0U; - cfg->hb_pub.ttl = 0U; - cfg->hb_pub.period = 0U; - - k_delayed_work_cancel(&cfg->hb_pub.timer); -} - static void net_key_del(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) @@ -2139,9 +2124,7 @@ static void friend_set(struct bt_mesh_model *model, } } - if (cfg->hb_pub.feat & BT_MESH_FEAT_FRIEND) { - (void)bt_mesh_heartbeat_send(NULL, NULL); - } + bt_mesh_hb_feature_changed(BT_MESH_FEAT_FRIEND); send_status: send_friend_status(model, ctx); @@ -2249,17 +2232,6 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, send_krp_status(model, ctx, idx, phase, status); } -static uint8_t hb_log(uint16_t val) -{ - if (!val) { - return 0x00; - } else if (val == 0xffff) { - return 0xff; - } else { - return 32 - __builtin_clz(val); - } -} - static uint8_t hb_pub_count_log(uint16_t val) { if (!val) { @@ -2273,17 +2245,6 @@ static uint8_t hb_pub_count_log(uint16_t val) } } -static uint16_t hb_pwr2(uint8_t val, uint8_t sub) -{ - if (!val) { - return 0x0000; - } else if (val == 0xff || val == 0x11) { - return 0xffff; - } else { - return (1 << (val - sub)); - } -} - struct hb_pub_param { uint16_t dst; uint8_t count_log; @@ -2295,10 +2256,9 @@ struct hb_pub_param { static void hb_pub_send_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint8_t status, - struct hb_pub_param *orig_msg) + const struct bt_mesh_hb_pub *pub) { BT_MESH_MODEL_BUF_DEFINE(msg, OP_HEARTBEAT_PUB_STATUS, 10); - struct bt_mesh_cfg_srv *cfg = model->user_data; BT_DBG("src 0x%04x status 0x%02x", ctx->addr, status); @@ -2306,20 +2266,13 @@ static void hb_pub_send_status(struct bt_mesh_model *model, net_buf_simple_add_u8(&msg, status); - if (orig_msg) { - memcpy(net_buf_simple_add(&msg, sizeof(*orig_msg)), orig_msg, - sizeof(*orig_msg)); - goto send; - } + net_buf_simple_add_le16(&msg, pub->dst); + net_buf_simple_add_u8(&msg, hb_pub_count_log(pub->count)); + net_buf_simple_add_u8(&msg, bt_mesh_hb_log(pub->period)); + net_buf_simple_add_u8(&msg, pub->ttl); + net_buf_simple_add_le16(&msg, pub->feat); + net_buf_simple_add_le16(&msg, pub->net_idx); - net_buf_simple_add_le16(&msg, cfg->hb_pub.dst); - net_buf_simple_add_u8(&msg, hb_pub_count_log(cfg->hb_pub.count)); - net_buf_simple_add_u8(&msg, cfg->hb_pub.period); - net_buf_simple_add_u8(&msg, cfg->hb_pub.ttl); - net_buf_simple_add_le16(&msg, cfg->hb_pub.feat); - net_buf_simple_add_le16(&msg, cfg->hb_pub.net_idx); - -send: if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { BT_ERR("Unable to send Heartbeat Publication Status"); } @@ -2329,9 +2282,13 @@ static void heartbeat_pub_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + struct bt_mesh_hb_pub pub; + BT_DBG("src 0x%04x", ctx->addr); - hb_pub_send_status(model, ctx, STATUS_SUCCESS, NULL); + bt_mesh_hb_pub_get(&pub); + + hb_pub_send_status(model, ctx, STATUS_SUCCESS, &pub); } static void heartbeat_pub_set(struct bt_mesh_model *model, @@ -2339,27 +2296,32 @@ static void heartbeat_pub_set(struct bt_mesh_model *model, struct net_buf_simple *buf) { struct hb_pub_param *param = (void *)buf->data; - struct bt_mesh_cfg_srv *cfg = model->user_data; - uint16_t dst, feat, idx; + struct bt_mesh_hb_pub pub; uint8_t status; BT_DBG("src 0x%04x", ctx->addr); - dst = sys_le16_to_cpu(param->dst); + pub.dst = sys_le16_to_cpu(param->dst); + pub.count = bt_mesh_hb_pwr2(param->count_log); + pub.period = bt_mesh_hb_pwr2(param->period_log); + pub.ttl = param->ttl; + pub.feat = sys_le16_to_cpu(param->feat); + pub.net_idx = sys_le16_to_cpu(param->net_idx); + /* All other address types but virtual are valid */ - if (BT_MESH_ADDR_IS_VIRTUAL(dst)) { + if (BT_MESH_ADDR_IS_VIRTUAL(pub.dst)) { status = STATUS_INVALID_ADDRESS; - goto failed; + goto rsp; } if (param->count_log > 0x11 && param->count_log != 0xff) { status = STATUS_CANNOT_SET; - goto failed; + goto rsp; } if (param->period_log > 0x10) { status = STATUS_CANNOT_SET; - goto failed; + goto rsp; } if (param->ttl > BT_MESH_TTL_MAX && param->ttl != BT_MESH_TTL_DEFAULT) { @@ -2367,82 +2329,34 @@ static void heartbeat_pub_set(struct bt_mesh_model *model, return; } - feat = sys_le16_to_cpu(param->feat); - - idx = sys_le16_to_cpu(param->net_idx); - if (idx > 0xfff) { - BT_ERR("Invalid NetKeyIndex 0x%04x", idx); + if (pub.net_idx > 0xfff) { + BT_ERR("Invalid NetKeyIndex 0x%04x", pub.net_idx); return; } - if (!bt_mesh_subnet_get(idx)) { - status = STATUS_INVALID_NETKEY; - goto failed; - } + status = bt_mesh_hb_pub_set(&pub); - cfg->hb_pub.dst = dst; - cfg->hb_pub.period = param->period_log; - cfg->hb_pub.feat = feat & BT_MESH_FEAT_SUPPORTED; - cfg->hb_pub.net_idx = idx; - - if (dst == BT_MESH_ADDR_UNASSIGNED) { - hb_pub_disable(cfg); - } else { - /* 2^(n-1) */ - cfg->hb_pub.count = hb_pwr2(param->count_log, 1); - cfg->hb_pub.ttl = param->ttl; - - BT_DBG("period %u ms", hb_pwr2(param->period_log, 1) * 1000U); - - /* The first Heartbeat message shall be published as soon - * as possible after the Heartbeat Publication Period state - * has been configured for periodic publishing. - */ - if (param->period_log && param->count_log) { - k_work_submit(&cfg->hb_pub.timer.work); - } else { - k_delayed_work_cancel(&cfg->hb_pub.timer); - } - } - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_hb_pub(); - } - - hb_pub_send_status(model, ctx, STATUS_SUCCESS, NULL); - - return; - -failed: - hb_pub_send_status(model, ctx, status, param); +rsp: + hb_pub_send_status(model, ctx, status, &pub); } static void hb_sub_send_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, uint8_t status) + struct bt_mesh_msg_ctx *ctx, + const struct bt_mesh_hb_sub *sub) { BT_MESH_MODEL_BUF_DEFINE(msg, OP_HEARTBEAT_SUB_STATUS, 9); - struct bt_mesh_cfg_srv *cfg = model->user_data; - uint16_t period; - int64_t uptime; - BT_DBG("src 0x%04x status 0x%02x", ctx->addr, status); - - uptime = k_uptime_get(); - if (uptime > cfg->hb_sub.expiry) { - period = 0U; - } else { - period = (cfg->hb_sub.expiry - uptime) / 1000; - } + BT_DBG("src 0x%04x ", ctx->addr); bt_mesh_model_msg_init(&msg, OP_HEARTBEAT_SUB_STATUS); - net_buf_simple_add_u8(&msg, status); - net_buf_simple_add_le16(&msg, cfg->hb_sub.src); - net_buf_simple_add_le16(&msg, cfg->hb_sub.dst); - net_buf_simple_add_u8(&msg, hb_log(period)); - net_buf_simple_add_u8(&msg, hb_log(cfg->hb_sub.count)); - net_buf_simple_add_u8(&msg, cfg->hb_sub.min_hops); - net_buf_simple_add_u8(&msg, cfg->hb_sub.max_hops); + net_buf_simple_add_u8(&msg, STATUS_SUCCESS); + net_buf_simple_add_le16(&msg, sub->src); + net_buf_simple_add_le16(&msg, sub->dst); + net_buf_simple_add_u8(&msg, bt_mesh_hb_log(sub->remaining)); + net_buf_simple_add_u8(&msg, bt_mesh_hb_log(sub->count)); + net_buf_simple_add_u8(&msg, sub->min_hops); + net_buf_simple_add_u8(&msg, sub->max_hops); if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { BT_ERR("Unable to send Heartbeat Subscription Status"); @@ -2453,92 +2367,58 @@ static void heartbeat_sub_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + struct bt_mesh_hb_sub sub; + BT_DBG("src 0x%04x", ctx->addr); - hb_sub_send_status(model, ctx, STATUS_SUCCESS); + bt_mesh_hb_sub_get(&sub); + + hb_sub_send_status(model, ctx, &sub); } static void heartbeat_sub_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_cfg_srv *cfg = model->user_data; + uint8_t period_log, status; + struct bt_mesh_hb_sub sub; uint16_t sub_src, sub_dst; - uint8_t sub_period; - int32_t period_ms; + uint32_t period; BT_DBG("src 0x%04x", ctx->addr); sub_src = net_buf_simple_pull_le16(buf); sub_dst = net_buf_simple_pull_le16(buf); - sub_period = net_buf_simple_pull_u8(buf); + period_log = net_buf_simple_pull_u8(buf); BT_DBG("sub_src 0x%04x sub_dst 0x%04x period 0x%02x", - sub_src, sub_dst, sub_period); + sub_src, sub_dst, period_log); - if (sub_src != BT_MESH_ADDR_UNASSIGNED && - !BT_MESH_ADDR_IS_UNICAST(sub_src)) { - BT_WARN("Prohibited source address"); + if (period_log > 0x11) { + BT_WARN("Prohibited subscription period 0x%02x", period_log); return; } - if (BT_MESH_ADDR_IS_VIRTUAL(sub_dst) || BT_MESH_ADDR_IS_RFU(sub_dst) || - (BT_MESH_ADDR_IS_UNICAST(sub_dst) && - sub_dst != bt_mesh_primary_addr())) { - BT_WARN("Prohibited destination address"); - return; - } + period = bt_mesh_hb_pwr2(period_log); - if (sub_period > 0x11) { - BT_WARN("Prohibited subscription period 0x%02x", sub_period); - return; - } - - if (sub_src == BT_MESH_ADDR_UNASSIGNED || - sub_dst == BT_MESH_ADDR_UNASSIGNED || - sub_period == 0x00) { - /* Only an explicit address change to unassigned should - * trigger clearing of the values according to - * MESH/NODE/CFG/HBS/BV-02-C. + status = bt_mesh_hb_sub_set(sub_src, sub_dst, period); + if (status != STATUS_SUCCESS) { + /* All errors are caused by invalid packets, which should be + * ignored. */ - if (sub_src == BT_MESH_ADDR_UNASSIGNED || - sub_dst == BT_MESH_ADDR_UNASSIGNED) { - cfg->hb_sub.src = BT_MESH_ADDR_UNASSIGNED; - cfg->hb_sub.dst = BT_MESH_ADDR_UNASSIGNED; - cfg->hb_sub.min_hops = BT_MESH_TTL_MAX; - cfg->hb_sub.max_hops = 0U; - cfg->hb_sub.count = 0U; - } - - period_ms = 0; - } else { - cfg->hb_sub.src = sub_src; - cfg->hb_sub.dst = sub_dst; - cfg->hb_sub.min_hops = BT_MESH_TTL_MAX; - cfg->hb_sub.max_hops = 0U; - cfg->hb_sub.count = 0U; - period_ms = hb_pwr2(sub_period, 1) * 1000U; + return; } - /* Let the transport layer know it needs to handle this address */ - bt_mesh_set_hb_sub_dst(cfg->hb_sub.dst); - - BT_DBG("period_ms %u", period_ms); - - if (period_ms) { - cfg->hb_sub.expiry = k_uptime_get() + period_ms; - } else { - cfg->hb_sub.expiry = 0; - } - - hb_sub_send_status(model, ctx, STATUS_SUCCESS); + bt_mesh_hb_sub_get(&sub); /* MESH/NODE/CFG/HBS/BV-01-C expects the MinHops to be 0x7f after * disabling subscription, but 0x00 for subsequent Get requests. */ - if (!period_ms) { - cfg->hb_sub.min_hops = 0U; + if (!period_log) { + sub.min_hops = BT_MESH_TTL_MAX; } + + hb_sub_send_status(model, ctx, &sub); } const struct bt_mesh_model_op bt_mesh_cfg_srv_op[] = { @@ -2592,60 +2472,6 @@ const struct bt_mesh_model_op bt_mesh_cfg_srv_op[] = { BT_MESH_MODEL_OP_END, }; -static void hb_publish_end_cb(int err, void *cb_data) -{ - struct bt_mesh_cfg_srv *cfg = cb_data; - uint16_t period_ms; - - period_ms = hb_pwr2(cfg->hb_pub.period, 1) * 1000U; - if (period_ms && cfg->hb_pub.count > 1) { - k_delayed_work_submit(&cfg->hb_pub.timer, K_MSEC(period_ms)); - } - - if (cfg->hb_pub.count != 0xffff) { - cfg->hb_pub.count--; - } -} - -static void hb_publish_start_cb(uint16_t duration, int err, void *cb_data) -{ - if (err) { - hb_publish_end_cb(err, cb_data); - } -} - -static void hb_publish(struct k_work *work) -{ - static const struct bt_mesh_send_cb publish_cb = { - .start = hb_publish_start_cb, - .end = hb_publish_end_cb, - }; - struct bt_mesh_cfg_srv *cfg = CONTAINER_OF(work, - struct bt_mesh_cfg_srv, - hb_pub.timer.work); - struct bt_mesh_subnet *sub; - int err; - - BT_DBG("hb_pub.count: %u", cfg->hb_pub.count); - - sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx); - if (!sub) { - BT_ERR("No matching subnet for idx 0x%02x", - cfg->hb_pub.net_idx); - cfg->hb_pub.dst = BT_MESH_ADDR_UNASSIGNED; - return; - } - - if (cfg->hb_pub.count == 0U) { - return; - } - - err = bt_mesh_heartbeat_send(&publish_cb, cfg); - if (err) { - hb_publish_end_cb(err, cfg); - } -} - static bool conf_is_valid(struct bt_mesh_cfg_srv *cfg) { if (cfg->relay > 0x02) { @@ -2671,6 +2497,14 @@ static bool conf_is_valid(struct bt_mesh_cfg_srv *cfg) return true; } +static void (*hb_sub_cb)(uint8_t hops, uint16_t features); +static struct bt_mesh_hb_cb hb_cb; + +static void hb_recv_wrapper(const struct bt_mesh_hb_sub *sub, uint8_t hops, uint16_t features) +{ + hb_sub_cb(hops, features); +} + static int cfg_srv_init(struct bt_mesh_model *model) { struct bt_mesh_cfg_srv *cfg = model->user_data; @@ -2690,6 +2524,11 @@ static int cfg_srv_init(struct bt_mesh_model *model) return -EINVAL; } + if (cfg->hb_sub.func) { + hb_sub_cb = cfg->hb_sub.func; + hb_cb.recv = hb_recv_wrapper; + } + /* * Configuration Model security is device-key based and only the local * device-key is allowed to access this model. @@ -2708,10 +2547,6 @@ static int cfg_srv_init(struct bt_mesh_model *model) cfg->gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED; } - k_delayed_work_init(&cfg->hb_pub.timer, hb_publish); - cfg->hb_pub.net_idx = BT_MESH_KEY_UNUSED; - cfg->hb_sub.expiry = 0; - cfg->model = model; conf = cfg; @@ -2749,49 +2584,9 @@ static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, void bt_mesh_cfg_reset(void) { - struct bt_mesh_cfg_srv *cfg = conf; - - BT_DBG(""); - - bt_mesh_set_hb_sub_dst(BT_MESH_ADDR_UNASSIGNED); - - cfg->hb_sub.src = BT_MESH_ADDR_UNASSIGNED; - cfg->hb_sub.dst = BT_MESH_ADDR_UNASSIGNED; - cfg->hb_sub.expiry = 0; - bt_mesh_model_foreach(mod_reset, NULL); } -void bt_mesh_heartbeat(uint16_t src, uint16_t dst, uint8_t hops, uint16_t feat) -{ - struct bt_mesh_cfg_srv *cfg = conf; - - if (src != cfg->hb_sub.src || dst != cfg->hb_sub.dst) { - BT_WARN("No subscription for received heartbeat"); - return; - } - - if (k_uptime_get() > cfg->hb_sub.expiry) { - BT_WARN("Heartbeat subscription period expired"); - return; - } - - cfg->hb_sub.min_hops = MIN(cfg->hb_sub.min_hops, hops); - cfg->hb_sub.max_hops = MAX(cfg->hb_sub.max_hops, hops); - - if (cfg->hb_sub.count < 0xffff) { - cfg->hb_sub.count++; - } - - BT_DBG("src 0x%04x dst 0x%04x hops %u min %u max %u count %u", src, - dst, hops, cfg->hb_sub.min_hops, cfg->hb_sub.max_hops, - cfg->hb_sub.count); - - if (cfg->hb_sub.func) { - cfg->hb_sub.func(hops, feat); - } -} - uint8_t bt_mesh_net_transmit_get(void) { if (conf) { @@ -2856,16 +2651,6 @@ uint8_t bt_mesh_default_ttl_get(void) return DEFAULT_TTL; } -struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void) -{ - return &conf->hb_pub; -} - -void bt_mesh_hb_pub_disable(void) -{ - hb_pub_disable(conf); -} - struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void) { return conf; diff --git a/subsys/bluetooth/mesh/foundation.h b/subsys/bluetooth/mesh/foundation.h index 5d6d088e9ef..39b6ca7c34c 100644 --- a/subsys/bluetooth/mesh/foundation.h +++ b/subsys/bluetooth/mesh/foundation.h @@ -125,12 +125,8 @@ struct label { void bt_mesh_cfg_reset(void); -void bt_mesh_heartbeat(uint16_t src, uint16_t dst, uint8_t hops, uint16_t feat); - void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time); -struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void); -void bt_mesh_hb_pub_disable(void); struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void); uint8_t bt_mesh_net_transmit_get(void); diff --git a/subsys/bluetooth/mesh/heartbeat.c b/subsys/bluetooth/mesh/heartbeat.c new file mode 100644 index 00000000000..bea0c6c3054 --- /dev/null +++ b/subsys/bluetooth/mesh/heartbeat.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "net.h" +#include "rpl.h" +#include "access.h" +#include "lpn.h" +#include "settings.h" +#include "mesh.h" +#include "transport.h" +#include "heartbeat.h" +#include "foundation.h" + +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_TRANS) +#define LOG_MODULE_NAME bt_mesh_hb +#include "common/log.h" + +static struct bt_mesh_hb_pub pub; +static struct bt_mesh_hb_sub sub; +static struct k_delayed_work sub_timer; +static struct k_delayed_work pub_timer; + +static int64_t sub_remaining(void) +{ + if (sub.dst == BT_MESH_ADDR_UNASSIGNED) { + return 0U; + } + + return k_delayed_work_remaining_get(&sub_timer) / MSEC_PER_SEC; +} + +static void hb_publish_end_cb(int err, void *cb_data) +{ + if (pub.period && pub.count > 1) { + k_delayed_work_submit(&pub_timer, K_SECONDS(pub.period)); + } + + if (pub.count != 0xffff) { + pub.count--; + } +} + +static void notify_recv(uint8_t hops, uint16_t feat) +{ + sub.remaining = sub_remaining(); + + Z_STRUCT_SECTION_FOREACH(bt_mesh_hb_cb, cb) { + if (cb->recv) { + cb->recv(&sub, hops, feat); + } + } +} + +static void notify_sub_end(void) +{ + sub.remaining = 0; + + Z_STRUCT_SECTION_FOREACH(bt_mesh_hb_cb, cb) { + if (cb->sub_end) { + cb->sub_end(&sub); + } + } +} + +static void sub_end(struct k_work *work) +{ + notify_sub_end(); +} + +static int heartbeat_send(const struct bt_mesh_send_cb *cb, void *cb_data) +{ + uint16_t feat = 0U; + struct __packed { + uint8_t init_ttl; + uint16_t feat; + } hb; + struct bt_mesh_msg_ctx ctx = { + .net_idx = pub.net_idx, + .app_idx = BT_MESH_KEY_UNUSED, + .addr = pub.dst, + .send_ttl = pub.ttl, + }; + struct bt_mesh_net_tx tx = { + .sub = bt_mesh_subnet_get(pub.net_idx), + .ctx = &ctx, + .src = bt_mesh_primary_addr(), + .xmit = bt_mesh_net_transmit_get(), + }; + + /* Do nothing if heartbeat publication is not enabled */ + if (pub.dst == BT_MESH_ADDR_UNASSIGNED) { + return 0U; + } + + hb.init_ttl = pub.ttl; + + if (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED) { + feat |= BT_MESH_FEAT_RELAY; + } + + if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) { + feat |= BT_MESH_FEAT_PROXY; + } + + if (bt_mesh_friend_get() == BT_MESH_FRIEND_ENABLED) { + feat |= BT_MESH_FEAT_FRIEND; + } + + if (bt_mesh_lpn_established()) { + feat |= BT_MESH_FEAT_LOW_POWER; + } + + hb.feat = sys_cpu_to_be16(feat); + + BT_DBG("InitTTL %u feat 0x%04x", pub.ttl, feat); + + return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_HEARTBEAT, &hb, sizeof(hb), + cb, cb_data); +} + +static void hb_publish_start_cb(uint16_t duration, int err, void *cb_data) +{ + if (err) { + hb_publish_end_cb(err, cb_data); + } +} + +static void hb_publish(struct k_work *work) +{ + static const struct bt_mesh_send_cb publish_cb = { + .start = hb_publish_start_cb, + .end = hb_publish_end_cb, + }; + struct bt_mesh_subnet *sub; + int err; + + BT_DBG("hb_pub.count: %u", pub.count); + + sub = bt_mesh_subnet_get(pub.net_idx); + if (!sub) { + BT_ERR("No matching subnet for idx 0x%02x", pub.net_idx); + pub.dst = BT_MESH_ADDR_UNASSIGNED; + return; + } + + if (pub.count == 0U) { + return; + } + + err = heartbeat_send(&publish_cb, NULL); + if (err) { + hb_publish_end_cb(err, NULL); + } +} + +int bt_mesh_hb_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) +{ + uint8_t init_ttl, hops; + uint16_t feat; + + if (buf->len < 3) { + BT_ERR("Too short heartbeat message"); + return -EINVAL; + } + + init_ttl = (net_buf_simple_pull_u8(buf) & 0x7f); + feat = net_buf_simple_pull_be16(buf); + + hops = (init_ttl - rx->ctx.recv_ttl + 1); + + if (rx->ctx.addr != sub.src || rx->ctx.recv_dst != sub.dst) { + BT_DBG("No subscription for received heartbeat"); + return 0; + } + + if (!k_delayed_work_pending(&sub_timer)) { + BT_DBG("Heartbeat subscription period expired"); + return 0; + } + + sub.min_hops = MIN(sub.min_hops, hops); + sub.max_hops = MAX(sub.max_hops, hops); + + if (sub.count < 0xffff) { + sub.count++; + } + + BT_DBG("src 0x%04x TTL %u InitTTL %u (%u hop%s) feat 0x%04x", + rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops, + (hops == 1U) ? "" : "s", feat); + + notify_recv(hops, feat); + + return 0; +} + +static void pub_disable(void) +{ + BT_DBG(""); + + pub.dst = BT_MESH_ADDR_UNASSIGNED; + pub.count = 0U; + pub.ttl = 0U; + pub.period = 0U; + + k_delayed_work_cancel(&pub_timer); +} + +uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *new_pub) +{ + if (!new_pub || new_pub->dst == BT_MESH_ADDR_UNASSIGNED) { + pub_disable(); + + if (IS_ENABLED(CONFIG_BT_SETTINGS) && + bt_mesh_is_provisioned()) { + bt_mesh_store_hb_pub(); + } + + return STATUS_SUCCESS; + } + + if (!bt_mesh_subnet_get(new_pub->net_idx)) { + BT_ERR("Unknown NetKey 0x%04x", new_pub->net_idx); + return STATUS_INVALID_NETKEY; + } + + new_pub->feat &= BT_MESH_FEAT_SUPPORTED; + pub = *new_pub; + + if (!bt_mesh_is_provisioned()) { + return STATUS_SUCCESS; + } + + /* The first Heartbeat message shall be published as soon as possible + * after the Heartbeat Publication Period state has been configured for + * periodic publishing. + */ + if (pub.period && pub.count) { + k_work_submit(&pub_timer.work); + } else { + k_delayed_work_cancel(&pub_timer); + } + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_store_hb_pub(); + } + + return STATUS_SUCCESS; +} + +void bt_mesh_hb_pub_get(struct bt_mesh_hb_pub *get) +{ + *get = pub; +} + +uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period) +{ + if (src != BT_MESH_ADDR_UNASSIGNED && !BT_MESH_ADDR_IS_UNICAST(src)) { + BT_WARN("Prohibited source address"); + return STATUS_INVALID_ADDRESS; + } + + if (BT_MESH_ADDR_IS_VIRTUAL(dst) || BT_MESH_ADDR_IS_RFU(dst) || + (BT_MESH_ADDR_IS_UNICAST(dst) && dst != bt_mesh_primary_addr())) { + BT_WARN("Prohibited destination address"); + return STATUS_INVALID_ADDRESS; + } + + if (period > (1U << 16)) { + BT_WARN("Prohibited subscription period %u s", period); + return STATUS_CANNOT_SET; + } + + /* Only an explicit address change to unassigned should trigger clearing + * of the values according to MESH/NODE/CFG/HBS/BV-02-C. + */ + if (src == BT_MESH_ADDR_UNASSIGNED || dst == BT_MESH_ADDR_UNASSIGNED) { + sub.src = BT_MESH_ADDR_UNASSIGNED; + sub.dst = BT_MESH_ADDR_UNASSIGNED; + sub.min_hops = 0U; + sub.max_hops = 0U; + sub.count = 0U; + sub.period = sub.period - sub_remaining(); + if (!k_delayed_work_cancel(&sub_timer)) { + notify_sub_end(); + } + } else if (period) { + sub.src = src; + sub.dst = dst; + sub.min_hops = BT_MESH_TTL_MAX; + sub.max_hops = 0U; + sub.count = 0U; + sub.period = period; + k_delayed_work_submit(&sub_timer, K_SECONDS(period)); + } else { + /* Clearing the period should stop heartbeat subscription + * without clearing the parameters, so we can still read them. + */ + sub.period = sub.period - sub_remaining(); + if (!k_delayed_work_cancel(&sub_timer)) { + notify_sub_end(); + } + } + + return STATUS_SUCCESS; +} + +void bt_mesh_hb_sub_get(struct bt_mesh_hb_sub *get) +{ + *get = sub; + get->remaining = sub_remaining(); +} + +void bt_mesh_hb_feature_changed(uint16_t features) +{ + if (pub.dst == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + if (!(pub.feat & features)) { + return; + } + + heartbeat_send(NULL, NULL); +} + +void bt_mesh_hb_init(void) +{ + pub.net_idx = BT_MESH_KEY_UNUSED; + k_delayed_work_init(&pub_timer, hb_publish); + k_delayed_work_init(&sub_timer, sub_end); +} + +void bt_mesh_hb_start(void) +{ + if (pub.count && pub.period) { + BT_DBG("Starting heartbeat publication"); + k_work_submit(&pub_timer.work); + } +} + +void bt_mesh_hb_suspend(void) +{ + k_delayed_work_cancel(&pub_timer); +} + +void bt_mesh_hb_resume(void) +{ + if (pub.period && pub.count) { + BT_DBG("Starting heartbeat publication"); + k_work_submit(&pub_timer.work); + } +} diff --git a/subsys/bluetooth/mesh/heartbeat.h b/subsys/bluetooth/mesh/heartbeat.h new file mode 100644 index 00000000000..501a0ac690a --- /dev/null +++ b/subsys/bluetooth/mesh/heartbeat.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +static inline uint16_t bt_mesh_hb_pwr2(uint8_t val) +{ + if (!val) { + return 0x0000; + } else if (val == 0xff || val == 0x11) { + return 0xffff; + } else { + return (1 << (val - 1)); + } +} + +static inline uint8_t bt_mesh_hb_log(uint32_t val) +{ + if (!val) { + return 0x00; + } else if (val == 0xffff) { + return 0xff; + } else { + return 32 - __builtin_clz(val); + } +} + +void bt_mesh_hb_init(void); +void bt_mesh_hb_start(void); +void bt_mesh_hb_suspend(void); +void bt_mesh_hb_resume(void); + +int bt_mesh_hb_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf); +void bt_mesh_hb_feature_changed(uint16_t features); + +uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *hb_pub); +uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period); diff --git a/subsys/bluetooth/mesh/lpn.c b/subsys/bluetooth/mesh/lpn.c index 2cfa2a11433..7027158aa79 100644 --- a/subsys/bluetooth/mesh/lpn.c +++ b/subsys/bluetooth/mesh/lpn.c @@ -23,6 +23,7 @@ #include "mesh.h" #include "net.h" #include "transport.h" +#include "heartbeat.h" #include "access.h" #include "beacon.h" #include "foundation.h" @@ -197,7 +198,6 @@ static int send_friend_clear(void) static void clear_friendship(bool force, bool disable) { - struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); struct bt_mesh_lpn *lpn = &bt_mesh.lpn; BT_DBG("force %u disable %u", force, disable); @@ -246,9 +246,7 @@ static void clear_friendship(bool force, bool disable) */ lpn->groups_changed = 1U; - if (cfg->hb_pub.feat & BT_MESH_FEAT_LOW_POWER) { - (void)bt_mesh_heartbeat_send(NULL, NULL); - } + bt_mesh_hb_feature_changed(BT_MESH_FEAT_LOW_POWER); if (disable) { lpn_set_state(BT_MESH_LPN_DISABLED); @@ -972,8 +970,6 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, } if (!lpn->established) { - struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); - /* This is normally checked on the transport layer, however * in this state we're also still accepting master * credentials so we need to ensure the right ones (Friend @@ -988,9 +984,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, BT_INFO("Friendship established with 0x%04x", lpn->frnd); - if (cfg->hb_pub.feat & BT_MESH_FEAT_LOW_POWER) { - (void)bt_mesh_heartbeat_send(NULL, NULL); - } + bt_mesh_hb_feature_changed(BT_MESH_FEAT_LOW_POWER); Z_STRUCT_SECTION_FOREACH(bt_mesh_lpn_cb, cb) { if (cb->established) { diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 7600c457836..ce6956f4969 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -32,6 +32,7 @@ #include "lpn.h" #include "friend.h" #include "transport.h" +#include "heartbeat.h" #include "access.h" #include "foundation.h" #include "proxy.h" @@ -244,7 +245,7 @@ int bt_mesh_suspend(void) return err; } - bt_mesh_hb_pub_disable(); + bt_mesh_hb_suspend(); if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED) { bt_mesh_beacon_disable(); @@ -287,6 +288,8 @@ int bt_mesh_resume(void) return err; } + bt_mesh_hb_resume(); + if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED) { bt_mesh_beacon_enable(); } @@ -324,6 +327,7 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, bt_mesh_net_init(); bt_mesh_trans_init(); + bt_mesh_hb_init(); bt_mesh_beacon_init(); bt_mesh_adv_init(); @@ -373,6 +377,8 @@ int bt_mesh_start(void) bt_mesh_prov_complete(sub->net_idx, addr); } + bt_mesh_hb_start(); + bt_mesh_model_foreach(model_start, NULL); return 0; diff --git a/subsys/bluetooth/mesh/settings.c b/subsys/bluetooth/mesh/settings.c index accc538cff6..928f77214a7 100644 --- a/subsys/bluetooth/mesh/settings.c +++ b/subsys/bluetooth/mesh/settings.c @@ -31,6 +31,7 @@ #include "crypto.h" #include "rpl.h" #include "transport.h" +#include "heartbeat.h" #include "access.h" #include "foundation.h" #include "proxy.h" @@ -397,43 +398,30 @@ static int app_key_set(const char *name, size_t len_rd, static int hb_pub_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { - struct bt_mesh_hb_pub *pub = bt_mesh_hb_pub_get(); + struct bt_mesh_hb_pub pub; struct hb_pub_val hb_val; int err; - if (!pub) { - return -ENOENT; - } - - if (len_rd == 0) { - pub->dst = BT_MESH_ADDR_UNASSIGNED; - pub->count = 0U; - pub->ttl = 0U; - pub->period = 0U; - pub->feat = 0U; - - BT_DBG("Cleared heartbeat publication"); - return 0; - } - err = mesh_x_set(read_cb, cb_arg, &hb_val, sizeof(hb_val)); if (err) { BT_ERR("Failed to set \'hb_val\'"); return err; } - pub->dst = hb_val.dst; - pub->period = hb_val.period; - pub->ttl = hb_val.ttl; - pub->feat = hb_val.feat; - pub->net_idx = hb_val.net_idx; + pub.dst = hb_val.dst; + pub.period = bt_mesh_hb_pwr2(hb_val.period); + pub.ttl = hb_val.ttl; + pub.feat = hb_val.feat; + pub.net_idx = hb_val.net_idx; if (hb_val.indefinite) { - pub->count = 0xffff; + pub.count = 0xffff; } else { - pub->count = 0U; + pub.count = 0U; } + (void)bt_mesh_hb_pub_set(&pub); + BT_DBG("Restored heartbeat publication"); return 0; @@ -1006,7 +994,6 @@ static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, static int mesh_commit(void) { - struct bt_mesh_hb_pub *hb_pub; struct bt_mesh_cfg_srv *cfg; if (!bt_mesh_subnet_next(NULL)) { @@ -1024,13 +1011,6 @@ static int mesh_commit(void) bt_mesh_model_foreach(commit_mod, NULL); - hb_pub = bt_mesh_hb_pub_get(); - if (hb_pub && hb_pub->dst != BT_MESH_ADDR_UNASSIGNED && - hb_pub->count && hb_pub->period) { - BT_DBG("Starting heartbeat publication"); - k_work_submit(&hb_pub->timer.work); - } - cfg = bt_mesh_cfg_get(); if (cfg && stored_cfg.valid) { cfg->net_transmit = stored_cfg.cfg.net_transmit; @@ -1245,23 +1225,20 @@ static void store_pending_rpl(struct bt_mesh_rpl *rpl, void *user_data) static void store_pending_hb_pub(void) { - struct bt_mesh_hb_pub *pub = bt_mesh_hb_pub_get(); + struct bt_mesh_hb_pub pub; struct hb_pub_val val; int err; - if (!pub) { - return; - } - - if (pub->dst == BT_MESH_ADDR_UNASSIGNED) { + bt_mesh_hb_pub_get(&pub); + if (pub.dst == BT_MESH_ADDR_UNASSIGNED) { err = settings_delete("bt/mesh/HBPub"); } else { - val.indefinite = (pub->count == 0xffff); - val.dst = pub->dst; - val.period = pub->period; - val.ttl = pub->ttl; - val.feat = pub->feat; - val.net_idx = pub->net_idx; + val.indefinite = (pub.count == 0xffff); + val.dst = pub.dst; + val.period = bt_mesh_hb_log(pub.period); + val.ttl = pub.ttl; + val.feat = pub.feat; + val.net_idx = pub.net_idx; err = settings_save_one("bt/mesh/HBPub", &val, sizeof(val)); } diff --git a/subsys/bluetooth/mesh/transport.c b/subsys/bluetooth/mesh/transport.c index 6cd8a54ced2..31de048507f 100644 --- a/subsys/bluetooth/mesh/transport.c +++ b/subsys/bluetooth/mesh/transport.c @@ -35,6 +35,7 @@ #include "access.h" #include "foundation.h" #include "settings.h" +#include "heartbeat.h" #include "transport.h" #define AID_MASK ((uint8_t)(BIT_MASK(6))) @@ -124,13 +125,6 @@ K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4); static struct bt_mesh_va virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT]; -static uint16_t hb_sub_dst = BT_MESH_ADDR_UNASSIGNED; - -void bt_mesh_set_hb_sub_dst(uint16_t addr) -{ - hb_sub_dst = addr; -} - static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, const uint8_t *ctl_op) @@ -862,36 +856,6 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, return 0; } -static int trans_heartbeat(struct bt_mesh_net_rx *rx, - struct net_buf_simple *buf) -{ - uint8_t init_ttl, hops; - uint16_t feat; - - if (buf->len < 3) { - BT_ERR("Too short heartbeat message"); - return -EINVAL; - } - - if (rx->ctx.recv_dst != hb_sub_dst) { - BT_WARN("Ignoring heartbeat to non-subscribed destination"); - return 0; - } - - init_ttl = (net_buf_simple_pull_u8(buf) & 0x7f); - feat = net_buf_simple_pull_be16(buf); - - hops = (init_ttl - rx->ctx.recv_ttl + 1); - - BT_DBG("src 0x%04x TTL %u InitTTL %u (%u hop%s) feat 0x%04x", - rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops, - (hops == 1U) ? "" : "s", feat); - - bt_mesh_heartbeat(rx->ctx.addr, rx->ctx.recv_dst, hops, feat); - - return 0; -} - static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, struct net_buf_simple *buf, uint64_t *seq_auth) { @@ -903,7 +867,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, case TRANS_CTL_OP_ACK: return trans_ack(rx, hdr, buf, seq_auth); case TRANS_CTL_OP_HEARTBEAT: - return trans_heartbeat(rx, buf); + return bt_mesh_hb_recv(rx, buf); } /* Only acks and heartbeats may need processing without local_match */ @@ -1627,58 +1591,6 @@ void bt_mesh_trans_init(void) } } -int bt_mesh_heartbeat_send(const struct bt_mesh_send_cb *cb, void *cb_data) -{ - struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); - uint16_t feat = 0U; - struct __packed { - uint8_t init_ttl; - uint16_t feat; - } hb; - struct bt_mesh_msg_ctx ctx = { - .net_idx = cfg->hb_pub.net_idx, - .app_idx = BT_MESH_KEY_UNUSED, - .addr = cfg->hb_pub.dst, - .send_ttl = cfg->hb_pub.ttl, - }; - struct bt_mesh_net_tx tx = { - .sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx), - .ctx = &ctx, - .src = bt_mesh_model_elem(cfg->model)->addr, - .xmit = bt_mesh_net_transmit_get(), - }; - - /* Do nothing if heartbeat publication is not enabled */ - if (cfg->hb_pub.dst == BT_MESH_ADDR_UNASSIGNED) { - return 0; - } - - hb.init_ttl = cfg->hb_pub.ttl; - - if (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED) { - feat |= BT_MESH_FEAT_RELAY; - } - - if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) { - feat |= BT_MESH_FEAT_PROXY; - } - - if (bt_mesh_friend_get() == BT_MESH_FRIEND_ENABLED) { - feat |= BT_MESH_FEAT_FRIEND; - } - - if (bt_mesh_lpn_established()) { - feat |= BT_MESH_FEAT_LOW_POWER; - } - - hb.feat = sys_cpu_to_be16(feat); - - BT_DBG("InitTTL %u feat 0x%04x", cfg->hb_pub.ttl, feat); - - return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_HEARTBEAT, &hb, sizeof(hb), - cb, cb_data); -} - struct bt_mesh_va *bt_mesh_va_get(uint16_t index) { if (index >= ARRAY_SIZE(virtual_addrs)) { diff --git a/subsys/bluetooth/mesh/transport.h b/subsys/bluetooth/mesh/transport.h index e44ddb32eec..a258f0834b5 100644 --- a/subsys/bluetooth/mesh/transport.h +++ b/subsys/bluetooth/mesh/transport.h @@ -86,8 +86,6 @@ struct bt_mesh_va { uint8_t uuid[16]; }; -void bt_mesh_set_hb_sub_dst(uint16_t addr); - bool bt_mesh_tx_in_progress(void); void bt_mesh_rx_reset(void); @@ -115,8 +113,6 @@ void bt_mesh_trans_init(void); void bt_mesh_trans_reset(void); -int bt_mesh_heartbeat_send(const struct bt_mesh_send_cb *cb, void *cb_data); - struct bt_mesh_va *bt_mesh_va_get(uint16_t index); struct bt_mesh_va *bt_mesh_va_find(uint8_t uuid[16]);