linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added
@ 2019-07-11 22:59 Brian Gix
  2019-07-11 22:59 ` [PATCH BlueZ v2 1/9] doc: Cleanup API Provisioner1 interface Brian Gix
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: Brian Gix @ 2019-07-11 22:59 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, michal.lowas-rzechonek, brian.gix

v2 additions:
* Style guide changes noted by Michal
* Additional patch to use packed structures for Mesh Spec specifid OTA messages

The added functionality of this patch set allows any node with a keyring
provision a new node into the network. It does *not* implement a
user App that can store a Configuration Database, but it does provide
extensions to the python test script to test the primitives.

Brian Gix (9):
  doc: Cleanup API Provisioner1 interface
  mesh: Fix support for Provisioner Initiator
  mesh: Add special Beacon handler for Provisioning
  mesh: Expose mapping function for D-Bus errors
  mesh: Expose resources needed by Management1 interface
  mesh: Fix implementation of Provisioner Initiator
  mesh: Implement DBus Provisioning methods
  mesh: Convert provisioning pkts to packed structs
  test: This extends the mesh tool to exercise Provisioning methods

 doc/mesh-api.txt       |  13 ++-
 mesh/crypto.c          |   8 +-
 mesh/crypto.h          |   8 +-
 mesh/manager.c         | 304 +++++++++++++++++++++++++++++++++++++++++++++++--
 mesh/mesh-io-generic.c |   2 +-
 mesh/mesh-io.c         |   6 +-
 mesh/mesh-io.h         |   7 +-
 mesh/mesh.c            |  10 +-
 mesh/mesh.h            |   4 +-
 mesh/node.c            |  42 +++++--
 mesh/node.h            |   3 +
 mesh/pb-adv.c          | 177 +++++++++++++++++-----------
 mesh/pb-adv.h          |   3 +-
 mesh/prov-acceptor.c   | 158 +++++++++++++------------
 mesh/prov-initiator.c  | 283 +++++++++++++++++++++++++++++++++------------
 mesh/prov.h            |  51 ++++++++-
 mesh/provision.h       |  10 +-
 test/test-mesh         | 113 ++++++++++++++++++
 18 files changed, 946 insertions(+), 256 deletions(-)

-- 
2.14.5


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

* [PATCH BlueZ v2 1/9] doc: Cleanup API Provisioner1 interface
  2019-07-11 22:59 [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Brian Gix
@ 2019-07-11 22:59 ` Brian Gix
  2019-07-11 22:59 ` [PATCH BlueZ v2 2/9] mesh: Fix support for Provisioner Initiator Brian Gix
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Brian Gix @ 2019-07-11 22:59 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, michal.lowas-rzechonek, brian.gix

Modified the RequestProvData In and Out param list to eliminate
parameters which can be provided by the Node which owns the
procedure, and clean-up the actual error list.
---
 doc/mesh-api.txt | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/doc/mesh-api.txt b/doc/mesh-api.txt
index 893a1a6c0..0ac2fdfd1 100644
--- a/doc/mesh-api.txt
+++ b/doc/mesh-api.txt
@@ -365,7 +365,9 @@ Methods:
 		ScanResult() method on the app will be called with the result.
 
 		PossibleErrors:
+			org.bluez.mesh.Error.InvalidArguments
 			org.bluez.mesh.Error.NotAuthorized
+			org.bluez.mesh.Error.Busy
 
 	void UnprovisionedScanCancel(void)
 
@@ -374,6 +376,7 @@ Methods:
 		(scanning) for unprovisioned devices in the area.
 
 		PossibleErrors:
+			org.bluez.mesh.Error.InvalidArguments
 			org.bluez.mesh.Error.NotAuthorized
 
 	void AddNode(array{byte}[16] uuid)
@@ -860,7 +863,7 @@ Service		unique name
 Interface	org.bluez.mesh.Provisioner1
 Object path	freely definable
 
-	ScanResult(int8 rssi, array{byte} data)
+	void ScanResult(int16 rssi, array{byte} data)
 
 		The method is called from the bluetooth-meshd daemon when a
 		unique UUID has been seen during UnprovisionedScan() for
@@ -881,17 +884,17 @@ Object path	freely definable
 		was recieved at a higher rssi power level.
 
 
-	uint16 net_index, uint8 flags, uint32 iv_index, uint16 unicast
-							RequestProvData()
+	uint16 net_index, uint16 unicast RequestProvData(uint8 count)
 
 		This method is implemented by a Provisioner capable application
 		and is called when the remote device has been fully
 		authenticated and confirmed.
 
+		The count parameter is the number of consecutive unicast
+		addresses the remote device is requesting.
+
 		Return Parameters are from the Mesh Profile Spec:
 		net_index - Subnet index of the net_key
-		flags - Flags for IV_Update and Key Refresh
-		iv_index - Current IvIndex being used on the network
 		unicast - Primary Unicast address of the new node
 
 		PossibleErrors:
-- 
2.14.5


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

* [PATCH BlueZ v2 2/9] mesh: Fix support for Provisioner Initiator
  2019-07-11 22:59 [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Brian Gix
  2019-07-11 22:59 ` [PATCH BlueZ v2 1/9] doc: Cleanup API Provisioner1 interface Brian Gix
@ 2019-07-11 22:59 ` Brian Gix
  2019-07-11 22:59 ` [PATCH BlueZ v2 3/9] mesh: Add special Beacon handler for Provisioning Brian Gix
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Brian Gix @ 2019-07-11 22:59 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, michal.lowas-rzechonek, brian.gix

---
 mesh/pb-adv.c         | 128 ++++++++++++++++++++++++++++----------------------
 mesh/pb-adv.h         |   3 +-
 mesh/prov-acceptor.c  |   2 +-
 mesh/prov-initiator.c |   2 +-
 4 files changed, 77 insertions(+), 58 deletions(-)

diff --git a/mesh/pb-adv.c b/mesh/pb-adv.c
index 8762afd7c..4d85ee72e 100644
--- a/mesh/pb-adv.c
+++ b/mesh/pb-adv.c
@@ -39,16 +39,16 @@ struct pb_adv_session {
 	mesh_prov_receive_func_t rx_cb;
 	mesh_prov_ack_func_t ack_cb;
 	struct l_timeout *tx_timeout;
-	uint32_t conn_id;
+	uint32_t link_id;
 	uint16_t exp_len;
 	uint8_t exp_fcs;
 	uint8_t exp_segs;
 	uint8_t got_segs;
-	uint8_t msg_num;
+	uint8_t trans_num;
 	uint8_t local_acked;
-	uint8_t local_msg_num;
-	uint8_t peer_msg_num;
-	uint8_t last_peer_msg_num;
+	uint8_t local_trans_num;
+	uint8_t peer_trans_num;
+	uint8_t last_peer_trans_num;
 	uint8_t sar[80];
 	uint8_t uuid[16];
 	bool initiator;
@@ -65,6 +65,8 @@ struct pb_adv_session {
 
 static struct pb_adv_session *pb_session = NULL;
 
+static const uint8_t filter[1] = { MESH_AD_TYPE_PROVISION };
+
 static void send_adv_segs(struct pb_adv_session *session, const uint8_t *data,
 							uint16_t size)
 {
@@ -77,10 +79,10 @@ static void send_adv_segs(struct pb_adv_session *session, const uint8_t *data,
 	if (!size)
 		return;
 
-	mesh_send_cancel(buf, 1);
+	mesh_send_cancel(filter, sizeof(filter));
 
-	l_put_be32(session->conn_id, buf + 1);
-	buf[1 + 4] = ++session->local_msg_num;
+	l_put_be32(session->link_id, buf + 1);
+	buf[1 + 4] = ++session->local_trans_num;
 
 	if (size > PB_ADV_MTU - 4) {
 		max_seg = 1 +
@@ -103,7 +105,7 @@ static void send_adv_segs(struct pb_adv_session *session, const uint8_t *data,
 	l_debug("max_seg: %2.2x", max_seg);
 	l_debug("size: %2.2x, CRC: %2.2x", size, buf[9]);
 	/* print_packet("PB-TX", buf + 1, init_size + 9); */
-	mesh_send_pkt(MESH_IO_TX_COUNT_UNLIMITED, 50, buf, init_size + 10);
+	mesh_send_pkt(MESH_IO_TX_COUNT_UNLIMITED, 200, buf, init_size + 10);
 
 	consumed = init_size;
 
@@ -120,7 +122,7 @@ static void send_adv_segs(struct pb_adv_session *session, const uint8_t *data,
 
 		/* print_packet("PB-TX", buf + 1, seg_size + 6); */
 
-		mesh_send_pkt(MESH_IO_TX_COUNT_UNLIMITED, 50,
+		mesh_send_pkt(MESH_IO_TX_COUNT_UNLIMITED, 200,
 							buf, seg_size + 7);
 
 		consumed += seg_size;
@@ -130,7 +132,6 @@ static void send_adv_segs(struct pb_adv_session *session, const uint8_t *data,
 static void tx_timeout(struct l_timeout *timeout, void *user_data)
 {
 	struct pb_adv_session *session = user_data;
-	uint8_t cancel[] = { MESH_AD_TYPE_PROVISION };
 	mesh_prov_close_func_t cb;
 
 	if (!session || pb_session != session)
@@ -139,7 +140,7 @@ static void tx_timeout(struct l_timeout *timeout, void *user_data)
 	l_timeout_remove(session->tx_timeout);
 	session->tx_timeout = NULL;
 
-	mesh_send_cancel(cancel, sizeof(cancel));
+	mesh_send_cancel(filter, sizeof(filter));
 
 	l_info("TX timeout");
 	cb = pb_session->close_cb;
@@ -162,29 +163,40 @@ static void pb_adv_tx(void *user_data, uint8_t *data, uint16_t len)
 	send_adv_segs(session, data, len);
 }
 
+static void send_open_req(struct pb_adv_session *session)
+{
+	uint8_t open_req[23] = { MESH_AD_TYPE_PROVISION };
+
+	l_put_be32(session->link_id, open_req + 1);
+	open_req[1 + 4] = 0;
+	open_req[1 + 4 + 1] = PB_ADV_OPEN_REQ;
+	memcpy(open_req + 7, session->uuid, 16);
+
+	mesh_send_cancel(filter, sizeof(filter));
+	mesh_send_pkt(MESH_IO_TX_COUNT_UNLIMITED, 500, open_req,
+						sizeof(open_req));
+}
+
 static void send_open_cfm(struct pb_adv_session *session)
 {
 	uint8_t open_cfm[7] = { MESH_AD_TYPE_PROVISION };
 
-	l_put_be32(session->conn_id, open_cfm + 1);
+	l_put_be32(session->link_id, open_cfm + 1);
 	open_cfm[1 + 4] = 0;
-	open_cfm[1 + 4 + 1] = 0x07; /* OPEN_CFM */
-
-	/* print_packet("PB-TX", open_cfm + 1, sizeof(open_cfm) - 1); */
+	open_cfm[1 + 4 + 1] = PB_ADV_OPEN_CFM; /* OPEN_CFM */
 
-	mesh_send_cancel(open_cfm, 1);
+	mesh_send_cancel(filter, sizeof(filter));
 	mesh_send_pkt(5, 100, open_cfm, sizeof(open_cfm));
 }
 
-static void send_ack(struct pb_adv_session *session, uint8_t msg_num)
+static void send_ack(struct pb_adv_session *session, uint8_t trans_num)
 {
 	uint8_t ack[7] = { MESH_AD_TYPE_PROVISION };
 
-	l_put_be32(session->conn_id, ack + 1);
-	ack[1 + 4] = msg_num;
-	ack[1 + 4 + 1] = 0x01; /* ACK */
+	l_put_be32(session->link_id, ack + 1);
+	ack[1 + 4] = trans_num;
+	ack[1 + 4 + 1] = PB_ADV_ACK;
 
-	/* print_packet("ADV-ACK", ack + 1, sizeof(ack) - 1); */
 	mesh_send_pkt(1, 100, ack, sizeof(ack));
 }
 
@@ -192,43 +204,43 @@ static void send_close_ind(struct pb_adv_session *session, uint8_t reason)
 {
 	uint8_t close_ind[8] = { MESH_AD_TYPE_PROVISION };
 
-	if (!pb_session || pb_session->user_data != session)
+	if (!pb_session || pb_session != session)
 		return;
 
-	l_put_be32(session->conn_id, close_ind + 1);
+	l_put_be32(session->link_id, close_ind + 1);
 	close_ind[5] = 0;
-	close_ind[6] = PB_ADV_CLOSE;		/* CLOSE_IND */
+	close_ind[6] = PB_ADV_CLOSE;
 	close_ind[7] = reason;
 
-	mesh_send_cancel(close_ind, 1);
-	mesh_send_pkt(5, 100, close_ind, sizeof(close_ind));
+	mesh_send_cancel(filter, sizeof(filter));
+	mesh_send_pkt(10, 100, close_ind, sizeof(close_ind));
 }
 
 static void pb_adv_packet(void *user_data, const uint8_t *pkt, uint16_t len)
 {
 	struct pb_adv_session *session = user_data;
-	uint32_t conn_id;
+	uint32_t link_id;
 	size_t offset;
-	uint8_t msg_num;
+	uint8_t trans_num;
 	uint8_t type;
 	bool first;
 
 	if (!session || pb_session != session)
 		return;
 
-	conn_id = l_get_be32(pkt + 1);
+	link_id = l_get_be32(pkt + 1);
 	type = l_get_u8(pkt + 6);
 
 	/* Validate new or existing Connection ID */
-	if (session->conn_id) {
-		if (session->conn_id != conn_id)
+	if (session->link_id) {
+		if (session->link_id != link_id)
 			return;
 	} else if (type != 0x03)
 		return;
-	else if (!conn_id)
+	else if (!link_id)
 		return;
 
-	msg_num = l_get_u8(pkt + 5);
+	trans_num = l_get_u8(pkt + 5);
 	pkt += 7;
 	len -= 7;
 
@@ -237,7 +249,7 @@ static void pb_adv_packet(void *user_data, const uint8_t *pkt, uint16_t len)
 		/*
 		 * Ignore if:
 		 * 1. We are acceptor
-		 * 2. We are already provisioning on different conn_id
+		 * 2. We are already provisioning on different link_id
 		 */
 
 		if (!session->initiator)
@@ -259,7 +271,7 @@ static void pb_adv_packet(void *user_data, const uint8_t *pkt, uint16_t len)
 		 * Ignore if:
 		 * 1. We are initiator
 		 * 2. Open request not addressed to us
-		 * 3. We are already provisioning on different conn_id
+		 * 3. We are already provisioning on different link_id
 		 */
 
 		if (session->initiator)
@@ -268,12 +280,12 @@ static void pb_adv_packet(void *user_data, const uint8_t *pkt, uint16_t len)
 		if (memcmp(pkt, session->uuid, 16))
 			return;
 
-		first = !session->conn_id;
-		session->conn_id = conn_id;
-		session->last_peer_msg_num = 0xFF;
+		first = !session->link_id;
+		session->link_id = link_id;
+		session->last_peer_trans_num = 0xFF;
 		session->local_acked = 0xFF;
-		session->peer_msg_num = 0x00;
-		session->local_msg_num = 0x7F;
+		session->peer_trans_num = 0x00;
+		session->local_trans_num = 0x7F;
 		session->opened = true;
 
 		/* Only call Open callback once */
@@ -305,29 +317,29 @@ static void pb_adv_packet(void *user_data, const uint8_t *pkt, uint16_t len)
 		if (!session->opened)
 			return;
 
-		if (msg_num != session->local_msg_num)
+		if (trans_num != session->local_trans_num)
 			return;
 
-		if (session->local_acked > msg_num)
+		if (session->local_acked > trans_num)
 			return;
 
-		l_debug("Got ACK %d", msg_num);
-		session->local_acked = msg_num;
-		session->ack_cb(session->user_data, msg_num);
+		mesh_send_cancel(filter, sizeof(filter));
+		session->local_acked = trans_num;
+		session->ack_cb(session->user_data, trans_num);
 		break;
 
 	default: /* DATA SEGMENT */
 		if (!session->opened)
 			return;
 
-		if (msg_num == session->last_peer_msg_num) {
-			send_ack(session, msg_num);
+		if (trans_num == session->last_peer_trans_num) {
+			send_ack(session, trans_num);
 			return;
 		}
 
 		switch(type & 0x03) {
 		case 0x00:
-			session->peer_msg_num = msg_num;
+			session->peer_trans_num = trans_num;
 			session->exp_len = l_get_be16(pkt);
 
 			l_debug("PB-ADV start with %u fragments, %d octets",
@@ -348,7 +360,7 @@ static void pb_adv_packet(void *user_data, const uint8_t *pkt, uint16_t len)
 			break;
 
 		case 0x02:
-			session->peer_msg_num = msg_num;
+			session->peer_trans_num = trans_num;
 			offset = 20 + (((type >> 2) - 1) * 23);
 
 			if (offset + len - 3 > sizeof(session->sar)) {
@@ -384,18 +396,19 @@ static void pb_adv_packet(void *user_data, const uint8_t *pkt, uint16_t len)
 			return;
 		}
 
-		if (session->last_peer_msg_num != session->peer_msg_num) {
+		if (session->last_peer_trans_num != session->peer_trans_num) {
 			session->got_segs = 0;
 			session->rx_cb(session->user_data, session->sar,
 							session->exp_len);
 		}
 
-		session->last_peer_msg_num = session->peer_msg_num;
-		send_ack(session, session->last_peer_msg_num);
+		session->last_peer_trans_num = session->peer_trans_num;
+		send_ack(session, session->last_peer_trans_num);
 	}
 }
 
-bool pb_adv_reg(mesh_prov_open_func_t open_cb, mesh_prov_close_func_t close_cb,
+bool pb_adv_reg(bool initiator, mesh_prov_open_func_t open_cb,
+		mesh_prov_close_func_t close_cb,
 		mesh_prov_receive_func_t rx_cb, mesh_prov_ack_func_t ack_cb,
 		uint8_t uuid[16], void *user_data)
 {
@@ -408,11 +421,16 @@ bool pb_adv_reg(mesh_prov_open_func_t open_cb, mesh_prov_close_func_t close_cb,
 	pb_session->rx_cb = rx_cb;
 	pb_session->ack_cb = ack_cb;
 	pb_session->user_data = user_data;
+	pb_session->initiator = initiator;
 	memcpy(pb_session->uuid, uuid, 16);
 
-	/* TODO: register PB AD type and Start Beaconing ? */
 	mesh_reg_prov_rx(pb_adv_packet, pb_session);
 
+	if (initiator) {
+		l_getrandom(&pb_session->link_id, sizeof(pb_session->link_id));
+		send_open_req(pb_session);
+	}
+
 	return true;
 }
 
diff --git a/mesh/pb-adv.h b/mesh/pb-adv.h
index a5870d5a2..80d53d234 100644
--- a/mesh/pb-adv.h
+++ b/mesh/pb-adv.h
@@ -17,7 +17,8 @@
  *
  */
 
-bool pb_adv_reg(mesh_prov_open_func_t open_cb, mesh_prov_close_func_t close_cb,
+bool pb_adv_reg(bool initiator, mesh_prov_open_func_t open_cb,
+		mesh_prov_close_func_t close_cb,
 		mesh_prov_receive_func_t rx_cb, mesh_prov_ack_func_t ack_cb,
 		uint8_t uuid[16], void *user_data);
 void pb_adv_unreg(void *user_data);
diff --git a/mesh/prov-acceptor.c b/mesh/prov-acceptor.c
index 7b79fa916..111340db3 100644
--- a/mesh/prov-acceptor.c
+++ b/mesh/prov-acceptor.c
@@ -651,7 +651,7 @@ bool acceptor_start(uint8_t num_ele, uint8_t uuid[16],
 		goto error_fail;
 
 	/* Always register for PB-ADV */
-	result = pb_adv_reg(acp_prov_open, acp_prov_close, acp_prov_rx,
+	result = pb_adv_reg(false, acp_prov_open, acp_prov_close, acp_prov_rx,
 						acp_prov_ack, uuid, prov);
 
 	if (result)
diff --git a/mesh/prov-initiator.c b/mesh/prov-initiator.c
index f147c7ad8..b1ed96a60 100644
--- a/mesh/prov-initiator.c
+++ b/mesh/prov-initiator.c
@@ -613,7 +613,7 @@ bool initiator_start(enum trans_type transport,
 	prov->previous = -1;
 
 	/* Always register for PB-ADV */
-	result = pb_adv_reg(int_prov_open, int_prov_close, int_prov_rx,
+	result = pb_adv_reg(true, int_prov_open, int_prov_close, int_prov_rx,
 						int_prov_ack, uuid, prov);
 
 	if (result)
-- 
2.14.5


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

* [PATCH BlueZ v2 3/9] mesh: Add special Beacon handler for Provisioning
  2019-07-11 22:59 [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Brian Gix
  2019-07-11 22:59 ` [PATCH BlueZ v2 1/9] doc: Cleanup API Provisioner1 interface Brian Gix
  2019-07-11 22:59 ` [PATCH BlueZ v2 2/9] mesh: Fix support for Provisioner Initiator Brian Gix
@ 2019-07-11 22:59 ` Brian Gix
  2019-07-11 22:59 ` [PATCH BlueZ v2 4/9] mesh: Expose mapping function for D-Bus errors Brian Gix
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Brian Gix @ 2019-07-11 22:59 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, michal.lowas-rzechonek, brian.gix

Provisioning uses the same AD type for Provisioning that
is also used by the Secure Network Beacon, but their
usage is distinct from each other.  This change allows
us to enable/disable Unprovisioned Device Beacon capture
without disrupting SNB handling.
---
 mesh/mesh-io-generic.c | 2 +-
 mesh/mesh-io.c         | 6 ++++--
 mesh/mesh-io.h         | 7 ++++---
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/mesh/mesh-io-generic.c b/mesh/mesh-io-generic.c
index 42aaa0947..576c5df1b 100644
--- a/mesh/mesh-io-generic.c
+++ b/mesh/mesh-io-generic.c
@@ -40,7 +40,7 @@ struct mesh_io_private {
 	struct l_timeout *tx_timeout;
 	struct l_queue *rx_regs;
 	struct l_queue *tx_pkts;
-	uint8_t filters[3]; /* Simple filtering on AD type only */
+	uint8_t filters[4];
 	bool sending;
 	struct tx_pkt *tx;
 	uint16_t interval;
diff --git a/mesh/mesh-io.c b/mesh/mesh-io.c
index 62a8c0e2c..94a92e885 100644
--- a/mesh/mesh-io.c
+++ b/mesh/mesh-io.c
@@ -86,12 +86,14 @@ struct mesh_io *mesh_io_new(enum mesh_io_type type, void *opts)
 
 	if (api->set) {
 		uint8_t pkt = MESH_AD_TYPE_NETWORK;
-		uint8_t bec = MESH_AD_TYPE_BEACON;
 		uint8_t prv = MESH_AD_TYPE_PROVISION;
+		uint8_t snb[2] = {MESH_AD_TYPE_BEACON, 0x01};
+		uint8_t prvb[2] = {MESH_AD_TYPE_BEACON, 0x00};
 
-		api->set(io, 1, &bec, 1, NULL, NULL);
+		api->set(io, 1, snb, sizeof(snb), NULL, NULL);
 		api->set(io, 2, &prv, 1, NULL, NULL);
 		api->set(io, 3, &pkt, 1, NULL, NULL);
+		api->set(io, 4, prvb, sizeof(prvb), NULL, NULL);
 	}
 
 	if (l_queue_push_head(io_list, io))
diff --git a/mesh/mesh-io.h b/mesh/mesh-io.h
index 6585205c7..1c10779aa 100644
--- a/mesh/mesh-io.h
+++ b/mesh/mesh-io.h
@@ -19,9 +19,10 @@
 
 struct mesh_io;
 
-#define MESH_IO_FILTER_BEACON	1
-#define MESH_IO_FILTER_PROV	2
-#define MESH_IO_FILTER_NET	3
+#define MESH_IO_FILTER_BEACON		1
+#define MESH_IO_FILTER_PROV		2
+#define MESH_IO_FILTER_NET		3
+#define MESH_IO_FILTER_PROV_BEACON	4
 
 #define MESH_IO_TX_COUNT_UNLIMITED	0
 
-- 
2.14.5


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

* [PATCH BlueZ v2 4/9] mesh: Expose mapping function for D-Bus errors
  2019-07-11 22:59 [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Brian Gix
                   ` (2 preceding siblings ...)
  2019-07-11 22:59 ` [PATCH BlueZ v2 3/9] mesh: Add special Beacon handler for Provisioning Brian Gix
@ 2019-07-11 22:59 ` Brian Gix
  2019-07-11 22:59 ` [PATCH BlueZ v2 5/9] mesh: Expose resources needed by Management1 interface Brian Gix
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Brian Gix @ 2019-07-11 22:59 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, michal.lowas-rzechonek, brian.gix

---
 mesh/mesh.c | 8 ++++----
 mesh/mesh.h | 1 +
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/mesh/mesh.c b/mesh/mesh.c
index 26acfd4dc..62c80c0f3 100644
--- a/mesh/mesh.c
+++ b/mesh/mesh.c
@@ -266,7 +266,7 @@ static void prov_disc_cb(struct l_dbus *bus, void *user_data)
 	free_pending_join_call(true);
 }
 
-static const char *prov_status_str(uint8_t status)
+const char *mesh_prov_status_str(uint8_t status)
 {
 	switch (status) {
 	case PROV_ERR_SUCCESS:
@@ -301,7 +301,7 @@ static void send_join_failed(const char *owner, const char *path,
 						MESH_APPLICATION_INTERFACE,
 						"JoinFailed");
 
-	l_dbus_message_set_arguments(msg, "s", prov_status_str(status));
+	l_dbus_message_set_arguments(msg, "s", mesh_prov_status_str(status));
 	l_dbus_send(dbus_get_bus(), msg);
 
 	free_pending_join_call(true);
@@ -316,7 +316,7 @@ static bool prov_complete_cb(void *user_data, uint8_t status,
 	const char *path;
 	const uint8_t *token;
 
-	l_debug("Provisioning complete %s", prov_status_str(status));
+	l_debug("Provisioning complete %s", mesh_prov_status_str(status));
 
 	if (!join_pending)
 		return false;
@@ -342,7 +342,7 @@ static bool prov_complete_cb(void *user_data, uint8_t status,
 
 	l_dbus_message_set_arguments(msg, "t", l_get_be64(token));
 
-	l_dbus_send(dbus_get_bus(), msg);
+	l_dbus_send(dbus, msg);
 
 	free_pending_join_call(false);
 
diff --git a/mesh/mesh.h b/mesh/mesh.h
index 14b1fb517..2ef77b57d 100644
--- a/mesh/mesh.h
+++ b/mesh/mesh.h
@@ -42,3 +42,4 @@ bool mesh_send_pkt(uint8_t count, uint16_t interval, uint8_t *data,
 bool mesh_send_cancel(const uint8_t *filter, uint8_t len);
 bool mesh_reg_prov_rx(prov_rx_cb_t cb, void *user_data);
 void mesh_unreg_prov_rx(prov_rx_cb_t cb);
+const char *mesh_prov_status_str(uint8_t status);
-- 
2.14.5


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

* [PATCH BlueZ v2 5/9] mesh: Expose resources needed by Management1 interface
  2019-07-11 22:59 [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Brian Gix
                   ` (3 preceding siblings ...)
  2019-07-11 22:59 ` [PATCH BlueZ v2 4/9] mesh: Expose mapping function for D-Bus errors Brian Gix
@ 2019-07-11 22:59 ` Brian Gix
  2019-07-11 22:59 ` [PATCH BlueZ v2 6/9] mesh: Fix implementation of Provisioner Initiator Brian Gix
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Brian Gix @ 2019-07-11 22:59 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, michal.lowas-rzechonek, brian.gix

---
 mesh/node.c | 42 ++++++++++++++++++++++++++++++++----------
 mesh/node.h |  3 +++
 2 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/mesh/node.c b/mesh/node.c
index 1f781cfe9..27235ef34 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -80,7 +80,8 @@ struct mesh_node {
 	struct l_queue *elements;
 	char *app_path;
 	char *owner;
-	char *path;
+	char *obj_path;
+	struct mesh_agent *agent;
 	void *jconfig;
 	char *node_path;
 	uint32_t disc_watch;
@@ -242,14 +243,14 @@ static void free_node_dbus_resources(struct mesh_node *node)
 	l_free(node->app_path);
 	node->app_path = NULL;
 
-	if (node->path) {
-		l_dbus_object_remove_interface(dbus_get_bus(), node->path,
+	if (node->obj_path) {
+		l_dbus_object_remove_interface(dbus_get_bus(), node->obj_path,
 							MESH_NODE_INTERFACE);
 
-		l_dbus_object_remove_interface(dbus_get_bus(), node->path,
+		l_dbus_object_remove_interface(dbus_get_bus(), node->obj_path,
 						MESH_MANAGEMENT_INTERFACE);
-		l_free(node->path);
-		node->path = NULL;
+		l_free(node->obj_path);
+		node->obj_path = NULL;
 	}
 }
 
@@ -441,6 +442,11 @@ void node_cleanup_all(void)
 	l_dbus_unregister_interface(dbus_get_bus(), MESH_MANAGEMENT_INTERFACE);
 }
 
+bool node_is_provisioner(struct mesh_node *node)
+{
+	return node->provisioner;
+}
+
 bool node_is_provisioned(struct mesh_node *node)
 {
 	return (!IS_UNASSIGNED(node->primary));
@@ -1026,14 +1032,14 @@ static bool register_node_object(struct mesh_node *node)
 	if (!hex2str(node->uuid, sizeof(node->uuid), uuid, sizeof(uuid)))
 		return false;
 
-	node->path = l_strdup_printf(BLUEZ_MESH_PATH MESH_NODE_PATH_PREFIX
+	node->obj_path = l_strdup_printf(BLUEZ_MESH_PATH MESH_NODE_PATH_PREFIX
 								"%s", uuid);
 
-	if (!l_dbus_object_add_interface(dbus_get_bus(), node->path,
+	if (!l_dbus_object_add_interface(dbus_get_bus(), node->obj_path,
 						MESH_NODE_INTERFACE, node))
 		return false;
 
-	if (!l_dbus_object_add_interface(dbus_get_bus(), node->path,
+	if (!l_dbus_object_add_interface(dbus_get_bus(), node->obj_path,
 					MESH_MANAGEMENT_INTERFACE, node))
 		return false;
 
@@ -1509,6 +1515,9 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)
 								&properties);
 				if (!agent)
 					goto fail;
+
+				node->agent = agent;
+
 			} else if (!strcmp(MESH_PROVISIONER_INTERFACE,
 								interface)) {
 				node->provisioner = true;
@@ -1736,7 +1745,7 @@ void node_build_attach_reply(struct mesh_node *node,
 	builder = l_dbus_message_builder_new(reply);
 
 	/* Node object path */
-	l_dbus_message_builder_append_basic(builder, 'o', node->path);
+	l_dbus_message_builder_append_basic(builder, 'o', node->obj_path);
 
 	/* Array of element configurations "a*/
 	l_dbus_message_builder_enter_array(builder, "(ya(qa{sv}))");
@@ -2007,7 +2016,20 @@ char *node_path_get(struct mesh_node *node)
 	return node->node_path;
 }
 
+const char *node_get_app_path(struct mesh_node *node)
+{
+	if (!node)
+		return NULL;
+
+	return node->app_path;
+}
+
 struct mesh_net *node_get_net(struct mesh_node *node)
 {
 	return node->net;
 }
+
+struct mesh_agent *node_get_agent(struct mesh_node *node)
+{
+	return node->agent;
+}
diff --git a/mesh/node.h b/mesh/node.h
index 142527b30..d69887ed1 100644
--- a/mesh/node.h
+++ b/mesh/node.h
@@ -42,6 +42,7 @@ struct mesh_net *node_get_net(struct mesh_node *node);
 struct mesh_node *node_find_by_addr(uint16_t addr);
 struct mesh_node *node_find_by_uuid(uint8_t uuid[16]);
 struct mesh_node *node_find_by_token(uint64_t token);
+bool node_is_provisioner(struct mesh_node *node);
 bool node_is_provisioned(struct mesh_node *node);
 bool node_app_key_delete(struct mesh_net *net, uint16_t addr,
 				uint16_t net_idx, uint16_t idx);
@@ -82,6 +83,7 @@ uint8_t node_friend_mode_get(struct mesh_node *node);
 uint32_t node_seq_cache(struct mesh_node *node);
 const char *node_get_element_path(struct mesh_node *node, uint8_t ele_idx);
 const char *node_get_owner(struct mesh_node *node);
+const char *node_get_app_path(struct mesh_node *node);
 bool node_add_pending_local(struct mesh_node *node, void *info);
 void node_attach_io_all(struct mesh_io *io);
 void node_attach_io(struct mesh_node *node, struct mesh_io *io);
@@ -99,3 +101,4 @@ void node_jconfig_set(struct mesh_node *node, void *jconfig);
 void *node_jconfig_get(struct mesh_node *node);
 void node_path_set(struct mesh_node *node, char *path);
 char *node_path_get(struct mesh_node *node);
+struct mesh_agent *node_get_agent(struct mesh_node *node);
-- 
2.14.5


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

* [PATCH BlueZ v2 6/9] mesh: Fix implementation of Provisioner Initiator
  2019-07-11 22:59 [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Brian Gix
                   ` (4 preceding siblings ...)
  2019-07-11 22:59 ` [PATCH BlueZ v2 5/9] mesh: Expose resources needed by Management1 interface Brian Gix
@ 2019-07-11 22:59 ` Brian Gix
  2019-07-11 22:59 ` [PATCH BlueZ v2 7/9] mesh: Implement DBus Provisioning methods Brian Gix
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Brian Gix @ 2019-07-11 22:59 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, michal.lowas-rzechonek, brian.gix

This has had testing of baseline functionality that includes
OOB authentication type "3c" from BT Mesh v1.0 specification
---
 mesh/prov-initiator.c | 251 +++++++++++++++++++++++++++++++++++++++-----------
 mesh/provision.h      |  10 +-
 2 files changed, 203 insertions(+), 58 deletions(-)

diff --git a/mesh/prov-initiator.c b/mesh/prov-initiator.c
index b1ed96a60..208225f08 100644
--- a/mesh/prov-initiator.c
+++ b/mesh/prov-initiator.c
@@ -29,6 +29,8 @@
 #include "mesh/util.h"
 #include "mesh/crypto.h"
 #include "mesh/net.h"
+#include "mesh/node.h"
+#include "mesh/keyring.h"
 #include "mesh/prov.h"
 #include "mesh/provision.h"
 #include "mesh/pb-adv.h"
@@ -76,14 +78,18 @@ enum int_state {
 
 struct mesh_prov_initiator {
 	mesh_prov_initiator_complete_func_t cmplt;
+	mesh_prov_initiator_data_req_func_t get_prov_data;
 	prov_trans_tx_t trans_tx;
 	void *agent;
 	void *caller_data;
 	void *trans_data;
+	struct mesh_node *node;
 	struct l_timeout *timeout;
 	uint32_t to_secs;
 	enum int_state	state;
 	enum trans_type transport;
+	uint16_t net_idx;
+	uint16_t unicast;
 	uint8_t material;
 	uint8_t expected;
 	int8_t previous;
@@ -102,7 +108,6 @@ static struct mesh_prov_initiator *prov = NULL;
 
 static void initiator_free(void)
 {
-
 	if (prov)
 		l_timeout_remove(prov->timeout);
 
@@ -116,7 +121,34 @@ static void initiator_free(void)
 
 static void int_prov_close(void *user_data, uint8_t reason)
 {
-	/* TODO: Handle Close */
+	struct mesh_prov_initiator *prov = user_data;
+	struct mesh_prov_node_info info;
+
+	if (reason != PROV_ERR_SUCCESS) {
+		prov->cmplt(prov->caller_data, reason, NULL);
+		initiator_free();
+		return;
+	}
+
+	memcpy(info.device_key, prov->calc_key, 16);
+	info.net_index = prov->net_idx;
+	info.unicast = prov->unicast;
+	info.num_ele = prov->conf_inputs.caps.num_ele;
+
+	prov->cmplt(prov->caller_data, PROV_ERR_SUCCESS, &info);
+	initiator_free();
+}
+
+static void swap_u256_bytes(uint8_t *u256)
+{
+	int i;
+
+	/* End-to-End byte reflection of 32 octet buffer */
+	for (i = 0; i < 16; i++) {
+		u256[i] ^= u256[31 - i];
+		u256[31 - i] ^= u256[i];
+		u256[i] ^= u256[31 - i];
+	}
 }
 
 static void int_prov_open(void *user_data, prov_trans_tx_t trans_tx,
@@ -140,6 +172,8 @@ static void int_prov_open(void *user_data, prov_trans_tx_t trans_tx,
 
 	/* Always use an ephemeral key when Initiator */
 	ecc_make_key(prov->conf_inputs.prv_pub_key, prov->private_key);
+	swap_u256_bytes(prov->conf_inputs.prv_pub_key);
+	swap_u256_bytes(prov->conf_inputs.prv_pub_key + 32);
 	prov->material |= MAT_LOCAL_PRIVATE;
 
 	prov->trans_tx = trans_tx;
@@ -152,18 +186,6 @@ static void int_prov_open(void *user_data, prov_trans_tx_t trans_tx,
 	return;
 }
 
-static void swap_u256_bytes(uint8_t *u256)
-{
-	int i;
-
-	/* End-to-End byte reflection of 32 octet buffer */
-	for (i = 0; i < 16; i++) {
-		u256[i] ^= u256[31 - i];
-		u256[31 - i] ^= u256[i];
-		u256[i] ^= u256[31 - i];
-	}
-}
-
 static void prov_calc_secret(const uint8_t *pub, const uint8_t *priv,
 							uint8_t *secret)
 {
@@ -241,7 +263,6 @@ static void calc_local_material(const uint8_t *random)
 
 	print_packet("SessionKey", prov->s_key, sizeof(prov->s_key));
 	print_packet("Nonce", prov->s_nonce, sizeof(prov->s_nonce));
-	print_packet("RandomDevice", prov->rand_auth_workspace, 16);
 }
 
 static void number_cb(void *user_data, int err, uint32_t number)
@@ -307,6 +328,108 @@ static void pub_key_cb(void *user_data, int err, uint8_t *key, uint32_t len)
 			int_credentials(prov);
 }
 
+static void send_pub_key(struct mesh_prov_initiator *prov)
+{
+	uint8_t out[65];
+
+	out[0] = PROV_PUB_KEY;
+	memcpy(out + 1, prov->conf_inputs.prv_pub_key, 64);
+	prov->trans_tx(prov->trans_data, out, 65);
+	prov->state = INT_PROV_KEY_SENT;
+}
+
+static void send_confirm(struct mesh_prov_initiator *prov)
+{
+	uint8_t out[17];
+
+	out[0] = PROV_CONFIRM;
+	mesh_crypto_aes_cmac(prov->calc_key, prov->rand_auth_workspace,
+			32, out + 1);
+	prov->trans_tx(prov->trans_data, out, 17);
+	prov->state = INT_PROV_CONF_SENT;
+	prov->expected = PROV_CONFIRM;
+}
+
+static void send_random(struct mesh_prov_initiator *prov)
+{
+	uint8_t out[17];
+
+	out[0] = PROV_RANDOM;
+	memcpy(out + 1, prov->rand_auth_workspace, 16);
+	prov->trans_tx(prov->trans_data, out, 17);
+	prov->state = INT_PROV_RAND_SENT;
+	prov->expected = PROV_RANDOM;
+}
+
+void initiator_prov_data(uint16_t net_idx, uint16_t primary, void *caller_data)
+{
+	struct keyring_net_key key;
+	struct mesh_net *net;
+	uint64_t mic;
+	uint32_t iv_index;
+	uint8_t snb_flags;
+	uint8_t out[34];
+
+	if (!prov || caller_data != prov->caller_data)
+		return;
+
+	if (prov->state != INT_PROV_RAND_ACKED)
+		return;
+
+	net = node_get_net(prov->node);
+	prov->expected = PROV_COMPLETE;
+
+	/* Calculate remote device key */
+	mesh_crypto_device_key(prov->secret,
+			prov->salt,
+			prov->calc_key);
+
+	print_packet("DevKey", prov->calc_key, 16);
+
+	/* Fill Prov Data Structure */
+	if (!keyring_get_net_key(prov->node, net_idx, &key)) {
+		out[1] = PROV_ERR_UNEXPECTED_ERR;
+		goto failure;
+	}
+
+	prov->unicast = primary;
+	prov->net_idx = net_idx;
+	mesh_net_get_snb_state(net, &snb_flags, &iv_index);
+
+	out[0] = PROV_DATA;
+
+	if (key.phase == KEY_REFRESH_PHASE_TWO) {
+		memcpy(out + 1, key.new_key, 16);
+		snb_flags |= PROV_FLAG_KR;
+	} else
+		memcpy(out + 1, key.old_key, 16);
+
+	l_put_be16(net_idx, out + 1 + 16);
+	l_put_u8(snb_flags, out + 1 + 16 + 2);
+	l_put_be32(iv_index, out + 1 + 16 + 2 + 1);
+	l_put_be16(primary, out + 1 + 16 + 2 + 1 + 4);
+
+	print_packet("ProvData", out + 1, 25);
+	/* Encrypt Prov Data */
+	mesh_crypto_aes_ccm_encrypt(prov->s_nonce, prov->s_key,
+			NULL, 0,
+			out + 1,
+			25,
+			out + 1,
+			&mic, sizeof(mic));
+	print_packet("EncData", out + 1, 25 + 8);
+	prov->trans_tx(prov->trans_data, out, 34);
+	prov->state = INT_PROV_DATA_SENT;
+	return;
+
+failure:
+	l_debug("Failing... %d", out[1]);
+	out[0] = PROV_FAILED;
+	prov->trans_tx(prov->trans_data, out, 2);
+	/* TODO: Call Complete Callback (Fail)*/
+}
+
+
 static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 {
 	struct mesh_prov_initiator *rx_prov = user_data;
@@ -314,7 +437,6 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 	uint8_t type = *data++;
 	uint8_t fail_code[2];
 	uint32_t oob_key;
-	uint64_t mic;
 
 	if (rx_prov != prov || !prov->trans_tx)
 		return;
@@ -425,8 +547,7 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 		int_credentials(prov);
 		prov->state = INT_PROV_KEY_ACKED;
 
-		prov->expected = PROV_CONFIRM;
-
+		l_debug("auth_method: %d", prov->conf_inputs.start.auth_method);
 		memset(prov->rand_auth_workspace + 16, 0, 32);
 		switch (prov->conf_inputs.start.auth_method) {
 		default:
@@ -464,7 +585,6 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 
 			break;
 
-
 		case 3:
 			/* Auth Type 3b - input OOB */
 			l_getrandom(&oob_key, sizeof(oob_key));
@@ -492,19 +612,16 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 
 			break;
 
-
 		}
+
+		if (prov->material & MAT_RAND_AUTH)
+			send_confirm(prov);
+
 		break;
 
 	case PROV_INP_CMPLT: /* Provisioning Input Complete */
 		/* TODO: Cancel Agent prompt */
-		prov->expected = PROV_CONFIRM;
-		out = l_malloc(17);
-		out[0] = PROV_CONFIRM;
-		mesh_crypto_aes_cmac(prov->calc_key, prov->rand_auth_workspace,
-								32, out + 1);
-		prov->trans_tx(prov->trans_data, out, 17);
-		l_free(out);
+		send_confirm(prov);
 		break;
 
 	case PROV_CONFIRM: /* Confirmation */
@@ -512,58 +629,46 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 		/* RXed Device Confirmation */
 		memcpy(prov->confirm, data, 16);
 		print_packet("ConfirmationDevice", prov->confirm, 16);
-		prov->expected = PROV_RANDOM;
-		out = l_malloc(17);
-		out[0] = PROV_RANDOM;
-		memcpy(out + 1, prov->rand_auth_workspace, 16);
-		prov->trans_tx(prov->trans_data, out, 17);
-		l_free(out);
+		send_random(prov);
 		break;
 
 	case PROV_RANDOM: /* Random */
 		prov->state = INT_PROV_RAND_ACKED;
 
 		/* RXed Device Confirmation */
+		calc_local_material(data);
 		memcpy(prov->rand_auth_workspace + 16, data, 16);
 		print_packet("RandomDevice", data, 16);
-		calc_local_material(data);
 
 		mesh_crypto_aes_cmac(prov->calc_key,
 						prov->rand_auth_workspace + 16,
 						32, prov->rand_auth_workspace);
 
+		print_packet("Dev-Conf", prov->rand_auth_workspace, 16);
 		if (memcmp(prov->rand_auth_workspace, prov->confirm, 16)) {
-			l_error("Provisioning Failed-Confirm compare)");
+			l_error("Provisioning Failed-Confirm compare");
 			fail_code[1] = PROV_ERR_CONFIRM_FAILED;
 			goto failure;
 		}
 
-		if (prov->state == INT_PROV_RAND_ACKED) {
-			prov->expected = PROV_COMPLETE;
-			out = l_malloc(34);
-			out[0] = PROV_DATA;
-			/* TODO: Fill Prov Data Structure */
-			/* Encrypt Prov Data */
-			mesh_crypto_aes_ccm_encrypt(prov->s_nonce, prov->s_key,
-					NULL, 0,
-					out + 1,
-					25,
-					out + 1,
-					&mic, sizeof(mic));
-			prov->trans_tx(prov->trans_data, out, 34);
-			l_free(out);
+		if (!prov->get_prov_data(prov->caller_data,
+					prov->conf_inputs.caps.num_ele)) {
+			l_error("Provisioning Failed-Data Get");
+			fail_code[1] = PROV_ERR_CANT_ASSIGN_ADDR;
+			goto failure;
 		}
 		break;
 
 	case PROV_COMPLETE: /* Complete */
 		l_info("Provisioning Complete");
 		prov->state = INT_PROV_IDLE;
-		//mesh_prov_close(prov, 0);
+		int_prov_close(prov, PROV_ERR_SUCCESS);
 		break;
 
 	case PROV_FAILED: /* Failed */
 		l_error("Provisioning Failed (reason: %d)", data[0]);
-		//mesh_prov_close(prov, data[0]);
+		prov->state = INT_PROV_IDLE;
+		int_prov_close(prov, data[0]);
 		break;
 
 	default:
@@ -572,20 +677,51 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 		goto failure;
 	}
 
-	prov->previous = type;
+	if (prov)
+		prov->previous = type;
+
 	return;
 
 failure:
+	l_debug("Failing... %d", fail_code[1]);
 	fail_code[0] = PROV_FAILED;
 	prov->trans_tx(prov->trans_data, fail_code, 2);
-	/* TODO: Call Complete Callback (Fail)*/
+	int_prov_close(prov, fail_code[1]);
 }
 
 static void int_prov_ack(void *user_data, uint8_t msg_num)
 {
-	/* TODO: Handle PB-ADV Ack */
-}
+	struct mesh_prov_initiator *rx_prov = user_data;
 
+	if (rx_prov != prov || !prov->trans_tx)
+		return;
+
+	switch (prov->state) {
+	case INT_PROV_START_SENT:
+		prov->state = INT_PROV_START_ACKED;
+		if (prov->conf_inputs.caps.pub_type == 0)
+			send_pub_key(prov);
+		break;
+
+	case INT_PROV_DATA_SENT:
+		prov->state = INT_PROV_DATA_ACKED;
+		break;
+
+	case INT_PROV_IDLE:
+	case INT_PROV_INVITE_SENT:
+	case INT_PROV_INVITE_ACKED:
+	case INT_PROV_START_ACKED:
+	case INT_PROV_KEY_SENT:
+	case INT_PROV_KEY_ACKED:
+	case INT_PROV_CONF_SENT:
+	case INT_PROV_CONF_ACKED:
+	case INT_PROV_RAND_SENT:
+	case INT_PROV_RAND_ACKED:
+	case INT_PROV_DATA_ACKED:
+	default:
+		break;
+	}
+}
 
 bool initiator_start(enum trans_type transport,
 		uint8_t uuid[16],
@@ -593,8 +729,9 @@ bool initiator_start(enum trans_type transport,
 		uint16_t server, /* Only valid for PB-Remote */
 		uint32_t timeout, /* in seconds from mesh.conf */
 		struct mesh_agent *agent,
+		mesh_prov_initiator_data_req_func_t get_prov_data,
 		mesh_prov_initiator_complete_func_t complete_cb,
-		void *caller_data)
+		void *node, void *caller_data)
 {
 	bool result;
 
@@ -607,8 +744,10 @@ bool initiator_start(enum trans_type transport,
 
 	prov = l_new(struct mesh_prov_initiator, 1);
 	prov->to_secs = timeout;
+	prov->node = node;
 	prov->agent = agent;
 	prov->cmplt = complete_cb;
+	prov->get_prov_data = get_prov_data;
 	prov->caller_data = caller_data;
 	prov->previous = -1;
 
diff --git a/mesh/provision.h b/mesh/provision.h
index 6b61a45be..755d848a0 100644
--- a/mesh/provision.h
+++ b/mesh/provision.h
@@ -90,6 +90,7 @@ struct mesh_prov_node_info {
 	uint32_t iv_index;
 	uint16_t unicast;
 	uint16_t net_index;
+	uint8_t num_ele;
 	uint8_t net_key[16];
 	uint8_t device_key[16];
 	uint8_t flags; /* IVU and KR bits */
@@ -99,6 +100,9 @@ typedef bool (*mesh_prov_acceptor_complete_func_t)(void *user_data,
 					uint8_t status,
 					struct mesh_prov_node_info *info);
 
+typedef bool (*mesh_prov_initiator_data_req_func_t)(void *user_data,
+							uint8_t num_elem);
+
 typedef bool (*mesh_prov_initiator_complete_func_t)(void *user_data,
 					uint8_t status,
 					struct mesh_prov_node_info *info);
@@ -117,6 +121,8 @@ bool initiator_start(enum trans_type transport,
 		uint16_t server, /* Only valid for PB-Remote */
 		uint32_t timeout, /* in seconds from mesh.conf */
 		struct mesh_agent *agent,
+		mesh_prov_initiator_data_req_func_t get_prov_data,
 		mesh_prov_initiator_complete_func_t complete_cb,
-		void *caller_data);
-void initiator_cancel(void *user_data);
+		void *node, void *caller_data);
+void initiator_prov_data(uint16_t net_idx, uint16_t primary, void *caller_data);
+void initiator_cancel(void *caller_data);
-- 
2.14.5


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

* [PATCH BlueZ v2 7/9] mesh: Implement DBus Provisioning methods
  2019-07-11 22:59 [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Brian Gix
                   ` (5 preceding siblings ...)
  2019-07-11 22:59 ` [PATCH BlueZ v2 6/9] mesh: Fix implementation of Provisioner Initiator Brian Gix
@ 2019-07-11 22:59 ` Brian Gix
  2019-07-11 22:59 ` [PATCH BlueZ v2 8/9] mesh: Convert provisioning pkts to packed structs Brian Gix
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Brian Gix @ 2019-07-11 22:59 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, michal.lowas-rzechonek, brian.gix

This implements the Interface and Methods for:
UnprovisionedScan()
UnprovisionedScanCancel()
AddNode()
---
 mesh/manager.c | 304 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 296 insertions(+), 8 deletions(-)

diff --git a/mesh/manager.c b/mesh/manager.c
index ca3562512..77d7b7516 100644
--- a/mesh/manager.c
+++ b/mesh/manager.c
@@ -28,19 +28,202 @@
 #include "mesh/dbus.h"
 #include "mesh/error.h"
 #include "mesh/mesh.h"
+#include "mesh/mesh-io.h"
 #include "mesh/node.h"
+#include "mesh/net.h"
 #include "mesh/keyring.h"
+#include "mesh/agent.h"
+#include "mesh/provision.h"
 #include "mesh/manager.h"
 
+struct add_data{
+	struct l_dbus_message *msg;
+	struct mesh_agent *agent;
+	struct mesh_node *node;
+	uint32_t disc_watch;
+	uint16_t primary;
+	uint16_t net_idx;
+	uint8_t num_ele;
+	uint8_t uuid[16];
+};
+
+static int8_t scan_rssi;
+static uint8_t scan_uuid[16];
+static struct mesh_node *scan_node;
+static struct l_timeout *scan_timeout;
+static struct add_data *add_pending;
+
+static void scan_cancel(struct l_timeout *timeout, void *user_data)
+{
+	struct mesh_node *node = user_data;
+	struct mesh_io *io;
+	struct mesh_net *net;
+
+	l_debug("scan_cancel");
+
+	if (scan_timeout)
+		l_timeout_remove(scan_timeout);
+
+	net = node_get_net(node);
+	io = mesh_net_get_io(net);
+	mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_PROV_BEACON);
+	scan_node = NULL;
+	scan_timeout = NULL;
+}
+
+static void free_pending_add_call()
+{
+	if (!add_pending)
+		return;
+
+	if (add_pending->disc_watch)
+		l_dbus_remove_watch(dbus_get_bus(),
+						add_pending->disc_watch);
+
+	mesh_agent_remove(add_pending->agent);
+
+	l_free(add_pending);
+	add_pending = NULL;
+}
+
+static void prov_disc_cb(struct l_dbus *bus, void *user_data)
+{
+	if (!add_pending)
+		return;
+
+	initiator_cancel(add_pending);
+	add_pending->disc_watch = 0;
+
+	free_pending_add_call();
+}
+
+static void send_add_failed(const char *owner, const char *path,
+							uint8_t status)
+{
+	struct l_dbus *dbus = dbus_get_bus();
+	struct l_dbus_message_builder *builder;
+	struct l_dbus_message *msg;
+
+	msg = l_dbus_message_new_method_call(dbus, owner, path,
+						MESH_PROVISIONER_INTERFACE,
+						"AddNodeFailed");
+
+	builder = l_dbus_message_builder_new(msg);
+	dbus_append_byte_array(builder, add_pending->uuid, 16);
+	l_dbus_message_builder_append_basic(builder, 's',
+						mesh_prov_status_str(status));
+	l_dbus_message_builder_finalize(builder);
+	l_dbus_message_builder_destroy(builder);
+	l_dbus_send(dbus, msg);
+
+	free_pending_add_call();
+}
+
+static bool add_cmplt(void *user_data, uint8_t status,
+					struct mesh_prov_node_info *info)
+{
+	struct add_data *pending = user_data;
+	struct mesh_node *node = pending->node;
+	struct l_dbus *dbus = dbus_get_bus();
+	struct l_dbus_message_builder *builder;
+	struct l_dbus_message *msg;
+	bool result;
+
+	if (pending != add_pending)
+		return false;
+
+	if (status != PROV_ERR_SUCCESS) {
+		send_add_failed(node_get_owner(node), node_get_app_path(node),
+									status);
+		return false;
+	}
+
+	result = keyring_put_remote_dev_key(add_pending->node, info->unicast,
+					info->num_ele, info->device_key);
+
+	if (!result) {
+		send_add_failed(node_get_owner(node), node_get_app_path(node),
+						PROV_ERR_CANT_ASSIGN_ADDR);
+		return false;
+	}
+
+	msg = l_dbus_message_new_method_call(dbus, node_get_owner(node),
+						node_get_app_path(node),
+						MESH_PROVISIONER_INTERFACE,
+						"AddNodeComplete");
+
+	builder = l_dbus_message_builder_new(msg);
+	dbus_append_byte_array(builder, add_pending->uuid, 16);
+	l_dbus_message_builder_append_basic(builder, 'q', &info->unicast);
+	l_dbus_message_builder_append_basic(builder, 'y', &info->num_ele);
+	l_dbus_message_builder_finalize(builder);
+	l_dbus_message_builder_destroy(builder);
+
+	l_dbus_send(dbus, msg);
+
+	free_pending_add_call();
+
+	return true;
+}
+
+static void mgr_prov_data (struct l_dbus_message *reply, void *user_data)
+{
+	struct add_data *pending = user_data;
+	uint16_t net_idx;
+	uint16_t primary;
+
+	if (pending != add_pending)
+		return;
+
+	if (l_dbus_message_is_error(reply))
+		return;
+
+	if (!l_dbus_message_get_arguments(reply, "qq", &net_idx, &primary))
+		return;
+
+	add_pending->primary = primary;
+	add_pending->net_idx = net_idx;
+	initiator_prov_data(net_idx, primary, add_pending);
+}
+
+static bool add_data_get(void *user_data, uint8_t num_ele)
+{
+	struct add_data *pending = user_data;
+	struct l_dbus_message *msg;
+	struct l_dbus *dbus;
+	const char *app_path;
+	const char *sender;
+
+	if (pending != add_pending)
+		return false;
+
+	dbus = dbus_get_bus();
+	app_path = node_get_app_path(add_pending->node);
+	sender = node_get_owner(add_pending->node);
+
+	msg = l_dbus_message_new_method_call(dbus, sender, app_path,
+						MESH_PROVISIONER_INTERFACE,
+						"RequestProvData");
+
+	l_dbus_message_set_arguments(msg, "y", num_ele);
+	l_dbus_send_with_reply(dbus, msg, mgr_prov_data, add_pending, NULL);
+
+	add_pending->num_ele = num_ele;
+
+	return true;
+}
+
 static struct l_dbus_message *add_node_call(struct l_dbus *dbus,
 						struct l_dbus_message *msg,
 						void *user_data)
 {
+	struct mesh_node *node = user_data;
 	struct l_dbus_message_iter iter_uuid;
+	struct l_dbus_message *reply;
 	uint8_t *uuid;
 	uint32_t n;
 
-	l_debug("Add node request");
+	l_debug("AddNode request");
 
 	if (!l_dbus_message_get_arguments(msg, "ay", &iter_uuid))
 		return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
@@ -50,8 +233,47 @@ static struct l_dbus_message *add_node_call(struct l_dbus *dbus,
 		return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
 							"Bad device UUID");
 
-	/* TODO */
-	return dbus_error(msg, MESH_ERROR_NOT_IMPLEMENTED, NULL);
+	/* Allow AddNode to cancel Scanning if from the same node */
+	if (scan_node) {
+		if (scan_node != node)
+			return dbus_error(msg, MESH_ERROR_BUSY, NULL);
+
+		scan_cancel(NULL, node);
+	}
+
+	/* Invoke Prov Initiator */
+
+	add_pending = l_new(struct add_data, 1);
+	memcpy(add_pending->uuid, uuid, 16);
+	add_pending->node = node;
+	add_pending->agent = node_get_agent(node);;
+
+	if (!node_is_provisioner(node) || (add_pending->agent == NULL)) {
+		l_info("Provisioner: %d", node_is_provisioner(node));
+		l_info("Agent: %p", add_pending->agent);
+		reply = dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED,
+							"Missing Interfaces");
+		goto fail;
+	}
+
+
+	if (!initiator_start(PB_ADV, uuid, 99, 0, 60, add_pending->agent,
+				add_data_get, add_cmplt, node, add_pending)) {
+		reply = dbus_error(msg, MESH_ERROR_FAILED,
+				"Failed to start provisioning initiator");
+		goto fail;
+	}
+
+	add_pending->disc_watch = l_dbus_add_disconnect_watch(dbus,
+						node_get_owner(node),
+						prov_disc_cb, NULL, NULL);
+
+	return l_dbus_message_new_method_return(msg);
+
+fail:
+	l_free(add_pending);
+	add_pending = NULL;
+	return reply;
 }
 
 
@@ -97,25 +319,91 @@ static struct l_dbus_message *delete_node_call(struct l_dbus *dbus,
 	return l_dbus_message_new_method_return(msg);
 }
 
+static void prov_beacon_recv(void *user_data, struct mesh_io_recv_info *info,
+					const uint8_t *data, uint16_t len)
+{
+	struct mesh_node *node = user_data;
+	struct l_dbus_message_builder *builder;
+	struct l_dbus_message *msg;
+	struct l_dbus *dbus;
+	int16_t rssi;
+
+	if (scan_node != node || len < sizeof(scan_uuid) + 2 || data[1] != 0x00)
+		return;
+
+	if (!memcmp(data + 2, scan_uuid, sizeof(scan_uuid))) {
+		if (info->rssi <= scan_rssi)
+			return;
+	}
+
+	memcpy(scan_uuid, data + 2, sizeof(scan_uuid));
+	scan_rssi = info->rssi;
+	rssi = info->rssi;
+
+	dbus = dbus_get_bus();
+	msg = l_dbus_message_new_method_call(dbus, node_get_owner(node),
+						node_get_app_path(node),
+						MESH_PROVISIONER_INTERFACE,
+						"ScanResult");
+
+	builder = l_dbus_message_builder_new(msg);
+	l_dbus_message_builder_append_basic(builder, 'n', &rssi);
+	dbus_append_byte_array(builder, data + 2, len -2);
+	l_dbus_message_builder_finalize(builder);
+	l_dbus_message_builder_destroy(builder);
+
+	l_dbus_send(dbus, msg);
+}
+
 static struct l_dbus_message *start_scan_call(struct l_dbus *dbus,
 						struct l_dbus_message *msg,
 						void *user_data)
 {
+	struct mesh_node *node = user_data;
 	uint16_t duration;
+	struct mesh_io *io;
+	struct mesh_net *net;
 
 	if (!l_dbus_message_get_arguments(msg, "q", &duration))
 		return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
 
-	/* TODO */
-	return dbus_error(msg, MESH_ERROR_NOT_IMPLEMENTED, NULL);
+	if (scan_node && scan_node != node)
+		return dbus_error(msg, MESH_ERROR_BUSY, NULL);
+
+	if (!node_is_provisioner(node))
+		return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL);
+
+	if (scan_timeout)
+		l_timeout_remove(scan_timeout);
+
+	memset(scan_uuid, 0, sizeof(scan_uuid));
+	scan_rssi = -128;
+	scan_timeout = NULL;
+	net = node_get_net(node);
+	io = mesh_net_get_io(net);
+	scan_node = node;
+	mesh_io_register_recv_cb(io, MESH_IO_FILTER_PROV_BEACON,
+						prov_beacon_recv, node);
+
+	if (duration)
+		scan_timeout = l_timeout_create(duration, scan_cancel,
+								node, NULL);
+
+	return l_dbus_message_new_method_return(msg);
 }
 
 static struct l_dbus_message *cancel_scan_call(struct l_dbus *dbus,
 						struct l_dbus_message *msg,
 						void *user_data)
 {
-	/* TODO */
-	return dbus_error(msg, MESH_ERROR_NOT_IMPLEMENTED, NULL);
+	struct mesh_node *node = user_data;
+
+	if (scan_node != node)
+		return dbus_error(msg, MESH_ERROR_BUSY, NULL);
+
+	scan_cancel(NULL, node);
+
+	return l_dbus_message_new_method_return(msg);
 }
 
 static struct l_dbus_message *store_new_subnet(struct mesh_node *node,
@@ -416,7 +704,7 @@ static struct l_dbus_message *set_key_phase_call(struct l_dbus *dbus,
 static void setup_management_interface(struct l_dbus_interface *iface)
 {
 	l_dbus_interface_method(iface, "AddNode", 0, add_node_call, "", "ay",
-								"", "uuid");
+								"uuid");
 	l_dbus_interface_method(iface, "ImportRemoteNode", 0, import_node_call,
 						"", "qyay", "", "primary",
 						"count", "dev_key");
-- 
2.14.5


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

* [PATCH BlueZ v2 8/9] mesh: Convert provisioning pkts to packed structs
  2019-07-11 22:59 [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Brian Gix
                   ` (6 preceding siblings ...)
  2019-07-11 22:59 ` [PATCH BlueZ v2 7/9] mesh: Implement DBus Provisioning methods Brian Gix
@ 2019-07-11 22:59 ` Brian Gix
  2019-07-11 22:59 ` [PATCH BlueZ v2 9/9] test: This extends the mesh tool to exercise Provisioning methods Brian Gix
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Brian Gix @ 2019-07-11 22:59 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, michal.lowas-rzechonek, brian.gix

Provisioning packets are defined in the specification
as packed big endian structures. Instead of specifying
an octet array, we now use struct matching the spec.
---
 mesh/crypto.c         |   8 +--
 mesh/crypto.h         |   8 +--
 mesh/mesh.c           |   2 +-
 mesh/mesh.h           |   3 +-
 mesh/pb-adv.c         |  79 +++++++++++++++++--------
 mesh/prov-acceptor.c  | 156 +++++++++++++++++++++++++++-----------------------
 mesh/prov-initiator.c |  94 +++++++++++++++---------------
 mesh/prov.h           |  51 ++++++++++++++++-
 8 files changed, 247 insertions(+), 154 deletions(-)

diff --git a/mesh/crypto.c b/mesh/crypto.c
index 3fa0df246..a4679d88e 100644
--- a/mesh/crypto.c
+++ b/mesh/crypto.c
@@ -102,8 +102,8 @@ bool mesh_crypto_aes_cmac(const uint8_t key[16], const uint8_t *msg,
 
 bool mesh_crypto_aes_ccm_encrypt(const uint8_t nonce[13], const uint8_t key[16],
 					const uint8_t *aad, uint16_t aad_len,
-					const uint8_t *msg, uint16_t msg_len,
-					uint8_t *out_msg,
+					const void *msg, uint16_t msg_len,
+					void *out_msg,
 					void *out_mic, size_t mic_size)
 {
 	void *cipher;
@@ -128,8 +128,8 @@ bool mesh_crypto_aes_ccm_encrypt(const uint8_t nonce[13], const uint8_t key[16],
 
 bool mesh_crypto_aes_ccm_decrypt(const uint8_t nonce[13], const uint8_t key[16],
 				const uint8_t *aad, uint16_t aad_len,
-				const uint8_t *enc_msg, uint16_t enc_msg_len,
-				uint8_t *out_msg,
+				const void *enc_msg, uint16_t enc_msg_len,
+				void *out_msg,
 				void *out_mic, size_t mic_size)
 {
 	void *cipher;
diff --git a/mesh/crypto.h b/mesh/crypto.h
index ffd312231..3e6815a35 100644
--- a/mesh/crypto.h
+++ b/mesh/crypto.h
@@ -22,13 +22,13 @@
 
 bool mesh_crypto_aes_ccm_encrypt(const uint8_t nonce[13], const uint8_t key[16],
 					const uint8_t *aad, uint16_t aad_len,
-					const uint8_t *msg, uint16_t msg_len,
-					uint8_t *out_msg,
+					const void *msg, uint16_t msg_len,
+					void *out_msg,
 					void *out_mic, size_t mic_size);
 bool mesh_crypto_aes_ccm_decrypt(const uint8_t nonce[13], const uint8_t key[16],
 				const uint8_t *aad, uint16_t aad_len,
-				const uint8_t *enc_msg, uint16_t enc_msg_len,
-				uint8_t *out_msg,
+				const void *enc_msg, uint16_t enc_msg_len,
+				void *out_msg,
 				void *out_mic, size_t mic_size);
 bool mesh_aes_ecb_one(const uint8_t key[16],
 			const uint8_t plaintext[16], uint8_t encrypted[16]);
diff --git a/mesh/mesh.c b/mesh/mesh.c
index 62c80c0f3..b9e3162eb 100644
--- a/mesh/mesh.c
+++ b/mesh/mesh.c
@@ -86,7 +86,7 @@ static bool simple_match(const void *a, const void *b)
 /* Used for any outbound traffic that doesn't have Friendship Constraints */
 /* This includes Beacons, Provisioning and unrestricted Network Traffic */
 bool mesh_send_pkt(uint8_t count, uint16_t interval,
-					uint8_t *data, uint16_t len)
+					void *data, uint16_t len)
 {
 	struct mesh_io_send_info info = {
 		.type = MESH_IO_TIMING_TYPE_GENERAL,
diff --git a/mesh/mesh.h b/mesh/mesh.h
index 2ef77b57d..78d4d4926 100644
--- a/mesh/mesh.h
+++ b/mesh/mesh.h
@@ -37,8 +37,7 @@ void mesh_cleanup(void);
 bool mesh_dbus_init(struct l_dbus *dbus);
 
 const char *mesh_status_str(uint8_t err);
-bool mesh_send_pkt(uint8_t count, uint16_t interval, uint8_t *data,
-								uint16_t len);
+bool mesh_send_pkt(uint8_t count, uint16_t interval, void *data, uint16_t len);
 bool mesh_send_cancel(const uint8_t *filter, uint8_t len);
 bool mesh_reg_prov_rx(prov_rx_cb_t cb, void *user_data);
 void mesh_unreg_prov_rx(prov_rx_cb_t cb);
diff --git a/mesh/pb-adv.c b/mesh/pb-adv.c
index 4d85ee72e..6b4a70052 100644
--- a/mesh/pb-adv.c
+++ b/mesh/pb-adv.c
@@ -63,6 +63,36 @@ struct pb_adv_session {
 
 #define PB_ADV_MTU	24
 
+struct pb_ack {
+	uint8_t ad_type;
+	uint32_t link_id;
+	uint8_t trans_num;
+	uint8_t opcode;
+} __packed;
+
+struct pb_open_req{
+	uint8_t ad_type;
+	uint32_t link_id;
+	uint8_t trans_num;
+	uint8_t opcode;
+	uint8_t uuid[16];
+} __packed;
+
+struct pb_open_cfm{
+	uint8_t ad_type;
+	uint32_t link_id;
+	uint8_t trans_num;
+	uint8_t opcode;
+} __packed;
+
+struct pb_close_ind {
+	uint8_t ad_type;
+	uint32_t link_id;
+	uint8_t trans_num;
+	uint8_t opcode;
+	uint8_t reason;
+} __packed;
+
 static struct pb_adv_session *pb_session = NULL;
 
 static const uint8_t filter[1] = { MESH_AD_TYPE_PROVISION };
@@ -150,7 +180,7 @@ static void tx_timeout(struct l_timeout *timeout, void *user_data)
 	cb(user_data, 1);
 }
 
-static void pb_adv_tx(void *user_data, uint8_t *data, uint16_t len)
+static void pb_adv_tx(void *user_data, void *data, uint16_t len)
 {
 	struct pb_adv_session *session = user_data;
 
@@ -165,55 +195,56 @@ static void pb_adv_tx(void *user_data, uint8_t *data, uint16_t len)
 
 static void send_open_req(struct pb_adv_session *session)
 {
-	uint8_t open_req[23] = { MESH_AD_TYPE_PROVISION };
+	struct pb_open_req open_req = { MESH_AD_TYPE_PROVISION };
 
-	l_put_be32(session->link_id, open_req + 1);
-	open_req[1 + 4] = 0;
-	open_req[1 + 4 + 1] = PB_ADV_OPEN_REQ;
-	memcpy(open_req + 7, session->uuid, 16);
+	l_put_be32(session->link_id, &open_req.link_id);
+	open_req.trans_num = 0;
+	open_req.opcode = PB_ADV_OPEN_REQ;
+	memcpy(open_req.uuid, session->uuid, 16);
 
 	mesh_send_cancel(filter, sizeof(filter));
-	mesh_send_pkt(MESH_IO_TX_COUNT_UNLIMITED, 500, open_req,
-						sizeof(open_req));
+	mesh_send_pkt(MESH_IO_TX_COUNT_UNLIMITED, 500, &open_req,
+							sizeof(open_req));
 }
 
 static void send_open_cfm(struct pb_adv_session *session)
 {
-	uint8_t open_cfm[7] = { MESH_AD_TYPE_PROVISION };
+	struct pb_open_cfm open_cfm = { MESH_AD_TYPE_PROVISION };
 
-	l_put_be32(session->link_id, open_cfm + 1);
-	open_cfm[1 + 4] = 0;
-	open_cfm[1 + 4 + 1] = PB_ADV_OPEN_CFM; /* OPEN_CFM */
+	l_put_be32(session->link_id, &open_cfm.link_id);
+	open_cfm.trans_num = 0;
+	open_cfm.opcode = PB_ADV_OPEN_CFM;
 
 	mesh_send_cancel(filter, sizeof(filter));
-	mesh_send_pkt(5, 100, open_cfm, sizeof(open_cfm));
+	mesh_send_pkt(MESH_IO_TX_COUNT_UNLIMITED, 500, &open_cfm,
+							sizeof(open_cfm));
 }
 
 static void send_ack(struct pb_adv_session *session, uint8_t trans_num)
 {
-	uint8_t ack[7] = { MESH_AD_TYPE_PROVISION };
+	struct pb_ack ack = { MESH_AD_TYPE_PROVISION };
 
-	l_put_be32(session->link_id, ack + 1);
-	ack[1 + 4] = trans_num;
-	ack[1 + 4 + 1] = PB_ADV_ACK;
+	l_put_be32(session->link_id, &ack.link_id);
+	ack.trans_num = trans_num;
+	ack.opcode = PB_ADV_ACK;
 
-	mesh_send_pkt(1, 100, ack, sizeof(ack));
+	mesh_send_pkt(1, 100, &ack, sizeof(ack));
 }
 
 static void send_close_ind(struct pb_adv_session *session, uint8_t reason)
 {
-	uint8_t close_ind[8] = { MESH_AD_TYPE_PROVISION };
+	struct pb_close_ind close_ind = { MESH_AD_TYPE_PROVISION };
 
 	if (!pb_session || pb_session != session)
 		return;
 
-	l_put_be32(session->link_id, close_ind + 1);
-	close_ind[5] = 0;
-	close_ind[6] = PB_ADV_CLOSE;
-	close_ind[7] = reason;
+	l_put_be32(session->link_id, &close_ind.link_id);
+	close_ind.trans_num = 0;
+	close_ind.opcode = PB_ADV_CLOSE;
+	close_ind.reason = reason;
 
 	mesh_send_cancel(filter, sizeof(filter));
-	mesh_send_pkt(10, 100, close_ind, sizeof(close_ind));
+	mesh_send_pkt(10, 100, &close_ind, sizeof(close_ind));
 }
 
 static void pb_adv_packet(void *user_data, const uint8_t *pkt, uint16_t len)
diff --git a/mesh/prov-acceptor.c b/mesh/prov-acceptor.c
index 111340db3..57eb1e750 100644
--- a/mesh/prov-acceptor.c
+++ b/mesh/prov-acceptor.c
@@ -232,15 +232,15 @@ static uint32_t digit_mod(uint8_t power)
 static void number_cb(void *user_data, int err, uint32_t number)
 {
 	struct mesh_prov_acceptor *rx_prov = user_data;
-	uint8_t out[2];
+	struct prov_fail_msg msg;
 
 	if (prov != rx_prov)
 		return;
 
 	if (err) {
-		out[0] = PROV_FAILED;
-		out[1] = PROV_ERR_UNEXPECTED_ERR;
-		prov->trans_tx(prov->trans_data, out, 2);
+		msg.opcode = PROV_FAILED;
+		msg.reason = PROV_ERR_UNEXPECTED_ERR;
+		prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
 		return;
 	}
 
@@ -248,22 +248,22 @@ static void number_cb(void *user_data, int err, uint32_t number)
 	l_put_be32(number, prov->rand_auth_workspace + 28);
 	l_put_be32(number, prov->rand_auth_workspace + 44);
 	prov->material |= MAT_RAND_AUTH;
-	out[0] = PROV_INP_CMPLT;
-	prov->trans_tx(prov->trans_data, out, 1);
+	msg.opcode = PROV_INP_CMPLT;
+	prov->trans_tx(prov->trans_data, &msg.opcode, 1);
 }
 
 static void static_cb(void *user_data, int err, uint8_t *key, uint32_t len)
 {
 	struct mesh_prov_acceptor *rx_prov = user_data;
-	uint8_t out[2];
+	struct prov_fail_msg msg;
 
 	if (prov != rx_prov)
 		return;
 
 	if (err || !key || len != 16) {
-		out[0] = PROV_FAILED;
-		out[1] = PROV_ERR_UNEXPECTED_ERR;
-		prov->trans_tx(prov->trans_data, out, 2);
+		msg.opcode = PROV_FAILED;
+		msg.reason = PROV_ERR_UNEXPECTED_ERR;
+		prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
 		return;
 	}
 
@@ -276,15 +276,15 @@ static void static_cb(void *user_data, int err, uint8_t *key, uint32_t len)
 static void priv_key_cb(void *user_data, int err, uint8_t *key, uint32_t len)
 {
 	struct mesh_prov_acceptor *rx_prov = user_data;
-	uint8_t out[2];
+	struct prov_fail_msg msg;
 
 	if (prov != rx_prov)
 		return;
 
 	if (err || !key || len != 32) {
-		out[0] = PROV_FAILED;
-		out[1] = PROV_ERR_UNEXPECTED_ERR;
-		prov->trans_tx(prov->trans_data, out, 2);
+		msg.opcode = PROV_FAILED;
+		msg.reason = PROV_ERR_UNEXPECTED_ERR;
+		prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
 		return;
 	}
 
@@ -301,13 +301,53 @@ static void priv_key_cb(void *user_data, int err, uint8_t *key, uint32_t len)
 		acp_credentials(prov);
 }
 
+static void send_caps(struct mesh_prov_acceptor *prov)
+{
+	struct prov_caps_msg msg;
+
+	msg.opcode = PROV_CAPS;
+	memcpy(&msg.caps, &prov->conf_inputs.caps,
+			sizeof(prov->conf_inputs.caps));
+
+	prov->state = ACP_PROV_CAPS_SENT;
+	prov->expected = PROV_START;
+	prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
+}
+
+static void send_pub_key(struct mesh_prov_acceptor *prov)
+{
+	struct prov_pub_key_msg msg;
+
+	msg.opcode = PROV_PUB_KEY;
+	memcpy(msg.pub_key, prov->conf_inputs.dev_pub_key, sizeof(msg.pub_key));
+	prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
+}
+
+static void send_conf(struct mesh_prov_acceptor *prov)
+{
+	struct prov_conf_msg msg;
+
+	msg.opcode = PROV_CONFIRM;
+	mesh_crypto_aes_cmac(prov->calc_key, prov->rand_auth_workspace, 32,
+								msg.conf);
+	prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
+}
+
+static void send_rand(struct mesh_prov_acceptor *prov)
+{
+	struct prov_rand_msg msg;
+
+	msg.opcode = PROV_RANDOM;
+	memcpy(msg.rand, prov->rand_auth_workspace, sizeof(msg.rand));
+	prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
+}
+
 static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 {
 	struct mesh_prov_acceptor *rx_prov = user_data;
 	struct mesh_prov_node_info *info;
-	uint8_t *out;
+	struct prov_fail_msg fail;
 	uint8_t type = *data++;
-	uint8_t fail_code[2];
 	uint32_t oob_key;
 	uint64_t decode_mic;
 	bool result;
@@ -323,7 +363,7 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 		return;
 	} else if (type > prov->expected || type < prov->previous) {
 		l_error("Expected %2.2x, Got:%2.2x", prov->expected, type);
-		fail_code[1] = PROV_ERR_UNEXPECTED_PDU;
+		fail.reason = PROV_ERR_UNEXPECTED_PDU;
 		goto failure;
 	}
 
@@ -331,25 +371,14 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 					len != expected_pdu_size[type]) {
 		l_error("Expected PDU size %d, Got %d (type: %2.2x)",
 			len, expected_pdu_size[type], type);
-		fail_code[1] = PROV_ERR_INVALID_FORMAT;
+		fail.reason = PROV_ERR_INVALID_FORMAT;
 		goto failure;
 	}
 
 	switch (type){
 	case PROV_INVITE: /* Prov Invite */
-		/* Prov Capabilities */
-		out = l_malloc(1 + sizeof(struct mesh_net_prov_caps));
-		out[0] = PROV_CAPS;
-		memcpy(out + 1, &prov->conf_inputs.caps,
-					sizeof(prov->conf_inputs.caps));
-
 		prov->conf_inputs.invite.attention = data[0];
-
-		prov->state = ACP_PROV_CAPS_SENT;
-		prov->expected = PROV_START;
-		prov->trans_tx(prov->trans_data,
-				out, sizeof(prov->conf_inputs.caps) + 1);
-		l_free(out);
+		send_caps(prov);
 		break;
 
 	case PROV_START: /* Prov Start */
@@ -359,7 +388,7 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 		if (prov->conf_inputs.start.algorithm ||
 				prov->conf_inputs.start.pub_key > 1 ||
 				prov->conf_inputs.start.auth_method > 3) {
-			fail_code[1] = PROV_ERR_INVALID_FORMAT;
+			fail.reason = PROV_ERR_INVALID_FORMAT;
 			goto failure;
 		}
 
@@ -369,7 +398,7 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 				mesh_agent_request_private_key(prov->agent,
 							priv_key_cb, prov);
 			} else {
-				fail_code[1] = PROV_ERR_INVALID_PDU;
+				fail.reason = PROV_ERR_INVALID_PDU;
 				goto failure;
 			}
 		} else {
@@ -395,13 +424,8 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 
 		acp_credentials(prov);
 
-		if (!prov->conf_inputs.start.pub_key) {
-			out = l_malloc(65);
-			out[0] = PROV_PUB_KEY;
-			memcpy(out + 1, prov->conf_inputs.dev_pub_key, 64);
-			prov->trans_tx(prov->trans_data, out, 65);
-			l_free(out);
-		}
+		if (!prov->conf_inputs.start.pub_key)
+			send_pub_key(prov);
 
 		/* Start Step 3 */
 		switch (prov->conf_inputs.start.auth_method) {
@@ -413,10 +437,10 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 		case 1:
 			/* Auth Type 3c - Static OOB */
 			/* Prompt Agent for Static OOB */
-			fail_code[1] = mesh_agent_request_static(prov->agent,
+			fail.reason = mesh_agent_request_static(prov->agent,
 					static_cb, prov);
 
-			if (fail_code[1])
+			if (fail.reason)
 				goto failure;
 
 			break;
@@ -434,17 +458,17 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 			if (prov->conf_inputs.start.auth_action ==
 							PROV_ACTION_OUT_ALPHA) {
 				/* TODO: Construst NUL-term string to pass */
-				fail_code[1] = mesh_agent_display_string(
+				fail.reason = mesh_agent_display_string(
 					prov->agent, NULL, NULL, prov);
 			} else {
 				/* Ask Agent to Display U32 */
-				fail_code[1] = mesh_agent_display_number(
+				fail.reason = mesh_agent_display_number(
 					prov->agent, false,
 					prov->conf_inputs.start.auth_action,
 					oob_key, NULL, prov);
 			}
 
-			if (fail_code[1])
+			if (fail.reason)
 				goto failure;
 
 			break;
@@ -454,17 +478,17 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 			/* Prompt Agent for Input OOB */
 			if (prov->conf_inputs.start.auth_action ==
 							PROV_ACTION_IN_ALPHA) {
-				fail_code[1] = mesh_agent_prompt_alpha(
+				fail.reason = mesh_agent_prompt_alpha(
 					prov->agent,
 					static_cb, prov);
 			} else {
-				fail_code[1] = mesh_agent_prompt_number(
+				fail.reason = mesh_agent_prompt_number(
 					prov->agent, false,
 					prov->conf_inputs.start.auth_action,
 					number_cb, prov);
 			}
 
-			if (fail_code[1])
+			if (fail.reason)
 				goto failure;
 
 			break;
@@ -474,22 +498,14 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 		break;
 
 	case PROV_CONFIRM: /* Confirmation */
-		out = l_malloc(17);
-		out[0] = PROV_CONFIRM;
-
-		/* Calculate and Send our Confirmation */
-		mesh_crypto_aes_cmac(prov->calc_key, prov->rand_auth_workspace,
-								32, out + 1);
-		prov->trans_tx(prov->trans_data, out, 17);
-		l_free(out);
-
 		/* Save Provisioners confirmation for later compare */
 		memcpy(prov->confirm, data, 16);
 		prov->expected = PROV_RANDOM;
+
+		send_conf(prov);
 		break;
 
 	case PROV_RANDOM: /* Random Value */
-		out = l_malloc(17);
 		/* Calculate Session key (needed later) while data is fresh */
 		mesh_crypto_prov_prov_salt(prov->salt, data,
 						prov->rand_auth_workspace,
@@ -500,20 +516,17 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 		/* Calculate expected Provisioner Confirm */
 		memcpy(prov->rand_auth_workspace + 16, data, 16);
 		mesh_crypto_aes_cmac(prov->calc_key,
-				prov->rand_auth_workspace + 16, 32, out);
+					prov->rand_auth_workspace + 16, 32,
+					prov->calc_key);
 
 		/* Compare our calculation with Provisioners */
-		if (memcmp(out, prov->confirm, 16)) {
-			fail_code[1] = PROV_ERR_CONFIRM_FAILED;
-			l_free(out);
+		if (memcmp(prov->calc_key, prov->confirm, 16)) {
+			fail.reason = PROV_ERR_CONFIRM_FAILED;
 			goto failure;
 		}
 
 		/* Send Random value we used */
-		out[0] = PROV_RANDOM;
-		memcpy(out + 1, prov->rand_auth_workspace, 16);
-		prov->trans_tx(prov->trans_data, out, 17);
-		l_free(out);
+		send_rand(prov);
 		prov->expected = PROV_DATA;
 		break;
 
@@ -533,7 +546,7 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 		/* Validate that the data hasn't been messed with in transit */
 		if (l_get_be64(data + 25) != decode_mic) {
 			l_error("Provisioning Failed-MIC compare");
-			fail_code[1] = PROV_ERR_DECRYPT_FAILED;
+			fail.reason = PROV_ERR_DECRYPT_FAILED;
 			goto failure;
 		}
 
@@ -556,7 +569,7 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 					prov->rand_auth_workspace, 1);
 			goto cleanup;
 		} else {
-			fail_code[1] = PROV_ERR_UNEXPECTED_ERR;
+			fail.reason = PROV_ERR_UNEXPECTED_ERR;
 			goto failure;
 		}
 		break;
@@ -570,14 +583,15 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
 		goto cleanup;
 	}
 
-	prov->previous = type;
+	if (prov)
+		prov->previous = type;
 	return;
 
 failure:
-	fail_code[0] = PROV_FAILED;
-	prov->trans_tx(prov->trans_data, fail_code, 2);
+	fail.opcode = PROV_FAILED;
+	prov->trans_tx(prov->trans_data, &fail, sizeof(fail));
 	if (prov->cmplt)
-		prov->cmplt(prov->caller_data, fail_code[1], NULL);
+		prov->cmplt(prov->caller_data, fail.reason, NULL);
 	prov->cmplt = NULL;
 
 cleanup:
diff --git a/mesh/prov-initiator.c b/mesh/prov-initiator.c
index 208225f08..eb59f53f1 100644
--- a/mesh/prov-initiator.c
+++ b/mesh/prov-initiator.c
@@ -155,7 +155,7 @@ static void int_prov_open(void *user_data, prov_trans_tx_t trans_tx,
 				void *trans_data, uint8_t transport)
 {
 	struct mesh_prov_initiator *rx_prov = user_data;
-	uint8_t invite[] = { PROV_INVITE, 30 };
+	struct prov_invite_msg msg = { PROV_INVITE, { 30 }};
 
 	/* Only one provisioning session may be open at a time */
 	if (rx_prov != prov)
@@ -181,8 +181,8 @@ static void int_prov_open(void *user_data, prov_trans_tx_t trans_tx,
 	prov->state = INT_PROV_INVITE_SENT;
 	prov->expected = PROV_CAPS;
 
-	prov->conf_inputs.invite.attention = invite[1];
-	prov->trans_tx(prov->trans_data, invite, sizeof(invite));
+	prov->conf_inputs.invite.attention = msg.invite.attention;
+	prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
 	return;
 }
 
@@ -268,15 +268,15 @@ static void calc_local_material(const uint8_t *random)
 static void number_cb(void *user_data, int err, uint32_t number)
 {
 	struct mesh_prov_initiator *rx_prov = user_data;
-	uint8_t out[2];
+	struct prov_fail_msg msg;
 
 	if (prov != rx_prov)
 		return;
 
 	if (err) {
-		out[0] = PROV_FAILED;
-		out[1] = PROV_ERR_UNEXPECTED_ERR;
-		prov->trans_tx(prov->trans_data, out, 2);
+		msg.opcode = PROV_FAILED;
+		msg.reason = PROV_ERR_UNEXPECTED_ERR;
+		prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
 		return;
 	}
 
@@ -289,15 +289,15 @@ static void number_cb(void *user_data, int err, uint32_t number)
 static void static_cb(void *user_data, int err, uint8_t *key, uint32_t len)
 {
 	struct mesh_prov_initiator *rx_prov = user_data;
-	uint8_t out[2];
+	struct prov_fail_msg msg;
 
 	if (prov != rx_prov)
 		return;
 
 	if (err || !key || len != 16) {
-		out[0] = PROV_FAILED;
-		out[1] = PROV_ERR_UNEXPECTED_ERR;
-		prov->trans_tx(prov->trans_data, out, 2);
+		msg.opcode = PROV_FAILED;
+		msg.reason = PROV_ERR_UNEXPECTED_ERR;
+		prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
 		return;
 	}
 
@@ -309,15 +309,15 @@ static void static_cb(void *user_data, int err, uint8_t *key, uint32_t len)
 static void pub_key_cb(void *user_data, int err, uint8_t *key, uint32_t len)
 {
 	struct mesh_prov_initiator *rx_prov = user_data;
-	uint8_t out[2];
+	struct prov_fail_msg msg;
 
 	if (prov != rx_prov)
 		return;
 
 	if (err || !key || len != 64) {
-		out[0] = PROV_FAILED;
-		out[1] = PROV_ERR_UNEXPECTED_ERR;
-		prov->trans_tx(prov->trans_data, out, 2);
+		msg.opcode = PROV_FAILED;
+		msg.reason = PROV_ERR_UNEXPECTED_ERR;
+		prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
 		return;
 	}
 
@@ -330,45 +330,45 @@ static void pub_key_cb(void *user_data, int err, uint8_t *key, uint32_t len)
 
 static void send_pub_key(struct mesh_prov_initiator *prov)
 {
-	uint8_t out[65];
+	struct prov_pub_key_msg msg;
 
-	out[0] = PROV_PUB_KEY;
-	memcpy(out + 1, prov->conf_inputs.prv_pub_key, 64);
-	prov->trans_tx(prov->trans_data, out, 65);
+	msg.opcode = PROV_PUB_KEY;
+	memcpy(msg.pub_key, prov->conf_inputs.prv_pub_key, 64);
+	prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
 	prov->state = INT_PROV_KEY_SENT;
 }
 
 static void send_confirm(struct mesh_prov_initiator *prov)
 {
-	uint8_t out[17];
+	struct prov_conf_msg msg;
 
-	out[0] = PROV_CONFIRM;
+	msg.opcode = PROV_CONFIRM;
 	mesh_crypto_aes_cmac(prov->calc_key, prov->rand_auth_workspace,
-			32, out + 1);
-	prov->trans_tx(prov->trans_data, out, 17);
+			32, msg.conf);
+	prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
 	prov->state = INT_PROV_CONF_SENT;
 	prov->expected = PROV_CONFIRM;
 }
 
 static void send_random(struct mesh_prov_initiator *prov)
 {
-	uint8_t out[17];
+	struct prov_rand_msg msg;
 
-	out[0] = PROV_RANDOM;
-	memcpy(out + 1, prov->rand_auth_workspace, 16);
-	prov->trans_tx(prov->trans_data, out, 17);
+	msg.opcode = PROV_RANDOM;
+	memcpy(msg.rand, prov->rand_auth_workspace, sizeof(msg.rand));
+	prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
 	prov->state = INT_PROV_RAND_SENT;
 	prov->expected = PROV_RANDOM;
 }
 
 void initiator_prov_data(uint16_t net_idx, uint16_t primary, void *caller_data)
 {
+	struct prov_data_msg prov_data;
+	struct prov_fail_msg prov_fail;
 	struct keyring_net_key key;
 	struct mesh_net *net;
-	uint64_t mic;
 	uint32_t iv_index;
 	uint8_t snb_flags;
-	uint8_t out[34];
 
 	if (!prov || caller_data != prov->caller_data)
 		return;
@@ -388,7 +388,7 @@ void initiator_prov_data(uint16_t net_idx, uint16_t primary, void *caller_data)
 
 	/* Fill Prov Data Structure */
 	if (!keyring_get_net_key(prov->node, net_idx, &key)) {
-		out[1] = PROV_ERR_UNEXPECTED_ERR;
+		prov_fail.reason = PROV_ERR_UNEXPECTED_ERR;
 		goto failure;
 	}
 
@@ -396,36 +396,36 @@ void initiator_prov_data(uint16_t net_idx, uint16_t primary, void *caller_data)
 	prov->net_idx = net_idx;
 	mesh_net_get_snb_state(net, &snb_flags, &iv_index);
 
-	out[0] = PROV_DATA;
+	prov_data.opcode = PROV_DATA;
 
 	if (key.phase == KEY_REFRESH_PHASE_TWO) {
-		memcpy(out + 1, key.new_key, 16);
+		memcpy(&prov_data.data.net_key, key.new_key, 16);
 		snb_flags |= PROV_FLAG_KR;
 	} else
-		memcpy(out + 1, key.old_key, 16);
+		memcpy(&prov_data.data.net_key, key.old_key, 16);
 
-	l_put_be16(net_idx, out + 1 + 16);
-	l_put_u8(snb_flags, out + 1 + 16 + 2);
-	l_put_be32(iv_index, out + 1 + 16 + 2 + 1);
-	l_put_be16(primary, out + 1 + 16 + 2 + 1 + 4);
+	l_put_be16(net_idx, &prov_data.data.net_idx);
+	l_put_u8(snb_flags, &prov_data.data.flags);
+	l_put_be32(iv_index, &prov_data.data.iv_index);
+	l_put_be16(primary, &prov_data.data.primary);
 
-	print_packet("ProvData", out + 1, 25);
+	print_packet("ProvData", &prov_data.data, sizeof(prov_data.data));
 	/* Encrypt Prov Data */
 	mesh_crypto_aes_ccm_encrypt(prov->s_nonce, prov->s_key,
 			NULL, 0,
-			out + 1,
-			25,
-			out + 1,
-			&mic, sizeof(mic));
-	print_packet("EncData", out + 1, 25 + 8);
-	prov->trans_tx(prov->trans_data, out, 34);
+			&prov_data.data,
+			sizeof(prov_data.data),
+			&prov_data.data,
+			NULL, sizeof(prov_data.mic));
+	print_packet("EncdData", &prov_data.data, sizeof(prov_data) - 1);
+	prov->trans_tx(prov->trans_data, &prov_data, sizeof(prov_data));
 	prov->state = INT_PROV_DATA_SENT;
 	return;
 
 failure:
-	l_debug("Failing... %d", out[1]);
-	out[0] = PROV_FAILED;
-	prov->trans_tx(prov->trans_data, out, 2);
+	l_debug("Failing... %d", prov_fail.reason);
+	prov_fail.opcode = PROV_FAILED;
+	prov->trans_tx(prov->trans_data, &prov_fail, sizeof(prov_fail));
 	/* TODO: Call Complete Callback (Fail)*/
 }
 
diff --git a/mesh/prov.h b/mesh/prov.h
index 61ec08e10..11b20b31f 100644
--- a/mesh/prov.h
+++ b/mesh/prov.h
@@ -48,7 +48,7 @@ enum mesh_prov_mode {
 
 struct mesh_prov;
 
-typedef void (*prov_trans_tx_t)(void *trans_data, uint8_t *data, uint16_t len);
+typedef void (*prov_trans_tx_t)(void *trans_data, void *data, uint16_t len);
 typedef void (*mesh_prov_open_func_t)(void *user_data, prov_trans_tx_t trans_tx,
 					void *trans_data, uint8_t trans_type);
 
@@ -63,6 +63,11 @@ struct prov_invite {
 	uint8_t attention;
 } __packed;
 
+struct prov_invite_msg {
+	uint8_t opcode;
+	struct prov_invite invite;
+} __packed;
+
 struct prov_start {
 	uint8_t algorithm;
 	uint8_t pub_key;
@@ -71,6 +76,50 @@ struct prov_start {
 	uint8_t auth_size;
 } __packed;
 
+struct prov_caps_msg {
+	uint8_t opcode;
+	struct mesh_net_prov_caps caps;
+} __packed;
+
+struct prov_start_msg {
+	uint8_t opcode;
+	struct prov_start start;
+} __packed;
+
+struct prov_pub_key_msg {
+	uint8_t opcode;
+	uint8_t pub_key[64];
+} __packed;
+
+struct prov_conf_msg {
+	uint8_t opcode;
+	uint8_t conf[16];
+} __packed;
+
+struct prov_rand_msg {
+	uint8_t opcode;
+	uint8_t rand[16];
+} __packed;
+
+struct prov_data {
+	uint8_t net_key[16];
+	uint16_t net_idx;
+	uint8_t flags;
+	uint32_t iv_index;
+	uint16_t primary;
+} __packed;
+
+struct prov_data_msg {
+	uint8_t opcode;
+	struct prov_data data;
+	uint64_t mic;
+} __packed;
+
+struct prov_fail_msg {
+	uint8_t opcode;
+	uint8_t reason;
+} __packed;
+
 struct conf_input {
 	struct prov_invite		invite;
 	struct mesh_net_prov_caps	caps;
-- 
2.14.5


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

* [PATCH BlueZ v2 9/9] test: This extends the mesh tool to exercise Provisioning methods
  2019-07-11 22:59 [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Brian Gix
                   ` (7 preceding siblings ...)
  2019-07-11 22:59 ` [PATCH BlueZ v2 8/9] mesh: Convert provisioning pkts to packed structs Brian Gix
@ 2019-07-11 22:59 ` Brian Gix
  2019-07-12  8:39 ` [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Michał Lowas-Rzechonek
  2019-07-14 15:47 ` Gix, Brian
  10 siblings, 0 replies; 12+ messages in thread
From: Brian Gix @ 2019-07-11 22:59 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, michal.lowas-rzechonek, brian.gix

Note:  This script is *not* a suitable tool for expanding into
a Mesh Provisioner. It is only intended to demonstrate the arguments
and methods required.
---
 test/test-mesh | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)

diff --git a/test/test-mesh b/test/test-mesh
index 4d515e186..6e9196366 100755
--- a/test/test-mesh
+++ b/test/test-mesh
@@ -24,10 +24,13 @@
 # The main menu:
 #       token
 #       create
+#       scan
+#       add
 #       join
 #       attach
 #       remove
 #       dest
+#       uuid
 #       app-index
 #       client-menu
 #       exit
@@ -50,6 +53,16 @@
 #            for the runtime of the test, and may be used in future
 #            attach requests.
 #
+#     scan
+#            Scan for unprovisioned devices
+#
+#     add
+#            Adds a remote node to a mesh network that we have provisioning
+#            authorization to. The test prompts for a remote devices
+#            UUID, and supplies an Agent that will handle the interaction,
+#            and provide the provisioning data which will complete to
+#            process.
+#
 #     join
 #            Request provisioning of a device to become a node
 #            on a mesh network. The test generates device UUID
@@ -145,9 +158,11 @@ MESH_SERVICE_NAME = 'org.bluez.mesh'
 DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
 DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
 
+MESH_MGR_IFACE = 'org.bluez.mesh.Management1'
 MESH_NETWORK_IFACE = 'org.bluez.mesh.Network1'
 MESH_NODE_IFACE = 'org.bluez.mesh.Node1'
 MESH_APPLICATION_IFACE = 'org.bluez.mesh.Application1'
+MESH_PROV_IFACE = 'org.bluez.mesh.Provisioner1'
 MESH_ELEMENT_IFACE = 'org.bluez.mesh.Element1'
 
 APP_COMPANY_ID = 0x05f1
@@ -160,6 +175,7 @@ app = None
 bus = None
 mainloop = None
 node = None
+node_mgr = None
 mesh_net = None
 
 dst_addr = 0x0000
@@ -170,6 +186,10 @@ token = None
 have_token = False
 attached = False
 
+# Remote device UUID
+have_uuid = False
+remote_uuid = None
+
 # Menu housekeeping
 MAIN_MENU = 0
 ON_OFF_CLIENT_MENU = 1
@@ -179,6 +199,7 @@ INPUT_TOKEN = 1
 INPUT_DEST_ADDRESS = 2
 INPUT_APP_KEY_INDEX = 3
 INPUT_MESSAGE_PAYLOAD = 4
+INPUT_UUID = 5
 
 menus = []
 current_menu = None
@@ -226,6 +247,17 @@ def set_token(str_value):
 	token = numpy.uint64(input_number)
 	have_token = True
 
+def set_uuid(str_value):
+	global remote_uuid
+	global have_uuid
+
+	if len(str_value) != 32:
+		raise_error('Expected 32 digits')
+		return
+
+	remote_uuid = bytearray.fromhex(str_value)
+	have_uuid = True
+
 def array_to_string(b_array):
 	str_value = ""
 	for b in b_array:
@@ -248,6 +280,18 @@ def attach(token):
 					reply_handler=attach_app_cb,
 					error_handler=attach_app_error_cb)
 
+def scan_cb():
+	print('Scan procedure started')
+
+def scan_error_cb(reason):
+	print('Scan procedure failed ', reason)
+
+def add_cb():
+	print('AddNode procedure started')
+
+def add_error_cb(reason):
+	print('AddNode procedure failed ', reason)
+
 def join_cb():
 	print('Join procedure started')
 
@@ -306,6 +350,9 @@ def attach_app_cb(node_path, dict_array):
 
 	obj = bus.get_object(MESH_SERVICE_NAME, node_path)
 
+	global node_mgr
+	node_mgr = dbus.Interface(obj, MESH_MGR_IFACE)
+
 	global node
 	node = dbus.Interface(obj, MESH_NODE_IFACE)
 
@@ -392,6 +439,8 @@ class Application(dbus.service.Object):
 				'CompanyID': dbus.UInt16(APP_COMPANY_ID),
 				'ProductID': dbus.UInt16(APP_PRODUCT_ID),
 				'VersionID': dbus.UInt16(APP_VERSION_ID)
+			},
+			MESH_PROV_IFACE: {
 			}
 		}
 
@@ -424,6 +473,35 @@ class Application(dbus.service.Object):
 	def JoinFailed(self, value):
 		print(set_error('JoinFailed '), value)
 
+	@dbus.service.method(MESH_PROV_IFACE,
+					in_signature="nay", out_signature="")
+	def ScanResult(self, rssi, uuid):
+		uuid_str = array_to_string(uuid)
+		print(set_yellow('ScanResult RSSI ')
+					+ set_green(format(rssi, 'd'))
+					+ ' ' + uuid_str)
+
+	@dbus.service.method(MESH_PROV_IFACE,
+					in_signature="y", out_signature="qq")
+	def RequestProvData(self, count):
+		print('RequestProvData for Ele_Cnt '
+					+ set_green(format(count, 'd')))
+		return dbus.Struct((dbus.UInt16(0), dbus.UInt16(678)))
+
+	@dbus.service.method(MESH_PROV_IFACE,
+					in_signature="ayqy", out_signature="")
+	def AddNodeComplete(self, uuid, unicast, count):
+		uuid_str = array_to_string(uuid)
+		print(set_yellow('AddNodeComplete of node ')
+					+ set_green(format(unicast, '04x'))
+					+ ' uuid ' + uuid_str)
+
+	@dbus.service.method(MESH_PROV_IFACE,
+					in_signature="ays", out_signature="")
+
+	def AddNodeFailed(self, uuid, value):
+		print(set_error('AddNodeFailed '), value)
+
 
 class Element(dbus.service.Object):
 	PATH_BASE = '/example/ele'
@@ -768,6 +846,10 @@ class MainMenu(Menu):
 						self.__cmd_set_token),
 			'create': MenuItem(' - create mesh network',
 						self.__cmd_create),
+			'scan': MenuItem(' - scan for near unprovisioned devs',
+						self.__cmd_scan),
+			'add': MenuItem(' - add device to mesh network',
+						self.__cmd_add),
 			'join': MenuItem(' - join mesh network',
 						self.__cmd_join),
 			'attach': MenuItem(' - attach mesh node',
@@ -776,6 +858,8 @@ class MainMenu(Menu):
 						self.__cmd_remove),
 			'dest': MenuItem(' - set destination address',
 						self.__cmd_set_dest),
+			'uuid': MenuItem(' - set remote uuid',
+						self.__cmd_set_uuid),
 			'app-index': MenuItem(' - set AppKey index',
 						self.__cmd_set_app_idx),
 			'vendor-send': MenuItem(' - send raw vendor message',
@@ -809,6 +893,12 @@ class MainMenu(Menu):
 		user_input = INPUT_DEST_ADDRESS
 		print(set_cyan('Enter 4-digit hex destination address:'))
 
+	def __cmd_set_uuid(self):
+		global user_input
+
+		user_input = INPUT_UUID
+		print(set_cyan('Enter 32-digit hex remote UUID:'))
+
 	def __cmd_set_app_idx(self):
 		global user_input
 
@@ -851,6 +941,26 @@ class MainMenu(Menu):
 			reply_handler=join_cb,
 			error_handler=join_error_cb)
 
+	def __cmd_scan(self):
+
+		print(set_yellow('Scanning...'))
+		node_mgr.UnprovisionedScan(0, reply_handler=add_cb,
+						error_handler=add_error_cb)
+
+	def __cmd_add(self):
+		global user_input
+		if agent == None:
+			print(set_error('Provisioning agent not found'))
+			return
+
+		uuid_str = array_to_string(remote_uuid)
+		caps = ["in-numeric"]
+		oob = ["other"]
+
+		print(set_yellow('Adding dev UUID ') + set_green(uuid_str))
+		node_mgr.AddNode(remote_uuid, reply_handler=add_cb,
+						error_handler=add_error_cb)
+
 	def __cmd_attach(self):
 		if have_token == False:
 			print(set_error('Token is not set'))
@@ -887,6 +997,8 @@ class MainMenu(Menu):
 
 		if user_input == INPUT_TOKEN:
 			set_token(str_value)
+		elif user_input == INPUT_UUID:
+			set_uuid(str_value)
 		elif user_input == INPUT_DEST_ADDRESS:
 			res = set_value(str_value, 4, 4)
 			if is_error() != True:
@@ -977,6 +1089,7 @@ def main():
 	mesh_net = dbus.Interface(bus.get_object(MESH_SERVICE_NAME,
 						"/org/bluez/mesh"),
 						MESH_NETWORK_IFACE)
+
 	mesh_net.connect_to_signal('InterfacesRemoved', interfaces_removed_cb)
 
 	app = Application(bus)
-- 
2.14.5


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

* Re: [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added
  2019-07-11 22:59 [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Brian Gix
                   ` (8 preceding siblings ...)
  2019-07-11 22:59 ` [PATCH BlueZ v2 9/9] test: This extends the mesh tool to exercise Provisioning methods Brian Gix
@ 2019-07-12  8:39 ` Michał Lowas-Rzechonek
  2019-07-14 15:47 ` Gix, Brian
  10 siblings, 0 replies; 12+ messages in thread
From: Michał Lowas-Rzechonek @ 2019-07-12  8:39 UTC (permalink / raw)
  To: Brian Gix; +Cc: linux-bluetooth, inga.stotland

On 07/11, Brian Gix wrote:
> v2 additions:
> * Style guide changes noted by Michal
> * Additional patch to use packed structures for Mesh Spec specifid OTA messages
> 
> The added functionality of this patch set allows any node with a keyring
> provision a new node into the network. It does *not* implement a
> user App that can store a Configuration Database, but it does provide
> extensions to the python test script to test the primitives.
> 
> Brian Gix (9):
>   doc: Cleanup API Provisioner1 interface
>   mesh: Fix support for Provisioner Initiator
>   mesh: Add special Beacon handler for Provisioning
>   mesh: Expose mapping function for D-Bus errors
>   mesh: Expose resources needed by Management1 interface
>   mesh: Fix implementation of Provisioner Initiator
>   mesh: Implement DBus Provisioning methods
>   mesh: Convert provisioning pkts to packed structs
>   test: This extends the mesh tool to exercise Provisioning methods
> 
>  doc/mesh-api.txt       |  13 ++-
>  mesh/crypto.c          |   8 +-
>  mesh/crypto.h          |   8 +-
>  mesh/manager.c         | 304 +++++++++++++++++++++++++++++++++++++++++++++++--
>  mesh/mesh-io-generic.c |   2 +-
>  mesh/mesh-io.c         |   6 +-
>  mesh/mesh-io.h         |   7 +-
>  mesh/mesh.c            |  10 +-
>  mesh/mesh.h            |   4 +-
>  mesh/node.c            |  42 +++++--
>  mesh/node.h            |   3 +
>  mesh/pb-adv.c          | 177 +++++++++++++++++-----------
>  mesh/pb-adv.h          |   3 +-
>  mesh/prov-acceptor.c   | 158 +++++++++++++------------
>  mesh/prov-initiator.c  | 283 +++++++++++++++++++++++++++++++++------------
>  mesh/prov.h            |  51 ++++++++-
>  mesh/provision.h       |  10 +-
>  test/test-mesh         | 113 ++++++++++++++++++
>  18 files changed, 946 insertions(+), 256 deletions(-)

Reviewed-by: Michał Lowas-Rzechonek <michal.lowas-rzechonek@silvair.com>

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

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

* Re: [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added
  2019-07-11 22:59 [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Brian Gix
                   ` (9 preceding siblings ...)
  2019-07-12  8:39 ` [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Michał Lowas-Rzechonek
@ 2019-07-14 15:47 ` Gix, Brian
  10 siblings, 0 replies; 12+ messages in thread
From: Gix, Brian @ 2019-07-14 15:47 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: michal.lowas-rzechonek, Stotland, Inga

Applied

On Thu, 2019-07-11 at 15:59 -0700, Brian Gix wrote:
> v2 additions:
> * Style guide changes noted by Michal
> * Additional patch to use packed structures for Mesh Spec specifid OTA messages
> 
> The added functionality of this patch set allows any node with a keyring
> provision a new node into the network. It does *not* implement a
> user App that can store a Configuration Database, but it does provide
> extensions to the python test script to test the primitives.
> 
> Brian Gix (9):
>   doc: Cleanup API Provisioner1 interface
>   mesh: Fix support for Provisioner Initiator
>   mesh: Add special Beacon handler for Provisioning
>   mesh: Expose mapping function for D-Bus errors
>   mesh: Expose resources needed by Management1 interface
>   mesh: Fix implementation of Provisioner Initiator
>   mesh: Implement DBus Provisioning methods
>   mesh: Convert provisioning pkts to packed structs
>   test: This extends the mesh tool to exercise Provisioning methods
> 
>  doc/mesh-api.txt       |  13 ++-
>  mesh/crypto.c          |   8 +-
>  mesh/crypto.h          |   8 +-
>  mesh/manager.c         | 304 +++++++++++++++++++++++++++++++++++++++++++++++--
>  mesh/mesh-io-generic.c |   2 +-
>  mesh/mesh-io.c         |   6 +-
>  mesh/mesh-io.h         |   7 +-
>  mesh/mesh.c            |  10 +-
>  mesh/mesh.h            |   4 +-
>  mesh/node.c            |  42 +++++--
>  mesh/node.h            |   3 +
>  mesh/pb-adv.c          | 177 +++++++++++++++++-----------
>  mesh/pb-adv.h          |   3 +-
>  mesh/prov-acceptor.c   | 158 +++++++++++++------------
>  mesh/prov-initiator.c  | 283 +++++++++++++++++++++++++++++++++------------
>  mesh/prov.h            |  51 ++++++++-
>  mesh/provision.h       |  10 +-
>  test/test-mesh         | 113 ++++++++++++++++++
>  18 files changed, 946 insertions(+), 256 deletions(-)
> 

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

end of thread, other threads:[~2019-07-14 15:47 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-11 22:59 [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 1/9] doc: Cleanup API Provisioner1 interface Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 2/9] mesh: Fix support for Provisioner Initiator Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 3/9] mesh: Add special Beacon handler for Provisioning Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 4/9] mesh: Expose mapping function for D-Bus errors Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 5/9] mesh: Expose resources needed by Management1 interface Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 6/9] mesh: Fix implementation of Provisioner Initiator Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 7/9] mesh: Implement DBus Provisioning methods Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 8/9] mesh: Convert provisioning pkts to packed structs Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 9/9] test: This extends the mesh tool to exercise Provisioning methods Brian Gix
2019-07-12  8:39 ` [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Michał Lowas-Rzechonek
2019-07-14 15:47 ` 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).