|
|
@@ -1544,4 +1544,235 @@ int bt_mesh_provisioner_store_node_info(struct bt_mesh_node *node)
|
|
|
}
|
|
|
#endif /* CONFIG_BLE_MESH_TEST_AUTO_ENTER_NETWORK */
|
|
|
|
|
|
+#if CONFIG_BLE_MESH_PROVISIONER_RECV_HB
|
|
|
+
|
|
|
+#define HEARTBEAT_FILTER_ACCEPTLIST 0x00
|
|
|
+#define HEARTBEAT_FILTER_REJECTLIST 0x01
|
|
|
+
|
|
|
+#define HEARTBEAT_FILTER_ADD 0x00
|
|
|
+#define HEARTBEAT_FILTER_REMOVE 0x01
|
|
|
+
|
|
|
+#define HEARTBEAT_FILTER_WITH_SRC BIT(0)
|
|
|
+#define HEARTBEAT_FILTER_WITH_DST BIT(1)
|
|
|
+#define HEARTBEAT_FILTER_WITH_BOTH (BIT(1) | BIT(0))
|
|
|
+
|
|
|
+static struct heartbeat_recv {
|
|
|
+ struct heartbeat_filter {
|
|
|
+ u8_t type; /* Indicate if using src or dst or both to filter heartbeat messages */
|
|
|
+ u16_t src; /* Heartbeat source address (unicast address) */
|
|
|
+ u16_t dst; /* Heartbeat destination address (unicast address or group address) */
|
|
|
+ } filter[CONFIG_BLE_MESH_PROVISIONER_RECV_HB_FILTER_SIZE];
|
|
|
+ u8_t type; /* Heartbeat filter type */
|
|
|
+ bt_mesh_heartbeat_recv_cb_t cb; /* Heartbeat receive callback */
|
|
|
+} hb_rx;
|
|
|
+
|
|
|
+int bt_mesh_provisioner_recv_heartbeat(bt_mesh_heartbeat_recv_cb_t cb)
|
|
|
+{
|
|
|
+ memset(&hb_rx, 0, sizeof(hb_rx));
|
|
|
+
|
|
|
+ /* Start with an empty rejectlist, which means all heartbeat messages will be reported */
|
|
|
+ hb_rx.type = HEARTBEAT_FILTER_REJECTLIST;
|
|
|
+ hb_rx.cb = cb;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int bt_mesh_provisioner_set_heartbeat_filter_type(u8_t type)
|
|
|
+{
|
|
|
+ if (type > HEARTBEAT_FILTER_REJECTLIST) {
|
|
|
+ BT_ERR("Invalid heartbeat filter type 0x%02x", type);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If the heartbeat filter type is different with previous one,
|
|
|
+ * clear the existing filter entries.
|
|
|
+ */
|
|
|
+ if (hb_rx.type != type) {
|
|
|
+ memset(&hb_rx, 0, offsetof(struct heartbeat_recv, cb));
|
|
|
+ hb_rx.type = type;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static inline u8_t get_filter_addr_type(u16_t src, u16_t dst)
|
|
|
+{
|
|
|
+ if (BLE_MESH_ADDR_IS_UNICAST(src)) {
|
|
|
+ if (BLE_MESH_ADDR_IS_UNICAST(dst) || BLE_MESH_ADDR_IS_GROUP(dst)) {
|
|
|
+ return HEARTBEAT_FILTER_WITH_BOTH;
|
|
|
+ } else {
|
|
|
+ return HEARTBEAT_FILTER_WITH_SRC;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return HEARTBEAT_FILTER_WITH_DST;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int hb_filter_alloc(u16_t src, u16_t dst)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(hb_rx.filter); i++) {
|
|
|
+ struct heartbeat_filter *filter = &hb_rx.filter[i];
|
|
|
+
|
|
|
+ if (filter->src == BLE_MESH_ADDR_UNASSIGNED &&
|
|
|
+ filter->dst == BLE_MESH_ADDR_UNASSIGNED) {
|
|
|
+ filter->type = get_filter_addr_type(src, dst);
|
|
|
+ filter->src = src;
|
|
|
+ filter->dst = dst;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ BT_ERR("Heartbeat filter is full!");
|
|
|
+ return -ENOMEM;
|
|
|
+}
|
|
|
+
|
|
|
+static int hb_filter_add(u16_t src, u16_t dst)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (!BLE_MESH_ADDR_IS_UNICAST(src) &&
|
|
|
+ !BLE_MESH_ADDR_IS_UNICAST(dst) && !BLE_MESH_ADDR_IS_GROUP(dst)) {
|
|
|
+ BT_ERR("Invalid filter address, src 0x%04x, dst 0x%04x", src, dst);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Check if filter entries with the same src or dst exist. */
|
|
|
+ for (i = 0; i < ARRAY_SIZE(hb_rx.filter); i++) {
|
|
|
+ struct heartbeat_filter *filter = &hb_rx.filter[i];
|
|
|
+
|
|
|
+ if ((BLE_MESH_ADDR_IS_UNICAST(src) && filter->src == src) ||
|
|
|
+ ((BLE_MESH_ADDR_IS_UNICAST(dst) || BLE_MESH_ADDR_IS_GROUP(dst)) &&
|
|
|
+ filter->dst == dst)) {
|
|
|
+ memset(filter, 0, sizeof(struct heartbeat_filter));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return hb_filter_alloc(src, dst);
|
|
|
+}
|
|
|
+
|
|
|
+static int hb_filter_remove(u16_t src, u16_t dst)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (!BLE_MESH_ADDR_IS_UNICAST(src) &&
|
|
|
+ !BLE_MESH_ADDR_IS_UNICAST(dst) && !BLE_MESH_ADDR_IS_GROUP(dst)) {
|
|
|
+ BT_ERR("Invalid filter address, src 0x%04x, dst 0x%04x", src, dst);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(hb_rx.filter); i++) {
|
|
|
+ struct heartbeat_filter *filter = &hb_rx.filter[i];
|
|
|
+
|
|
|
+ if ((BLE_MESH_ADDR_IS_UNICAST(src) && filter->src == src) ||
|
|
|
+ ((BLE_MESH_ADDR_IS_UNICAST(dst) || BLE_MESH_ADDR_IS_GROUP(dst)) &&
|
|
|
+ filter->dst == dst)) {
|
|
|
+ memset(filter, 0, sizeof(struct heartbeat_filter));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int bt_mesh_provisioner_set_heartbeat_filter_info(u8_t op, u16_t src, u16_t dst)
|
|
|
+{
|
|
|
+ switch (op) {
|
|
|
+ case HEARTBEAT_FILTER_ADD:
|
|
|
+ return hb_filter_add(src, dst);
|
|
|
+ case HEARTBEAT_FILTER_REMOVE:
|
|
|
+ return hb_filter_remove(src, dst);
|
|
|
+ default:
|
|
|
+ BT_ERR("Invalid heartbeat filter opcode 0x%02x", op);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static bool filter_with_rejectlist(struct heartbeat_filter *filter,
|
|
|
+ u16_t hb_src, u16_t hb_dst)
|
|
|
+{
|
|
|
+ switch (filter->type) {
|
|
|
+ case HEARTBEAT_FILTER_WITH_SRC:
|
|
|
+ if (hb_src == filter->src) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case HEARTBEAT_FILTER_WITH_DST:
|
|
|
+ if (hb_dst == filter->dst) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case HEARTBEAT_FILTER_WITH_BOTH:
|
|
|
+ if (hb_src == filter->src && hb_dst == filter->dst) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ BT_WARN("Unknown filter addr type 0x%02x", filter->type);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static bool filter_with_acceptlist(struct heartbeat_filter *filter,
|
|
|
+ u16_t hb_src, u16_t hb_dst)
|
|
|
+{
|
|
|
+ switch (filter->type) {
|
|
|
+ case HEARTBEAT_FILTER_WITH_SRC:
|
|
|
+ if (hb_src == filter->src) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case HEARTBEAT_FILTER_WITH_DST:
|
|
|
+ if (hb_dst == filter->dst) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case HEARTBEAT_FILTER_WITH_BOTH:
|
|
|
+ if (hb_src == filter->src && hb_dst == filter->dst) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ BT_WARN("Unknown filter addr type 0x%02x", filter->type);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+void bt_mesh_provisioner_heartbeat(u16_t hb_src, u16_t hb_dst,
|
|
|
+ u8_t init_ttl, u8_t rx_ttl,
|
|
|
+ u8_t hops, u16_t feat, s8_t rssi)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (hb_rx.cb == NULL) {
|
|
|
+ BT_DBG("Receiving heartbeat is not enabled");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(hb_rx.filter); i++) {
|
|
|
+ struct heartbeat_filter *filter = &hb_rx.filter[i];
|
|
|
+
|
|
|
+ if (hb_rx.type == HEARTBEAT_FILTER_REJECTLIST) {
|
|
|
+ if (filter_with_rejectlist(filter, hb_src, hb_dst)) {
|
|
|
+ BT_DBG("Filtered by rejectlist, src 0x%04x, dst 0x%04x", hb_src, hb_dst);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (filter_with_acceptlist(filter, hb_src, hb_dst)) {
|
|
|
+ BT_DBG("Filtered by acceptlist, src 0x%04x, dst 0x%04x", hb_src, hb_dst);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hb_rx.cb) {
|
|
|
+ hb_rx.cb(hb_src, hb_dst, init_ttl, rx_ttl, hops, feat, rssi);
|
|
|
+ }
|
|
|
+}
|
|
|
+#endif /* CONFIG_BLE_MESH_PROVISIONER_RECV_HB */
|
|
|
+
|
|
|
#endif /* CONFIG_BLE_MESH_PROVISIONER */
|