From cad1f4ce7b0e0d3ff96c740c4f0cda35fe24bb5e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 2 Nov 2017 13:30:46 +0200 Subject: [PATCH] Bluetooth: Mesh: Fix transport layer heartbeat subscription matching Signed-off-by: Johan Hedberg --- subsys/bluetooth/host/mesh/cfg.c | 3 ++ subsys/bluetooth/host/mesh/main.c | 2 + subsys/bluetooth/host/mesh/transport.c | 51 +++++++++++++++++--------- subsys/bluetooth/host/mesh/transport.h | 2 + 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/subsys/bluetooth/host/mesh/cfg.c b/subsys/bluetooth/host/mesh/cfg.c index d118d5f5fa5..b7fdefd9b0c 100644 --- a/subsys/bluetooth/host/mesh/cfg.c +++ b/subsys/bluetooth/host/mesh/cfg.c @@ -2902,6 +2902,9 @@ static void heartbeat_sub_set(struct bt_mesh_model *model, period_ms = hb_pwr2(sub_period, 1) * 1000; } + /* 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) { diff --git a/subsys/bluetooth/host/mesh/main.c b/subsys/bluetooth/host/mesh/main.c index 526e5747ee6..8563946b374 100644 --- a/subsys/bluetooth/host/mesh/main.c +++ b/subsys/bluetooth/host/mesh/main.c @@ -105,6 +105,8 @@ void bt_mesh_reset(void) bt_mesh.last_update = 0; bt_mesh.ivu_initiator = 0; + bt_mesh_set_hb_sub_dst(BT_MESH_ADDR_UNASSIGNED); + k_delayed_work_cancel(&bt_mesh.ivu_complete); if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { diff --git a/subsys/bluetooth/host/mesh/transport.c b/subsys/bluetooth/host/mesh/transport.c index 0041e089a53..46a69abeb4b 100644 --- a/subsys/bluetooth/host/mesh/transport.c +++ b/subsys/bluetooth/host/mesh/transport.c @@ -90,6 +90,13 @@ static struct seg_rx { }, }; +static u16_t hb_sub_dst = BT_MESH_ADDR_UNASSIGNED; + +void bt_mesh_set_hb_sub_dst(u16_t addr) +{ + hb_sub_dst = addr; +} + static int send_unseg(struct bt_mesh_net_tx *tx, u8_t aid, struct net_buf_simple *sdu) { @@ -687,6 +694,11 @@ static int trans_heartbeat(struct bt_mesh_net_rx *rx, return -EINVAL; } + if (rx->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); @@ -711,18 +723,15 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, u8_t hdr, switch (ctl_op) { case TRANS_CTL_OP_ACK: return trans_ack(rx, hdr, buf, seq_auth); - } - - /* Only acks need processing for Friend behavior */ - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && !rx->local_match) { - return 0; - } - - switch (ctl_op) { case TRANS_CTL_OP_HEARTBEAT: return trans_heartbeat(rx, buf); } + /* Only acks and heartbeats may need processing without local_match */ + if (!rx->local_match) { + return 0; + } + if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { switch (ctl_op) { case TRANS_CTL_OP_FRIEND_POLL: @@ -784,6 +793,11 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, if (rx->ctl) { return ctl_recv(rx, hdr, buf, seq_auth); } else { + /* SDUs must match a local element or an LPN of this Friend. */ + if (!rx->local_match && !rx->friend_match) { + return 0; + } + return sdu_recv(rx, hdr, 4, 0, buf); } } @@ -1197,12 +1211,8 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) rx->friend_match = false; } - if (!rx->local_match && !rx->friend_match) { - return 0; - } - - BT_DBG("src 0x%04x dst 0x%04x seq 0x%08x", rx->ctx.addr, rx->dst, - rx->seq); + BT_DBG("src 0x%04x dst 0x%04x seq 0x%08x friend_match %u", + rx->ctx.addr, rx->dst, rx->seq, rx->friend_match); /* Remove network headers */ net_buf_simple_pull(buf, BT_MESH_NET_HDR_LEN); @@ -1217,8 +1227,7 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) bt_mesh_lpn_established() && (!bt_mesh_lpn_waiting_update() || !rx->ctx.friend_cred)) { BT_WARN("Ignoring unexpected message in Low Power mode"); - err = -EAGAIN; - goto done; + return -EAGAIN; } /* Save the parsing state so the buffer can later be relayed or @@ -1227,6 +1236,13 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) net_buf_simple_save(buf, &state); if (SEG(buf->data)) { + /* Segmented messages must match a local element or an + * LPN of this Friend. + */ + if (!rx->local_match && !rx->friend_match) { + return 0; + } + err = trans_seg(buf, rx, &pdu_type, &seq_auth); } else { err = trans_unseg(buf, rx, &seq_auth); @@ -1244,10 +1260,9 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) bt_mesh_lpn_msg_received(rx); } -done: net_buf_simple_restore(buf, &state); - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && !err) { + if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && rx->friend_match && !err) { if (seq_auth == TRANS_SEQ_AUTH_NVAL) { bt_mesh_friend_enqueue_rx(rx, pdu_type, NULL, buf); } else { diff --git a/subsys/bluetooth/host/mesh/transport.h b/subsys/bluetooth/host/mesh/transport.h index 8642531c31b..92d3edde87f 100644 --- a/subsys/bluetooth/host/mesh/transport.h +++ b/subsys/bluetooth/host/mesh/transport.h @@ -74,6 +74,8 @@ struct bt_mesh_ctl_friend_sub_confirm { u8_t xact; } __packed; +void bt_mesh_set_hb_sub_dst(u16_t addr); + struct bt_mesh_app_key *bt_mesh_app_key_find(u16_t app_idx); bool bt_mesh_tx_in_progress(void);