diff --git a/components/bt/esp_ble_mesh/mesh_core/prov.c b/components/bt/esp_ble_mesh/mesh_core/prov.c index 0a3329ff65..4a9572328a 100644 --- a/components/bt/esp_ble_mesh/mesh_core/prov.c +++ b/components/bt/esp_ble_mesh/mesh_core/prov.c @@ -105,7 +105,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 */ - TIMEOUT_START, /* Provision timeout timer has started */ + LINK_INVALID, /* Error occurred during provisioning */ NUM_FLAGS, }; @@ -161,8 +161,7 @@ struct prov_link { } tx; #endif - /* Provision timeout timer */ - struct k_delayed_work timeout; + struct k_delayed_work prot_timer; }; struct prov_rx { @@ -176,11 +175,11 @@ struct prov_rx { #if defined(CONFIG_BLE_MESH_FAST_PROV) #define RETRANSMIT_TIMEOUT K_MSEC(360) #define TRANSACTION_TIMEOUT K_SECONDS(3) -#define PROVISION_TIMEOUT K_SECONDS(6) +#define PROTOCOL_TIMEOUT K_SECONDS(6) #else #define RETRANSMIT_TIMEOUT K_MSEC(500) #define TRANSACTION_TIMEOUT K_SECONDS(30) -#define PROVISION_TIMEOUT K_SECONDS(60) +#define PROTOCOL_TIMEOUT K_SECONDS(60) #endif /* CONFIG_BLE_MESH_FAST_PROV */ #if defined(CONFIG_BLE_MESH_PB_GATT) @@ -197,10 +196,10 @@ static struct prov_link link; static const struct bt_mesh_prov *prov; -static void close_link(u8_t err, u8_t reason); - static void reset_state(void) { + k_delayed_work_cancel(&link.prot_timer); + /* Disable Attention Timer if it was set */ if (link.conf_inputs[0]) { bt_mesh_attention(NULL, 0); @@ -213,7 +212,9 @@ static void reset_state(void) #endif #if defined(CONFIG_BLE_MESH_PB_ADV) - /* Clear everything except the retransmit delayed work config */ + /* Clear everything except the retransmit and protocol timer + * delayed work objects. + */ (void)memset(&link, 0, offsetof(struct prov_link, tx.retransmit)); link.rx.prev_id = XACT_NVAL; @@ -224,8 +225,9 @@ static void reset_state(void) link.rx.buf = &rx_buf; #endif /* PB_GATT */ -#else - (void)memset(&link, 0, offsetof(struct prov_link, timeout)); +#else /* !PB_ADV */ + /* Clear everything except the protocol timer (k_delayed_work) */ + (void)memset(&link, 0, offsetof(struct prov_link, prot_timer)); #endif /* PB_ADV */ } @@ -280,10 +282,6 @@ static void reset_link(void) { prov_clear_tx(); - if (bt_mesh_atomic_test_and_clear_bit(link.flags, TIMEOUT_START)) { - k_delayed_work_cancel(&link.timeout); - } - if (prov->link_close) { prov->link_close(BLE_MESH_PROV_ADV); } @@ -425,7 +423,7 @@ static int prov_send_adv(struct net_buf_simple *msg) struct net_buf *start, *buf; u8_t seg_len, seg_id; u8_t xact_id; - s32_t timeout = PROVISION_TIMEOUT; + s32_t timeout = PROTOCOL_TIMEOUT; BT_DBG("%s, len %u: %s", __func__, msg->len, bt_hex(msg->data, msg->len)); @@ -486,17 +484,12 @@ static int prov_send_adv(struct net_buf_simple *msg) /* Changed by Espressif, add provisioning timeout timer operations. * When sending a provisioning PDU successfully, restart the 60s timer. */ - if (bt_mesh_atomic_test_and_clear_bit(link.flags, TIMEOUT_START)) { - k_delayed_work_cancel(&link.timeout); - } #if defined(CONFIG_BLE_MESH_FAST_PROV) if (link.tx_pdu_type >= PROV_COMPLETE) { timeout = K_SECONDS(60); } #endif - if (!bt_mesh_atomic_test_and_set_bit(link.flags, TIMEOUT_START)) { - k_delayed_work_submit(&link.timeout, timeout); - } + k_delayed_work_submit(&link.prot_timer, timeout); return 0; } @@ -521,14 +514,7 @@ static int prov_send_gatt(struct net_buf_simple *msg) return err; } - if (bt_mesh_atomic_test_and_clear_bit(link.flags, TIMEOUT_START)) { - k_delayed_work_cancel(&link.timeout); - } - if (msg->data[1] != PROV_COMPLETE && msg->data[1] != PROV_FAILED) { - if (!bt_mesh_atomic_test_and_set_bit(link.flags, TIMEOUT_START)) { - k_delayed_work_submit(&link.timeout, PROVISION_TIMEOUT); - } - } + k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); return 0; } @@ -561,6 +547,8 @@ static void prov_send_fail_msg(u8_t err) prov_buf_init(&buf, PROV_FAILED); net_buf_simple_add_u8(&buf, err); prov_send(&buf); + + bt_mesh_atomic_set_bit(link.flags, LINK_INVALID); } static void prov_invite(const u8_t *data) @@ -605,7 +593,7 @@ static void prov_invite(const u8_t *data) if (prov_send(&buf)) { BT_ERR("%s, Failed to send capabilities", __func__); - close_link(PROV_ERR_RESOURCES, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_RESOURCES); return; } @@ -821,7 +809,7 @@ static void send_confirm(void) if (bt_mesh_prov_conf_salt(link.conf_inputs, link.conf_salt)) { BT_ERR("%s, Unable to generate confirmation salt", __func__); - close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_UNEXP_ERR); return; } @@ -829,7 +817,7 @@ static void send_confirm(void) if (bt_mesh_prov_conf_key(link.dhkey, link.conf_salt, link.conf_key)) { BT_ERR("%s, Unable to generate confirmation key", __func__); - close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_UNEXP_ERR); return; } @@ -837,7 +825,7 @@ static void send_confirm(void) if (bt_mesh_rand(link.rand, 16)) { BT_ERR("%s, Unable to generate random number", __func__); - close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_UNEXP_ERR); return; } @@ -848,13 +836,13 @@ 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("%s, Unable to generate confirmation value", __func__); - close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_UNEXP_ERR); return; } if (prov_send(&cfm)) { BT_ERR("%s, Unable to send Provisioning Confirm", __func__); - close_link(PROV_ERR_RESOURCES, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_RESOURCES); return; } @@ -921,7 +909,7 @@ static void prov_dh_key_cb(const u8_t key[32], const u8_t idx) if (!key) { BT_ERR("%s, DHKey generation failed", __func__); - close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_UNEXP_ERR); return; } @@ -949,7 +937,7 @@ static void send_pub_key(void) key = bt_mesh_pub_key_get(); if (!key) { BT_ERR("%s, No public key available", __func__); - close_link(PROV_ERR_RESOURCES, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_UNEXP_ERR); return; } @@ -974,7 +962,7 @@ static void send_pub_key(void) if (bt_mesh_dh_key_gen(buf.data, prov_dh_key_cb, 0)) { BT_ERR("%s, Unable to generate DHKey", __func__); - close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_UNEXP_ERR); return; } @@ -994,7 +982,7 @@ static int bt_mesh_calc_dh_key(void) if (bt_mesh_dh_key_gen(buf.data, prov_dh_key_cb, 0)) { BT_ERR("%s, Unable to generate DHKey", __func__); - close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_UNEXP_ERR); return -EIO; } @@ -1096,7 +1084,7 @@ static void prov_random(const u8_t *data) if (bt_mesh_prov_conf(link.conf_key, data, link.auth, conf_verify)) { BT_ERR("%s, Unable to calculate confirmation verification", __func__); - close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_UNEXP_ERR); return; } @@ -1104,7 +1092,7 @@ static void prov_random(const u8_t *data) BT_ERR("%s, Invalid confirmation value", __func__); 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); return; } @@ -1113,14 +1101,14 @@ static void prov_random(const u8_t *data) if (prov_send(&rnd)) { BT_ERR("%s, Failed to send Provisioning Random", __func__); - close_link(PROV_ERR_RESOURCES, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_RESOURCES); return; } if (bt_mesh_prov_salt(link.conf_salt, data, link.rand, link.prov_salt)) { BT_ERR("%s, Failed to generate provisioning salt", __func__); - close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_UNEXP_ERR); return; } @@ -1157,7 +1145,7 @@ static void prov_data(const u8_t *data) err = bt_mesh_session_key(link.dhkey, link.prov_salt, session_key); if (err) { BT_ERR("%s, Unable to generate session key", __func__); - close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_UNEXP_ERR); return; } @@ -1166,7 +1154,7 @@ static void prov_data(const u8_t *data) err = bt_mesh_prov_nonce(link.dhkey, link.prov_salt, nonce); if (err) { BT_ERR("%s, Unable to generate session nonce", __func__); - close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_UNEXP_ERR); return; } @@ -1175,14 +1163,14 @@ static void prov_data(const u8_t *data) err = bt_mesh_prov_decrypt(session_key, nonce, data, pdu); if (err) { BT_ERR("%s, Unable to decrypt provisioning data", __func__); - close_link(PROV_ERR_DECRYPT, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_DECRYPT); return; } err = bt_mesh_dev_key(link.dhkey, link.prov_salt, dev_key); if (err) { BT_ERR("%s, Unable to generate device key", __func__); - close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_UNEXP_ERR); return; } @@ -1249,35 +1237,6 @@ static const struct { { prov_failed, 1 }, }; -static void close_link(u8_t err, u8_t reason) -{ -#if defined(CONFIG_BLE_MESH_PB_GATT) - if (link.conn) { - bt_mesh_pb_gatt_close(link.conn); - return; - } -#endif - -#if defined(CONFIG_BLE_MESH_PB_ADV) - if (err) { - prov_send_fail_msg(err); - } - - link.rx.seg = 0U; - bearer_ctl_send(LINK_CLOSE, &reason, sizeof(reason)); -#endif - - reset_state(); -} - -/* Changed by Espressif, add provisioning timeout timer callback */ -static void prov_timeout(struct k_work *work) -{ - BT_DBG("%s", __func__); - - close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_TIMEOUT); -} - #if defined(CONFIG_BLE_MESH_PB_ADV) static void prov_retransmit(struct k_work *work) { @@ -1425,6 +1384,12 @@ static void prov_msg_recv(void) link.rx.prev_id = link.rx.id; link.rx.id = 0U; + if (bt_mesh_atomic_test_bit(link.flags, LINK_INVALID)) { + BT_WARN("Unexpected msg 0x%02x on invalidated link", type); + 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); @@ -1433,26 +1398,21 @@ static void prov_msg_recv(void) if (type >= ARRAY_SIZE(prov_handlers)) { BT_ERR("%s, Unknown provisioning PDU type 0x%02x", __func__, type); - close_link(PROV_ERR_NVAL_PDU, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_NVAL_PDU); return; } if (1 + prov_handlers[type].len != link.rx.buf->len) { BT_ERR("%s, Invalid length %u for type 0x%02x", __func__, link.rx.buf->len, type); - close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_NVAL_FMT); return; } /* Changed by Espressif, add provisioning timeout timer operations. * When received a provisioning PDU, restart the 60s timer. */ - if (bt_mesh_atomic_test_and_clear_bit(link.flags, TIMEOUT_START)) { - k_delayed_work_cancel(&link.timeout); - } - if (!bt_mesh_atomic_test_and_set_bit(link.flags, TIMEOUT_START)) { - k_delayed_work_submit(&link.timeout, PROVISION_TIMEOUT); - } + k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); prov_handlers[type].func(&link.rx.buf->data[1]); } @@ -1485,7 +1445,7 @@ static void gen_prov_cont(struct prov_rx *rx, struct net_buf_simple *buf) if (seg > link.rx.last_seg) { BT_ERR("%s, Invalid segment index %u", __func__, seg); - close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_NVAL_FMT); return; } else if (seg == link.rx.last_seg) { u8_t expect_len; @@ -1495,7 +1455,7 @@ static void gen_prov_cont(struct prov_rx *rx, struct net_buf_simple *buf) if (expect_len != buf->len) { BT_ERR("%s, Incorrect last seg len: %u != %u", __func__, expect_len, buf->len); - close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_NVAL_FMT); return; } } @@ -1548,20 +1508,20 @@ static void gen_prov_start(struct prov_rx *rx, struct net_buf_simple *buf) if (link.rx.buf->len < 1) { BT_ERR("%s, Ignoring zero-length provisioning PDU", __func__); - close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_NVAL_FMT); return; } if (link.rx.buf->len > link.rx.buf->size) { BT_ERR("%s, Too large provisioning PDU (%u bytes)", __func__, link.rx.buf->len); - // close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED); + // prov_send_fail_msg(PROV_ERR_NVAL_FMT); return; } if (START_LAST_SEG(rx->gpc) > 0 && link.rx.buf->len <= 20U) { BT_ERR("%s, Too small total length for multi-segment PDU", __func__); - close_link(PROV_ERR_NVAL_FMT, CLOSE_REASON_FAILED); + prov_send_fail_msg(PROV_ERR_NVAL_FMT); return; } @@ -1668,12 +1628,7 @@ int bt_mesh_pb_gatt_recv(struct bt_mesh_conn *conn, struct net_buf_simple *buf) /* Changed by Espressif, add provisioning timeout timer operations. * When received a provisioning PDU, restart the 60s timer. */ - if (bt_mesh_atomic_test_and_clear_bit(link.flags, TIMEOUT_START)) { - k_delayed_work_cancel(&link.timeout); - } - if (!bt_mesh_atomic_test_and_set_bit(link.flags, TIMEOUT_START)) { - k_delayed_work_submit(&link.timeout, PROVISION_TIMEOUT); - } + k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); prov_handlers[type].func(buf->data); @@ -1727,6 +1682,27 @@ bool bt_prov_active(void) return bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE); } +static void protocol_timeout(struct k_work *work) +{ + BT_DBG("Protocol timeout"); + +#if defined(CONFIG_BLE_MESH_PB_GATT) + if (link.conn) { + bt_mesh_pb_gatt_close(link.conn); + return; + } +#endif + +#if defined(CONFIG_BLE_MESH_PB_ADV) + u8_t reason = CLOSE_REASON_TIMEOUT; + + link.rx.seg = 0U; + bearer_ctl_send(LINK_CLOSE, &reason, sizeof(reason)); + + reset_state(); +#endif +} + int bt_mesh_prov_init(const struct bt_mesh_prov *prov_info) { const u8_t *key = NULL; @@ -1743,15 +1719,14 @@ int bt_mesh_prov_init(const struct bt_mesh_prov *prov_info) return -EIO; } + k_delayed_work_init(&link.prot_timer, protocol_timeout); + prov = prov_info; #if defined(CONFIG_BLE_MESH_PB_ADV) k_delayed_work_init(&link.tx.retransmit, prov_retransmit); #endif - /* Changed by Espressif, add provisioning timeout timer init */ - k_delayed_work_init(&link.timeout, prov_timeout); - reset_state(); return 0;