Re-arranged for efficientcy. Replay Protection was set up as an atomic check-and-add operation. Now we check the message early so we can discard it without taking further action, and only add it to the RPL once fully verified that it was authorized and addressed to us. --- mesh/model.c | 23 +++++++++---------- mesh/net.c | 62 ++++++++++++++++++++++++++-------------------------- mesh/net.h | 7 +++--- 3 files changed, 45 insertions(+), 47 deletions(-) diff --git a/mesh/model.c b/mesh/model.c index 92a00496c..574b6621a 100644 --- a/mesh/model.c +++ b/mesh/model.c @@ -964,10 +964,12 @@ bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0, /* Unicast and not addressed to us */ return false; - clear_text = l_malloc(size); - if (!clear_text) + /* Don't process if already in RPL */ + crpl = node_get_crpl(node); + if (net_msg_check_replay_cache(net, src, crpl, seq, iv_index)) return false; + clear_text = l_malloc(size); forward.data = clear_text; /* @@ -995,16 +997,6 @@ bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0, goto done; } - /* print_packet("Clr Rx (pre-cache-check)", clear_text, size - 4); */ - - crpl = node_get_crpl(node); - - if (net_msg_in_replay_cache(net, (uint16_t) decrypt_idx, src, - crpl, seq, iv_index)) { - result = true; - goto done; - } - print_packet("Clr Rx", clear_text, size - (szmict ? 8 : 4)); forward.virt = decrypt_virt; @@ -1073,7 +1065,7 @@ bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0, * Either the message has been processed internally or * has been passed on to an external model. */ - result = forward.has_dst | forward.done; + result |= forward.has_dst | forward.done; /* If the message was to unicast address, we are done */ if (!is_subscription && ele_idx == i) @@ -1088,8 +1080,13 @@ bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0, break; } + /* If this message handlable by us, add to RPL */ + if (result) + net_msg_add_replay_cache(net, src, seq, iv_index); + done: l_free(clear_text); + return result; } diff --git a/mesh/net.c b/mesh/net.c index 19f3b87b7..d85df63da 100644 --- a/mesh/net.c +++ b/mesh/net.c @@ -3759,9 +3759,8 @@ static bool clean_old_iv_index(void *a, void *b) return false; } -bool net_msg_in_replay_cache(struct mesh_net *net, uint16_t idx, - uint16_t src, uint16_t crpl, uint32_t seq, - uint32_t iv_index) +bool net_msg_check_replay_cache(struct mesh_net *net, uint16_t src, + uint16_t crpl, uint32_t seq, uint32_t iv_index) { struct mesh_rpl *rpe; @@ -3782,49 +3781,50 @@ bool net_msg_in_replay_cache(struct mesh_net *net, uint16_t idx, L_UINT_TO_PTR(src)); if (rpe) { - if (iv_index > rpe->iv_index) { - rpe->seq = seq; - rpe->iv_index = iv_index; - rpl_put_entry(net->node, src, iv_index, seq); + if (iv_index > rpe->iv_index) return false; - } - - if (seq < rpe->seq) { - l_debug("Ignoring packet with lower sequence number"); - return true; - } - if (seq == rpe->seq) { - l_debug("Message already processed (duplicate)"); + /* return true if (iv_index | seq) too low */ + if (iv_index < rpe->iv_index || seq <= rpe->seq) { + l_debug("Ignoring replayed packet"); return true; } - - rpe->seq = seq; - - rpl_put_entry(net->node, src, iv_index, seq); - - return false; } - l_debug("New Entry for %4.4x", src); - - /* Replay Cache is fixed sized */ - if (l_queue_length(net->replay_cache) >= crpl) { + /* SRC not in Replay Cache... see if there is space for it */ + else if (l_queue_length(net->replay_cache) >= crpl) { int ret = l_queue_foreach_remove(net->replay_cache, clean_old_iv_index, L_UINT_TO_PTR(iv_index)); + /* Return true if no space could be freed */ if (!ret) return true; } - if (!rpl_put_entry(net->node, src, iv_index, seq)) - return true; + return false; +} + +void net_msg_add_replay_cache(struct mesh_net *net, uint16_t src, uint32_t seq, + uint32_t iv_index) +{ + struct mesh_rpl *rpe; + + if (!net || !net->node || !net->replay_cache) + return; + + rpe = l_queue_remove_if(net->replay_cache, match_replay_cache, + L_UINT_TO_PTR(src)); + + if (!rpe) { + l_debug("New Entry for %4.4x", src); + rpe = l_new(struct mesh_rpl, 1); + rpe->seq = src; + } - rpe = l_new(struct mesh_rpl, 1); - rpe->src = src; rpe->seq = seq; rpe->iv_index = iv_index; - l_queue_push_head(net->replay_cache, rpe); + rpl_put_entry(net->node, src, iv_index, seq); - return false; + /* Optimize so that most recent conversations stay earliest in cache */ + l_queue_push_head(net->replay_cache, rpe); } diff --git a/mesh/net.h b/mesh/net.h index ff0a9bb2b..6fedd69d7 100644 --- a/mesh/net.h +++ b/mesh/net.h @@ -379,6 +379,7 @@ void mesh_net_set_prov(struct mesh_net *net, struct mesh_prov *prov); uint32_t mesh_net_get_instant(struct mesh_net *net); struct l_queue *mesh_net_get_friends(struct mesh_net *net); struct l_queue *mesh_net_get_negotiations(struct mesh_net *net); -bool net_msg_in_replay_cache(struct mesh_net *net, uint16_t idx, - uint16_t src, uint16_t crpl, uint32_t seq, - uint32_t iv_index); +bool net_msg_check_replay_cache(struct mesh_net *net, uint16_t src, + uint16_t crpl, uint32_t seq, uint32_t iv_index); +void net_msg_add_replay_cache(struct mesh_net *net, uint16_t src, uint32_t seq, + uint32_t iv_index); -- 2.21.1