[PATCH BlueZ] mesh: Fix IV_Index recovery logic

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux