linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH BlueZ v2] mesh: Fix Relaying for multiple nodes
@ 2019-01-18 23:13 Brian Gix
  2019-01-22 20:50 ` Gix, Brian
  0 siblings, 1 reply; 2+ messages in thread
From: Brian Gix @ 2019-01-18 23:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, brian.gix

Relay is now a cooperation between all the nodes on the daemon.
If any one or more nodes have relay enabled and a received packet
is addressed to a Group, or a non-present Unicast address, then the
packet's TTL is decremented and it is resent.
---
 mesh/crypto.c    |   8 +--
 mesh/mesh-defs.h |   9 ++-
 mesh/net.c       | 186 ++++++++++++++++++++++++++++++++-----------------------
 3 files changed, 118 insertions(+), 85 deletions(-)

diff --git a/mesh/crypto.c b/mesh/crypto.c
index e68cc2d5f..451e2da71 100644
--- a/mesh/crypto.c
+++ b/mesh/crypto.c
@@ -1169,13 +1169,13 @@ bool mesh_crypto_packet_parse(const uint8_t *packet, uint8_t packet_len,
 				*payload = packet + 9;
 
 			if (payload_len)
-				*payload_len = packet_len - 9 - 8;
+				*payload_len = packet_len - 9;
 		} else {
 			if (payload)
 				*payload = packet + 10;
 
 			if (payload_len)
-				*payload_len = packet_len - 10 - 8;
+				*payload_len = packet_len - 10;
 		}
 	} else {
 		if (cookie)
@@ -1202,13 +1202,13 @@ bool mesh_crypto_packet_parse(const uint8_t *packet, uint8_t packet_len,
 				*payload = packet + 13;
 
 			if (payload_len)
-				*payload_len = packet_len - 13 - 4;
+				*payload_len = packet_len - 13;
 		} else {
 			if (payload)
 				*payload = packet + 10;
 
 			if (payload_len)
-				*payload_len = packet_len - 10 - 4;
+				*payload_len = packet_len - 10;
 		}
 	}
 
diff --git a/mesh/mesh-defs.h b/mesh/mesh-defs.h
index d40fc43e8..c30041e4a 100644
--- a/mesh/mesh-defs.h
+++ b/mesh/mesh-defs.h
@@ -62,7 +62,9 @@
 #define VIRTUAL_ADDRESS_LOW	0x8000
 #define VIRTUAL_ADDRESS_HIGH	0xbfff
 #define GROUP_ADDRESS_LOW	0xc000
-#define GROUP_ADDRESS_HIGH	0xff00
+#define GROUP_ADDRESS_HIGH	0xfeff
+#define FIXED_GROUP_LOW		0xff00
+#define FIXED_GROUP_HIGH	0xffff
 
 #define NODE_IDENTITY_STOPPED		0x00
 #define NODE_IDENTITY_RUNNING		0x01
@@ -79,6 +81,7 @@
 					((x) < VIRTUAL_ADDRESS_LOW))
 #define IS_VIRTUAL(x)		(((x) >= VIRTUAL_ADDRESS_LOW) && \
 					((x) <= VIRTUAL_ADDRESS_HIGH))
-#define IS_GROUP(x)		(((x) >= GROUP_ADDRESS_LOW) && \
-					((x) <= GROUP_ADDRESS_HIGH))
+#define IS_GROUP(x)		((((x) >= GROUP_ADDRESS_LOW) && \
+					((x) < FIXED_GROUP_HIGH)) || \
+					((x) == ALL_NODES_ADDRESS))
 #define IS_ALL_NODES(x)	((x) == ALL_NODES_ADDRESS)
diff --git a/mesh/net.c b/mesh/net.c
index 6ef056b56..9e509a8ea 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -71,6 +71,13 @@
 
 #define SAR_KEY(src, seq0)	((((uint32_t)(seq0)) << 16) | (src))
 
+enum _relay_advice {
+	RELAY_NONE,		/* Relay not enabled in node */
+	RELAY_ALLOWED,		/* Relay enabled, msg not to node's unicast */
+	RELAY_DISALLOWED,	/* Msg was unicast handled by this node */
+	RELAY_ALWAYS		/* Relay enabled, msg to a group */
+};
+
 enum _iv_upd_state {
 	/* Allows acceptance of any iv_index secure net beacon */
 	IV_UPD_INIT,
@@ -160,7 +167,6 @@ struct mesh_net {
 	struct l_queue *frnd_msgs;
 	struct l_queue *friends;
 	struct l_queue *destinations;
-	struct l_queue *fast_cache;
 
 	uint8_t prov_priv_key[32];
 
@@ -248,6 +254,8 @@ struct net_decode {
 	bool proxy;
 };
 
+#define FAST_CACHE_SIZE 8
+static struct l_queue *fast_cache;
 static struct l_queue *nets;
 
 static inline struct mesh_subnet *get_primary_subnet(struct mesh_net *net)
@@ -673,7 +681,6 @@ struct mesh_net *mesh_net_new(struct mesh_node *node)
 	net->tx_interval = DEFAULT_TRANSMIT_INTERVAL;
 
 	net->subnets = l_queue_new();
-	net->fast_cache = l_queue_new();
 	net->msg_cache = l_queue_new();
 	net->sar_in = l_queue_new();
 	net->sar_out = l_queue_new();
@@ -687,6 +694,9 @@ struct mesh_net *mesh_net_new(struct mesh_node *node)
 	if (!nets)
 		nets = l_queue_new();
 
+	if (!fast_cache)
+		fast_cache = l_queue_new();
+
 	return net;
 }
 
@@ -696,7 +706,6 @@ void mesh_net_free(struct mesh_net *net)
 		return;
 
 	l_queue_destroy(net->subnets, subnet_free);
-	l_queue_destroy(net->fast_cache, mesh_msg_free);
 	l_queue_destroy(net->msg_cache, mesh_msg_free);
 	l_queue_destroy(net->sar_in, mesh_sar_free);
 	l_queue_destroy(net->sar_out, mesh_sar_free);
@@ -1021,7 +1030,6 @@ int mesh_net_add_key(struct mesh_net *net, bool update, uint16_t idx,
 void mesh_net_flush_msg_queues(struct mesh_net *net)
 {
 	l_queue_clear(net->msg_cache, mesh_msg_free);
-	l_queue_clear(net->fast_cache, mesh_msg_free);
 }
 
 uint32_t mesh_net_get_iv_index(struct mesh_net *net)
@@ -2210,23 +2218,23 @@ static bool find_fast_hash(const void *a, const void *b)
 	return *entry == *test;
 }
 
-static void *check_fast_cache(struct mesh_net *net, uint64_t hash)
+static bool check_fast_cache(uint64_t hash)
 {
-	void *found = l_queue_find(net->fast_cache, find_fast_hash, &hash);
+	void *found = l_queue_find(fast_cache, find_fast_hash, &hash);
 	uint64_t *new_hash;
 
 	if (found)
-		return NULL;
+		return false;
 
-	if (l_queue_length(net->fast_cache) >= 8)
-		new_hash = l_queue_pop_head(net->fast_cache);
+	if (l_queue_length(fast_cache) >= FAST_CACHE_SIZE)
+		new_hash = l_queue_pop_head(fast_cache);
 	else
 		new_hash = l_malloc(sizeof(hash));
 
 	*new_hash = hash;
-	l_queue_push_tail(net->fast_cache, new_hash);
+	l_queue_push_tail(fast_cache, new_hash);
 
-	return new_hash;
+	return true;
 }
 
 static bool match_by_dst(const void *a, const void *b)
@@ -2237,8 +2245,9 @@ static bool match_by_dst(const void *a, const void *b)
 	return dest->dst == dst;
 }
 
-static void send_relay_pkt(struct mesh_net *net, uint8_t *packet, uint8_t size)
+static void send_relay_pkt(struct mesh_net *net, uint8_t *data, uint8_t size)
 {
+	uint8_t packet[30];
 	struct mesh_io *io = net->io;
 	struct mesh_io_send_info info = {
 		.type = MESH_IO_TIMING_TYPE_GENERAL,
@@ -2249,8 +2258,9 @@ static void send_relay_pkt(struct mesh_net *net, uint8_t *packet, uint8_t size)
 	};
 
 	packet[0] = MESH_AD_TYPE_NETWORK;
+	memcpy(packet + 1, data, size);
 
-	mesh_io_send(io, &info, packet, size);
+	mesh_io_send(io, &info, packet, size + 1);
 }
 
 static void send_msg_pkt(struct mesh_net *net, uint8_t *packet, uint8_t size)
@@ -2270,15 +2280,12 @@ static void send_msg_pkt(struct mesh_net *net, uint8_t *packet, uint8_t size)
 	mesh_io_send(io, &info, packet, size);
 }
 
-static void packet_received(void *user_data, const void *data, uint8_t size,
-								int8_t rssi)
+static enum _relay_advice packet_received(void *user_data,
+				uint32_t key_id, uint32_t iv_index,
+				const void *data, uint8_t size, int8_t rssi)
 {
 	struct mesh_net *net = user_data;
-	uint32_t iv_index;
-	uint8_t iv_flag;
 	const uint8_t *msg = data;
-	uint8_t *out;
-	size_t out_size;
 	uint8_t app_msg_len;
 	uint8_t net_ttl, net_key_id, net_segO, net_segN, net_opcode;
 	uint32_t net_seq, cache_cookie;
@@ -2287,50 +2294,13 @@ static void packet_received(void *user_data, const void *data, uint8_t size,
 	bool net_ctl, net_segmented, net_szmic, net_relay;
 	struct mesh_friend *net_frnd = NULL;
 	bool drop = false;
-	uint64_t hash, *isNew = NULL;
-	uint32_t key_id;
-
-	iv_flag = msg[0] >> 7;
-	iv_index = net->iv_index;
-	l_debug("%s iv_index %d NID: %2.2x", __func__, iv_index, msg[0] & 0x7f);
-
-	if (sizeof(uint16_t) <= sizeof(void *)) {
-		/* Add in additional cache to allow us to
-		 * avoid decrypting duplicatesr
-		 * Fast 64 bit Hash, Network MIC doesn't matter
-		 * With 64 bit hash, false pos chance is 1 in 1.8 * 10^19
-		 */
-		hash = l_get_le64(msg + 1) ^ l_get_le64(msg + 9);
-		isNew = check_fast_cache(net, hash);
-		if (!isNew)
-			return;
-
-		l_debug("New");
-	}
-
-	memcpy(packet + 2, data, size);
-
-	if (iv_index && (iv_index & 0x01) != iv_flag)
-		iv_index--;
 
 	/* Tester--Drop 90% of packets */
 	/* l_getrandom(&iv_flag, 1); */
 	/* if (iv_flag%10<9) drop = true; */
 
-	if (!drop)
-		print_packet("RX: Network [enc] :", data, size);
-
-	key_id = net_key_decrypt(iv_index, packet + 2, size, &out, &out_size);
 
-	if (!key_id) {
-		l_debug("Failed to decode packet");
-		/* Remove fast-cache-hash */
-		l_queue_remove(net->fast_cache, isNew);
-		l_free(isNew);
-		return;
-	}
-
-	memcpy(packet + 2, out, out_size);
+	memcpy(packet + 2, data, size);
 
 	if (!drop)
 		print_packet("RX: Network [clr] :", packet + 2, size);
@@ -2347,7 +2317,7 @@ static void packet_received(void *user_data, const void *data, uint8_t size,
 					&net_segO, &net_segN,
 					&msg, &app_msg_len)) {
 		l_error("Failed to parse packet content");
-		return;
+		return RELAY_NONE;
 	}
 
 	/* Ignore incoming packets if we are LPN and frnd bit not set */
@@ -2357,7 +2327,7 @@ static void packet_received(void *user_data, const void *data, uint8_t size,
 		subnet = l_queue_find(net->subnets, match_key_id,
 							L_UINT_TO_PTR(key_id));
 		if (subnet)
-			return;
+			return RELAY_NONE;
 
 		/* If the queue is empty, stop polling */
 		if (net_ctl && net_opcode == NET_OP_FRND_UPDATE && !msg[5])
@@ -2368,16 +2338,16 @@ static void packet_received(void *user_data, const void *data, uint8_t size,
 	} else if (net_dst == 0) {
 		l_error("illegal parms: DST: %4.4x Ctl: %d TTL: %2.2x",
 						net_dst, net_ctl, net_ttl);
-		return;
+		return RELAY_NONE;
 	}
 
 	/* Ignore if we originally sent this */
 	if (is_us(net, net_src, true))
-		return;
+		return RELAY_NONE;
 
 	if (drop) {
 		l_info("Dropping SEQ 0x%06x", net_seq);
-		return;
+		return RELAY_NONE;
 	}
 
 	l_debug("check %08x", cache_cookie);
@@ -2385,7 +2355,7 @@ static void packet_received(void *user_data, const void *data, uint8_t size,
 	/* As a Relay, suppress repeats of last N packets that pass through */
 	/* The "cache_cookie" should be unique part of App message */
 	if (msg_in_cache(net, net_src, net_seq, cache_cookie))
-		return;
+		return RELAY_NONE;
 
 	l_debug("RX: Network %04x -> %04x : TTL 0x%02x : IV : %8.8x SEQ 0x%06x",
 			net_src, net_dst, net_ttl, iv_index, net_seq);
@@ -2403,12 +2373,12 @@ static void packet_received(void *user_data, const void *data, uint8_t size,
 			if (net_opcode == NET_OP_SEG_ACKNOWLEDGE) {
 				/* Illegal to send ACK to non-Unicast Addr */
 				if (net_dst & 0x8000)
-					return;
+					return RELAY_NONE;
 
 				/* print_packet("Got ACK", msg, app_msg_len); */
 				/* Pedantic check for correct size */
 				if (app_msg_len != 7)
-					return;
+					return RELAY_NONE;
 
 				/* If this is an ACK to our friend queue-only */
 				if (is_lpn_friend(net, net_dst, true))
@@ -2468,28 +2438,37 @@ static void packet_received(void *user_data, const void *data, uint8_t size,
 		if (!!(net_frnd))
 			l_info("Ask for more data!");
 
-		/* If this is one of our Unicast addresses, don't relay */
-		if (net_dst <= 0x7fff)
-			return;
+		/* If this is one of our Unicast addresses, disallow relay */
+		if (IS_UNICAST(net_dst))
+			return RELAY_DISALLOWED;
 	}
 
+	/* If relay not enable, or no more hops allowed */
 	if (!net->relay.enable || net_ttl < 0x02 || net_frnd)
-		return;
+		return RELAY_NONE;
 
-	packet[2 + 1] = (packet[2 + 1] & ~TTL_MASK) | (net_ttl - 1);
+	/* Group or Virtual destinations should *always* be relayed */
+	if (IS_GROUP(net_dst) || IS_VIRTUAL(net_dst))
+		return RELAY_ALWAYS;
 
-	if (!net_key_encrypt(key_id, iv_index, packet + 2, size)) {
-		l_error("Failed to encode relay packet");
-		return;
-	}
+	/* Unicast destinations for other nodes *may* be relayed */
+	else if (IS_UNICAST(net_dst))
+		return RELAY_ALLOWED;
 
-	if (net->relay.enable)
-		send_relay_pkt(net, packet, size + 1);
+	/* Otherwise, do not make a relay decision */
+	else
+		return RELAY_NONE;
 }
 
 struct net_queue_data {
 	struct mesh_io_recv_info *info;
+	struct mesh_net *net;
 	const uint8_t *data;
+	uint8_t *out;
+	size_t out_size;
+	enum _relay_advice relay_advice;
+	uint32_t key_id;
+	uint32_t iv_index;
 	uint16_t len;
 };
 
@@ -2497,30 +2476,78 @@ static void net_rx(void *net_ptr, void *user_data)
 {
 	struct net_queue_data *data = user_data;
 	struct mesh_net *net = net_ptr;
+	enum _relay_advice relay_advice;
+	uint8_t *out;
+	size_t out_size;
+	uint32_t key_id;
 	int8_t rssi = 0;
 
+	key_id = net_key_decrypt(net->iv_index, data->data, data->len,
+								&out, &out_size);
+
+	if (!key_id)
+		return;
+
+	print_packet("RX: Network [enc] :", data->data, data->len);
+
 	if (data->info) {
 		net->instant = data->info->instant;
 		net->chan = data->info->chan;
 		rssi = data->info->rssi;
 	}
 
-	packet_received(net, data->data, data->len, rssi);
+	relay_advice = packet_received(net, key_id, net->iv_index,
+							out, out_size, rssi);
+	if (relay_advice > data->relay_advice) {
+		bool iv_flag = !!(net->iv_index & 1);
+		bool iv_pkt = !!(data->data[0] & 0x80);
+
+		data->iv_index = net->iv_index;
+		if (iv_pkt != iv_flag)
+			data->iv_index--;
+
+		data->relay_advice = relay_advice;
+		data->key_id = key_id;
+		data->net = net;
+		data->out = out;
+		data->out_size = out_size;
+	}
 }
 
 static void net_msg_recv(void *user_data, struct mesh_io_recv_info *info,
 					const uint8_t *data, uint16_t len)
 {
+	uint64_t hash;
+	bool isNew;
 	struct net_queue_data net_data = {
 		.info = info,
 		.data = data + 1,
 		.len = len - 1,
+		.relay_advice = RELAY_NONE,
 	};
 
-	if (len <= 2)
+	if (len < 9)
+		return;
+
+	hash = l_get_le64(data + 1);
+
+	/* Only process packet once per reception */
+	isNew = check_fast_cache(hash);
+	if (!isNew)
 		return;
 
 	l_queue_foreach(nets, net_rx, &net_data);
+
+	if (net_data.relay_advice == RELAY_ALWAYS ||
+			net_data.relay_advice == RELAY_ALLOWED) {
+		uint8_t ttl = net_data.out[1] & TTL_MASK;
+
+		net_data.out[1] &=  ~TTL_MASK;
+		net_data.out[1] |= ttl - 1;
+		net_key_encrypt(net_data.key_id, net_data.iv_index,
+					net_data.out, net_data.out_size);
+		send_relay_pkt(net_data.net, net_data.out, net_data.out_size);
+	}
 }
 
 static void set_network_beacon(void *a, void *b)
@@ -2927,6 +2954,9 @@ bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io)
 		if (!nets)
 			nets = l_queue_new();
 
+		if (!fast_cache)
+			fast_cache = l_queue_new();
+
 		l_info("Register io cb");
 		mesh_io_register_recv_cb(io, MESH_IO_FILTER_BEACON,
 							beacon_recv, net);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* RE: [PATCH BlueZ v2] mesh: Fix Relaying for multiple nodes
  2019-01-18 23:13 [PATCH BlueZ v2] mesh: Fix Relaying for multiple nodes Brian Gix
@ 2019-01-22 20:50 ` Gix, Brian
  0 siblings, 0 replies; 2+ messages in thread
From: Gix, Brian @ 2019-01-22 20:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Stotland, Inga

patch applied

> -----Original Message-----
> From: Gix, Brian
> Sent: Friday, January 18, 2019 3:14 PM
> To: linux-bluetooth@vger.kernel.org
> Cc: Stotland, Inga <inga.stotland@intel.com>; Gix, Brian
> <brian.gix@intel.com>
> Subject: [PATCH BlueZ v2] mesh: Fix Relaying for multiple nodes
> 
> Relay is now a cooperation between all the nodes on the daemon.
> If any one or more nodes have relay enabled and a received packet is
> addressed to a Group, or a non-present Unicast address, then the packet's
> TTL is decremented and it is resent.
> ---
>  mesh/crypto.c    |   8 +--
>  mesh/mesh-defs.h |   9 ++-
>  mesh/net.c       | 186 ++++++++++++++++++++++++++++++++-----------------
> ------
>  3 files changed, 118 insertions(+), 85 deletions(-)
> 
> diff --git a/mesh/crypto.c b/mesh/crypto.c index e68cc2d5f..451e2da71
> 100644
> --- a/mesh/crypto.c
> +++ b/mesh/crypto.c
> @@ -1169,13 +1169,13 @@ bool mesh_crypto_packet_parse(const uint8_t
> *packet, uint8_t packet_len,
>  				*payload = packet + 9;
> 
>  			if (payload_len)
> -				*payload_len = packet_len - 9 - 8;
> +				*payload_len = packet_len - 9;
>  		} else {
>  			if (payload)
>  				*payload = packet + 10;
> 
>  			if (payload_len)
> -				*payload_len = packet_len - 10 - 8;
> +				*payload_len = packet_len - 10;
>  		}
>  	} else {
>  		if (cookie)
> @@ -1202,13 +1202,13 @@ bool mesh_crypto_packet_parse(const uint8_t
> *packet, uint8_t packet_len,
>  				*payload = packet + 13;
> 
>  			if (payload_len)
> -				*payload_len = packet_len - 13 - 4;
> +				*payload_len = packet_len - 13;
>  		} else {
>  			if (payload)
>  				*payload = packet + 10;
> 
>  			if (payload_len)
> -				*payload_len = packet_len - 10 - 4;
> +				*payload_len = packet_len - 10;
>  		}
>  	}
> 
> diff --git a/mesh/mesh-defs.h b/mesh/mesh-defs.h index
> d40fc43e8..c30041e4a 100644
> --- a/mesh/mesh-defs.h
> +++ b/mesh/mesh-defs.h
> @@ -62,7 +62,9 @@
>  #define VIRTUAL_ADDRESS_LOW	0x8000
>  #define VIRTUAL_ADDRESS_HIGH	0xbfff
>  #define GROUP_ADDRESS_LOW	0xc000
> -#define GROUP_ADDRESS_HIGH	0xff00
> +#define GROUP_ADDRESS_HIGH	0xfeff
> +#define FIXED_GROUP_LOW		0xff00
> +#define FIXED_GROUP_HIGH	0xffff
> 
>  #define NODE_IDENTITY_STOPPED		0x00
>  #define NODE_IDENTITY_RUNNING		0x01
> @@ -79,6 +81,7 @@
>  					((x) < VIRTUAL_ADDRESS_LOW))
>  #define IS_VIRTUAL(x)		(((x) >= VIRTUAL_ADDRESS_LOW)
> && \
>  					((x) <= VIRTUAL_ADDRESS_HIGH))
> -#define IS_GROUP(x)		(((x) >= GROUP_ADDRESS_LOW) && \
> -					((x) <= GROUP_ADDRESS_HIGH))
> +#define IS_GROUP(x)		((((x) >= GROUP_ADDRESS_LOW) && \
> +					((x) < FIXED_GROUP_HIGH)) || \
> +					((x) == ALL_NODES_ADDRESS))
>  #define IS_ALL_NODES(x)	((x) == ALL_NODES_ADDRESS)
> diff --git a/mesh/net.c b/mesh/net.c
> index 6ef056b56..9e509a8ea 100644
> --- a/mesh/net.c
> +++ b/mesh/net.c
> @@ -71,6 +71,13 @@
> 
>  #define SAR_KEY(src, seq0)	((((uint32_t)(seq0)) << 16) | (src))
> 
> +enum _relay_advice {
> +	RELAY_NONE,		/* Relay not enabled in node */
> +	RELAY_ALLOWED,		/* Relay enabled, msg not to node's
> unicast */
> +	RELAY_DISALLOWED,	/* Msg was unicast handled by this node */
> +	RELAY_ALWAYS		/* Relay enabled, msg to a group */
> +};
> +
>  enum _iv_upd_state {
>  	/* Allows acceptance of any iv_index secure net beacon */
>  	IV_UPD_INIT,
> @@ -160,7 +167,6 @@ struct mesh_net {
>  	struct l_queue *frnd_msgs;
>  	struct l_queue *friends;
>  	struct l_queue *destinations;
> -	struct l_queue *fast_cache;
> 
>  	uint8_t prov_priv_key[32];
> 
> @@ -248,6 +254,8 @@ struct net_decode {
>  	bool proxy;
>  };
> 
> +#define FAST_CACHE_SIZE 8
> +static struct l_queue *fast_cache;
>  static struct l_queue *nets;
> 
>  static inline struct mesh_subnet *get_primary_subnet(struct mesh_net
> *net) @@ -673,7 +681,6 @@ struct mesh_net *mesh_net_new(struct
> mesh_node *node)
>  	net->tx_interval = DEFAULT_TRANSMIT_INTERVAL;
> 
>  	net->subnets = l_queue_new();
> -	net->fast_cache = l_queue_new();
>  	net->msg_cache = l_queue_new();
>  	net->sar_in = l_queue_new();
>  	net->sar_out = l_queue_new();
> @@ -687,6 +694,9 @@ struct mesh_net *mesh_net_new(struct mesh_node
> *node)
>  	if (!nets)
>  		nets = l_queue_new();
> 
> +	if (!fast_cache)
> +		fast_cache = l_queue_new();
> +
>  	return net;
>  }
> 
> @@ -696,7 +706,6 @@ void mesh_net_free(struct mesh_net *net)
>  		return;
> 
>  	l_queue_destroy(net->subnets, subnet_free);
> -	l_queue_destroy(net->fast_cache, mesh_msg_free);
>  	l_queue_destroy(net->msg_cache, mesh_msg_free);
>  	l_queue_destroy(net->sar_in, mesh_sar_free);
>  	l_queue_destroy(net->sar_out, mesh_sar_free); @@ -1021,7
> +1030,6 @@ int mesh_net_add_key(struct mesh_net *net, bool update,
> uint16_t idx,  void mesh_net_flush_msg_queues(struct mesh_net *net)  {
>  	l_queue_clear(net->msg_cache, mesh_msg_free);
> -	l_queue_clear(net->fast_cache, mesh_msg_free);
>  }
> 
>  uint32_t mesh_net_get_iv_index(struct mesh_net *net) @@ -2210,23
> +2218,23 @@ static bool find_fast_hash(const void *a, const void *b)
>  	return *entry == *test;
>  }
> 
> -static void *check_fast_cache(struct mesh_net *net, uint64_t hash)
> +static bool check_fast_cache(uint64_t hash)
>  {
> -	void *found = l_queue_find(net->fast_cache, find_fast_hash,
> &hash);
> +	void *found = l_queue_find(fast_cache, find_fast_hash, &hash);
>  	uint64_t *new_hash;
> 
>  	if (found)
> -		return NULL;
> +		return false;
> 
> -	if (l_queue_length(net->fast_cache) >= 8)
> -		new_hash = l_queue_pop_head(net->fast_cache);
> +	if (l_queue_length(fast_cache) >= FAST_CACHE_SIZE)
> +		new_hash = l_queue_pop_head(fast_cache);
>  	else
>  		new_hash = l_malloc(sizeof(hash));
> 
>  	*new_hash = hash;
> -	l_queue_push_tail(net->fast_cache, new_hash);
> +	l_queue_push_tail(fast_cache, new_hash);
> 
> -	return new_hash;
> +	return true;
>  }
> 
>  static bool match_by_dst(const void *a, const void *b) @@ -2237,8 +2245,9
> @@ static bool match_by_dst(const void *a, const void *b)
>  	return dest->dst == dst;
>  }
> 
> -static void send_relay_pkt(struct mesh_net *net, uint8_t *packet, uint8_t
> size)
> +static void send_relay_pkt(struct mesh_net *net, uint8_t *data, uint8_t
> +size)
>  {
> +	uint8_t packet[30];
>  	struct mesh_io *io = net->io;
>  	struct mesh_io_send_info info = {
>  		.type = MESH_IO_TIMING_TYPE_GENERAL,
> @@ -2249,8 +2258,9 @@ static void send_relay_pkt(struct mesh_net *net,
> uint8_t *packet, uint8_t size)
>  	};
> 
>  	packet[0] = MESH_AD_TYPE_NETWORK;
> +	memcpy(packet + 1, data, size);
> 
> -	mesh_io_send(io, &info, packet, size);
> +	mesh_io_send(io, &info, packet, size + 1);
>  }
> 
>  static void send_msg_pkt(struct mesh_net *net, uint8_t *packet, uint8_t
> size) @@ -2270,15 +2280,12 @@ static void send_msg_pkt(struct mesh_net
> *net, uint8_t *packet, uint8_t size)
>  	mesh_io_send(io, &info, packet, size);  }
> 
> -static void packet_received(void *user_data, const void *data, uint8_t size,
> -								int8_t rssi)
> +static enum _relay_advice packet_received(void *user_data,
> +				uint32_t key_id, uint32_t iv_index,
> +				const void *data, uint8_t size, int8_t rssi)
>  {
>  	struct mesh_net *net = user_data;
> -	uint32_t iv_index;
> -	uint8_t iv_flag;
>  	const uint8_t *msg = data;
> -	uint8_t *out;
> -	size_t out_size;
>  	uint8_t app_msg_len;
>  	uint8_t net_ttl, net_key_id, net_segO, net_segN, net_opcode;
>  	uint32_t net_seq, cache_cookie;
> @@ -2287,50 +2294,13 @@ static void packet_received(void *user_data,
> const void *data, uint8_t size,
>  	bool net_ctl, net_segmented, net_szmic, net_relay;
>  	struct mesh_friend *net_frnd = NULL;
>  	bool drop = false;
> -	uint64_t hash, *isNew = NULL;
> -	uint32_t key_id;
> -
> -	iv_flag = msg[0] >> 7;
> -	iv_index = net->iv_index;
> -	l_debug("%s iv_index %d NID: %2.2x", __func__, iv_index, msg[0] &
> 0x7f);
> -
> -	if (sizeof(uint16_t) <= sizeof(void *)) {
> -		/* Add in additional cache to allow us to
> -		 * avoid decrypting duplicatesr
> -		 * Fast 64 bit Hash, Network MIC doesn't matter
> -		 * With 64 bit hash, false pos chance is 1 in 1.8 * 10^19
> -		 */
> -		hash = l_get_le64(msg + 1) ^ l_get_le64(msg + 9);
> -		isNew = check_fast_cache(net, hash);
> -		if (!isNew)
> -			return;
> -
> -		l_debug("New");
> -	}
> -
> -	memcpy(packet + 2, data, size);
> -
> -	if (iv_index && (iv_index & 0x01) != iv_flag)
> -		iv_index--;
> 
>  	/* Tester--Drop 90% of packets */
>  	/* l_getrandom(&iv_flag, 1); */
>  	/* if (iv_flag%10<9) drop = true; */
> 
> -	if (!drop)
> -		print_packet("RX: Network [enc] :", data, size);
> -
> -	key_id = net_key_decrypt(iv_index, packet + 2, size, &out,
> &out_size);
> 
> -	if (!key_id) {
> -		l_debug("Failed to decode packet");
> -		/* Remove fast-cache-hash */
> -		l_queue_remove(net->fast_cache, isNew);
> -		l_free(isNew);
> -		return;
> -	}
> -
> -	memcpy(packet + 2, out, out_size);
> +	memcpy(packet + 2, data, size);
> 
>  	if (!drop)
>  		print_packet("RX: Network [clr] :", packet + 2, size); @@ -
> 2347,7 +2317,7 @@ static void packet_received(void *user_data, const void
> *data, uint8_t size,
>  					&net_segO, &net_segN,
>  					&msg, &app_msg_len)) {
>  		l_error("Failed to parse packet content");
> -		return;
> +		return RELAY_NONE;
>  	}
> 
>  	/* Ignore incoming packets if we are LPN and frnd bit not set */ @@ -
> 2357,7 +2327,7 @@ static void packet_received(void *user_data, const void
> *data, uint8_t size,
>  		subnet = l_queue_find(net->subnets, match_key_id,
> 
> 	L_UINT_TO_PTR(key_id));
>  		if (subnet)
> -			return;
> +			return RELAY_NONE;
> 
>  		/* If the queue is empty, stop polling */
>  		if (net_ctl && net_opcode == NET_OP_FRND_UPDATE &&
> !msg[5]) @@ -2368,16 +2338,16 @@ static void packet_received(void
> *user_data, const void *data, uint8_t size,
>  	} else if (net_dst == 0) {
>  		l_error("illegal parms: DST: %4.4x Ctl: %d TTL: %2.2x",
>  						net_dst, net_ctl, net_ttl);
> -		return;
> +		return RELAY_NONE;
>  	}
> 
>  	/* Ignore if we originally sent this */
>  	if (is_us(net, net_src, true))
> -		return;
> +		return RELAY_NONE;
> 
>  	if (drop) {
>  		l_info("Dropping SEQ 0x%06x", net_seq);
> -		return;
> +		return RELAY_NONE;
>  	}
> 
>  	l_debug("check %08x", cache_cookie);
> @@ -2385,7 +2355,7 @@ static void packet_received(void *user_data, const
> void *data, uint8_t size,
>  	/* As a Relay, suppress repeats of last N packets that pass through */
>  	/* The "cache_cookie" should be unique part of App message */
>  	if (msg_in_cache(net, net_src, net_seq, cache_cookie))
> -		return;
> +		return RELAY_NONE;
> 
>  	l_debug("RX: Network %04x -> %04x : TTL 0x%02x : IV : %8.8x SEQ
> 0x%06x",
>  			net_src, net_dst, net_ttl, iv_index, net_seq); @@ -
> 2403,12 +2373,12 @@ static void packet_received(void *user_data, const
> void *data, uint8_t size,
>  			if (net_opcode == NET_OP_SEG_ACKNOWLEDGE) {
>  				/* Illegal to send ACK to non-Unicast Addr */
>  				if (net_dst & 0x8000)
> -					return;
> +					return RELAY_NONE;
> 
>  				/* print_packet("Got ACK", msg,
> app_msg_len); */
>  				/* Pedantic check for correct size */
>  				if (app_msg_len != 7)
> -					return;
> +					return RELAY_NONE;
> 
>  				/* If this is an ACK to our friend queue-only
> */
>  				if (is_lpn_friend(net, net_dst, true)) @@ -
> 2468,28 +2438,37 @@ static void packet_received(void *user_data, const
> void *data, uint8_t size,
>  		if (!!(net_frnd))
>  			l_info("Ask for more data!");
> 
> -		/* If this is one of our Unicast addresses, don't relay */
> -		if (net_dst <= 0x7fff)
> -			return;
> +		/* If this is one of our Unicast addresses, disallow relay */
> +		if (IS_UNICAST(net_dst))
> +			return RELAY_DISALLOWED;
>  	}
> 
> +	/* If relay not enable, or no more hops allowed */
>  	if (!net->relay.enable || net_ttl < 0x02 || net_frnd)
> -		return;
> +		return RELAY_NONE;
> 
> -	packet[2 + 1] = (packet[2 + 1] & ~TTL_MASK) | (net_ttl - 1);
> +	/* Group or Virtual destinations should *always* be relayed */
> +	if (IS_GROUP(net_dst) || IS_VIRTUAL(net_dst))
> +		return RELAY_ALWAYS;
> 
> -	if (!net_key_encrypt(key_id, iv_index, packet + 2, size)) {
> -		l_error("Failed to encode relay packet");
> -		return;
> -	}
> +	/* Unicast destinations for other nodes *may* be relayed */
> +	else if (IS_UNICAST(net_dst))
> +		return RELAY_ALLOWED;
> 
> -	if (net->relay.enable)
> -		send_relay_pkt(net, packet, size + 1);
> +	/* Otherwise, do not make a relay decision */
> +	else
> +		return RELAY_NONE;
>  }
> 
>  struct net_queue_data {
>  	struct mesh_io_recv_info *info;
> +	struct mesh_net *net;
>  	const uint8_t *data;
> +	uint8_t *out;
> +	size_t out_size;
> +	enum _relay_advice relay_advice;
> +	uint32_t key_id;
> +	uint32_t iv_index;
>  	uint16_t len;
>  };
> 
> @@ -2497,30 +2476,78 @@ static void net_rx(void *net_ptr, void
> *user_data)  {
>  	struct net_queue_data *data = user_data;
>  	struct mesh_net *net = net_ptr;
> +	enum _relay_advice relay_advice;
> +	uint8_t *out;
> +	size_t out_size;
> +	uint32_t key_id;
>  	int8_t rssi = 0;
> 
> +	key_id = net_key_decrypt(net->iv_index, data->data, data->len,
> +								&out,
> &out_size);
> +
> +	if (!key_id)
> +		return;
> +
> +	print_packet("RX: Network [enc] :", data->data, data->len);
> +
>  	if (data->info) {
>  		net->instant = data->info->instant;
>  		net->chan = data->info->chan;
>  		rssi = data->info->rssi;
>  	}
> 
> -	packet_received(net, data->data, data->len, rssi);
> +	relay_advice = packet_received(net, key_id, net->iv_index,
> +							out, out_size, rssi);
> +	if (relay_advice > data->relay_advice) {
> +		bool iv_flag = !!(net->iv_index & 1);
> +		bool iv_pkt = !!(data->data[0] & 0x80);
> +
> +		data->iv_index = net->iv_index;
> +		if (iv_pkt != iv_flag)
> +			data->iv_index--;
> +
> +		data->relay_advice = relay_advice;
> +		data->key_id = key_id;
> +		data->net = net;
> +		data->out = out;
> +		data->out_size = out_size;
> +	}
>  }
> 
>  static void net_msg_recv(void *user_data, struct mesh_io_recv_info *info,
>  					const uint8_t *data, uint16_t len)  {
> +	uint64_t hash;
> +	bool isNew;
>  	struct net_queue_data net_data = {
>  		.info = info,
>  		.data = data + 1,
>  		.len = len - 1,
> +		.relay_advice = RELAY_NONE,
>  	};
> 
> -	if (len <= 2)
> +	if (len < 9)
> +		return;
> +
> +	hash = l_get_le64(data + 1);
> +
> +	/* Only process packet once per reception */
> +	isNew = check_fast_cache(hash);
> +	if (!isNew)
>  		return;
> 
>  	l_queue_foreach(nets, net_rx, &net_data);
> +
> +	if (net_data.relay_advice == RELAY_ALWAYS ||
> +			net_data.relay_advice == RELAY_ALLOWED) {
> +		uint8_t ttl = net_data.out[1] & TTL_MASK;
> +
> +		net_data.out[1] &=  ~TTL_MASK;
> +		net_data.out[1] |= ttl - 1;
> +		net_key_encrypt(net_data.key_id, net_data.iv_index,
> +					net_data.out, net_data.out_size);
> +		send_relay_pkt(net_data.net, net_data.out,
> net_data.out_size);
> +	}
>  }
> 
>  static void set_network_beacon(void *a, void *b) @@ -2927,6 +2954,9 @@
> bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io)
>  		if (!nets)
>  			nets = l_queue_new();
> 
> +		if (!fast_cache)
> +			fast_cache = l_queue_new();
> +
>  		l_info("Register io cb");
>  		mesh_io_register_recv_cb(io, MESH_IO_FILTER_BEACON,
>  							beacon_recv, net);
> --
> 2.14.5


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2019-01-22 20:50 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-18 23:13 [PATCH BlueZ v2] mesh: Fix Relaying for multiple nodes Brian Gix
2019-01-22 20:50 ` Gix, Brian

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).