Diff between 4f5a1df1c4ddfbfea9fd46b43ca4ad3f67fd3858 and 9a6ffbbb88d8fb80f6e086e3da264b3505dfc904

Changed Files

File Additions Deletions Status
mesh/mesh-config-json.c +2 -1 modified
mesh/net.c +129 -221 modified

Full Patch

diff --git a/mesh/mesh-config-json.c b/mesh/mesh-config-json.c
index 198fef5..df58cbd 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 2785039..f07de4d 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -41,7 +41,7 @@
 
 #define IV_IDX_DIFF_RANGE	42
 
-/* #define IV_IDX_UPD_MIN	(60)		1 minute for Testing */
+/*#define IV_IDX_UPD_MIN	(5 * 60)	* 5 minute for Testing */
 #define IV_IDX_UPD_MIN	(60 * 60 * 96)	/* 96 Hours - per Spec */
 #define IV_IDX_UPD_HOLD	(IV_IDX_UPD_MIN/2)
 #define IV_IDX_UPD_MAX	(IV_IDX_UPD_MIN + IV_IDX_UPD_HOLD)
@@ -257,6 +257,11 @@ struct net_queue_data {
 	uint16_t len;
 };
 
+struct net_beacon_data {
+	const uint8_t *data;
+	uint16_t len;
+};
+
 #define FAST_CACHE_SIZE 8
 static struct l_queue *fast_cache;
 static struct l_queue *nets;
@@ -503,6 +508,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;
 }
@@ -568,9 +574,10 @@ static bool create_secure_beacon(struct mesh_net *net,
 					struct mesh_subnet *subnet,
 					uint8_t *beacon_data)
 {
+	bool kr = (subnet->kr_phase == KEY_REFRESH_PHASE_TWO);
+
 	return net_key_snb_compose(subnet->net_key_tx, net->iv_index,
-				!!subnet->key_refresh, iv_is_updating(net),
-								beacon_data);
+					kr, net->iv_update, beacon_data);
 }
 
 static void send_network_beacon(struct mesh_subnet *subnet,
@@ -718,6 +725,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 +1042,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? */
@@ -2616,10 +2624,15 @@ static void iv_upd_to(struct l_timeout *upd_timeout, void *user_data)
 			break;
 		}
 
-		l_info("iv_upd_state = IV_UPD_NORMAL_HOLD");
+		l_debug("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;
+		mesh_config_write_iv_index(node_config_get(net->node),
+							net->iv_index, false);
 		l_queue_foreach(net->subnets, set_network_beacon, net);
 		mesh_net_flush_msg_queues(net);
 		break;
@@ -2629,8 +2642,12 @@ static void iv_upd_to(struct l_timeout *upd_timeout, void *user_data)
 	case IV_UPD_NORMAL:
 		l_timeout_remove(upd_timeout);
 		net->iv_update_timeout = NULL;
-		l_info("iv_upd_state = IV_UPD_NORMAL");
+		l_debug("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;
@@ -2707,39 +2724,41 @@ static int key_refresh_finish(struct mesh_net *net, uint16_t idx)
 	return MESH_STATUS_SUCCESS;
 }
 
-static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index,
-				bool iv_update, bool kr_transition,
-				bool rxed_key_refresh, bool lpn)
+static void update_kr_state(struct mesh_subnet *subnet, bool kr, uint32_t id)
+{
+	/* Figure out the key refresh phase */
+	if (kr) {
+		if (id == subnet->net_key_upd) {
+			l_debug("Beacon based KR phase 2 change");
+			key_refresh_phase_two(subnet->net, subnet->idx);
+		}
+	} else {
+		if (id == subnet->net_key_upd) {
+			l_debug("Beacon based KR phase 3 change");
+			key_refresh_finish(subnet->net, subnet->idx);
+		}
+	}
+}
+
+static void update_iv_ivu_state(struct mesh_net *net, uint32_t iv_index,
+								bool ivu)
 {
-	struct mesh_net *net = subnet->net;
-	uint8_t local_kr;
 	uint32_t local_iv_index;
-	bool local_iv_update;
+	bool local_ivu;
 
-	/* Save original settings to avoid resetting same values,
-	 * and secure beacon timer
-	 */
+	/* Save original settings to differentiate what has changed */
 	local_iv_index = net->iv_index;
-	local_kr = subnet->key_refresh;
-	local_iv_update = iv_is_updating(net);
-
-	if (iv_index != local_iv_index || kr_transition)
-		l_info("SNB-RX: %8.8x - Key Refresh: %d IV Update: %d",
-					iv_index, rxed_key_refresh, iv_update);
+	local_ivu = net->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)");
-
-		return;
+	if ((iv_index - ivu) > (local_iv_index - local_ivu)) {
+		/* Don't accept IV_Index changes when performing SAR Out */
+		if (l_queue_length(net->sar_out))
+			return;
 	}
 
+	/* If first beacon seen, accept without judgement */
 	if (net->iv_upd_state == IV_UPD_INIT) {
-		if (iv_index > net->iv_index)
-			mesh_net_set_seq_num(net, 0);
-		net->iv_index = iv_index;
-
-		if (iv_update) {
+		if (ivu) {
 			/* Other devices will be accepting old or new iv_index,
 			 * but we don't know how far through update they are.
 			 * Starting permissive state will allow us maximum
@@ -2753,164 +2772,89 @@ static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index,
 			l_info("iv_upd_state = IV_UPD_NORMAL");
 			net->iv_upd_state = IV_UPD_NORMAL;
 		}
-
-		mesh_config_write_iv_index(node_config_get(net->node), iv_index,
-							net->iv_upd_state);
-
-		/* Figure out the key refresh phase */
-		if (kr_transition) {
-			l_debug("Beacon based KR phase change");
-			if (rxed_key_refresh)
-				key_refresh_phase_two(net, subnet->idx);
-			else
-				key_refresh_finish(net, subnet->idx);
+	} else if (ivu) {
+		/* Ignore beacons with IVU if they come too soon */
+		if (!local_ivu && net->iv_upd_state == IV_UPD_NORMAL_HOLD) {
+			l_error("Update attempted too soon");
+			return;
 		}
 
-		if (!lpn)
-			set_network_beacon(subnet, net);
-
-		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)");
+		if (!local_ivu) {
+			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);
+		}
+	} else if (local_ivu) {
+		l_error("IVU clear attempted too soon");
 		return;
 	}
 
-	if (iv_index != local_iv_index || kr_transition)
-		l_info("IVindex 0x%8.8x / Key Refresh update received",
-								iv_index);
+	if ((iv_index - ivu) > (local_iv_index - local_ivu))
+		mesh_net_set_seq_num(net, 0);
 
-	if (iv_index > net->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);
-	}
+	if (ivu != net->iv_update || local_iv_index != net->iv_index) {
+		struct mesh_config *cfg = node_config_get(net->node);
 
-	/* Figure out the key refresh phase */
-	if (kr_transition) {
-		if (rxed_key_refresh)
-			key_refresh_phase_two(net, subnet->idx);
-		else
-			key_refresh_finish(net, subnet->idx);
+		mesh_config_write_iv_index(cfg, iv_index, ivu);
 	}
 
-	if (!lpn)
-		return;
-
-	if (local_kr != subnet->key_refresh ||
-					local_iv_index != net->iv_index ||
-					local_iv_update != iv_is_updating(net))
-		set_network_beacon(subnet, net);
+	net->iv_index = iv_index;
+	net->iv_update = ivu;
 }
 
-static void process_beacon(void *user_data, const void *data,
-						uint8_t size, int8_t rssi)
+static void process_beacon(void *net_ptr, void *user_data)
 {
-	struct mesh_net *net = user_data;
-	const uint8_t *buf = data;
-	uint32_t iv_index;
-	bool iv_update, rxed_iv_update, rxed_key_refresh;
+	struct mesh_net *net = net_ptr;
+	const uint8_t *buf = *(uint8_t **)user_data;
+	uint32_t ivi;
+	bool ivu, kr, local_kr;
 	struct mesh_subnet *subnet;
 	uint32_t key_id;
-	bool kr_transition = false;
-
-	if (size != 22 || buf[0] != 0x01)
-		return;
-
-	/* print_packet("Secure Net Beacon RXed", data, size); */
-	rxed_key_refresh = (buf[1] & 0x01) == 0x01;
-	rxed_iv_update = iv_update = (buf[1] & 0x02) == 0x02;
-	iv_index = l_get_be32(buf + 10);
-
-	l_debug("KR: %d -- IVU: %d -- IV: %8.8x",
-				rxed_key_refresh, rxed_iv_update, iv_index);
 
-	/* Inhibit recognizing iv_update true-->false
-	 * if we have outbound SAR messages in flight
-	 */
-	if (l_queue_length(net->sar_out)) {
-		if (!iv_update && iv_update != iv_is_updating(net))
-			iv_update = true;
-	}
+	ivi = l_get_be32(buf + 10);
 
-	key_id = net_key_network_id(buf + 2);
-	subnet = l_queue_find(net->subnets, match_key_id,
-						L_UINT_TO_PTR(key_id));
-	if (!subnet || !key_id)
+	/* Ignore out-of-range IV_Index for this network */
+	if ((net->iv_index + IV_IDX_DIFF_RANGE < ivi) || (ivi < net->iv_index))
 		return;
 
-	/* Check if Key Refresh flag value is different from
-	 * the locally stored one
-	 */
-	if (rxed_key_refresh != subnet->key_refresh)
-		kr_transition = true;
-
-	/* If the local node is a provisioner or there are no new keys,
-	 * ignore KR beacon setting
-	 */
-	if (net->provisioner)
-		kr_transition = false;
-	else if (!subnet->net_key_upd)
-		kr_transition = false;
-	/* If beacon's key refresh bit is not set and the beacon is encoded
-	 * with the "new" network key, this signals transition from
-	 * key refresh procedure to normal operation
-	 */
-	else if (!rxed_key_refresh && subnet->net_key_upd == key_id)
-		kr_transition = true;
-
-	if ((net->iv_index + IV_IDX_DIFF_RANGE < iv_index) ||
-						(iv_index < net->iv_index)) {
-		l_info("iv index outside range");
-		return;
-	}
-
-	/* Don't bother going further if nothing has changed */
-	if (!memcmp(&subnet->snb.beacon[1], buf, size)) {
-		subnet->snb.observed++;
+	/* Ignore Network IDs unknown to this mesh universe */
+	key_id = net_key_network_id(buf + 2);
+	if (!key_id)
 		return;
-	}
 
-	if (!rxed_key_refresh && !subnet->key_refresh && !kr_transition)
-		key_id = subnet->net_key_cur;
-	else if (subnet->net_key_upd)
-		key_id = subnet->net_key_upd;
-	else
+	subnet = l_queue_find(net->subnets, match_key_id,
+							L_UINT_TO_PTR(key_id));
+	if (!subnet)
 		return;
 
-	if (!net_key_snb_check(key_id, iv_index, rxed_key_refresh,
-						rxed_iv_update,
-						l_get_be64(buf + 14))) {
-		l_error("mesh_crypto_beacon verify failed");
-		return;
-	}
+	/* Get IVU and KR boolean bits from beacon */
+	ivu = !!(buf[1] & 0x02);
+	kr = !!(buf[1] & 0x01);
+	local_kr = !!(subnet->kr_phase != KEY_REFRESH_PHASE_TWO);
 
-	if (iv_index == net->iv_index &&
-			iv_is_updating(net) == iv_update && !kr_transition) {
-		l_info("No change: IV index %4.4x, rxed KR = %d ",
-						iv_index, rxed_key_refresh);
-		if (net->iv_upd_state == IV_UPD_INIT) {
-			l_info("iv_upd_state = IV_UPD_NORMAL");
-			net->iv_upd_state = IV_UPD_NORMAL;
+	if (net->iv_upd_state != IV_UPD_INIT) {
+		/* Ignore beacons that indicate *no change* */
+		if (!memcmp(&subnet->snb.beacon[1], buf, 22)) {
+			subnet->snb.observed++;
+			return;
 		}
+	}
 
-		subnet->snb.observed++;
+	/* Validate beacon before accepting */
+	if (!net_key_snb_check(key_id, ivi, kr, ivu, l_get_be64(buf + 14))) {
+		l_error("mesh_crypto_beacon verify failed");
 		return;
 	}
 
+	/* We have officially *seen* this beacon now */
 	subnet->snb.observed++;
 
-	update_iv_kr_state(subnet, iv_index, iv_update, kr_transition,
-						rxed_key_refresh, false);
+	update_iv_ivu_state(net, ivi, ivu);
+	update_kr_state(subnet, kr, key_id);
+
+	if (ivi != net->iv_index || ivu != net->iv_update || kr != local_kr)
+		set_network_beacon(subnet, net);
 }
 
 static void lpn_process_beacon(void *user_data, const void *data,
@@ -2918,87 +2862,50 @@ static void lpn_process_beacon(void *user_data, const void *data,
 {
 	struct mesh_net *net = user_data;
 	const uint8_t *buf = data;
-	uint32_t iv_index;
-	bool iv_update, rxed_key_refresh;
+	uint32_t ivi;
+	bool ivu, kr, local_kr;
 	struct mesh_subnet *subnet;
 	bool kr_transition = false;
 
 	/* print_packet("lpn: Secure Net Beacon RXed", data, size); */
-	rxed_key_refresh = (buf[0] & 0x01) == 0x01;
-	iv_update = (buf[0] & 0x02) == 0x02;
-	iv_index = l_get_be32(buf + 1);
+	kr = !!(buf[0] & 0x01);
+	ivu = !!(buf[0] & 0x02);
+	ivi = l_get_be32(buf + 1);
 
-	/* Inhibit recognizing iv_update true-->false if we have outbound
-	 * SAR messages in flight
-	 */
-	if (l_queue_length(net->sar_out)) {
-		if (!iv_update && iv_update != iv_is_updating(net))
-			iv_update = true;
-	}
-
-	l_debug("KR: %d -- IVU: %d -- IV: %8.8x",
-				rxed_key_refresh, iv_update, iv_index);
+	l_debug("KR: %d -- IVU: %d -- IVI: %8.8x", kr, ivu, ivi);
 
 	/* TODO: figure out actual network index (i.e., friendship subnet) */
 	subnet = get_primary_subnet(net);
 	if (!subnet)
 		return;
 
-	/* Check if Key Refresh flag value is different from
-	 * the locally stored one
-	 */
-	if (rxed_key_refresh != subnet->key_refresh)
-		kr_transition = true;
-
-	/* If the local node is a provisioner or there are no new keys,
-	 * ignore KR beacon setting
-	 */
-	if (!subnet->net_key_upd)
-		kr_transition = false;
-
-	if ((net->iv_index + IV_IDX_DIFF_RANGE < iv_index) ||
-					(iv_index < net->iv_index)) {
-		l_info("iv index outside range");
-		return;
-	}
+	local_kr = (subnet->kr_phase == KEY_REFRESH_PHASE_TWO);
 
 	/* Don't bother going further if nothing has changed */
-	if (!kr_transition && iv_index == net->iv_index &&
-			iv_update == iv_is_updating(net) &&
-			net->iv_upd_state != IV_UPD_INIT)
+	if (local_kr == kr && ivi == net->iv_index && ivu == net->iv_update &&
+					net->iv_upd_state != IV_UPD_INIT)
 		return;
 
-	if (iv_index == net->iv_index &&
-			iv_is_updating(net) == iv_update && !kr_transition) {
-		l_info("No change: IV index %4.4x, rxed KR = %d ",
-						iv_index, rxed_key_refresh);
-		if (net->iv_upd_state == IV_UPD_INIT) {
-			l_info("iv_upd_state = IV_UPD_NORMAL");
-			net->iv_upd_state = IV_UPD_NORMAL;
-		}
-		return;
-	}
+	update_iv_ivu_state(net, ivi, ivu);
 
-	update_iv_kr_state(subnet, iv_index, iv_update, kr_transition,
-						rxed_key_refresh, true);
+	if (kr)
+		update_kr_state(subnet, kr_transition, subnet->net_key_upd);
+	else
+		update_kr_state(subnet, kr_transition, subnet->net_key_cur);
 }
 
 static void beacon_recv(void *user_data, struct mesh_io_recv_info *info,
 					const uint8_t *data, uint16_t len)
 {
-	struct mesh_net *net = user_data;
-	int8_t rssi = 0;
+	const uint8_t *ptr = data + 1;
 
-	if (len <= 2 || !net)
+	if (len != 23 || data[1] != 0x01)
 		return;
 
-	if (info) {
-		net->instant = info->instant;
-		net->chan = info->chan;
-		rssi = info->rssi;
-	}
+	l_debug("KR: %d -- IVU: %d -- IV: %8.8x",
+			data[2] & 1, !!(data[2] & 2), l_get_be32(data + 11));
 
-	process_beacon(user_data, data + 1, len - 1, rssi);
+	l_queue_foreach(nets, process_beacon, &ptr);
 }
 
 bool mesh_net_set_beacon_mode(struct mesh_net *net, bool enable)
@@ -3044,7 +2951,7 @@ bool mesh_net_set_key(struct mesh_net *net, uint16_t idx, const uint8_t *key,
 	if (!subnet)
 		return false;
 
-	if (new_key)
+	if (new_key && phase)
 		subnet->net_key_upd = net_key_add(new_key);
 
 	/* Preserve key refresh state to generate secure beacon flags*/
@@ -3085,7 +2992,7 @@ bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io)
 
 		l_info("Register io cb");
 		mesh_io_register_recv_cb(io, MESH_IO_FILTER_BEACON,
-							beacon_recv, net);
+							beacon_recv, NULL);
 		mesh_io_register_recv_cb(io, MESH_IO_FILTER_NET,
 							net_msg_recv, NULL);
 		l_queue_foreach(net->subnets, start_network_beacon, net);
@@ -3128,12 +3035,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,