Linux-Bluetooth Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH BlueZ] mesh: Fix IV_Index recovery logic
@ 2019-10-07 20:33 Brian Gix
  0 siblings, 0 replies; only message in thread
From: Brian Gix @ 2019-10-07 20:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, inga.stotland, michal.lowas-rzechonek

This fix divorces the state tracking of the IV Index updating stages
from the actual realtime setting of IV_Index and IV_Update values.

We are more permissive about what we accept as IV_Index and the IVU
boolean from incoming Secure Network Beacons on Startup, in case the
daemon has "Been Away" from the mesh network. But we need to more
carefully track what IV_Index we use for outgoing messages, and the
instant we reset the outgoing Sequence number to Zero.  So iv_index,
and iv_update are now fully independant of the iv_upd_state.
---
 mesh/mesh-config-json.c |  3 +-
 mesh/net.c              | 83 ++++++++++++++++++++++++++---------------
 2 files changed, 55 insertions(+), 31 deletions(-)

diff --git a/mesh/mesh-config-json.c b/mesh/mesh-config-json.c
index 198fef518..df58cbd7d 100644
--- a/mesh/mesh-config-json.c
+++ b/mesh/mesh-config-json.c
@@ -2057,7 +2057,8 @@ bool mesh_config_write_seq_number(struct mesh_config *cfg, uint32_t seq,
 		return mesh_config_save(cfg, true, NULL, NULL);
 	}
 
-	if (get_int(cfg->jnode, "sequenceNumber", &value))
+	/* If resetting seq to Zero, make sure cached value reset as well */
+	if (seq && get_int(cfg->jnode, "sequenceNumber", &value))
 		cached = (uint32_t)value;
 
 	/*
diff --git a/mesh/net.c b/mesh/net.c
index 2785039db..64333f64c 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -503,6 +503,7 @@ void mesh_friend_sub_del(struct mesh_net *net, uint16_t lpn,
 uint32_t mesh_net_next_seq_num(struct mesh_net *net)
 {
 	uint32_t seq = net->seq_num++;
+
 	node_set_sequence_number(net->node, net->seq_num);
 	return seq;
 }
@@ -718,6 +719,7 @@ bool mesh_net_set_seq_num(struct mesh_net *net, uint32_t seq)
 		return false;
 
 	net->seq_num = seq;
+	node_set_sequence_number(net->node, net->seq_num);
 
 	return true;
 }
@@ -1034,7 +1036,7 @@ uint32_t mesh_net_get_iv_index(struct mesh_net *net)
 	if (!net)
 		return 0xffffffff;
 
-	return net->iv_index - (iv_is_updating(net) ? 1 : 0);
+	return net->iv_index - net->iv_update;
 }
 
 /* TODO: net key index? */
@@ -2619,7 +2621,10 @@ static void iv_upd_to(struct l_timeout *upd_timeout, void *user_data)
 		l_info("iv_upd_state = IV_UPD_NORMAL_HOLD");
 		net->iv_upd_state = IV_UPD_NORMAL_HOLD;
 		l_timeout_modify(net->iv_update_timeout, IV_IDX_UPD_MIN);
-		mesh_net_set_seq_num(net, 0);
+		if (net->iv_update)
+			mesh_net_set_seq_num(net, 0);
+
+		net->iv_update = false;
 		l_queue_foreach(net->subnets, set_network_beacon, net);
 		mesh_net_flush_msg_queues(net);
 		break;
@@ -2631,6 +2636,10 @@ static void iv_upd_to(struct l_timeout *upd_timeout, void *user_data)
 		net->iv_update_timeout = NULL;
 		l_info("iv_upd_state = IV_UPD_NORMAL");
 		net->iv_upd_state = IV_UPD_NORMAL;
+		if (net->iv_update)
+			mesh_net_set_seq_num(net, 0);
+
+		net->iv_update = false;
 		if (net->seq_num > IV_UPDATE_SEQ_TRIGGER)
 			mesh_net_iv_index_update(net);
 		break;
@@ -2721,23 +2730,33 @@ static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index,
 	 */
 	local_iv_index = net->iv_index;
 	local_kr = subnet->key_refresh;
-	local_iv_update = iv_is_updating(net);
+	local_iv_update = net->iv_update;
 
-	if (iv_index != local_iv_index || kr_transition)
+	if ((iv_index - iv_update) < (local_iv_index - local_iv_update)) {
+		/* Disallow negative adjustments */
+		l_debug("Expired beacon received");
+		return;
+	}
+
+	if (iv_index != local_iv_index || iv_update != local_iv_update ||
+								kr_transition)
 		l_info("SNB-RX: %8.8x - Key Refresh: %d IV Update: %d",
 					iv_index, rxed_key_refresh, iv_update);
 
 	if (iv_update && (net->iv_upd_state > IV_UPD_UPDATING)) {
 		if (iv_index != net->iv_index)
-			l_error("Update attempted to0 soon (Normal < MIN)");
+			l_error("Update attempted too soon (Normal < MIN)");
 
 		return;
 	}
 
 	if (net->iv_upd_state == IV_UPD_INIT) {
-		if (iv_index > net->iv_index)
+		local_iv_index -= local_iv_update;
+		if ((iv_index - iv_update) > local_iv_index)
 			mesh_net_set_seq_num(net, 0);
+
 		net->iv_index = iv_index;
+		net->iv_update = iv_update;
 
 		if (iv_update) {
 			/* Other devices will be accepting old or new iv_index,
@@ -2755,7 +2774,7 @@ static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index,
 		}
 
 		mesh_config_write_iv_index(node_config_get(net->node), iv_index,
-							net->iv_upd_state);
+								iv_update);
 
 		/* Figure out the key refresh phase */
 		if (kr_transition) {
@@ -2772,29 +2791,32 @@ static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index,
 		return;
 	}
 
-	if (iv_update && !iv_is_updating(net)) {
-		l_info("iv_upd_state = IV_UPD_UPDATING");
-		net->iv_upd_state = IV_UPD_UPDATING;
-		net->iv_update_timeout = l_timeout_create(IV_IDX_UPD_MIN,
-							iv_upd_to, net, NULL);
-		mesh_config_write_iv_index(node_config_get(net->node), iv_index,
-							net->iv_upd_state);
-	} else if (iv_update && iv_index != net->iv_index) {
-		l_error("Update attempted too soon (iv idx already updated)");
-		return;
+	if (iv_update) {
+		if (!local_iv_update &&
+				net->iv_upd_state == IV_UPD_NORMAL_HOLD) {
+			l_error("Update attempted too soon");
+			return;
+		}
+		if (!local_iv_update) {
+			l_info("iv_upd_state = IV_UPD_UPDATING");
+			net->iv_upd_state = IV_UPD_UPDATING;
+			net->iv_update_timeout = l_timeout_create(
+					IV_IDX_UPD_MIN, iv_upd_to, net, NULL);
+		}
 	}
 
-	if (iv_index != local_iv_index || kr_transition)
-		l_info("IVindex 0x%8.8x / Key Refresh update received",
-								iv_index);
+	net->iv_index = iv_index;
+	net->iv_update = iv_update;
 
-	if (iv_index > net->iv_index) {
+	if (iv_update != local_iv_update || iv_index != local_iv_index) {
 		l_queue_clear(net->msg_cache, mesh_msg_free);
-		net->iv_index = iv_index;
 		mesh_config_write_iv_index(node_config_get(net->node), iv_index,
-							net->iv_upd_state);
+								iv_update);
 	}
 
+	if ((iv_index - iv_update) > (local_iv_index - local_iv_update))
+		mesh_net_set_seq_num(net, 0);
+
 	/* Figure out the key refresh phase */
 	if (kr_transition) {
 		if (rxed_key_refresh)
@@ -2803,12 +2825,12 @@ static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index,
 			key_refresh_finish(net, subnet->idx);
 	}
 
-	if (!lpn)
+	/* Don't Beacon if we are an LPN */
+	if (lpn)
 		return;
 
-	if (local_kr != subnet->key_refresh ||
-					local_iv_index != net->iv_index ||
-					local_iv_update != iv_is_updating(net))
+	if (local_kr != subnet->key_refresh || local_iv_index != iv_index ||
+						local_iv_update != iv_update)
 		set_network_beacon(subnet, net);
 }
 
@@ -3128,12 +3150,13 @@ bool mesh_net_iv_index_update(struct mesh_net *net)
 
 	l_info("iv_upd_state = IV_UPD_UPDATING");
 	mesh_net_flush_msg_queues(net);
-	net->iv_upd_state = IV_UPD_UPDATING;
-	net->iv_index++;
 	if (!mesh_config_write_iv_index(node_config_get(net->node),
-					net->iv_index, IV_UPD_UPDATING))
+						net->iv_index + 1, true))
 		return false;
 
+	net->iv_upd_state = IV_UPD_UPDATING;
+	net->iv_index++;
+	net->iv_update = true;
 	l_queue_foreach(net->subnets, set_network_beacon, net);
 	net->iv_update_timeout = l_timeout_create(
 			IV_IDX_UPD_MIN,
-- 
2.21.0


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, back to index

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-07 20:33 [PATCH BlueZ] mesh: Fix IV_Index recovery logic Brian Gix

Linux-Bluetooth Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-bluetooth/0 linux-bluetooth/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-bluetooth linux-bluetooth/ https://lore.kernel.org/linux-bluetooth \
		linux-bluetooth@vger.kernel.org linux-bluetooth@archiver.kernel.org
	public-inbox-index linux-bluetooth

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-bluetooth


AGPL code for this site: git clone https://public-inbox.org/ public-inbox