ble_mesh: update protocol error timeout from zephyr
This commit is contained in:
parent
716db01a7f
commit
630e911958
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue