linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH BlueZ 0/3] mesh: Propagate/Preserve Net Index for Access Layer
@ 2019-07-16 22:56 Brian Gix
  2019-07-16 22:56 ` [PATCH BlueZ 1/3] mesh: Add bound Net Index lookup for App Keys Brian Gix
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Brian Gix @ 2019-07-16 22:56 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, brian.gix, michal.lowas-rzechonek

Two major flaws are corrected by this patch-set:

1. The Spec defined Access Layer AID was being confused with the internally used
key_id which is used to identify Network keys for multiple networks,
sub-networks, and friendships. This confused ID was then being used instead
of the correct Network Key ID for outgoing messages.

2. The specification requires *responses* to all standard Server messages to
be sent with the same credentials as the received command that triggered them.
This requires more complete propagation of the Net Index value on received
messages, so that the same Network key is used in the reverse direction.

This additionally now uses the requested Net Index when sending Device Key
secured messages through the D-Bus interface.

Brian Gix (3):
  mesh: Add bound Net Index lookup for App Keys
  mesh: Normalize Access Key AID naming convention
  mesh: Propagate Net Index up Rx message chain

 mesh/appkey.c        |  59 +++++++++++++-------
 mesh/appkey.h        |   1 +
 mesh/cfgmod-server.c | 154 ++++++++++++++++++++++++++++-----------------------
 mesh/crypto.c        |  37 ++++++-------
 mesh/crypto.h        |   8 +--
 mesh/model.c         | 129 +++++++++++++++++++++---------------------
 mesh/model.h         |  10 ++--
 mesh/net.c           |  92 +++++++++++++++++-------------
 mesh/net.h           |  10 ++--
 mesh/node.c          |  10 ++--
 10 files changed, 276 insertions(+), 234 deletions(-)

-- 
2.14.5


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

* [PATCH BlueZ 1/3] mesh: Add bound Net Index lookup for App Keys
  2019-07-16 22:56 [PATCH BlueZ 0/3] mesh: Propagate/Preserve Net Index for Access Layer Brian Gix
@ 2019-07-16 22:56 ` Brian Gix
  2019-07-16 22:56 ` [PATCH BlueZ 2/3] mesh: Normalize Access Key AID naming convention Brian Gix
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Brian Gix @ 2019-07-16 22:56 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, brian.gix, michal.lowas-rzechonek

This patch also normalizes the naming convention in favor of key_aid
when referring to the calculated AID of the used Access Layer key.
---
 mesh/appkey.c | 59 ++++++++++++++++++++++++++++++++++++++---------------------
 mesh/appkey.h |  1 +
 2 files changed, 39 insertions(+), 21 deletions(-)

diff --git a/mesh/appkey.c b/mesh/appkey.c
index 412a2c48c..bdc6ac29e 100644
--- a/mesh/appkey.c
+++ b/mesh/appkey.c
@@ -39,9 +39,9 @@ struct mesh_app_key {
 	uint16_t net_idx;
 	uint16_t app_idx;
 	uint8_t key[16];
-	uint8_t key_id;
+	uint8_t key_aid;
 	uint8_t new_key[16];
-	uint8_t new_key_id;
+	uint8_t new_key_aid;
 };
 
 struct mesh_msg {
@@ -62,7 +62,7 @@ struct mod_decrypt {
 	uint16_t idx;
 	uint16_t size;
 	uint16_t virt_size;
-	uint8_t key_id;
+	uint8_t key_aid;
 	bool szmict;
 	bool decrypted;
 };
@@ -108,16 +108,16 @@ static void packet_decrypt(void *a, void *b)
 	if (dec->decrypted)
 		return;
 
-	if (key->key_id != dec->key_id &&
-			key->new_key_id != dec->key_id)
+	if (key->key_aid != dec->key_aid &&
+			key->new_key_aid != dec->key_aid)
 		return;
 
 	dec->key = key;
 
-	if (key->key_id == dec->key_id) {
+	if (key->key_aid == dec->key_aid) {
 		dec->decrypted = mesh_crypto_payload_decrypt(dec->virt,
 				dec->virt_size, dec->data, dec->size,
-				dec->szmict, dec->src, dec->dst, dec->key_id,
+				dec->szmict, dec->src, dec->dst, dec->key_aid,
 				dec->seq, dec->iv_idx, dec->out, key->key);
 		if (dec->decrypted)
 			print_packet("Used App Key", dec->key->key, 16);
@@ -125,10 +125,10 @@ static void packet_decrypt(void *a, void *b)
 			print_packet("Failed with App Key", dec->key->key, 16);
 	}
 
-	if (!dec->decrypted && key->new_key_id == dec->key_id) {
+	if (!dec->decrypted && key->new_key_aid == dec->key_aid) {
 		dec->decrypted = mesh_crypto_payload_decrypt(dec->virt,
 				dec->virt_size, dec->data, dec->size,
-				dec->szmict, dec->src, dec->dst, dec->key_id,
+				dec->szmict, dec->src, dec->dst, dec->key_aid,
 				dec->seq, dec->iv_idx, dec->out, key->new_key);
 		if (dec->decrypted)
 			print_packet("Used App Key", dec->key->new_key, 16);
@@ -144,7 +144,7 @@ static void packet_decrypt(void *a, void *b)
 int appkey_packet_decrypt(struct mesh_net *net, bool szmict, uint32_t seq,
 				uint32_t iv_index, uint16_t src,
 				uint16_t dst, uint8_t *virt, uint16_t virt_size,
-				uint8_t key_id, const uint8_t *data,
+				uint8_t key_aid, const uint8_t *data,
 				uint16_t data_size, uint8_t *out)
 {
 	struct l_queue *app_keys;
@@ -156,7 +156,7 @@ int appkey_packet_decrypt(struct mesh_net *net, bool szmict, uint32_t seq,
 		.data = data,
 		.out = out,
 		.size = data_size,
-		.key_id = key_id,
+		.key_aid = key_aid,
 		.iv_idx = iv_index,
 		.virt = virt,
 		.virt_size = virt_size,
@@ -244,7 +244,7 @@ static struct mesh_app_key *app_key_new(void)
 {
 	struct mesh_app_key *key = l_new(struct mesh_app_key, 1);
 
-	key->new_key_id = 0xFF;
+	key->new_key_aid = 0xFF;
 	key->replay_cache = l_queue_new();
 	return key;
 }
@@ -252,16 +252,16 @@ static struct mesh_app_key *app_key_new(void)
 static bool set_key(struct mesh_app_key *key, uint16_t app_idx,
 			const uint8_t *key_value, bool is_new)
 {
-	uint8_t key_id;
+	uint8_t key_aid;
 
-	if (!mesh_crypto_k4(key_value, &key_id))
+	if (!mesh_crypto_k4(key_value, &key_aid))
 		return false;
 
-	key_id = KEY_ID_AKF | (key_id << KEY_AID_SHIFT);
+	key_aid = KEY_ID_AKF | (key_aid << KEY_AID_SHIFT);
 	if (!is_new)
-		key->key_id = key_id;
+		key->key_aid = key_aid;
 	else
-		key->new_key_id = key_id;
+		key->new_key_aid = key_aid;
 
 	memcpy(is_new ? key->new_key : key->key, key_value, 16);
 
@@ -314,7 +314,7 @@ bool appkey_key_init(struct mesh_net *net, uint16_t net_idx, uint16_t app_idx,
 }
 
 const uint8_t *appkey_get_key(struct mesh_net *net, uint16_t app_idx,
-							uint8_t *key_id)
+							uint8_t *key_aid)
 {
 	struct mesh_app_key *app_key;
 	uint8_t phase;
@@ -334,14 +334,14 @@ const uint8_t *appkey_get_key(struct mesh_net *net, uint16_t app_idx,
 		return NULL;
 
 	if (phase != KEY_REFRESH_PHASE_TWO) {
-		*key_id = app_key->key_id;
+		*key_aid = app_key->key_aid;
 		return app_key->key;
 	}
 
-	if (app_key->new_key_id == NET_NID_INVALID)
+	if (app_key->new_key_aid == NET_NID_INVALID)
 		return NULL;
 
-	*key_id = app_key->new_key_id;
+	*key_aid = app_key->new_key_aid;
 	return app_key->new_key;
 }
 
@@ -362,6 +362,23 @@ bool appkey_have_key(struct mesh_net *net, uint16_t app_idx)
 		return true;
 }
 
+uint16_t appkey_net_idx(struct mesh_net *net, uint16_t app_idx)
+{
+	struct mesh_app_key *key;
+	struct l_queue *app_keys;
+
+	app_keys = mesh_net_get_app_keys(net);
+	if (!app_keys)
+		return NET_IDX_INVALID;
+
+	key = l_queue_find(app_keys, match_key_index, L_UINT_TO_PTR(app_idx));
+
+	if (!key)
+		return NET_IDX_INVALID;
+	else
+		return key->net_idx;
+}
+
 int appkey_key_update(struct mesh_net *net, uint16_t net_idx, uint16_t app_idx,
 							const uint8_t *new_key)
 {
diff --git a/mesh/appkey.h b/mesh/appkey.h
index 1c22e801c..4c135580a 100644
--- a/mesh/appkey.h
+++ b/mesh/appkey.h
@@ -34,6 +34,7 @@ bool appkey_msg_in_replay_cache(struct mesh_net *net, uint16_t idx,
 const uint8_t *appkey_get_key(struct mesh_net *net, uint16_t app_idx,
 							uint8_t *key_id);
 bool appkey_have_key(struct mesh_net *net, uint16_t app_idx);
+uint16_t appkey_net_idx(struct mesh_net *net, uint16_t app_idx);
 int appkey_key_add(struct mesh_net *net, uint16_t net_idx, uint16_t app_idx,
 							const uint8_t *new_key);
 int appkey_key_update(struct mesh_net *net, uint16_t net_idx, uint16_t app_idx,
-- 
2.14.5


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

* [PATCH BlueZ 2/3] mesh: Normalize Access Key AID naming convention
  2019-07-16 22:56 [PATCH BlueZ 0/3] mesh: Propagate/Preserve Net Index for Access Layer Brian Gix
  2019-07-16 22:56 ` [PATCH BlueZ 1/3] mesh: Add bound Net Index lookup for App Keys Brian Gix
@ 2019-07-16 22:56 ` Brian Gix
  2019-07-16 22:56 ` [PATCH BlueZ 3/3] mesh: Propagate Net Index up Rx message chain Brian Gix
  2019-07-18 17:07 ` [PATCH BlueZ 0/3] mesh: Propagate/Preserve Net Index for Access Layer Gix, Brian
  3 siblings, 0 replies; 6+ messages in thread
From: Brian Gix @ 2019-07-16 22:56 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, brian.gix, michal.lowas-rzechonek

---
 mesh/crypto.c | 37 ++++++++++++++++++-------------------
 mesh/crypto.h |  8 ++++----
 mesh/net.h    |  4 +---
 3 files changed, 23 insertions(+), 26 deletions(-)

diff --git a/mesh/crypto.c b/mesh/crypto.c
index a4679d88e..b1b1fa9a8 100644
--- a/mesh/crypto.c
+++ b/mesh/crypto.c
@@ -429,8 +429,9 @@ bool mesh_crypto_device_nonce(uint32_t seq, uint16_t src,
 	return true;
 }
 
-bool mesh_crypto_application_encrypt(uint8_t key_id, uint32_t seq, uint16_t src,
-					uint16_t dst, uint32_t iv_index,
+bool mesh_crypto_application_encrypt(uint8_t key_aid, uint32_t seq,
+					uint16_t src, uint16_t dst,
+					uint32_t iv_index,
 					const uint8_t app_key[16],
 					const uint8_t *aad, uint8_t aad_len,
 					const uint8_t *msg, uint8_t msg_len,
@@ -440,11 +441,11 @@ bool mesh_crypto_application_encrypt(uint8_t key_id, uint32_t seq, uint16_t src,
 	uint8_t nonce[13];
 	bool aszmic = (mic_size == 8) ? true : false;
 
-	if (!key_id && !mesh_crypto_device_nonce(seq, src, dst,
+	if (!key_aid && !mesh_crypto_device_nonce(seq, src, dst,
 						iv_index, aszmic, nonce))
 		return false;
 
-	if (key_id && !mesh_crypto_application_nonce(seq, src, dst,
+	if (key_aid && !mesh_crypto_application_nonce(seq, src, dst,
 						iv_index, aszmic, nonce))
 		return false;
 
@@ -453,8 +454,8 @@ bool mesh_crypto_application_encrypt(uint8_t key_id, uint32_t seq, uint16_t src,
 						out, app_mic, mic_size);
 }
 
-bool mesh_crypto_application_decrypt(uint8_t key_id, uint32_t seq, uint16_t src,
-				uint16_t dst, uint32_t iv_index,
+bool mesh_crypto_application_decrypt(uint8_t key_aid, uint32_t seq,
+				uint16_t src, uint16_t dst, uint32_t iv_index,
 				const uint8_t app_key[16],
 				const uint8_t *aad, uint8_t aad_len,
 				const uint8_t *enc_msg, uint8_t enc_msg_len,
@@ -463,11 +464,11 @@ bool mesh_crypto_application_decrypt(uint8_t key_id, uint32_t seq, uint16_t src,
 	uint8_t nonce[13];
 	bool aszmic = (mic_size == 8) ? true : false;
 
-	if (!key_id && !mesh_crypto_device_nonce(seq, src, dst,
+	if (!key_aid && !mesh_crypto_device_nonce(seq, src, dst,
 						iv_index, aszmic, nonce))
 		return false;
 
-	if (key_id && !mesh_crypto_application_nonce(seq, src, dst,
+	if (key_aid && !mesh_crypto_application_nonce(seq, src, dst,
 						iv_index, aszmic, nonce))
 		return false;
 
@@ -638,7 +639,7 @@ bool mesh_crypto_packet_build(bool ctl, uint8_t ttl,
 				uint32_t seq,
 				uint16_t src, uint16_t dst,
 				uint8_t opcode,
-				bool segmented, uint8_t key_id,
+				bool segmented, uint8_t key_aid,
 				bool szmic, bool relay, uint16_t seqZero,
 				uint8_t segO, uint8_t segN,
 				const uint8_t *payload, uint8_t payload_len,
@@ -656,7 +657,7 @@ bool mesh_crypto_packet_build(bool ctl, uint8_t ttl,
 
 	if (!ctl) {
 		hdr = segmented << SEG_HDR_SHIFT;
-		hdr |= (key_id & KEY_ID_MASK) << KEY_HDR_SHIFT;
+		hdr |= (key_aid & KEY_ID_MASK) << KEY_HDR_SHIFT;
 		if (segmented) {
 			hdr |= szmic << SZMIC_HDR_SHIFT;
 			hdr |= (seqZero & SEQ_ZERO_MASK) << SEQ_ZERO_HDR_SHIFT;
@@ -700,7 +701,7 @@ bool mesh_crypto_packet_parse(const uint8_t *packet, uint8_t packet_len,
 				bool *ctl, uint8_t *ttl, uint32_t *seq,
 				uint16_t *src, uint16_t *dst,
 				uint32_t *cookie, uint8_t *opcode,
-				bool *segmented, uint8_t *key_id,
+				bool *segmented, uint8_t *key_aid,
 				bool *szmic, bool *relay, uint16_t *seqZero,
 				uint8_t *segO, uint8_t *segN,
 				const uint8_t **payload, uint8_t *payload_len)
@@ -769,8 +770,8 @@ bool mesh_crypto_packet_parse(const uint8_t *packet, uint8_t packet_len,
 		if (cookie)
 			*cookie = l_get_be32(packet + packet_len - 8);
 
-		if (key_id)
-			*key_id = (hdr >> KEY_HDR_SHIFT) & KEY_ID_MASK;
+		if (key_aid)
+			*key_aid = (hdr >> KEY_HDR_SHIFT) & KEY_ID_MASK;
 
 		if (is_segmented) {
 			if (szmic)
@@ -805,7 +806,7 @@ bool mesh_crypto_packet_parse(const uint8_t *packet, uint8_t packet_len,
 
 bool mesh_crypto_payload_encrypt(uint8_t *aad, const uint8_t *payload,
 				uint8_t *out, uint16_t payload_len,
-				uint16_t src, uint16_t dst, uint8_t key_id,
+				uint16_t src, uint16_t dst, uint8_t key_aid,
 				uint32_t seq_num, uint32_t iv_index,
 				bool aszmic,
 				const uint8_t application_key[16])
@@ -815,8 +816,7 @@ bool mesh_crypto_payload_encrypt(uint8_t *aad, const uint8_t *payload,
 	if (payload_len < 1)
 		return false;
 
-	/* Key_ID == 0 means the Device Key is being used */
-	if (!key_id)
+	if (key_aid == APP_AID_DEV)
 		application_nonce[0] = 0x02;
 
 	/* Seq Num */
@@ -848,7 +848,7 @@ bool mesh_crypto_payload_decrypt(uint8_t *aad, uint16_t aad_len,
 				const uint8_t *payload, uint16_t payload_len,
 				bool szmict,
 				uint16_t src, uint16_t dst,
-				uint8_t key_id, uint32_t seq_num,
+				uint8_t key_aid, uint32_t seq_num,
 				uint32_t iv_index, uint8_t *out,
 				const uint8_t app_key[16])
 {
@@ -859,8 +859,7 @@ bool mesh_crypto_payload_decrypt(uint8_t *aad, uint16_t aad_len,
 	if (payload_len < 5 || !out)
 		return false;
 
-	/* Key_ID == 0 means the Device Key is being used */
-	if (!key_id)
+	if (key_aid == APP_AID_DEV)
 		app_nonce[0] = 0x02;
 
 	/* Seq Num */
diff --git a/mesh/crypto.h b/mesh/crypto.h
index 3e6815a35..1a73bcaa3 100644
--- a/mesh/crypto.h
+++ b/mesh/crypto.h
@@ -119,7 +119,7 @@ bool mesh_crypto_packet_build(bool ctl, uint8_t ttl,
 				uint32_t seq,
 				uint16_t src, uint16_t dst,
 				uint8_t opcode,
-				bool segmented, uint8_t key_id,
+				bool segmented, uint8_t key_aid,
 				bool szmic, bool relay, uint16_t seqZero,
 				uint8_t segO, uint8_t segN,
 				const uint8_t *payload, uint8_t payload_len,
@@ -128,20 +128,20 @@ bool mesh_crypto_packet_parse(const uint8_t *packet, uint8_t packet_len,
 				bool *ctl, uint8_t *ttl, uint32_t *seq,
 				uint16_t *src, uint16_t *dst,
 				uint32_t *cookie, uint8_t *opcode,
-				bool *segmented, uint8_t *key_id,
+				bool *segmented, uint8_t *key_aid,
 				bool *szmic, bool *relay, uint16_t *seqZero,
 				uint8_t *segO, uint8_t *segN,
 				const uint8_t **payload, uint8_t *payload_len);
 bool mesh_crypto_payload_encrypt(uint8_t *aad, const uint8_t *payload,
 				uint8_t *out, uint16_t payload_len,
-				uint16_t src, uint16_t dst, uint8_t key_id,
+				uint16_t src, uint16_t dst, uint8_t key_aid,
 				uint32_t seq_num, uint32_t iv_index,
 				bool aszmic,
 				const uint8_t application_key[16]);
 bool mesh_crypto_payload_decrypt(uint8_t *aad, uint16_t aad_len,
 				const uint8_t *payload, uint16_t payload_len,
 				bool szmict,
-				uint16_t src, uint16_t dst, uint8_t key_id,
+				uint16_t src, uint16_t dst, uint8_t key_aid,
 				uint32_t seq_num, uint32_t iv_index,
 				uint8_t *out,
 				const uint8_t application_key[16]);
diff --git a/mesh/net.h b/mesh/net.h
index 8848e6df0..7b0733578 100644
--- a/mesh/net.h
+++ b/mesh/net.h
@@ -28,9 +28,7 @@ struct mesh_node;
 
 #define UNUSED_KEY_IDX	0xffff
 
-#define APP_ID_DEV	0
-#define APP_ID_ANY	((unsigned int) -1)
-#define NET_ID_ANY	(APP_ID_ANY - 1)
+#define APP_AID_DEV	0x00
 
 #define CTL		0x80
 #define TTL_MASK	0x7f
-- 
2.14.5


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

* [PATCH BlueZ 3/3] mesh: Propagate Net Index up Rx message chain
  2019-07-16 22:56 [PATCH BlueZ 0/3] mesh: Propagate/Preserve Net Index for Access Layer Brian Gix
  2019-07-16 22:56 ` [PATCH BlueZ 1/3] mesh: Add bound Net Index lookup for App Keys Brian Gix
  2019-07-16 22:56 ` [PATCH BlueZ 2/3] mesh: Normalize Access Key AID naming convention Brian Gix
@ 2019-07-16 22:56 ` Brian Gix
  2019-07-17  8:48   ` Michał Lowas-Rzechonek
  2019-07-18 17:07 ` [PATCH BlueZ 0/3] mesh: Propagate/Preserve Net Index for Access Layer Gix, Brian
  3 siblings, 1 reply; 6+ messages in thread
From: Brian Gix @ 2019-07-16 22:56 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, brian.gix, michal.lowas-rzechonek

When a model receives a message, it is required by the spec
to respond using the same credentials. When an App Key is used,
this is trivial because App keys are bound to Net keys, so only
the App Index is required.  Messages received on a Device key
however, need the Net Index preserved from original message for
re-use during the response.
---
 mesh/cfgmod-server.c | 154 ++++++++++++++++++++++++++++-----------------------
 mesh/model.c         | 129 +++++++++++++++++++++---------------------
 mesh/model.h         |  10 ++--
 mesh/net.c           |  92 +++++++++++++++++-------------
 mesh/net.h           |   6 +-
 mesh/node.c          |  10 ++--
 6 files changed, 214 insertions(+), 187 deletions(-)

diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c
index a19ddc72e..420cac6ed 100644
--- a/mesh/cfgmod-server.c
+++ b/mesh/cfgmod-server.c
@@ -38,7 +38,8 @@
 
 #define CFG_MAX_MSG_LEN 380
 
-static void send_pub_status(struct mesh_node *node, uint16_t src, uint16_t dst,
+static void send_pub_status(struct mesh_node *node, uint16_t net_idx,
+			uint16_t src, uint16_t dst,
 			uint8_t status, uint16_t ele_addr, uint16_t pub_addr,
 			uint32_t mod_id, uint16_t idx, bool cred_flag,
 			uint8_t ttl, uint8_t period, uint8_t retransmit)
@@ -69,11 +70,12 @@ static void send_pub_status(struct mesh_node *node, uint16_t src, uint16_t dst,
 		n += 2;
 	}
 
-	mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, DEFAULT_TTL,
+	mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL,
 								msg, n);
 }
 
-static bool config_pub_get(struct mesh_node *node, uint16_t src, uint16_t dst,
+static bool config_pub_get(struct mesh_node *node, uint16_t net_idx,
+					uint16_t src, uint16_t dst,
 					const uint8_t *pkt, uint16_t size)
 {
 	uint32_t mod_id;
@@ -100,16 +102,17 @@ static bool config_pub_get(struct mesh_node *node, uint16_t src, uint16_t dst,
 		status = MESH_STATUS_INVALID_ADDRESS;
 
 	if (pub && status == MESH_STATUS_SUCCESS)
-		send_pub_status(node, src, dst, status, ele_addr, pub->addr,
-				mod_id, pub->idx, pub->credential, pub->ttl,
-						pub->period, pub->retransmit);
+		send_pub_status(node, net_idx, src, dst, status, ele_addr,
+				pub->addr, mod_id, pub->idx, pub->credential,
+				pub->ttl, pub->period, pub->retransmit);
 	else
-		send_pub_status(node, src, dst, status, ele_addr, 0, mod_id,
-								0, 0, 0, 0, 0);
+		send_pub_status(node, net_idx, src, dst, status, ele_addr, 0,
+							mod_id, 0, 0, 0, 0, 0);
 	return true;
 }
 
-static bool config_pub_set(struct mesh_node *node, uint16_t src, uint16_t dst,
+static bool config_pub_set(struct mesh_node *node, uint16_t net_idx,
+					uint16_t src, uint16_t dst,
 					const uint8_t *pkt, uint16_t size,
 					bool unreliable)
 {
@@ -228,13 +231,13 @@ static bool config_pub_set(struct mesh_node *node, uint16_t src, uint16_t dst,
 
 done:
 	if (!unreliable)
-		send_pub_status(node, src, dst, status, ele_addr, ota,
-				mod_id, idx, cred_flag, ttl, period,
-				retransmit);
+		send_pub_status(node, net_idx, src, dst, status, ele_addr, ota,
+			mod_id, idx, cred_flag, ttl, period, retransmit);
 	return true;
 }
 
-static void send_sub_status(struct mesh_node *node, uint16_t src, uint16_t dst,
+static void send_sub_status(struct mesh_node *node, uint16_t net_idx,
+					uint16_t src, uint16_t dst,
 					uint8_t status, uint16_t ele_addr,
 					uint16_t addr, uint32_t mod)
 {
@@ -255,10 +258,12 @@ static void send_sub_status(struct mesh_node *node, uint16_t src, uint16_t dst,
 		n += 2;
 	}
 
-	mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, DEFAULT_TTL, msg, n);
+	mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx,
+							DEFAULT_TTL, msg, n);
 }
 
-static bool config_sub_get(struct mesh_node *node, uint16_t src, uint16_t dst,
+static bool config_sub_get(struct mesh_node *node, uint16_t net_idx,
+					uint16_t src, uint16_t dst,
 					const uint8_t *pkt, uint16_t size)
 {
 	uint16_t ele_addr;
@@ -313,7 +318,8 @@ static bool config_sub_get(struct mesh_node *node, uint16_t src, uint16_t dst,
 
 	*msg_status = (uint8_t) status;
 
-	mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, DEFAULT_TTL, msg, n);
+	mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL,
+									msg, n);
 	return true;
 }
 
@@ -349,7 +355,8 @@ static bool save_config_sub(struct mesh_node *node, uint16_t ele_addr,
 					vendor, &db_sub);
 }
 
-static void config_sub_set(struct mesh_node *node, uint16_t src, uint16_t dst,
+static void config_sub_set(struct mesh_node *node, uint16_t net_idx,
+					uint16_t src, uint16_t dst,
 					const uint8_t *pkt, uint16_t size,
 					bool virt, uint32_t opcode)
 {
@@ -464,14 +471,15 @@ static void config_sub_set(struct mesh_node *node, uint16_t src, uint16_t dst,
 	}
 
 	if (!unreliable)
-		send_sub_status(node, src, dst, status, ele_addr, grp, mod_id);
+		send_sub_status(node, net_idx, src, dst, status, ele_addr,
+								grp, mod_id);
 
 }
 
-static void send_model_app_status(struct mesh_node *node, uint16_t src,
-					uint16_t dst, uint8_t status,
-					uint16_t addr, uint32_t id,
-					uint16_t idx)
+static void send_model_app_status(struct mesh_node *node, uint16_t net_idx,
+					uint16_t src, uint16_t dst,
+					uint8_t status, uint16_t addr,
+					uint32_t id, uint16_t idx)
 {
 	uint8_t msg[12];
 	size_t n = mesh_model_opcode_set(OP_MODEL_APP_STATUS, msg);
@@ -488,10 +496,12 @@ static void send_model_app_status(struct mesh_node *node, uint16_t src,
 	l_put_le16(id, msg + n);
 	n += 2;
 
-	mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, DEFAULT_TTL, msg, n);
+	mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL,
+									msg, n);
 }
 
-static void model_app_list(struct mesh_node *node, uint16_t src, uint16_t dst,
+static void model_app_list(struct mesh_node *node, uint16_t net_idx,
+					uint16_t src, uint16_t dst,
 					const uint8_t *pkt, uint16_t size)
 {
 	uint16_t ele_addr;
@@ -541,14 +551,15 @@ static void model_app_list(struct mesh_node *node, uint16_t src, uint16_t dst,
 
 	if (result >= 0) {
 		*status = result;
-		mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, DEFAULT_TTL,
-								msg, n);
+		mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx,
+							DEFAULT_TTL, msg, n);
 	}
 
 	l_free(msg);
 }
 
-static bool model_app_bind(struct mesh_node *node, uint16_t src, uint16_t dst,
+static bool model_app_bind(struct mesh_node *node, uint16_t net_idx,
+					uint16_t src, uint16_t dst,
 					const uint8_t *pkt, uint16_t size,
 					bool unbind)
 {
@@ -582,7 +593,8 @@ static bool model_app_bind(struct mesh_node *node, uint16_t src, uint16_t dst,
 	else
 		result = mesh_model_binding_add(node, ele_addr, mod_id, idx);
 
-	send_model_app_status(node, src, dst, result, ele_addr, mod_id, idx);
+	send_model_app_status(node, net_idx, src, dst, result, ele_addr,
+								mod_id, idx);
 
 	return true;
 }
@@ -737,8 +749,8 @@ static void node_reset(struct l_timeout *timeout, void *user_data)
 	l_main_quit();
 }
 
-static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
-				uint16_t unicast, uint16_t idx,
+static bool cfg_srv_pkt(uint16_t src, uint32_t dst, uint16_t unicast,
+				uint16_t app_idx, uint16_t net_idx,
 				const uint8_t *data, uint16_t size,
 				uint8_t ttl, const void *user_data)
 {
@@ -751,7 +763,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 	uint8_t msg[11];
 	uint8_t *long_msg = NULL;
 	struct mesh_net_heartbeat *hb;
-	uint16_t net_idx, app_idx;
+	uint16_t n_idx, a_idx;
 	uint8_t state, status;
 	uint8_t phase;
 	bool virt = false;
@@ -759,7 +771,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 	uint16_t interval;
 	uint16_t n;
 
-	if (idx != APP_IDX_DEV_LOCAL)
+	if (app_idx != APP_IDX_DEV_LOCAL)
 		return false;
 
 	if (mesh_model_opcode_get(pkt, size, &opcode, &n)) {
@@ -770,7 +782,8 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 
 	net = node_get_net(node);
 	hb = mesh_net_heartbeat_get(net);
-	l_debug("CONFIG-SRV-opcode 0x%x size %u idx %3.3x", opcode, size, idx);
+	l_debug("CONFIG-SRV-opcode 0x%x size %u idx %3.3x", opcode, size,
+								net_idx);
 
 	n = 0;
 
@@ -814,7 +827,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 		if (size != 25 && size != 27)
 			return true;
 
-		config_pub_set(node, src, unicast, pkt, size,
+		config_pub_set(node, net_idx, src, unicast, pkt, size,
 				!!(opcode & OP_UNRELIABLE));
 		break;
 
@@ -822,24 +835,26 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 		if (size != 11 && size != 13)
 			return true;
 
-		config_pub_set(node, src, unicast, pkt, size,
+		config_pub_set(node, net_idx, src, unicast, pkt, size,
 				!!(opcode & OP_UNRELIABLE));
 		break;
 
 	case OP_CONFIG_MODEL_PUB_GET:
-		config_pub_get(node, src, unicast, pkt, size);
+		config_pub_get(node, net_idx, src, unicast, pkt, size);
 		break;
 
 	case OP_CONFIG_VEND_MODEL_SUB_GET:
 		if (size != 6)
 			return true;
-		config_sub_get(node, src, unicast, pkt, size);
+
+		config_sub_get(node, net_idx, src, unicast, pkt, size);
 		break;
 
 	case OP_CONFIG_MODEL_SUB_GET:
 		if (size != 4)
 			return true;
-		config_sub_get(node, src, unicast, pkt, size);
+
+		config_sub_get(node, net_idx, src, unicast, pkt, size);
 		break;
 
 	case OP_CONFIG_MODEL_SUB_VIRT_OVERWRITE:
@@ -851,7 +866,8 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 	case OP_CONFIG_MODEL_SUB_DELETE:
 	case OP_CONFIG_MODEL_SUB_ADD:
 	case OP_CONFIG_MODEL_SUB_DELETE_ALL:
-		config_sub_set(node, src, unicast, pkt, size, virt, opcode);
+		config_sub_set(node, net_idx, src, unicast, pkt, size, virt,
+									opcode);
 		break;
 
 	case OP_CONFIG_RELAY_SET:
@@ -911,8 +927,8 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 		if (size != 3 || pkt[2] > 0x01)
 			return true;
 
-		net_idx = l_get_le16(pkt);
-		if (net_idx > 0xfff)
+		n_idx = l_get_le16(pkt);
+		if (n_idx > 0xfff)
 			return true;
 
 		/*
@@ -925,17 +941,17 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 		if (size < 2)
 			return true;
 
-		net_idx = l_get_le16(pkt);
-		if (net_idx > 0xfff)
+		n_idx = l_get_le16(pkt);
+		if (n_idx > 0xfff)
 			return true;
 
 		n = mesh_model_opcode_set(OP_NODE_IDENTITY_STATUS, msg);
 
-		status = mesh_net_get_identity_mode(net, net_idx, &state);
+		status = mesh_net_get_identity_mode(net, n_idx, &state);
 
 		msg[n++] = status;
 
-		l_put_le16(net_idx, msg + n);
+		l_put_le16(n_idx, msg + n);
 		n += 2;
 
 		msg[n++] = state;
@@ -984,13 +1000,13 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 		if (size != 2)
 			return true;
 
-		net_idx = l_get_le16(pkt);
+		n_idx = l_get_le16(pkt);
 
 		n = mesh_model_opcode_set(OP_CONFIG_KEY_REFRESH_PHASE_STATUS,
 						msg);
 
 		/* State: 0x00-0x03 phase of key refresh */
-		status = mesh_net_key_refresh_phase_get(net, net_idx,
+		status = mesh_net_key_refresh_phase_get(net, n_idx,
 							&phase);
 		if (status != MESH_STATUS_SUCCESS) {
 			b_res = status;
@@ -998,7 +1014,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 		}
 
 		msg[n++] = b_res;
-		l_put_le16(net_idx, msg + n);
+		l_put_le16(n_idx, msg + n);
 		n += 2;
 		msg[n++] = phase;
 
@@ -1010,18 +1026,18 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 		if (size != 19)
 			return true;
 
-		net_idx = l_get_le16(pkt) & 0xfff;
-		app_idx = l_get_le16(pkt + 1) >> 4;
+		n_idx = l_get_le16(pkt) & 0xfff;
+		a_idx = l_get_le16(pkt + 1) >> 4;
 
 		if (opcode == OP_APPKEY_ADD)
-			b_res = appkey_key_add(net, net_idx, app_idx, pkt + 3);
+			b_res = appkey_key_add(net, n_idx, a_idx, pkt + 3);
 		else
-			b_res = appkey_key_update(net, net_idx, app_idx,
+			b_res = appkey_key_update(net, n_idx, a_idx,
 								pkt + 3);
 
 		l_debug("Add/Update AppKey %s: Net_Idx %3.3x, App_Idx %3.3x",
 			(b_res == MESH_STATUS_SUCCESS) ? "success" : "fail",
-							net_idx, app_idx);
+							n_idx, a_idx);
 
 
 		n = mesh_model_opcode_set(OP_APPKEY_STATUS, msg);
@@ -1034,15 +1050,14 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 
 	case OP_APPKEY_DELETE:
 		if (size != 3)
-			return
-				true;
+			return true;
 
-		net_idx = l_get_le16(pkt) & 0xfff;
-		app_idx = l_get_le16(pkt + 1) >> 4;
-		b_res = appkey_key_delete(net, net_idx, app_idx);
+		n_idx = l_get_le16(pkt) & 0xfff;
+		a_idx = l_get_le16(pkt + 1) >> 4;
+		b_res = appkey_key_delete(net, n_idx, a_idx);
 		l_debug("Delete AppKey %s Net_Idx %3.3x to App_Idx %3.3x",
 			(b_res == MESH_STATUS_SUCCESS) ? "success" : "fail",
-							net_idx, app_idx);
+							n_idx, a_idx);
 
 		n = mesh_model_opcode_set(OP_APPKEY_STATUS, msg);
 		msg[n++] = b_res;
@@ -1054,16 +1069,17 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 	case OP_APPKEY_GET:
 		if (size != 2)
 			return true;
-		net_idx = l_get_le16(pkt);
+
+		n_idx = l_get_le16(pkt);
 
 		long_msg = l_malloc(CFG_MAX_MSG_LEN);
 		n = mesh_model_opcode_set(OP_APPKEY_LIST, long_msg);
 
-		status = appkey_list(net, net_idx, long_msg + n + 3,
+		status = appkey_list(net, n_idx, long_msg + n + 3,
 						CFG_MAX_MSG_LEN - n - 3, &size);
 
 		long_msg[n] = status;
-		l_put_le16(net_idx, long_msg + n + 1);
+		l_put_le16(n_idx, long_msg + n + 1);
 		n += (size + 3);
 		break;
 
@@ -1072,12 +1088,12 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 		if (size != 18)
 			return true;
 
-		net_idx = l_get_le16(pkt);
+		n_idx = l_get_le16(pkt);
 
 		if (opcode == OP_NETKEY_ADD)
-			b_res = mesh_net_add_key(net, net_idx, pkt + 2);
+			b_res = mesh_net_add_key(net, n_idx, pkt + 2);
 		else
-			b_res = mesh_net_update_key(net, net_idx, pkt + 2);
+			b_res = mesh_net_update_key(net, n_idx, pkt + 2);
 
 		l_debug("NetKey Add/Update %s",
 			(b_res == MESH_STATUS_SUCCESS) ? "success" : "fail");
@@ -1116,20 +1132,20 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 
 	case OP_MODEL_APP_BIND:
 	case OP_MODEL_APP_UNBIND:
-		model_app_bind(node, src, unicast, pkt, size,
+		model_app_bind(node, net_idx, src, unicast, pkt, size,
 				opcode != OP_MODEL_APP_BIND);
 		break;
 
 	case OP_VEND_MODEL_APP_GET:
 		if (size != 6)
 			return true;
-		model_app_list(node, src, unicast, pkt, size);
+		model_app_list(node, net_idx, src, unicast, pkt, size);
 		break;
 
 	case OP_MODEL_APP_GET:
 		if (size != 4)
 			return true;
-		model_app_list(node, src, unicast, pkt, size);
+		model_app_list(node, net_idx, src, unicast, pkt, size);
 		break;
 
 	case OP_CONFIG_HEARTBEAT_PUB_SET:
@@ -1260,7 +1276,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 	if (n) {
 		/* print_packet("App Tx", long_msg ? long_msg : msg, n); */
 		mesh_model_send(node, unicast, src,
-				APP_IDX_DEV_LOCAL, DEFAULT_TTL,
+				APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL,
 				long_msg ? long_msg : msg, n);
 	}
 	l_free(long_msg);
diff --git a/mesh/model.c b/mesh/model.c
index e08f95b71..bfd179b52 100644
--- a/mesh/model.c
+++ b/mesh/model.c
@@ -69,7 +69,8 @@ struct mod_forward {
 	uint16_t src;
 	uint16_t dst;
 	uint16_t unicast;
-	uint16_t idx;
+	uint16_t app_idx;
+	uint16_t net_idx;
 	uint16_t size;
 	uint8_t ttl;
 	int8_t rssi;
@@ -304,10 +305,11 @@ static void forward_model(void *a, void *b)
 	uint32_t dst;
 	bool result;
 
-	l_debug("model %8.8x with idx %3.3x", mod->id, fwd->idx);
+	l_debug("model %8.8x with idx %3.3x", mod->id, fwd->app_idx);
 
-	if (fwd->idx != APP_IDX_DEV_LOCAL && fwd->idx != APP_IDX_DEV_REMOTE &&
-					!has_binding(mod->bindings, fwd->idx))
+	if (fwd->app_idx != APP_IDX_DEV_LOCAL &&
+				fwd->app_idx != APP_IDX_DEV_REMOTE &&
+				!has_binding(mod->bindings, fwd->app_idx))
 		return;
 
 	dst = fwd->dst;
@@ -345,7 +347,8 @@ static void forward_model(void *a, void *b)
 	result = false;
 
 	if (mod->cbs->recv)
-		result = mod->cbs->recv(fwd->src, dst, fwd->unicast, fwd->idx,
+		result = mod->cbs->recv(fwd->src, dst, fwd->unicast,
+				fwd->app_idx, fwd->net_idx,
 				fwd->data, fwd->size, fwd->ttl, mod->user_data);
 
 	if (dst == fwd->unicast && result)
@@ -439,13 +442,17 @@ static void cmplt(uint16_t remote, uint8_t status,
 }
 
 static bool msg_send(struct mesh_node *node, bool credential, uint16_t src,
-		uint32_t dst, uint8_t key_id, const uint8_t *key,
-		uint8_t *label, uint8_t ttl, const void *msg, uint16_t msg_len)
+		uint32_t dst, uint16_t app_idx, uint16_t net_idx,
+		uint8_t *label, uint8_t ttl,
+		const void *msg, uint16_t msg_len)
 {
-	bool ret = false;
+	uint8_t dev_key[16];
 	uint32_t iv_index, seq_num;
+	const uint8_t *key;
 	uint8_t *out;
+	uint8_t key_aid = APP_AID_DEV;
 	bool szmic = false;
+	bool ret = false;
 	uint16_t out_len = msg_len + sizeof(uint32_t);
 	struct mesh_net *net = node_get_net(node);
 
@@ -457,22 +464,44 @@ static bool msg_send(struct mesh_node *node, bool credential, uint16_t src,
 		}
 	}
 
+	if (app_idx == APP_IDX_DEV_LOCAL) {
+		key = node_get_device_key(node);
+		if (!key)
+			return false;
+	} else if (app_idx == APP_IDX_DEV_REMOTE) {
+		if (!keyring_get_remote_dev_key(node, dst, dev_key))
+			return false;
+
+		key = dev_key;
+	} else {
+		key = appkey_get_key(node_get_net(node), app_idx, &key_aid);
+		if (!key) {
+			l_debug("no app key for (%x)", app_idx);
+			return false;
+		}
+
+		net_idx = appkey_net_idx(node_get_net(node), app_idx);
+	}
+
+	l_debug("(%x) %p", app_idx, key);
+	l_debug("net_idx %x", net_idx);
+
 	out = l_malloc(out_len);
 
 	iv_index = mesh_net_get_iv_index(net);
 
 	seq_num = mesh_net_get_seq_num(net);
 	if (!mesh_crypto_payload_encrypt(label, msg, out, msg_len, src, dst,
-				key_id, seq_num, iv_index, szmic, key)) {
+				key_aid, seq_num, iv_index, szmic, key)) {
 		l_error("Failed to Encrypt Payload");
 		goto done;
 	}
 
 	/* print_packet("Encrypted with", key, 16); */
 
-	ret = mesh_net_app_send(net, credential, src, dst, key_id, ttl,
-					seq_num, iv_index, szmic, out, out_len,
-								cmplt, NULL);
+	ret = mesh_net_app_send(net, credential, src, dst, key_aid, net_idx,
+					ttl, seq_num, iv_index, szmic, out,
+					out_len, cmplt, NULL);
 done:
 	l_free(out);
 	return ret;
@@ -770,8 +799,8 @@ static void send_msg_rcvd(struct mesh_node *node, uint8_t ele_idx, bool is_sub,
 
 bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
 			uint32_t seq, uint32_t iv_index, uint8_t ttl,
-			uint16_t src, uint16_t dst, uint8_t key_id,
-			const uint8_t *data, uint16_t size)
+			uint16_t net_idx, uint16_t src, uint16_t dst,
+			uint8_t key_aid, const uint8_t *data, uint16_t size)
 {
 	uint8_t *clear_text;
 	struct mod_forward forward = {
@@ -790,7 +819,7 @@ bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
 	bool result = false;
 	bool is_subscription;
 
-	l_debug("iv_index %8.8x key_id = %2.2x", iv_index, key_id);
+	l_debug("iv_index %8.8x key_aid = %2.2x", iv_index, key_aid);
 	if (!dst)
 		return false;
 
@@ -808,21 +837,21 @@ bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
 
 	/*
 	 * The packet needs to be decoded by the correct key which
-	 * is hinted by key_id, but is not necessarily definitive
+	 * is hinted by key_aid, but is not necessarily definitive
 	 */
-	if (key_id == APP_ID_DEV || mesh_net_provisioner_mode_get(net))
+	if (key_aid == APP_AID_DEV || mesh_net_provisioner_mode_get(net))
 		decrypt_idx = dev_packet_decrypt(node, data, size, szmict, src,
-						dst, key_id, seq0, iv_index,
+						dst, key_aid, seq0, iv_index,
 						clear_text);
 	else if ((dst & 0xc000) == 0x8000)
 		decrypt_idx = virt_packet_decrypt(net, data, size, szmict, src,
-							dst, key_id, seq0,
+							dst, key_aid, seq0,
 							iv_index, clear_text,
 							&decrypt_virt);
 	else
 		decrypt_idx = appkey_packet_decrypt(net, szmict, seq0,
 							iv_index, src, dst,
-							NULL, 0, key_id, data,
+							NULL, 0, key_aid, data,
 							size, clear_text);
 
 	if (decrypt_idx < 0) {
@@ -833,7 +862,7 @@ bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
 
 	/* print_packet("Clr Rx (pre-cache-check)", clear_text, size - 4); */
 
-	if (key_id != APP_ID_DEV) {
+	if (key_aid != APP_AID_DEV) {
 		uint16_t crpl = node_get_crpl(node);
 
 		if (appkey_msg_in_replay_cache(net, (uint16_t) decrypt_idx, src,
@@ -846,7 +875,8 @@ bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
 	print_packet("Clr Rx", clear_text, size - (szmict ? 8 : 4));
 
 	forward.virt = decrypt_virt;
-	forward.idx = decrypt_idx;
+	forward.app_idx = decrypt_idx;
+	forward.net_idx = net_idx;
 	num_ele = node_get_num_elements(node);
 	addr = node_get_primary(node);
 
@@ -876,7 +906,7 @@ bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
 		if (forward.has_dst && !forward.done) {
 			if ((decrypt_idx & APP_IDX_MASK) == decrypt_idx)
 				send_msg_rcvd(node, i, is_subscription, src,
-						forward.idx, forward.size,
+						forward.app_idx, forward.size,
 						forward.data);
 			else if (decrypt_idx == APP_IDX_DEV_REMOTE ||
 				(decrypt_idx == APP_IDX_DEV_LOCAL &&
@@ -910,8 +940,7 @@ int mesh_model_publish(struct mesh_node *node, uint32_t mod_id,
 	uint32_t target;
 	uint8_t *label = NULL;
 	uint16_t dst;
-	uint8_t key_id;
-	const uint8_t *key;
+	uint16_t net_idx;
 	bool result;
 	int status;
 
@@ -958,30 +987,21 @@ int mesh_model_publish(struct mesh_node *node, uint32_t mod_id,
 
 	l_debug("publish dst=%x", dst);
 
-	key = appkey_get_key(net, mod->pub->idx, &key_id);
-	if (!key) {
-		l_debug("no app key for (%x)", mod->pub->idx);
-		return false;
-	}
-
-	l_debug("(%x) %p", mod->pub->idx, key);
-	l_debug("key_id %x", key_id);
+	net_idx = appkey_net_idx(net, mod->pub->idx);
 
 	result = msg_send(node, mod->pub->credential != 0, src,
-				dst, key_id, key, label, ttl, msg, msg_len);
+				dst, mod->pub->idx, net_idx, label, ttl,
+				msg, msg_len);
 
 	return result ? MESH_ERROR_NONE : MESH_ERROR_FAILED;
 
 }
 
-bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t target,
-					uint16_t app_idx, uint8_t ttl,
+bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst,
+					uint16_t app_idx, uint16_t net_idx,
+					uint8_t ttl,
 					const void *msg, uint16_t msg_len)
 {
-	uint8_t key_id;
-	uint8_t dev_key[16];
-	const uint8_t *key;
-
 	/* print_packet("Mod Tx", msg, msg_len); */
 
 	/* If SRC is 0, use the Primary Element */
@@ -990,34 +1010,11 @@ bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t target,
 
 	gettimeofday(&tx_start, NULL);
 
-	if (IS_UNASSIGNED(target))
+	if (IS_UNASSIGNED(dst))
 		return false;
 
-	if (app_idx == APP_IDX_DEV_LOCAL) {
-		key = node_get_device_key(node);
-		if (!key)
-			return false;
-
-		key_id = APP_ID_DEV;
-	} else if (app_idx == APP_IDX_DEV_REMOTE) {
-		if (!keyring_get_remote_dev_key(node, target, dev_key))
-			return false;
-
-		key = dev_key;
-		key_id = APP_ID_DEV;
-	} else {
-		key = appkey_get_key(node_get_net(node), app_idx, &key_id);
-		if (!key) {
-			l_debug("no app key for (%x)", app_idx);
-			return false;
-		}
-
-		l_debug("(%x) %p", app_idx, key);
-		l_debug("key_id %x", key_id);
-	}
-
-	return msg_send(node, false, src, target, key_id, key, NULL, ttl,
-			msg, msg_len);
+	return msg_send(node, false, src, dst, app_idx, net_idx,
+						NULL, ttl, msg, msg_len);
 }
 
 int mesh_model_pub_set(struct mesh_node *node, uint16_t addr, uint32_t id,
diff --git a/mesh/model.h b/mesh/model.h
index a6951293f..fa031f598 100644
--- a/mesh/model.h
+++ b/mesh/model.h
@@ -67,7 +67,8 @@ struct mesh_model_pub {
 
 typedef void (*mesh_model_unregister)(void *user_data);
 typedef bool (*mesh_model_recv_cb)(uint16_t src, uint32_t dst, uint16_t unicast,
-					uint16_t app_idx, const uint8_t *data,
+					uint16_t app_idx, uint16_t net_idx,
+					const uint8_t *data,
 					uint16_t len, uint8_t ttl,
 					const void *user_data);
 typedef int (*mesh_model_bind_cb)(uint16_t app_idx, int action);
@@ -116,14 +117,15 @@ int mesh_model_sub_get(struct mesh_node *node, uint16_t addr, uint32_t id,
 			uint8_t *buf, uint16_t buf_size, uint16_t *size);
 uint16_t mesh_model_cfg_blk(uint8_t *pkt);
 bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst,
-					uint16_t app_idx, uint8_t ttl,
+					uint16_t app_idx, uint16_t net_idx,
+					uint8_t ttl,
 					const void *msg, uint16_t msg_len);
 int mesh_model_publish(struct mesh_node *node, uint32_t mod_id, uint16_t src,
 				uint8_t ttl, const void *msg, uint16_t msg_len);
 bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
 			uint32_t seq, uint32_t iv_index, uint8_t ttl,
-			uint16_t src, uint16_t dst, uint8_t key_id,
-			const uint8_t *data, uint16_t size);
+			uint16_t net_idx, uint16_t src, uint16_t dst,
+			uint8_t key_aid, const uint8_t *data, uint16_t size);
 void mesh_model_app_key_generate_new(struct mesh_node *node, uint16_t net_idx);
 void mesh_model_app_key_delete(struct mesh_node *node, struct l_queue *models,
 								uint16_t idx);
diff --git a/mesh/net.c b/mesh/net.c
index a5693f154..ba52867c4 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -119,7 +119,6 @@ struct mesh_net {
 	unsigned int pkt_id;
 	unsigned int bea_id;
 	unsigned int beacon_id;
-	unsigned int key_id_next;
 	unsigned int sar_id_next;
 
 	bool friend_enable;
@@ -203,7 +202,7 @@ struct mesh_sar {
 	bool frnd_cred;
 	uint8_t ttl;
 	uint8_t last_seg;
-	uint8_t key_id;
+	uint8_t key_aid;
 	uint8_t buf[4]; /* Large enough for ACK-Flags and MIC */
 };
 
@@ -225,7 +224,7 @@ struct msg_rx {
 	union {
 		struct {
 			uint16_t app_idx;
-			uint8_t key_id;
+			uint8_t key_aid;
 		} m;
 		struct {
 			uint16_t seq0;
@@ -668,7 +667,6 @@ struct mesh_net *mesh_net_new(struct mesh_node *node)
 	net->node = node;
 	net->pkt_id = 0;
 	net->bea_id = 0;
-	net->key_id_next = 0;
 
 	net->beacon_enable = true;
 	net->proxy_enable = false;
@@ -676,7 +674,7 @@ struct mesh_net *mesh_net_new(struct mesh_node *node)
 
 	net->seq_num = 0x000000;
 	net->src_addr = 0x0000;
-	net->default_ttl = 0x00;
+	net->default_ttl = 0x7f;
 
 	net->provisioner = false;
 
@@ -1764,12 +1762,11 @@ static void outseg_to(struct l_timeout *seg_timeout, void *user_data)
 	}
 }
 
-static bool msg_rxed(struct mesh_net *net, bool frnd,
-					uint32_t iv_index,
-					uint8_t ttl,
-					uint32_t seq,
+static bool msg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index,
+					uint8_t ttl, uint32_t seq,
+					uint16_t net_idx,
 					uint16_t src, uint16_t dst,
-					uint8_t key_id,
+					uint8_t key_aid,
 					bool szmic, uint16_t seqZero,
 					const uint8_t *data, uint16_t size)
 {
@@ -1781,7 +1778,7 @@ static bool msg_rxed(struct mesh_net *net, bool frnd,
 
 	/* Save un-decrypted messages for our friends */
 	if (!frnd && l_queue_length(net->friends)) {
-		uint32_t hdr = key_id << KEY_HDR_SHIFT;
+		uint32_t hdr = key_aid << KEY_HDR_SHIFT;
 		uint8_t frnd_ttl = ttl;
 
 		/* If not from us, decrement for our hop */
@@ -1806,8 +1803,8 @@ static bool msg_rxed(struct mesh_net *net, bool frnd,
 	}
 
 not_for_friend:
-	return mesh_model_rx(net->node, szmic, seqAuth, seq, iv_index,
-					ttl, src, dst, key_id, data, size);
+	return mesh_model_rx(net->node, szmic, seqAuth, seq, iv_index, ttl,
+					net_idx, src, dst, key_aid, data, size);
 }
 
 static bool match_frnd_sar_dst(const void *a, const void *b)
@@ -1915,12 +1912,11 @@ static void friend_seg_rxed(struct mesh_net *net,
 	frnd_msg->cnt_in++;
 }
 
-static bool seg_rxed(struct mesh_net *net, bool frnd,
-					uint32_t iv_index,
-					uint8_t ttl,
-					uint32_t seq,
+static bool seg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index,
+					uint8_t ttl, uint32_t seq,
+					uint16_t net_idx,
 					uint16_t src, uint16_t dst,
-					uint8_t key_id,
+					uint8_t key_aid,
 					bool szmic, uint16_t seqZero,
 					uint8_t segO, uint8_t segN,
 					const uint8_t *data, uint8_t size)
@@ -1967,7 +1963,7 @@ static bool seg_rxed(struct mesh_net *net, bool frnd,
 					seqZero, seq, size, segO, segN);
 		/* Sanity Check--> certain things must match */
 		if (SEG_MAX(sar_in->len) != segN ||
-				sar_in->key_id != key_id)
+				sar_in->key_aid != key_aid)
 			return false;
 
 		if (sar_in->flags == expected) {
@@ -1988,7 +1984,7 @@ static bool seg_rxed(struct mesh_net *net, bool frnd,
 		sar_in->src = dst;
 		sar_in->remote = src;
 		sar_in->seqZero = seqZero;
-		sar_in->key_id = key_id;
+		sar_in->key_aid = key_aid;
 		sar_in->len = len;
 		sar_in->last_seg = 0xff;
 		if (!net->friend_addr)
@@ -2022,12 +2018,9 @@ static bool seg_rxed(struct mesh_net *net, bool frnd,
 		if (!net->friend_addr)
 			send_net_ack(net, sar_in, expected);
 
-		msg_rxed(net, frnd,
-				iv_index,
-				ttl,
-				seq,
+		msg_rxed(net, frnd, iv_index, ttl, seq, net_idx,
 				sar_in->remote, dst,
-				key_id,
+				key_aid,
 				szmic, sar_in->seqZero,
 				sar_in->buf, sar_in->len);
 
@@ -2300,6 +2293,22 @@ static void send_msg_pkt(struct mesh_net *net, uint8_t *packet, uint8_t size)
 	mesh_io_send(io, &info, packet, size);
 }
 
+static uint16_t key_id_to_net_idx(struct mesh_net *net, uint32_t key_id)
+{
+	struct mesh_subnet *subnet;
+
+	if (!net)
+		return NET_IDX_INVALID;
+
+	subnet = l_queue_find(net->subnets, match_key_id,
+						L_UINT_TO_PTR(key_id));
+
+	if (subnet)
+		return subnet->idx;
+	else
+		return NET_IDX_INVALID;
+}
+
 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)
@@ -2310,6 +2319,7 @@ static enum _relay_advice packet_received(void *user_data,
 	uint8_t net_ttl, net_key_id, net_segO, net_segN, net_opcode;
 	uint32_t net_seq, cache_cookie;
 	uint16_t net_src, net_dst, net_seqZero;
+	uint16_t net_idx;
 	uint8_t packet[31];
 	bool net_ctl, net_segmented, net_szmic, net_relay;
 	struct mesh_friend *net_frnd = NULL;
@@ -2325,6 +2335,10 @@ static enum _relay_advice packet_received(void *user_data,
 	if (!drop)
 		print_packet("RX: Network [clr] :", packet + 2, size);
 
+	net_idx = key_id_to_net_idx(net, key_id);
+	if (net_idx == NET_IDX_INVALID)
+		return RELAY_NONE;
+
 	if (!mesh_crypto_packet_parse(packet + 2, size,
 					&net_ctl, &net_ttl,
 					&net_seq,
@@ -2433,10 +2447,8 @@ static enum _relay_advice packet_received(void *user_data,
 						msg, app_msg_len);
 				}
 			} else {
-				seg_rxed(net, net_frnd,
-						iv_index,
-						net_ttl,
-						net_seq,
+				seg_rxed(net, net_frnd, iv_index, net_ttl,
+						net_seq, net_idx,
 						net_src, net_dst,
 						net_key_id,
 						net_szmic, net_seqZero,
@@ -2449,6 +2461,7 @@ static enum _relay_advice packet_received(void *user_data,
 						iv_index,
 						net_ttl,
 						net_seq,
+						net_idx,
 						net_src, net_dst,
 						net_key_id,
 						false, net_seq & SEQ_ZERO_MASK,
@@ -3291,7 +3304,7 @@ static bool send_seg(struct mesh_net *net, struct mesh_sar *msg, uint8_t segO)
 					seq_num,
 					msg->src, msg->remote,
 					0,
-					segN ? true : false, msg->key_id,
+					segN ? true : false, msg->key_aid,
 					msg->szmic, false, msg->seqZero,
 					segO, segN,
 					msg->buf + seg_off, seg_len,
@@ -3389,9 +3402,9 @@ void mesh_net_send_seg(struct mesh_net *net, uint32_t net_key_id,
 }
 
 bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src,
-				uint16_t dst, uint8_t key_id, uint8_t ttl,
-				uint32_t seq, uint32_t iv_index, bool szmic,
-				const void *msg, uint16_t msg_len,
+				uint16_t dst, uint8_t key_aid, uint16_t net_idx,
+				uint8_t ttl, uint32_t seq, uint32_t iv_index,
+				bool szmic, const void *msg, uint16_t msg_len,
 				mesh_net_status_func_t status_func,
 				void *user_data)
 {
@@ -3408,18 +3421,17 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src,
 	if (!src || !dst)
 		return false;
 
-	if (ttl == 0xff)
+	if (ttl == DEFAULT_TTL)
 		ttl = net->default_ttl;
 
 	seg_max = SEG_MAX(msg_len);
 
 	/* First enqueue to any Friends and internal models */
-	result = msg_rxed(net, false,
-				iv_index,
-				ttl,
+	result = msg_rxed(net, false, iv_index, ttl,
 				seq + seg_max,
+				net_idx,
 				src, dst,
-				key_id,
+				key_aid,
 				szmic, seq & SEQ_ZERO_MASK,
 				msg, msg_len);
 
@@ -3450,7 +3462,7 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src,
 	payload->ttl = ttl;
 	payload->szmic = szmic;
 	payload->frnd_cred = frnd_cred;
-	payload->key_id = key_id;
+	payload->key_aid = key_aid;
 	if (seg_max) {
 		payload->flags = 0xffffffff >> (31 - seg_max);
 		payload->seqZero = seq & SEQ_ZERO_MASK;
@@ -3561,7 +3573,7 @@ void mesh_net_transport_send(struct mesh_net *net, uint32_t key_id,
 	if (src == dst)
 		return;
 
-	if (ttl == 0xff)
+	if (ttl == DEFAULT_TTL)
 		ttl = net->default_ttl;
 
 	/* Range check the Opcode and msg length*/
diff --git a/mesh/net.h b/mesh/net.h
index 7b0733578..834a7351a 100644
--- a/mesh/net.h
+++ b/mesh/net.h
@@ -300,9 +300,9 @@ void mesh_net_transport_send(struct mesh_net *net, uint32_t key_id,
 				const uint8_t *msg, uint16_t msg_len);
 
 bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src,
-				uint16_t dst, uint8_t key_id, uint8_t ttl,
-				uint32_t seq, uint32_t iv_index, bool szmic,
-				const void *msg, uint16_t msg_len,
+				uint16_t dst, uint8_t key_id, uint16_t net_idx,
+				uint8_t ttl, uint32_t seq, uint32_t iv_index,
+				bool szmic, const void *msg, uint16_t msg_len,
 				mesh_net_status_func_t status_func,
 				void *user_data);
 void mesh_net_ack_send(struct mesh_net *net, uint32_t key_id,
diff --git a/mesh/node.c b/mesh/node.c
index 27235ef34..40d103327 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -1790,12 +1790,12 @@ static struct l_dbus_message *send_call(struct l_dbus *dbus,
 		return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
 							"Incorrect data");
 
-	if ((app_idx & APP_IDX_MASK) != app_idx)
+	if (app_idx & ~APP_IDX_MASK)
 		return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
 						"Invalid key_index");
 
-	if (!mesh_model_send(node, src, dst, app_idx & APP_IDX_MASK,
-				mesh_net_get_default_ttl(node->net), data, len))
+	if (!mesh_model_send(node, src, dst, app_idx, 0, DEFAULT_TTL,
+								data, len))
 		return dbus_error(msg, MESH_ERROR_FAILED, NULL);
 
 	return l_dbus_message_new_method_return(msg);
@@ -1837,8 +1837,8 @@ static struct l_dbus_message *dev_key_send_call(struct l_dbus *dbus,
 							"Incorrect data");
 
 	/* TODO: use net_idx */
-	if (!mesh_model_send(node, src, dst, APP_IDX_DEV_REMOTE,
-				mesh_net_get_default_ttl(node->net), data, len))
+	if (!mesh_model_send(node, src, dst, APP_IDX_DEV_REMOTE, net_idx,
+							DEFAULT_TTL, data, len))
 		return dbus_error(msg, MESH_ERROR_NOT_FOUND, NULL);
 
 	return l_dbus_message_new_method_return(msg);
-- 
2.14.5


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

* Re: [PATCH BlueZ 3/3] mesh: Propagate Net Index up Rx message chain
  2019-07-16 22:56 ` [PATCH BlueZ 3/3] mesh: Propagate Net Index up Rx message chain Brian Gix
@ 2019-07-17  8:48   ` Michał Lowas-Rzechonek
  0 siblings, 0 replies; 6+ messages in thread
From: Michał Lowas-Rzechonek @ 2019-07-17  8:48 UTC (permalink / raw)
  To: Brian Gix; +Cc: linux-bluetooth, inga.stotland

Hi Brian,

On 07/16, Brian Gix wrote:
> When a model receives a message, it is required by the spec
> to respond using the same credentials. When an App Key is used,
> this is trivial because App keys are bound to Net keys, so only
> the App Index is required.  Messages received on a Device key
> however, need the Net Index preserved from original message for
> re-use during the response.
> ---
>  mesh/cfgmod-server.c | 154 ++++++++++++++++++++++++++++-----------------------
>  mesh/model.c         | 129 +++++++++++++++++++++---------------------
>  mesh/model.h         |  10 ++--
>  mesh/net.c           |  92 +++++++++++++++++-------------
>  mesh/net.h           |   6 +-
>  mesh/node.c          |  10 ++--
>  6 files changed, 214 insertions(+), 187 deletions(-)
> 
(...)
> diff --git a/mesh/net.c b/mesh/net.c
> index a5693f154..ba52867c4 100644
> --- a/mesh/net.c
> +++ b/mesh/net.c
> @@ -119,7 +119,6 @@ struct mesh_net {
>  	unsigned int pkt_id;
>  	unsigned int bea_id;
>  	unsigned int beacon_id;
> -	unsigned int key_id_next;
>  	unsigned int sar_id_next;
>  
>  	bool friend_enable;
> @@ -203,7 +202,7 @@ struct mesh_sar {
>  	bool frnd_cred;
>  	uint8_t ttl;
>  	uint8_t last_seg;
> -	uint8_t key_id;
> +	uint8_t key_aid;
>  	uint8_t buf[4]; /* Large enough for ACK-Flags and MIC */
>  };
>  
> @@ -225,7 +224,7 @@ struct msg_rx {
>  	union {
>  		struct {
>  			uint16_t app_idx;
> -			uint8_t key_id;
> +			uint8_t key_aid;
>  		} m;
>  		struct {
>  			uint16_t seq0;
> @@ -668,7 +667,6 @@ struct mesh_net *mesh_net_new(struct mesh_node *node)
>  	net->node = node;
>  	net->pkt_id = 0;
>  	net->bea_id = 0;
> -	net->key_id_next = 0;
>  
>  	net->beacon_enable = true;
>  	net->proxy_enable = false;
> @@ -676,7 +674,7 @@ struct mesh_net *mesh_net_new(struct mesh_node *node)
>  
>  	net->seq_num = 0x000000;
>  	net->src_addr = 0x0000;
> -	net->default_ttl = 0x00;
> +	net->default_ttl = 0x7f;
(...)
> @@ -3408,18 +3421,17 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src,
>  	if (!src || !dst)
>  		return false;
>  
> -	if (ttl == 0xff)
> +	if (ttl == DEFAULT_TTL)
>  		ttl = net->default_ttl;
(...)

I would keep these in a separate patch, it's not really related to key
ids/indexes.

Otherwise, LGTM!

-- 
Michał Lowas-Rzechonek <michal.lowas-rzechonek@silvair.com>
Silvair http://silvair.com
Jasnogórska 44, 31-358 Krakow, POLAND

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

* Re: [PATCH BlueZ 0/3] mesh: Propagate/Preserve Net Index for Access Layer
  2019-07-16 22:56 [PATCH BlueZ 0/3] mesh: Propagate/Preserve Net Index for Access Layer Brian Gix
                   ` (2 preceding siblings ...)
  2019-07-16 22:56 ` [PATCH BlueZ 3/3] mesh: Propagate Net Index up Rx message chain Brian Gix
@ 2019-07-18 17:07 ` Gix, Brian
  3 siblings, 0 replies; 6+ messages in thread
From: Gix, Brian @ 2019-07-18 17:07 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: michal.lowas-rzechonek, Stotland, Inga

Patch-set applied

On Tue, 2019-07-16 at 15:56 -0700, Brian Gix wrote:
> Two major flaws are corrected by this patch-set:
> 
> 1. The Spec defined Access Layer AID was being confused with the internally used
> key_id which is used to identify Network keys for multiple networks,
> sub-networks, and friendships. This confused ID was then being used instead
> of the correct Network Key ID for outgoing messages.
> 
> 2. The specification requires *responses* to all standard Server messages to
> be sent with the same credentials as the received command that triggered them.
> This requires more complete propagation of the Net Index value on received
> messages, so that the same Network key is used in the reverse direction.
> 
> This additionally now uses the requested Net Index when sending Device Key
> secured messages through the D-Bus interface.
> 
> Brian Gix (3):
>   mesh: Add bound Net Index lookup for App Keys
>   mesh: Normalize Access Key AID naming convention
>   mesh: Propagate Net Index up Rx message chain
> 
>  mesh/appkey.c        |  59 +++++++++++++-------
>  mesh/appkey.h        |   1 +
>  mesh/cfgmod-server.c | 154 ++++++++++++++++++++++++++++-----------------------
>  mesh/crypto.c        |  37 ++++++-------
>  mesh/crypto.h        |   8 +--
>  mesh/model.c         | 129 +++++++++++++++++++++---------------------
>  mesh/model.h         |  10 ++--
>  mesh/net.c           |  92 +++++++++++++++++-------------
>  mesh/net.h           |  10 ++--
>  mesh/node.c          |  10 ++--
>  10 files changed, 276 insertions(+), 234 deletions(-)
> 

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

end of thread, other threads:[~2019-07-18 17:07 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-16 22:56 [PATCH BlueZ 0/3] mesh: Propagate/Preserve Net Index for Access Layer Brian Gix
2019-07-16 22:56 ` [PATCH BlueZ 1/3] mesh: Add bound Net Index lookup for App Keys Brian Gix
2019-07-16 22:56 ` [PATCH BlueZ 2/3] mesh: Normalize Access Key AID naming convention Brian Gix
2019-07-16 22:56 ` [PATCH BlueZ 3/3] mesh: Propagate Net Index up Rx message chain Brian Gix
2019-07-17  8:48   ` Michał Lowas-Rzechonek
2019-07-18 17:07 ` [PATCH BlueZ 0/3] mesh: Propagate/Preserve Net Index for Access Layer 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).