You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by na...@apache.org on 2019/06/25 10:14:43 UTC

[mynewt-nimble] 01/02: nimble/mesh: Fix provisioning errors handling

This is an automated email from the ASF dual-hosted git repository.

naraj pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git

commit bc67ee39665807f1c26fff5358ce5f694626d4cb
Author: Szymon Czapracki <sz...@gmail.com>
AuthorDate: Fri Jun 14 14:30:01 2019 +0200

    nimble/mesh: Fix provisioning errors handling
    
    Provisioning errors won't cause device to close link.
    Upon error, device will send Provisioning Failed PDU, and any further
    PDU's will be considered as unexpected. (Mesh Pofile section 5.4.4)
    
    Also a timer starts every time device sends a correct PDU.
    This affects MESH/NODE/PROV/BV-10-C test case.
---
 nimble/host/mesh/src/prov.c | 100 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 75 insertions(+), 25 deletions(-)

diff --git a/nimble/host/mesh/src/prov.c b/nimble/host/mesh/src/prov.c
index af44e4a..056186a 100644
--- a/nimble/host/mesh/src/prov.c
+++ b/nimble/host/mesh/src/prov.c
@@ -104,6 +104,7 @@ enum {
 	SEND_CONFIRM,          /* Waiting to send Confirm value */
 	WAIT_NUMBER,           /* Waiting for number input from user */
 	WAIT_STRING,           /* Waiting for string input from user */
+	LINK_INVALID,          /* Error occured during provisioning */
 
 	NUM_FLAGS,
 };
@@ -166,6 +167,7 @@ struct prov_rx {
 #define RETRANSMIT_TIMEOUT   K_MSEC(500)
 #define BUF_TIMEOUT          K_MSEC(400)
 #define TRANSACTION_TIMEOUT  K_SECONDS(30)
+#define PROTOCOL_TIMEOUT     K_SECONDS(60)
 
 #if (MYNEWT_VAL(BLE_MESH_PB_GATT))
 #define PROV_BUF_HEADROOM 5
@@ -177,7 +179,7 @@ static struct os_mbuf *rx_buf;
 #define PROV_BUF(len) NET_BUF_SIMPLE(PROV_BUF_HEADROOM + len)
 
 static struct prov_link link;
-
+static struct k_delayed_work prot_timer;
 static const struct bt_mesh_prov *prov;
 
 static void close_link(u8_t err, u8_t reason);
@@ -228,6 +230,8 @@ static void prov_clear_tx(void)
 static void reset_link(void)
 {
 	atomic_clear_bit(link.flags, LINK_ACTIVE);
+	atomic_clear_bit(link.flags, LINK_INVALID);
+	k_delayed_work_cancel(&prot_timer);
 
 	prov_clear_tx();
 
@@ -462,6 +466,8 @@ static int prov_send_gatt(struct os_mbuf *msg)
 
 static inline int prov_send(struct os_mbuf *buf)
 {
+    k_delayed_work_submit(&prot_timer, PROTOCOL_TIMEOUT);
+
 #if (MYNEWT_VAL(BLE_MESH_PB_GATT))
 	if (link.conn_handle != BLE_HS_CONN_HANDLE_NONE) {
 		return prov_send_gatt(buf);
@@ -533,7 +539,8 @@ static void prov_invite(const u8_t *data)
 
 	if (prov_send(buf)) {
 		BT_ERR("Failed to send capabilities");
-		close_link(PROV_ERR_RESOURCES, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_RESOURCES);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		goto done;
 	}
 
@@ -709,12 +716,14 @@ static void prov_start(const u8_t *data)
 	if (data[0] != PROV_ALG_P256) {
 		BT_ERR("Unknown algorithm 0x%02x", data[0]);
 		prov_send_fail_msg(PROV_ERR_NVAL_FMT);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		return;
 	}
 
 	if (data[1] > 0x01) {
 		BT_ERR("Invalid public key value: 0x%02x", data[1]);
 		prov_send_fail_msg(PROV_ERR_NVAL_FMT);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		return;
 	}
 
@@ -728,6 +737,7 @@ static void prov_start(const u8_t *data)
 			"action: 0x%02x; size: 0x%02x", data[2], data[3],
 			data[4]);
 		prov_send_fail_msg(PROV_ERR_NVAL_FMT);
+		atomic_set_bit(link.flags, LINK_INVALID);
 	}
 }
 
@@ -741,7 +751,8 @@ static void send_confirm(void)
 
 	if (bt_mesh_prov_conf_salt(link.conf_inputs, link.conf_salt)) {
 		BT_ERR("Unable to generate confirmation salt");
-		close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		goto done;
 	}
 
@@ -749,7 +760,8 @@ static void send_confirm(void)
 
 	if (bt_mesh_prov_conf_key(link.dhkey, link.conf_salt, link.conf_key)) {
 		BT_ERR("Unable to generate confirmation key");
-		close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		goto done;
 	}
 
@@ -757,7 +769,8 @@ static void send_confirm(void)
 
 	if (bt_rand(link.rand, 16)) {
 		BT_ERR("Unable to generate random number");
-		close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		goto done;
 	}
 
@@ -768,13 +781,15 @@ static void send_confirm(void)
 	if (bt_mesh_prov_conf(link.conf_key, link.rand, link.auth,
 			      net_buf_simple_add(cfm, 16))) {
 		BT_ERR("Unable to generate confirmation value");
-		close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		goto done;
 	}
 
 	if (prov_send(cfm)) {
 		BT_ERR("Failed to send Provisioning Confirm");
-		close_link(PROV_ERR_RESOURCES, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_RESOURCES);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		goto done;
 	}
 
@@ -846,7 +861,8 @@ static void prov_dh_key_cb(const u8_t key[32])
 
 	if (!key) {
 		BT_ERR("DHKey generation failed");
-		close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		return;
 	}
 
@@ -874,7 +890,8 @@ static void send_pub_key(void)
 	key = bt_pub_key_get();
 	if (!key) {
 		BT_ERR("No public key available");
-		close_link(PROV_ERR_RESOURCES, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_RESOURCES);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		goto done;
 	}
 
@@ -899,7 +916,8 @@ static void send_pub_key(void)
 
 	if (bt_dh_key_gen(buf->om_data, prov_dh_key_cb)) {
 		BT_ERR("Failed to generate DHKey");
-		close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		goto done;
 	}
 
@@ -974,7 +992,8 @@ static void prov_random(const u8_t *data)
 
 	if (bt_mesh_prov_conf(link.conf_key, data, link.auth, conf_verify)) {
 		BT_ERR("Unable to calculate confirmation verification");
-		close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		goto done;
 	}
 
@@ -982,7 +1001,8 @@ static void prov_random(const u8_t *data)
 		BT_ERR("Invalid confirmation value");
 		BT_DBG("Received:   %s", bt_hex(link.conf, 16));
 		BT_DBG("Calculated: %s",  bt_hex(conf_verify, 16));
-		close_link(PROV_ERR_CFM_FAILED, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_CFM_FAILED);
+		atomic_set_bit(link.flags ,LINK_INVALID);
 		goto done;
 	}
 
@@ -991,14 +1011,16 @@ static void prov_random(const u8_t *data)
 
 	if (prov_send(rnd)) {
 		BT_ERR("Failed to send Provisioning Random");
-		close_link(PROV_ERR_RESOURCES, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_RESOURCES);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		goto done;
 	}
 
 	if (bt_mesh_prov_salt(link.conf_salt, data, link.rand,
 			      link.prov_salt)) {
 		BT_ERR("Failed to generate provisioning salt");
-		close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		goto done;
 	}
 
@@ -1038,7 +1060,8 @@ static void prov_data(const u8_t *data)
 	err = bt_mesh_session_key(link.dhkey, link.prov_salt, session_key);
 	if (err) {
 		BT_ERR("Unable to generate session key");
-		close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		goto done;
 	}
 
@@ -1047,7 +1070,8 @@ static void prov_data(const u8_t *data)
 	err = bt_mesh_prov_nonce(link.dhkey, link.prov_salt, nonce);
 	if (err) {
 		BT_ERR("Unable to generate session nonce");
-		close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		goto done;
 	}
 
@@ -1056,14 +1080,16 @@ static void prov_data(const u8_t *data)
 	err = bt_mesh_prov_decrypt(session_key, nonce, data, pdu);
 	if (err) {
 		BT_ERR("Unable to decrypt provisioning data");
-		close_link(PROV_ERR_DECRYPT, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_DECRYPT);
+		atomic_set_bit(link.flags ,LINK_INVALID);
 		goto done;
 	}
 
 	err = bt_mesh_dev_key(link.dhkey, link.prov_salt, dev_key);
 	if (err) {
 		BT_ERR("Unable to generate device key");
-		close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		goto done;
 	}
 
@@ -1195,6 +1221,12 @@ static void prov_retransmit(struct ble_npl_event *work)
 	}
 }
 
+static void prot_tmo_link_close(struct ble_npl_event *ev)
+{
+    close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
+    reset_link();
+}
+
 static void link_open(struct prov_rx *rx, struct os_mbuf *buf)
 {
 	BT_INFO("link open: len %u", buf->om_len);
@@ -1232,6 +1264,7 @@ static void link_open(struct prov_rx *rx, struct os_mbuf *buf)
 	bearer_ctl_send(LINK_ACK, NULL, 0);
 
 	link.expect = PROV_INVITE;
+
 }
 
 static void link_ack(struct prov_rx *rx, struct os_mbuf *buf)
@@ -1281,6 +1314,7 @@ static void gen_prov_ctl(struct prov_rx *rx, struct os_mbuf *buf)
 
 static void prov_msg_recv(void)
 {
+	k_delayed_work_submit(&prot_timer, PROTOCOL_TIMEOUT);
 	u8_t type = link.rx.buf->om_data[0];
 
 	BT_DBG("type 0x%02x len %u", type, link.rx.buf->om_len);
@@ -1294,22 +1328,31 @@ static void prov_msg_recv(void)
 	link.rx.prev_id = link.rx.id;
 	link.rx.id = 0;
 
+	if (atomic_test_bit(link.flags, LINK_INVALID)) {
+		BT_WARN("Unexpected msg 0x%02x != 0x%02x", type, link.expect);
+		prov_send_fail_msg(PROV_ERR_UNEXP_PDU);
+		return;
+	}
+
 	if (type != PROV_FAILED && type != link.expect) {
 		BT_WARN("Unexpected msg 0x%02x != 0x%02x", type, link.expect);
 		prov_send_fail_msg(PROV_ERR_UNEXP_PDU);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		return;
 	}
 
 	if (type >= ARRAY_SIZE(prov_handlers)) {
 		BT_ERR("Unknown provisioning PDU type 0x%02x", type);
-		close_link(PROV_ERR_NVAL_PDU, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_NVAL_PDU);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		return;
 	}
 
 	if (1 + prov_handlers[type].len != link.rx.buf->om_len) {
 		BT_ERR("Invalid length %u for type 0x%02x",
 		       link.rx.buf->om_len, type);
-		close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_NVAL_FMT);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		return;
 	}
 
@@ -1336,7 +1379,8 @@ static void gen_prov_cont(struct prov_rx *rx, struct os_mbuf *buf)
 
 	if (seg > link.rx.last_seg) {
 		BT_ERR("Invalid segment index %u", seg);
-		close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_NVAL_FMT);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		return;
 	} else if (seg == link.rx.last_seg) {
 		u8_t expect_len;
@@ -1346,7 +1390,8 @@ static void gen_prov_cont(struct prov_rx *rx, struct os_mbuf *buf)
 		if (expect_len != buf->om_len) {
 			BT_ERR("Incorrect last seg len: %u != %u",
 			       expect_len, buf->om_len);
-			close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED);
+			prov_send_fail_msg(PROV_ERR_NVAL_FMT);
+			atomic_set_bit(link.flags, LINK_INVALID);
 			return;
 		}
 	}
@@ -1403,20 +1448,23 @@ static void gen_prov_start(struct prov_rx *rx, struct os_mbuf *buf)
 
 	if (link.rx.buf->om_len < 1) {
 		BT_ERR("Ignoring zero-length provisioning PDU");
-		close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_NVAL_FMT);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		return;
 	}
 
 	if (link.rx.buf->om_len > trailing_space) {
 		BT_ERR("Too large provisioning PDU (%u bytes)",
 		       link.rx.buf->om_len);
-		close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_NVAL_FMT);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		return;
 	}
 
 	if (START_LAST_SEG(rx->gpc) > 0 && link.rx.buf->om_len <= 20) {
 		BT_ERR("Too small total length for multi-segment PDU");
-		close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED);
+		prov_send_fail_msg(PROV_ERR_NVAL_FMT);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		return;
 	}
 
@@ -1508,6 +1556,7 @@ int bt_mesh_pb_gatt_recv(uint16_t conn_handle, struct os_mbuf *buf)
 	if (type != PROV_FAILED && type != link.expect) {
 		BT_WARN("Unexpected msg 0x%02x != 0x%02x", type, link.expect);
 		prov_send_fail_msg(PROV_ERR_UNEXP_PDU);
+		atomic_set_bit(link.flags, LINK_INVALID);
 		return -EINVAL;
 	}
 
@@ -1588,6 +1637,7 @@ bool bt_prov_active(void)
 
 int bt_mesh_prov_init(const struct bt_mesh_prov *prov_info)
 {
+	k_delayed_work_init(&prot_timer, prot_tmo_link_close);
 	static struct bt_pub_key_cb pub_key_cb = {
 		.func = pub_key_ready,
 	};